Annotation of src/usr.bin/ctfdump/ctfdump.c, Revision 1.23
1.23 ! sunil 1: /* $OpenBSD: ctfdump.c,v 1.22 2019/03/16 16:35:03 sunil 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;
! 216: int error = 1;
! 217:
! 218: if (elf_getshdrstrndx(e, &shstrndx) != 0) {
! 219: warnx("elf_getshdrstrndx: %s", elf_errmsg(-1));
! 220: return error;
! 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));
! 227: return error;
! 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));
! 232: return error;
! 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);
! 253: return error;
! 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);
! 263: return error;
! 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: {
276: struct ctf_header *cth = (struct ctf_header *)p;
277: off_t dlen;
278:
279: if (filesize < sizeof(struct ctf_header)) {
280: warnx("file too small to be CTF");
281: return 0;
282: }
283:
284: if (cth->cth_magic != CTF_MAGIC || cth->cth_version != CTF_VERSION)
285: return 0;
286:
1.16 mpi 287: dlen = (off_t)cth->cth_stroff + cth->cth_strlen;
1.1 mpi 288: if (dlen > (off_t)filesize && !(cth->cth_flags & CTF_F_COMPRESS)) {
289: warnx("bogus file size");
290: return 0;
291: }
292:
293: if ((cth->cth_lbloff & 3) || (cth->cth_objtoff & 1) ||
294: (cth->cth_funcoff & 1) || (cth->cth_typeoff & 3)) {
295: warnx("wrongly aligned offset");
296: return 0;
297: }
298:
299: if ((cth->cth_lbloff >= dlen) || (cth->cth_objtoff >= dlen) ||
300: (cth->cth_funcoff >= dlen) || (cth->cth_typeoff >= dlen)) {
301: warnx("truncated file");
302: return 0;
303: }
304:
305: if ((cth->cth_lbloff > cth->cth_objtoff) ||
306: (cth->cth_objtoff > cth->cth_funcoff) ||
307: (cth->cth_funcoff > cth->cth_typeoff) ||
308: (cth->cth_typeoff > cth->cth_stroff)) {
309: warnx("corrupted file");
310: return 0;
311: }
312:
313: return 1;
314: }
315:
316: int
317: ctf_dump(const char *p, size_t size, uint8_t flags)
318: {
319: struct ctf_header *cth = (struct ctf_header *)p;
1.16 mpi 320: off_t dlen;
1.1 mpi 321: char *data;
322:
1.16 mpi 323: dlen = (off_t)cth->cth_stroff + cth->cth_strlen;
1.1 mpi 324: if (cth->cth_flags & CTF_F_COMPRESS) {
325: data = decompress(p + sizeof(*cth), size - sizeof(*cth), dlen);
326: if (data == NULL)
327: return 1;
328: } else {
329: data = (char *)p + sizeof(*cth);
330: }
331:
332: if (flags & DUMP_HEADER) {
333: printf(" cth_magic = 0x%04x\n", cth->cth_magic);
1.15 mpi 334: printf(" cth_version = %u\n", cth->cth_version);
1.1 mpi 335: printf(" cth_flags = 0x%02x\n", cth->cth_flags);
336: printf(" cth_parlabel = %s\n",
1.11 mpi 337: ctf_off2name(cth, data, dlen, cth->cth_parlabel));
1.1 mpi 338: printf(" cth_parname = %s\n",
339: ctf_off2name(cth, data, dlen, cth->cth_parname));
1.15 mpi 340: printf(" cth_lbloff = %u\n", cth->cth_lbloff);
341: printf(" cth_objtoff = %u\n", cth->cth_objtoff);
342: printf(" cth_funcoff = %u\n", cth->cth_funcoff);
343: printf(" cth_typeoff = %u\n", cth->cth_typeoff);
344: printf(" cth_stroff = %u\n", cth->cth_stroff);
345: printf(" cth_strlen = %u\n", cth->cth_strlen);
1.1 mpi 346: printf("\n");
347: }
348:
349: if (flags & DUMP_LABEL) {
350: uint32_t lbloff = cth->cth_lbloff;
351: struct ctf_lblent *ctl;
352:
353: while (lbloff < cth->cth_objtoff) {
354: ctl = (struct ctf_lblent *)(data + lbloff);
355:
356: printf(" %5u %s\n", ctl->ctl_typeidx,
357: ctf_off2name(cth, data, dlen, ctl->ctl_label));
358:
359: lbloff += sizeof(*ctl);
360: }
361: printf("\n");
362: }
363:
364: if (flags & DUMP_OBJECT) {
365: uint32_t objtoff = cth->cth_objtoff;
366: size_t idx = 0, i = 0;
367: uint16_t *dsp;
368: const char *s;
369: int l;
370:
371: while (objtoff < cth->cth_funcoff) {
372: dsp = (uint16_t *)(data + objtoff);
373:
374: l = printf(" [%zu] %u", i++, *dsp);
375: if ((s = elf_idx2sym(&idx, STT_OBJECT)) != NULL)
376: printf("%*s %s (%zu)\n", (14 - l), "", s, idx);
377: else
378: printf("\n");
379:
380: objtoff += sizeof(*dsp);
381: }
382: printf("\n");
383: }
384:
385: if (flags & DUMP_FUNCTION) {
386: uint16_t *fsp, kind, vlen;
1.13 mpi 387: uint16_t *fstart, *fend;
1.1 mpi 388: size_t idx = 0, i = -1;
389: const char *s;
390: int l;
391:
1.13 mpi 392: fstart = (uint16_t *)(data + cth->cth_funcoff);
393: fend = (uint16_t *)(data + cth->cth_typeoff);
394:
395: fsp = fstart;
396: while (fsp < fend) {
1.1 mpi 397: kind = CTF_INFO_KIND(*fsp);
398: vlen = CTF_INFO_VLEN(*fsp);
399: s = elf_idx2sym(&idx, STT_FUNC);
400: fsp++;
401: i++;
402:
403: if (kind == CTF_K_UNKNOWN && vlen == 0)
404: continue;
405:
406: l = printf(" [%zu] FUNC ", i);
407: if (s != NULL)
1.18 mpi 408: printf("(%s) ", s);
409: printf("returns: %u args: (", *fsp++);
1.13 mpi 410: while (vlen-- > 0 && fsp < fend)
1.1 mpi 411: printf("%u%s", *fsp++, (vlen > 0) ? ", " : "");
412: printf(")\n");
413: }
414: printf("\n");
415: }
416:
417: if (flags & DUMP_TYPE) {
418: uint32_t idx = 1, offset = cth->cth_typeoff;
1.14 mpi 419: uint32_t stroff = cth->cth_stroff;
1.1 mpi 420:
1.14 mpi 421: while (offset < stroff) {
422: ctf_dump_type(cth, data, dlen, stroff, &offset, idx++);
1.1 mpi 423: }
424: printf("\n");
425: }
426:
427: if (flags & DUMP_STRTAB) {
428: uint32_t offset = 0;
429: const char *str;
430:
431: while (offset < cth->cth_strlen) {
432: str = ctf_off2name(cth, data, dlen, offset);
433:
434: printf(" [%u] ", offset);
435: if (strcmp(str, "(anon)"))
436: offset += printf("%s\n", str);
437: else {
438: printf("\\0\n");
439: offset++;
440: }
441: }
442: printf("\n");
443: }
444:
445: if (cth->cth_flags & CTF_F_COMPRESS)
446: free(data);
447:
448: return 0;
449: }
450:
1.14 mpi 451: void
1.1 mpi 452: ctf_dump_type(struct ctf_header *cth, const char *data, off_t dlen,
1.14 mpi 453: uint32_t stroff, uint32_t *offset, uint32_t idx)
1.1 mpi 454: {
1.14 mpi 455: const char *p = data + *offset;
1.1 mpi 456: const struct ctf_type *ctt = (struct ctf_type *)p;
457: const struct ctf_array *cta;
458: uint16_t *argp, i, kind, vlen, root;
459: uint32_t eob, toff;
460: uint64_t size;
461: const char *name, *kname;
462:
463: kind = CTF_INFO_KIND(ctt->ctt_info);
464: vlen = CTF_INFO_VLEN(ctt->ctt_info);
465: root = CTF_INFO_ISROOT(ctt->ctt_info);
466: name = ctf_off2name(cth, data, dlen, ctt->ctt_name);
467:
468: if (root)
469: printf(" <%u> ", idx);
470: else
471: printf(" [%u] ", idx);
472:
473: if ((kname = ctf_kind2name(kind)) != NULL)
474: printf("%s %s", kname, name);
475:
476: if (ctt->ctt_size <= CTF_MAX_SIZE) {
477: size = ctt->ctt_size;
478: toff = sizeof(struct ctf_stype);
479: } else {
480: size = CTF_TYPE_LSIZE(ctt);
481: toff = sizeof(struct ctf_type);
482: }
483:
484: switch (kind) {
485: case CTF_K_UNKNOWN:
486: case CTF_K_FORWARD:
487: break;
488: case CTF_K_INTEGER:
489: eob = *((uint32_t *)(p + toff));
490: toff += sizeof(uint32_t);
491: printf(" encoding=%s offset=%u bits=%u",
492: ctf_enc2name(CTF_INT_ENCODING(eob)), CTF_INT_OFFSET(eob),
493: CTF_INT_BITS(eob));
494: break;
495: case CTF_K_FLOAT:
496: eob = *((uint32_t *)(p + toff));
497: toff += sizeof(uint32_t);
1.7 uwe 498: printf(" encoding=%s offset=%u bits=%u",
499: ctf_fpenc2name(CTF_FP_ENCODING(eob)), CTF_FP_OFFSET(eob),
500: CTF_FP_BITS(eob));
1.1 mpi 501: break;
502: case CTF_K_ARRAY:
503: cta = (struct ctf_array *)(p + toff);
504: printf(" content: %u index: %u nelems: %u\n", cta->cta_contents,
505: cta->cta_index, cta->cta_nelems);
506: toff += sizeof(struct ctf_array);
507: break;
508: case CTF_K_FUNCTION:
509: argp = (uint16_t *)(p + toff);
510: printf(" returns: %u args: (%u", ctt->ctt_type, *argp);
511: for (i = 1; i < vlen; i++) {
512: argp++;
1.22 sunil 513: if ((const char *)argp > data + dlen)
514: errx(1, "offset exceeds CTF section");
515:
1.1 mpi 516: printf(", %u", *argp);
517: }
518: printf(")");
519: toff += (vlen + (vlen & 1)) * sizeof(uint16_t);
520: break;
521: case CTF_K_STRUCT:
522: case CTF_K_UNION:
523: printf(" (%llu bytes)\n", size);
524:
525: if (size < CTF_LSTRUCT_THRESH) {
526: for (i = 0; i < vlen; i++) {
527: struct ctf_member *ctm;
528:
1.21 sunil 529: if (p + toff > data + dlen)
530: errx(1, "offset exceeds CTF section");
531:
1.14 mpi 532: if (toff > (stroff - sizeof(*ctm)))
533: break;
534:
1.1 mpi 535: ctm = (struct ctf_member *)(p + toff);
536: toff += sizeof(struct ctf_member);
537:
538: printf("\t%s type=%u off=%u\n",
539: ctf_off2name(cth, data, dlen,
540: ctm->ctm_name),
541: ctm->ctm_type, ctm->ctm_offset);
542: }
543: } else {
544: for (i = 0; i < vlen; i++) {
545: struct ctf_lmember *ctlm;
1.21 sunil 546:
547: if (p + toff > data + dlen)
548: errx(1, "offset exceeds CTF section");
1.1 mpi 549:
1.14 mpi 550: if (toff > (stroff - sizeof(*ctlm)))
551: break;
552:
1.1 mpi 553: ctlm = (struct ctf_lmember *)(p + toff);
554: toff += sizeof(struct ctf_lmember);
555:
556: printf("\t%s type=%u off=%llu\n",
557: ctf_off2name(cth, data, dlen,
558: ctlm->ctlm_name),
559: ctlm->ctlm_type, CTF_LMEM_OFFSET(ctlm));
560: }
561: }
562: break;
563: case CTF_K_ENUM:
564: printf("\n");
565: for (i = 0; i < vlen; i++) {
566: struct ctf_enum *cte;
1.20 sunil 567:
568: if (p + toff > data + dlen)
569: errx(1, "offset exceeds CTF section");
1.1 mpi 570:
1.14 mpi 571: if (toff > (stroff - sizeof(*cte)))
572: break;
573:
1.1 mpi 574: cte = (struct ctf_enum *)(p + toff);
575: toff += sizeof(struct ctf_enum);
576:
577: printf("\t%s = %d\n",
578: ctf_off2name(cth, data, dlen, cte->cte_name),
579: cte->cte_value);
580: }
581: break;
582: case CTF_K_POINTER:
583: case CTF_K_TYPEDEF:
584: case CTF_K_VOLATILE:
585: case CTF_K_CONST:
586: case CTF_K_RESTRICT:
587: printf(" refers to %u", ctt->ctt_type);
588: break;
589: default:
1.14 mpi 590: errx(1, "incorrect type %u at offset %u", kind, *offset);
1.1 mpi 591: }
592:
593: printf("\n");
594:
1.14 mpi 595: *offset += toff;
1.1 mpi 596: }
597:
598: const char *
599: ctf_kind2name(uint16_t kind)
600: {
601: static const char *kind_name[] = { NULL, "INTEGER", "FLOAT", "POINTER",
602: "ARRAY", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD",
603: "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" };
604:
605: if (kind >= nitems(kind_name))
606: return NULL;
607:
608: return kind_name[kind];
609: }
610:
611: const char *
612: ctf_enc2name(uint16_t enc)
613: {
614: static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
615: "BOOL", "SIGNED BOOL" };
616: static char invalid[7];
617:
618: if (enc == CTF_INT_VARARGS)
619: return "VARARGS";
620:
1.8 uwe 621: if (enc > 0 && enc <= nitems(enc_name))
1.7 uwe 622: return enc_name[enc - 1];
623:
624: snprintf(invalid, sizeof(invalid), "0x%x", enc);
625: return invalid;
626: }
627:
628: const char *
629: ctf_fpenc2name(uint16_t enc)
630: {
631: static const char *enc_name[] = { "SINGLE", "DOUBLE", NULL, NULL,
632: NULL, "LDOUBLE" };
633: static char invalid[7];
634:
635: if (enc > 0 && enc <= nitems(enc_name) && enc_name[enc - 1] != NULL)
1.1 mpi 636: return enc_name[enc - 1];
637:
638: snprintf(invalid, sizeof(invalid), "0x%x", enc);
639: return invalid;
640: }
641:
642: const char *
643: ctf_off2name(struct ctf_header *cth, const char *data, off_t dlen,
644: uint32_t offset)
645: {
646: const char *name;
647:
648: if (CTF_NAME_STID(offset) != CTF_STRTAB_0)
649: return "external";
650:
651: if (CTF_NAME_OFFSET(offset) >= cth->cth_strlen)
652: return "exceeds strlab";
653:
654: if (cth->cth_stroff + CTF_NAME_OFFSET(offset) >= dlen)
655: return "invalid";
656:
657: name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset);
658: if (*name == '\0')
659: return "(anon)";
660:
661: return name;
662: }
663:
664: char *
665: decompress(const char *buf, size_t size, off_t len)
666: {
667: #ifdef ZLIB
668: z_stream stream;
669: char *data;
670: int error;
671:
672: data = malloc(len);
673: if (data == NULL) {
674: warn(NULL);
675: return NULL;
676: }
677:
678: memset(&stream, 0, sizeof(stream));
679: stream.next_in = (void *)buf;
680: stream.avail_in = size;
681: stream.next_out = (uint8_t *)data;
682: stream.avail_out = len;
683:
684: if ((error = inflateInit(&stream)) != Z_OK) {
685: warnx("zlib inflateInit failed: %s", zError(error));
686: goto exit;
687: }
688:
689: if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
690: warnx("zlib inflate failed: %s", zError(error));
691: inflateEnd(&stream);
692: goto exit;
693: }
694:
695: if ((error = inflateEnd(&stream)) != Z_OK) {
696: warnx("zlib inflateEnd failed: %s", zError(error));
697: goto exit;
698: }
699:
700: if (stream.total_out != len) {
701: warnx("decompression failed: %llu != %llu",
702: stream.total_out, len);
703: goto exit;
704: }
705:
706: return data;
707:
708: exit:
709: free(data);
710: #endif /* ZLIB */
711: return NULL;
712: }
713:
714: __dead void
715: usage(void)
716: {
717: fprintf(stderr, "usage: %s [-dfhlst] file ...\n",
718: getprogname());
719: exit(1);
720: }