Annotation of src/usr.bin/ctfdump/ctfdump.c, Revision 1.25
1.25 ! bluhm 1: /* $OpenBSD: ctfdump.c,v 1.24 2019/09/03 10:32:15 mpi Exp $ */
1.2 jasper 2:
1.1 mpi 3: /*
4: * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20: #include <sys/stat.h>
21: #include <sys/mman.h>
22: #include <sys/ctf.h>
23:
24: #include <err.h>
25: #include <fcntl.h>
1.23 sunil 26: #include <gelf.h>
27: #include <libelf.h>
1.1 mpi 28: #include <locale.h>
29: #include <stdio.h>
30: #include <stdint.h>
31: #include <stdlib.h>
32: #include <string.h>
33: #include <unistd.h>
34:
35: #ifdef ZLIB
36: #include <zlib.h>
37: #endif /* ZLIB */
38:
39: #ifndef nitems
40: #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
41: #endif
42:
43: #define DUMP_OBJECT (1 << 0)
44: #define DUMP_FUNCTION (1 << 1)
45: #define DUMP_HEADER (1 << 2)
46: #define DUMP_LABEL (1 << 3)
47: #define DUMP_STRTAB (1 << 4)
48: #define DUMP_STATISTIC (1 << 5)
49: #define DUMP_TYPE (1 << 6)
50:
51: int dump(const char *, uint8_t);
52: int isctf(const char *, size_t);
53: __dead void usage(void);
54:
55: int ctf_dump(const char *, size_t, uint8_t);
1.14 mpi 56: void ctf_dump_type(struct ctf_header *, const char *, off_t,
57: uint32_t, uint32_t *, uint32_t);
1.1 mpi 58: const char *ctf_kind2name(uint16_t);
59: const char *ctf_enc2name(uint16_t);
1.7 uwe 60: const char *ctf_fpenc2name(uint16_t);
1.1 mpi 61: const char *ctf_off2name(struct ctf_header *, const char *, off_t,
62: uint32_t);
63:
1.23 sunil 64: char *decompress(const char *, size_t, off_t);
65: int elf_dump(uint8_t);
1.1 mpi 66: const char *elf_idx2sym(size_t *, uint8_t);
67:
68: int
69: main(int argc, char *argv[])
70: {
71: const char *filename;
72: uint8_t flags = 0;
73: int ch, error = 0;
1.3 jasper 74:
1.4 jasper 75: setlocale(LC_ALL, "");
76:
1.3 jasper 77: if (pledge("stdio rpath", NULL) == -1)
78: err(1, "pledge");
1.1 mpi 79:
80: while ((ch = getopt(argc, argv, "dfhlst")) != -1) {
81: switch (ch) {
82: case 'd':
83: flags |= DUMP_OBJECT;
84: break;
85: case 'f':
86: flags |= DUMP_FUNCTION;
87: break;
88: case 'h':
89: flags |= DUMP_HEADER;
90: break;
91: case 'l':
92: flags |= DUMP_LABEL;
93: break;
94: case 's':
95: flags |= DUMP_STRTAB;
96: break;
97: case 't':
98: flags |= DUMP_TYPE;
99: break;
100: default:
101: usage();
102: }
103: }
104:
105: argc -= optind;
106: argv += optind;
107:
108: if (argc <= 0)
109: usage();
110:
111: /* Dump everything by default */
112: if (flags == 0)
113: flags = 0xff;
114:
1.23 sunil 115: if (elf_version(EV_CURRENT) == EV_NONE)
116: errx(1, "elf_version: %s", elf_errmsg(-1));
117:
1.1 mpi 118: while ((filename = *argv++) != NULL)
119: error |= dump(filename, flags);
120:
121: return error;
122: }
123:
1.23 sunil 124: Elf *e;
125: Elf_Scn *scnsymtab;
126: size_t strtabndx, strtabsz, nsymb;
127:
1.1 mpi 128: int
129: dump(const char *path, uint8_t flags)
130: {
1.23 sunil 131: struct stat st;
132: char *p;
133: int fd, error = 1;
1.1 mpi 134:
135: fd = open(path, O_RDONLY);
136: if (fd == -1) {
137: warn("open");
138: return 1;
139: }
1.23 sunil 140:
141: if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
142: warnx("elf_begin: %s", elf_errmsg(-1));
143: goto done;
144: }
145:
146: if (elf_kind(e) == ELF_K_ELF) {
147: error = elf_dump(flags);
148: elf_end(e);
149: goto done;
150: }
151: elf_end(e);
152:
1.1 mpi 153: if (fstat(fd, &st) == -1) {
154: warn("fstat");
1.23 sunil 155: goto done;
1.1 mpi 156: }
157: if ((uintmax_t)st.st_size > SIZE_MAX) {
158: warnx("file too big to fit memory");
1.23 sunil 159: goto done;
1.1 mpi 160: }
161:
162: p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
163: if (p == MAP_FAILED)
164: err(1, "mmap");
165:
1.23 sunil 166: if (isctf(p, st.st_size))
1.1 mpi 167: error = ctf_dump(p, st.st_size, flags);
168:
169: munmap(p, st.st_size);
1.23 sunil 170:
171: done:
1.1 mpi 172: close(fd);
173: return error;
174: }
175:
176: const char *
177: elf_idx2sym(size_t *idx, uint8_t type)
178: {
1.23 sunil 179: GElf_Sym sym;
180: Elf_Data *data;
181: char *name;
1.1 mpi 182: size_t i;
1.17 mpi 183:
1.23 sunil 184: if (scnsymtab == NULL || strtabndx == 0)
1.17 mpi 185: return NULL;
1.1 mpi 186:
1.23 sunil 187: data = NULL;
188: while ((data = elf_rawdata(scnsymtab, data)) != NULL) {
189: for (i = *idx + 1; i < nsymb; i++) {
190: if (gelf_getsym(data, i, &sym) != &sym)
191: continue;
192: if (GELF_ST_TYPE(sym.st_info) != type)
193: continue;
194: if (sym.st_name >= strtabsz)
195: break;
196: if ((name = elf_strptr(e, strtabndx,
197: sym.st_name)) == NULL)
198: continue;
1.1 mpi 199:
1.23 sunil 200: *idx = i;
201: return name;
202: }
1.1 mpi 203: }
204:
205: return NULL;
206: }
207:
208: int
1.23 sunil 209: elf_dump(uint8_t flags)
1.1 mpi 210: {
1.23 sunil 211: GElf_Shdr shdr;
212: Elf_Scn *scn, *scnctf;
213: Elf_Data *data;
214: char *name;
215: size_t shstrndx;
1.24 mpi 216: int error = 0;
1.23 sunil 217:
218: if (elf_getshdrstrndx(e, &shstrndx) != 0) {
219: warnx("elf_getshdrstrndx: %s", elf_errmsg(-1));
1.24 mpi 220: return 1;
1.23 sunil 221: }
1.1 mpi 222:
1.23 sunil 223: scn = scnctf = NULL;
224: while ((scn = elf_nextscn(e, scn)) != NULL) {
225: if (gelf_getshdr(scn, &shdr) != &shdr) {
226: warnx("elf_getshdr: %s", elf_errmsg(-1));
1.24 mpi 227: return 1;
1.23 sunil 228: }
1.1 mpi 229:
1.23 sunil 230: if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) {
231: warnx("elf_strptr: %s", elf_errmsg(-1));
1.24 mpi 232: return 1;
1.23 sunil 233: }
1.1 mpi 234:
1.23 sunil 235: if (strcmp(name, ELF_CTF) == 0)
236: scnctf = scn;
1.1 mpi 237:
1.23 sunil 238: if (strcmp(name, ELF_SYMTAB) == 0 &&
239: shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) {
240: scnsymtab = scn;
241: nsymb = shdr.sh_size / shdr.sh_entsize;
242: }
1.1 mpi 243:
1.23 sunil 244: if (strcmp(name, ELF_STRTAB) == 0 &&
245: shdr.sh_type == SHT_STRTAB) {
246: strtabndx = elf_ndxscn(scn);
247: strtabsz = shdr.sh_size;
248: }
249: }
250:
251: if (scnctf == NULL) {
252: warnx("%s section not found", ELF_CTF);
1.24 mpi 253: return 1;
1.23 sunil 254: }
1.10 jsg 255:
1.23 sunil 256: if (scnsymtab == NULL)
257: warnx("symbol table not found");
1.1 mpi 258:
1.23 sunil 259: data = NULL;
260: while ((data = elf_rawdata(scnctf, data)) != NULL) {
261: if (data->d_buf == NULL) {
262: warnx("%s section size is zero", ELF_CTF);
1.24 mpi 263: return 1;
1.23 sunil 264: }
1.1 mpi 265:
1.23 sunil 266: if (isctf(data->d_buf, data->d_size))
267: error |= ctf_dump(data->d_buf, data->d_size, flags);
1.1 mpi 268: }
269:
1.23 sunil 270: return error;
1.1 mpi 271: }
272:
273: int
274: isctf(const char *p, size_t filesize)
275: {
1.25 ! bluhm 276: struct ctf_header cth;
! 277: off_t dlen;
1.1 mpi 278:
279: if (filesize < sizeof(struct ctf_header)) {
280: warnx("file too small to be CTF");
281: return 0;
282: }
283:
1.25 ! bluhm 284: memcpy(&cth, p, sizeof(struct ctf_header));
! 285: if (cth.cth_magic != CTF_MAGIC || cth.cth_version != CTF_VERSION)
1.1 mpi 286: return 0;
287:
1.25 ! bluhm 288: dlen = (off_t)cth.cth_stroff + cth.cth_strlen;
! 289: if (dlen > (off_t)filesize && !(cth.cth_flags & CTF_F_COMPRESS)) {
1.1 mpi 290: warnx("bogus file size");
291: return 0;
292: }
293:
1.25 ! bluhm 294: if ((cth.cth_lbloff & 3) || (cth.cth_objtoff & 1) ||
! 295: (cth.cth_funcoff & 1) || (cth.cth_typeoff & 3)) {
1.1 mpi 296: warnx("wrongly aligned offset");
297: return 0;
298: }
299:
1.25 ! bluhm 300: if ((cth.cth_lbloff >= dlen) || (cth.cth_objtoff >= dlen) ||
! 301: (cth.cth_funcoff >= dlen) || (cth.cth_typeoff >= dlen)) {
1.1 mpi 302: warnx("truncated file");
303: return 0;
304: }
305:
1.25 ! bluhm 306: if ((cth.cth_lbloff > cth.cth_objtoff) ||
! 307: (cth.cth_objtoff > cth.cth_funcoff) ||
! 308: (cth.cth_funcoff > cth.cth_typeoff) ||
! 309: (cth.cth_typeoff > cth.cth_stroff)) {
1.1 mpi 310: warnx("corrupted file");
311: return 0;
312: }
313:
314: return 1;
315: }
316:
317: int
318: ctf_dump(const char *p, size_t size, uint8_t flags)
319: {
1.25 ! bluhm 320: struct ctf_header cth;
! 321: off_t dlen;
1.1 mpi 322: char *data;
323:
1.25 ! bluhm 324: memcpy(&cth, p, sizeof(struct ctf_header));
! 325: dlen = (off_t)cth.cth_stroff + cth.cth_strlen;
! 326: if (cth.cth_flags & CTF_F_COMPRESS) {
! 327: data = decompress(p + sizeof(cth), size - sizeof(cth), dlen);
1.1 mpi 328: if (data == NULL)
329: return 1;
330: } else {
1.25 ! bluhm 331: data = (char *)p + sizeof(cth);
1.1 mpi 332: }
333:
334: if (flags & DUMP_HEADER) {
1.25 ! bluhm 335: printf(" cth_magic = 0x%04x\n", cth.cth_magic);
! 336: printf(" cth_version = %u\n", cth.cth_version);
! 337: printf(" cth_flags = 0x%02x\n", cth.cth_flags);
1.1 mpi 338: printf(" cth_parlabel = %s\n",
1.25 ! bluhm 339: ctf_off2name(&cth, data, dlen, cth.cth_parlabel));
1.1 mpi 340: printf(" cth_parname = %s\n",
1.25 ! bluhm 341: ctf_off2name(&cth, data, dlen, cth.cth_parname));
! 342: printf(" cth_lbloff = %u\n", cth.cth_lbloff);
! 343: printf(" cth_objtoff = %u\n", cth.cth_objtoff);
! 344: printf(" cth_funcoff = %u\n", cth.cth_funcoff);
! 345: printf(" cth_typeoff = %u\n", cth.cth_typeoff);
! 346: printf(" cth_stroff = %u\n", cth.cth_stroff);
! 347: printf(" cth_strlen = %u\n", cth.cth_strlen);
1.1 mpi 348: printf("\n");
349: }
350:
351: if (flags & DUMP_LABEL) {
1.25 ! bluhm 352: uint32_t lbloff = cth.cth_lbloff;
1.1 mpi 353: struct ctf_lblent *ctl;
354:
1.25 ! bluhm 355: while (lbloff < cth.cth_objtoff) {
1.1 mpi 356: ctl = (struct ctf_lblent *)(data + lbloff);
357:
358: printf(" %5u %s\n", ctl->ctl_typeidx,
1.25 ! bluhm 359: ctf_off2name(&cth, data, dlen, ctl->ctl_label));
1.1 mpi 360:
361: lbloff += sizeof(*ctl);
362: }
363: printf("\n");
364: }
365:
366: if (flags & DUMP_OBJECT) {
1.25 ! bluhm 367: uint32_t objtoff = cth.cth_objtoff;
1.1 mpi 368: size_t idx = 0, i = 0;
369: uint16_t *dsp;
370: const char *s;
371: int l;
372:
1.25 ! bluhm 373: while (objtoff < cth.cth_funcoff) {
1.1 mpi 374: dsp = (uint16_t *)(data + objtoff);
375:
376: l = printf(" [%zu] %u", i++, *dsp);
377: if ((s = elf_idx2sym(&idx, STT_OBJECT)) != NULL)
378: printf("%*s %s (%zu)\n", (14 - l), "", s, idx);
379: else
380: printf("\n");
381:
382: objtoff += sizeof(*dsp);
383: }
384: printf("\n");
385: }
386:
387: if (flags & DUMP_FUNCTION) {
388: uint16_t *fsp, kind, vlen;
1.13 mpi 389: uint16_t *fstart, *fend;
1.1 mpi 390: size_t idx = 0, i = -1;
391: const char *s;
392: int l;
393:
1.25 ! bluhm 394: fstart = (uint16_t *)(data + cth.cth_funcoff);
! 395: fend = (uint16_t *)(data + cth.cth_typeoff);
1.13 mpi 396:
397: fsp = fstart;
398: while (fsp < fend) {
1.1 mpi 399: kind = CTF_INFO_KIND(*fsp);
400: vlen = CTF_INFO_VLEN(*fsp);
401: s = elf_idx2sym(&idx, STT_FUNC);
402: fsp++;
403: i++;
404:
405: if (kind == CTF_K_UNKNOWN && vlen == 0)
406: continue;
407:
408: l = printf(" [%zu] FUNC ", i);
409: if (s != NULL)
1.18 mpi 410: printf("(%s) ", s);
411: printf("returns: %u args: (", *fsp++);
1.13 mpi 412: while (vlen-- > 0 && fsp < fend)
1.1 mpi 413: printf("%u%s", *fsp++, (vlen > 0) ? ", " : "");
414: printf(")\n");
415: }
416: printf("\n");
417: }
418:
419: if (flags & DUMP_TYPE) {
1.25 ! bluhm 420: uint32_t idx = 1, offset = cth.cth_typeoff;
! 421: uint32_t stroff = cth.cth_stroff;
1.1 mpi 422:
1.14 mpi 423: while (offset < stroff) {
1.25 ! bluhm 424: ctf_dump_type(&cth, data, dlen, stroff, &offset, idx++);
1.1 mpi 425: }
426: printf("\n");
427: }
428:
429: if (flags & DUMP_STRTAB) {
430: uint32_t offset = 0;
431: const char *str;
432:
1.25 ! bluhm 433: while (offset < cth.cth_strlen) {
! 434: str = ctf_off2name(&cth, data, dlen, offset);
1.1 mpi 435:
436: printf(" [%u] ", offset);
437: if (strcmp(str, "(anon)"))
438: offset += printf("%s\n", str);
439: else {
440: printf("\\0\n");
441: offset++;
442: }
443: }
444: printf("\n");
445: }
446:
1.25 ! bluhm 447: if (cth.cth_flags & CTF_F_COMPRESS)
1.1 mpi 448: free(data);
449:
450: return 0;
451: }
452:
1.14 mpi 453: void
1.1 mpi 454: ctf_dump_type(struct ctf_header *cth, const char *data, off_t dlen,
1.14 mpi 455: uint32_t stroff, uint32_t *offset, uint32_t idx)
1.1 mpi 456: {
1.14 mpi 457: const char *p = data + *offset;
1.1 mpi 458: const struct ctf_type *ctt = (struct ctf_type *)p;
459: const struct ctf_array *cta;
460: uint16_t *argp, i, kind, vlen, root;
461: uint32_t eob, toff;
462: uint64_t size;
463: const char *name, *kname;
464:
465: kind = CTF_INFO_KIND(ctt->ctt_info);
466: vlen = CTF_INFO_VLEN(ctt->ctt_info);
467: root = CTF_INFO_ISROOT(ctt->ctt_info);
468: name = ctf_off2name(cth, data, dlen, ctt->ctt_name);
469:
470: if (root)
471: printf(" <%u> ", idx);
472: else
473: printf(" [%u] ", idx);
474:
475: if ((kname = ctf_kind2name(kind)) != NULL)
476: printf("%s %s", kname, name);
477:
478: if (ctt->ctt_size <= CTF_MAX_SIZE) {
479: size = ctt->ctt_size;
480: toff = sizeof(struct ctf_stype);
481: } else {
482: size = CTF_TYPE_LSIZE(ctt);
483: toff = sizeof(struct ctf_type);
484: }
485:
486: switch (kind) {
487: case CTF_K_UNKNOWN:
488: case CTF_K_FORWARD:
489: break;
490: case CTF_K_INTEGER:
491: eob = *((uint32_t *)(p + toff));
492: toff += sizeof(uint32_t);
493: printf(" encoding=%s offset=%u bits=%u",
494: ctf_enc2name(CTF_INT_ENCODING(eob)), CTF_INT_OFFSET(eob),
495: CTF_INT_BITS(eob));
496: break;
497: case CTF_K_FLOAT:
498: eob = *((uint32_t *)(p + toff));
499: toff += sizeof(uint32_t);
1.7 uwe 500: printf(" encoding=%s offset=%u bits=%u",
501: ctf_fpenc2name(CTF_FP_ENCODING(eob)), CTF_FP_OFFSET(eob),
502: CTF_FP_BITS(eob));
1.1 mpi 503: break;
504: case CTF_K_ARRAY:
505: cta = (struct ctf_array *)(p + toff);
506: printf(" content: %u index: %u nelems: %u\n", cta->cta_contents,
507: cta->cta_index, cta->cta_nelems);
508: toff += sizeof(struct ctf_array);
509: break;
510: case CTF_K_FUNCTION:
511: argp = (uint16_t *)(p + toff);
512: printf(" returns: %u args: (%u", ctt->ctt_type, *argp);
513: for (i = 1; i < vlen; i++) {
514: argp++;
1.22 sunil 515: if ((const char *)argp > data + dlen)
516: errx(1, "offset exceeds CTF section");
517:
1.1 mpi 518: printf(", %u", *argp);
519: }
520: printf(")");
521: toff += (vlen + (vlen & 1)) * sizeof(uint16_t);
522: break;
523: case CTF_K_STRUCT:
524: case CTF_K_UNION:
525: printf(" (%llu bytes)\n", size);
526:
527: if (size < CTF_LSTRUCT_THRESH) {
528: for (i = 0; i < vlen; i++) {
529: struct ctf_member *ctm;
530:
1.21 sunil 531: if (p + toff > data + dlen)
532: errx(1, "offset exceeds CTF section");
533:
1.14 mpi 534: if (toff > (stroff - sizeof(*ctm)))
535: break;
536:
1.1 mpi 537: ctm = (struct ctf_member *)(p + toff);
538: toff += sizeof(struct ctf_member);
539:
540: printf("\t%s type=%u off=%u\n",
541: ctf_off2name(cth, data, dlen,
542: ctm->ctm_name),
543: ctm->ctm_type, ctm->ctm_offset);
544: }
545: } else {
546: for (i = 0; i < vlen; i++) {
547: struct ctf_lmember *ctlm;
1.21 sunil 548:
549: if (p + toff > data + dlen)
550: errx(1, "offset exceeds CTF section");
1.1 mpi 551:
1.14 mpi 552: if (toff > (stroff - sizeof(*ctlm)))
553: break;
554:
1.1 mpi 555: ctlm = (struct ctf_lmember *)(p + toff);
556: toff += sizeof(struct ctf_lmember);
557:
558: printf("\t%s type=%u off=%llu\n",
559: ctf_off2name(cth, data, dlen,
560: ctlm->ctlm_name),
561: ctlm->ctlm_type, CTF_LMEM_OFFSET(ctlm));
562: }
563: }
564: break;
565: case CTF_K_ENUM:
566: printf("\n");
567: for (i = 0; i < vlen; i++) {
568: struct ctf_enum *cte;
1.20 sunil 569:
570: if (p + toff > data + dlen)
571: errx(1, "offset exceeds CTF section");
1.1 mpi 572:
1.14 mpi 573: if (toff > (stroff - sizeof(*cte)))
574: break;
575:
1.1 mpi 576: cte = (struct ctf_enum *)(p + toff);
577: toff += sizeof(struct ctf_enum);
578:
579: printf("\t%s = %d\n",
580: ctf_off2name(cth, data, dlen, cte->cte_name),
581: cte->cte_value);
582: }
583: break;
584: case CTF_K_POINTER:
585: case CTF_K_TYPEDEF:
586: case CTF_K_VOLATILE:
587: case CTF_K_CONST:
588: case CTF_K_RESTRICT:
589: printf(" refers to %u", ctt->ctt_type);
590: break;
591: default:
1.14 mpi 592: errx(1, "incorrect type %u at offset %u", kind, *offset);
1.1 mpi 593: }
594:
595: printf("\n");
596:
1.14 mpi 597: *offset += toff;
1.1 mpi 598: }
599:
600: const char *
601: ctf_kind2name(uint16_t kind)
602: {
603: static const char *kind_name[] = { NULL, "INTEGER", "FLOAT", "POINTER",
604: "ARRAY", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD",
605: "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" };
606:
607: if (kind >= nitems(kind_name))
608: return NULL;
609:
610: return kind_name[kind];
611: }
612:
613: const char *
614: ctf_enc2name(uint16_t enc)
615: {
616: static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
617: "BOOL", "SIGNED BOOL" };
618: static char invalid[7];
619:
620: if (enc == CTF_INT_VARARGS)
621: return "VARARGS";
622:
1.8 uwe 623: if (enc > 0 && enc <= nitems(enc_name))
1.7 uwe 624: return enc_name[enc - 1];
625:
626: snprintf(invalid, sizeof(invalid), "0x%x", enc);
627: return invalid;
628: }
629:
630: const char *
631: ctf_fpenc2name(uint16_t enc)
632: {
633: static const char *enc_name[] = { "SINGLE", "DOUBLE", NULL, NULL,
634: NULL, "LDOUBLE" };
635: static char invalid[7];
636:
637: if (enc > 0 && enc <= nitems(enc_name) && enc_name[enc - 1] != NULL)
1.1 mpi 638: return enc_name[enc - 1];
639:
640: snprintf(invalid, sizeof(invalid), "0x%x", enc);
641: return invalid;
642: }
643:
644: const char *
645: ctf_off2name(struct ctf_header *cth, const char *data, off_t dlen,
646: uint32_t offset)
647: {
648: const char *name;
649:
650: if (CTF_NAME_STID(offset) != CTF_STRTAB_0)
651: return "external";
652:
653: if (CTF_NAME_OFFSET(offset) >= cth->cth_strlen)
654: return "exceeds strlab";
655:
656: if (cth->cth_stroff + CTF_NAME_OFFSET(offset) >= dlen)
657: return "invalid";
658:
659: name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset);
660: if (*name == '\0')
661: return "(anon)";
662:
663: return name;
664: }
665:
666: char *
667: decompress(const char *buf, size_t size, off_t len)
668: {
669: #ifdef ZLIB
670: z_stream stream;
671: char *data;
672: int error;
673:
674: data = malloc(len);
675: if (data == NULL) {
676: warn(NULL);
677: return NULL;
678: }
679:
680: memset(&stream, 0, sizeof(stream));
681: stream.next_in = (void *)buf;
682: stream.avail_in = size;
683: stream.next_out = (uint8_t *)data;
684: stream.avail_out = len;
685:
686: if ((error = inflateInit(&stream)) != Z_OK) {
687: warnx("zlib inflateInit failed: %s", zError(error));
688: goto exit;
689: }
690:
691: if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
692: warnx("zlib inflate failed: %s", zError(error));
693: inflateEnd(&stream);
694: goto exit;
695: }
696:
697: if ((error = inflateEnd(&stream)) != Z_OK) {
698: warnx("zlib inflateEnd failed: %s", zError(error));
699: goto exit;
700: }
701:
702: if (stream.total_out != len) {
703: warnx("decompression failed: %llu != %llu",
704: stream.total_out, len);
705: goto exit;
706: }
707:
708: return data;
709:
710: exit:
711: free(data);
712: #endif /* ZLIB */
713: return NULL;
714: }
715:
716: __dead void
717: usage(void)
718: {
719: fprintf(stderr, "usage: %s [-dfhlst] file ...\n",
720: getprogname());
721: exit(1);
722: }