2 * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <sys/param.h>
18 #include <sys/types.h>
20 #include <sys/exec_elf.h>
39 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
42 #define SUNW_CTF ".SUNW_ctf"
44 #define DUMP_OBJECT (1 << 0)
45 #define DUMP_FUNCTION (1 << 1)
46 #define DUMP_HEADER (1 << 2)
47 #define DUMP_LABEL (1 << 3)
48 #define DUMP_STRTAB (1 << 4)
49 #define DUMP_STATISTIC (1 << 5)
50 #define DUMP_TYPE (1 << 6)
52 int dump(const char *, uint8_t);
53 int isctf(const char *, size_t);
54 __dead void usage(void);
56 int ctf_dump(const char *, size_t, uint8_t);
57 unsigned int ctf_dump_type(struct ctf_header *, const char *, off_t,
58 unsigned int, unsigned int);
59 const char *ctf_kind2name(unsigned short);
60 const char *ctf_off2name(struct ctf_header *, const char *, off_t,
63 int elf_dump(const char *, size_t, uint8_t);
64 const char *elf_idx2sym(size_t *, unsigned char);
67 int iself(const char *, size_t);
68 int elf_getshstrtab(const char *, size_t, const char **, size_t *);
69 int elf_getsymtab(const char *, const char *, size_t,
70 const Elf_Sym **, size_t *);
71 int elf_getsection(const char *, const char *, const char *,
72 size_t, const char **, size_t *);
75 char *decompress(const char *, size_t, off_t);
79 main(int argc, char *argv[])
85 setlocale(LC_ALL, "");
87 while ((ch = getopt(argc, argv, "dfhlst")) != -1) {
93 flags |= DUMP_FUNCTION;
102 flags |= DUMP_STRTAB;
115 /* Dump everything by default */
119 while ((filename = *argv++) != NULL)
120 error |= dump(filename, flags);
126 dump(const char *path, uint8_t flags)
132 fd = open(path, O_RDONLY);
137 if (fstat(fd, &st) == -1) {
141 if (st.st_size < (off_t)sizeof(struct ctf_header)) {
142 warnx("file too small to be CTF");
145 if ((uintmax_t)st.st_size > SIZE_MAX) {
146 warnx("file too big to fit memory");
150 p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
154 if (iself(p, st.st_size)) {
155 error = elf_dump(p, st.st_size, flags);
156 } else if (isctf(p, st.st_size)) {
157 error = ctf_dump(p, st.st_size, flags);
160 munmap(p, st.st_size);
167 const Elf_Sym *symtab;
168 size_t strtabsize, nsymb;
171 elf_idx2sym(size_t *idx, unsigned char type)
176 for (i = *idx + 1; i < nsymb; i++) {
179 if (ELF_ST_TYPE(st->st_info) != type)
183 return strtab + st->st_name;
190 elf_dump(const char *p, size_t filesize, uint8_t flags)
192 Elf_Ehdr *eh = (Elf_Ehdr *)p;
194 const char *shstrtab;
195 size_t i, shstrtabsize;
197 /* Find section header string table location and size. */
198 if (elf_getshstrtab(p, filesize, &shstrtab, &shstrtabsize))
201 /* Find symbol table location and number of symbols. */
202 if (elf_getsymtab(p, shstrtab, shstrtabsize, &symtab, &nsymb))
203 warnx("symbol table not found");
205 /* Find string table location and size. */
206 if (elf_getsection(p, ELF_STRTAB, shstrtab, shstrtabsize, &strtab, &strtabsize))
207 warnx("string table not found");
209 /* Find CTF section and dump it. */
210 for (i = 0; i < eh->e_shnum; i++) {
211 sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
213 if ((sh->sh_link >= eh->e_shnum) ||
214 (sh->sh_name >= shstrtabsize))
217 if (strncmp(shstrtab + sh->sh_name, SUNW_CTF, strlen(SUNW_CTF)))
220 if (!isctf(p + sh->sh_offset, sh->sh_size))
223 return ctf_dump(p + sh->sh_offset, sh->sh_size, flags);
226 warnx("%s section not found", SUNW_CTF);
231 isctf(const char *p, size_t filesize)
233 struct ctf_header *cth = (struct ctf_header *)p;
234 off_t dlen = cth->cth_stroff + cth->cth_strlen;
236 if (cth->cth_magic != CTF_MAGIC || cth->cth_version != CTF_VERSION)
239 if (dlen > filesize && !(cth->cth_flags & CTF_F_COMPRESS)) {
240 warnx("bogus file size");
244 if ((cth->cth_lbloff & 3) || (cth->cth_objtoff & 1) ||
245 (cth->cth_funcoff & 1) || (cth->cth_typeoff & 3)) {
246 warnx("wrongly aligned offset");
250 if ((cth->cth_lbloff >= dlen) || (cth->cth_objtoff >= dlen) ||
251 (cth->cth_funcoff >= dlen) || (cth->cth_typeoff >= dlen)) {
252 warnx("truncated file");
256 if ((cth->cth_lbloff > cth->cth_objtoff) ||
257 (cth->cth_objtoff > cth->cth_funcoff) ||
258 (cth->cth_funcoff > cth->cth_typeoff) ||
259 (cth->cth_typeoff > cth->cth_stroff)) {
260 warnx("corrupted file");
268 ctf_dump(const char *p, size_t size, uint8_t flags)
270 struct ctf_header *cth = (struct ctf_header *)p;
271 off_t dlen = cth->cth_stroff + cth->cth_strlen;
274 if (cth->cth_flags & CTF_F_COMPRESS) {
275 data = decompress(p + sizeof(*cth), size - sizeof(*cth), dlen);
279 data = (char *)p + sizeof(*cth);
282 if (flags & DUMP_HEADER) {
283 printf(" cth_magic = 0x%04x\n", cth->cth_magic);
284 printf(" cth_version = %d\n", cth->cth_version);
285 printf(" cth_flags = 0x%02x\n", cth->cth_flags);
286 printf(" cth_parlabel = %s\n",
287 ctf_off2name(cth, data, dlen, cth->cth_parname));
288 printf(" cth_parname = %s\n",
289 ctf_off2name(cth, data, dlen, cth->cth_parname));
290 printf(" cth_lbloff = %d\n", cth->cth_lbloff);
291 printf(" cth_objtoff = %d\n", cth->cth_objtoff);
292 printf(" cth_funcoff = %d\n", cth->cth_funcoff);
293 printf(" cth_typeoff = %d\n", cth->cth_typeoff);
294 printf(" cth_stroff = %d\n", cth->cth_stroff);
295 printf(" cth_strlen = %d\n", cth->cth_strlen);
299 if (flags & DUMP_LABEL) {
300 unsigned int lbloff = cth->cth_lbloff;
301 struct ctf_lblent *ctl;
303 while (lbloff < cth->cth_objtoff) {
304 ctl = (struct ctf_lblent *)(data + lbloff);
306 printf(" %5u %s\n", ctl->ctl_typeidx,
307 ctf_off2name(cth, data, dlen, ctl->ctl_label));
309 lbloff += sizeof(*ctl);
314 if (flags & DUMP_OBJECT) {
315 unsigned int objtoff = cth->cth_objtoff;
316 size_t idx = 0, i = 0;
321 while (objtoff < cth->cth_funcoff) {
322 dsp = (unsigned short *)(data + objtoff);
324 l = printf(" [%zu] %u", i++, *dsp);
325 if ((s = elf_idx2sym(&idx, STT_OBJECT)) != NULL)
326 printf("%*s %s (%zu)\n", (15 - l), "", s, idx);
330 objtoff += sizeof(*dsp);
335 if (flags & DUMP_FUNCTION) {
336 unsigned short *fsp, kind, vlen;
337 size_t idx = 0, i = 0;
341 fsp = (unsigned short *)(data + cth->cth_funcoff);
342 while (fsp < (unsigned short *)(data + cth->cth_typeoff)) {
343 kind = CTF_INFO_KIND(*fsp);
344 vlen = CTF_INFO_VLEN(*fsp);
347 if (kind == CTF_K_UNKNOWN && vlen == 0)
350 l = printf(" [%zu]", i++);
351 if ((s = elf_idx2sym(&idx, STT_FUNC)) != NULL)
352 printf(" %s (%zu)", s, idx);
353 printf(" returns: %u args: (", *fsp++);
355 printf("%u%s", *fsp++, (vlen > 0) ? ", " : "");
361 if (flags & DUMP_STRTAB) {
362 unsigned int offset = 0;
365 while (offset < cth->cth_strlen) {
366 str = ctf_off2name(cth, data, dlen, offset);
368 printf(" [%u] ", offset);
369 if (strcmp(str, "(anon)"))
370 offset += printf("%s\n", str);
379 if (flags & DUMP_TYPE) {
380 unsigned int idx = 1, offset = 0;
382 while (offset < cth->cth_stroff) {
383 offset += ctf_dump_type(cth, data, dlen, offset, idx++);
388 if (cth->cth_flags & CTF_F_COMPRESS)
395 ctf_dump_type(struct ctf_header *cth, const char *data, off_t dlen,
396 unsigned int offset, unsigned int idx)
398 const char *p = data + cth->cth_typeoff + offset;
399 const struct ctf_type *ctt = (struct ctf_type *)p;
400 unsigned short i, kind, vlen, root;
401 unsigned int eob, toff;
403 const char *name, *kname;
405 kind = CTF_INFO_KIND(ctt->ctt_info);
406 vlen = CTF_INFO_VLEN(ctt->ctt_info);
407 root = CTF_INFO_ISROOT(ctt->ctt_info);
408 name = ctf_off2name(cth, data, dlen, ctt->ctt_name);
411 printf(" <%u> ", idx);
413 printf(" [%u] ", idx);
415 if ((kname = ctf_kind2name(kind)) != NULL)
416 printf("%s %s", kname, name);
418 if (ctt->ctt_size <= CTF_MAX_SIZE) {
419 size = ctt->ctt_size;
420 toff = sizeof(struct ctf_stype);
422 size = CTF_TYPE_LSIZE(ctt);
423 toff = sizeof(struct ctf_type);
431 eob = *((unsigned int *)((char *)ctt + toff));
432 toff += sizeof(unsigned int);
433 printf(" encoding=0x%x offset=%u bits=%u",
434 CTF_INT_ENCODING(eob), CTF_INT_OFFSET(eob),
438 eob = *((unsigned int *)((char *)ctt + toff));
439 toff += sizeof(unsigned int);
440 printf(" encoding=0x%x offset=%u bits=%u",
441 CTF_FP_ENCODING(eob), CTF_FP_OFFSET(eob), CTF_FP_BITS(eob));
444 toff += sizeof(struct ctf_array);
447 toff += (vlen + (vlen & 1)) * sizeof(unsigned short);
451 printf(" (%llu bytes)\n", size);
453 if (size < CTF_LSTRUCT_THRESH) {
454 for (i = 0; i < vlen; i++) {
455 struct ctf_member *ctm;
457 ctm = (struct ctf_member *)(p + toff);
458 toff += sizeof(struct ctf_member);
460 printf("\t%s type=%u off=%u\n",
461 ctf_off2name(cth, data, dlen,
463 ctm->ctm_type, ctm->ctm_offset);
466 for (i = 0; i < vlen; i++) {
467 struct ctf_lmember *ctlm;
469 ctlm = (struct ctf_lmember *)(p + toff);
470 toff += sizeof(struct ctf_lmember);
472 printf("\t%s type=%u off=%llu\n",
473 ctf_off2name(cth, data, dlen,
475 ctlm->ctlm_type, CTF_LMEM_OFFSET(ctlm));
481 for (i = 0; i < vlen; i++) {
482 struct ctf_enum *cte;
484 cte = (struct ctf_enum *)(p + toff);
485 toff += sizeof(struct ctf_enum);
487 printf("\t%s = %u\n",
488 ctf_off2name(cth, data, dlen, cte->cte_name),
497 printf(" refers to %u", ctt->ctt_type);
500 errx(1, "incorrect type %u at offset %u", kind, offset);
509 ctf_kind2name(unsigned short kind)
511 static const char *kind_name[] = { NULL, "INTEGER", "FLOAT", "POINTER",
512 "ARRAYS", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD",
513 "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" };
515 if (kind >= nitems(kind_name))
518 return kind_name[kind];
522 ctf_off2name(struct ctf_header *cth, const char *data, off_t dlen,
527 if (CTF_NAME_STID(offset) != CTF_STRTAB_0)
530 if (CTF_NAME_OFFSET(offset) >= cth->cth_strlen)
531 return "exceeds strlab";
533 if (cth->cth_stroff + CTF_NAME_OFFSET(offset) >= dlen)
536 name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset);
544 decompress(const char *buf, size_t size, off_t len)
557 memset(&stream, 0, sizeof(stream));
558 stream.next_in = (void *)buf;
559 stream.avail_in = size;
560 stream.next_out = data;
561 stream.avail_out = len;
563 if ((error = inflateInit(&stream)) != Z_OK) {
564 warnx("zlib inflateInit failed: %s", zError(error));
568 if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
569 warnx("zlib inflate failed: %s", zError(error));
573 if ((error = inflateEnd(&stream)) != Z_OK) {
574 warnx("zlib inflateEnd failed: %s", zError(error));
578 if (stream.total_out != len) {
579 warnx("decompression failed: %llu != %llu",
580 stream.total_out, len);
595 extern char *__progname;
597 fprintf(stderr, "usage: %s [-dfhlst] [file ...]\n",