clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ctfdump.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/ctfdump/obj -resource-dir /usr/local/lib/clang/13.0.0 -D ZLIB -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused -fdebug-compilation-dir=/usr/src/usr.bin/ctfdump/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/ctfdump/ctfdump.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
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> |
26 | #include <gelf.h> |
27 | #include <libelf.h> |
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); |
56 | void ctf_dump_type(struct ctf_header *, const char *, off_t, |
57 | uint32_t, uint32_t *, uint32_t); |
58 | const char *ctf_kind2name(uint16_t); |
59 | const char *ctf_enc2name(uint16_t); |
60 | const char *ctf_fpenc2name(uint16_t); |
61 | const char *ctf_off2name(struct ctf_header *, const char *, off_t, |
62 | uint32_t); |
63 | |
64 | char *decompress(const char *, size_t, off_t); |
65 | int elf_dump(uint8_t); |
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; |
74 | |
75 | setlocale(LC_ALL, ""); |
76 | |
77 | if (pledge("stdio rpath", NULL) == -1) |
| 1 | Assuming the condition is false | |
|
| |
78 | err(1, "pledge"); |
79 | |
80 | while ((ch = getopt(argc, argv, "dfhlst")) != -1) { |
| 3 | | Assuming the condition is false | |
|
| 4 | | Loop condition is false. Execution continues on line 105 | |
|
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 | |
112 | if (flags == 0) |
| |
113 | flags = 0xff; |
114 | |
115 | if (elf_version(EV_CURRENT) == EV_NONE) |
| 8 | | Assuming the condition is false | |
|
| |
116 | errx(1, "elf_version: %s", elf_errmsg(-1)); |
117 | |
118 | while ((filename = *argv++) != NULL) |
| 10 | | Assuming the condition is true | |
|
| 11 | | Loop condition is true. Entering loop body | |
|
119 | error |= dump(filename, flags); |
| |
120 | |
121 | return error; |
122 | } |
123 | |
124 | Elf *e; |
125 | Elf_Scn *scnsymtab; |
126 | size_t strtabndx, strtabsz, nsymb; |
127 | |
128 | int |
129 | dump(const char *path, uint8_t flags) |
130 | { |
131 | struct stat st; |
132 | char *p; |
133 | int fd, error = 1; |
134 | |
135 | fd = open(path, O_RDONLY); |
136 | if (fd == -1) { |
| 13 | | Assuming the condition is false | |
|
| |
137 | warn("open"); |
138 | return 1; |
139 | } |
140 | |
141 | if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { |
| 15 | | Assuming the condition is false | |
|
| |
142 | warnx("elf_begin: %s", elf_errmsg(-1)); |
143 | goto done; |
144 | } |
145 | |
146 | if (elf_kind(e) == ELF_K_ELF) { |
| 17 | | Assuming the condition is false | |
|
| |
147 | error = elf_dump(flags); |
148 | elf_end(e); |
149 | goto done; |
150 | } |
151 | elf_end(e); |
152 | |
153 | if (fstat(fd, &st) == -1) { |
| 19 | | Assuming the condition is false | |
|
| |
154 | warn("fstat"); |
155 | goto done; |
156 | } |
157 | if ((uintmax_t)st.st_size > SIZE_MAX) { |
| |
158 | warnx("file too big to fit memory"); |
159 | goto done; |
160 | } |
161 | |
162 | p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |
163 | if (p == MAP_FAILED) |
| 22 | | Assuming the condition is false | |
|
| |
164 | err(1, "mmap"); |
165 | |
166 | if (isctf(p, st.st_size)) |
| |
167 | error = ctf_dump(p, st.st_size, flags); |
| |
| 47 | | Returning; memory was released via 1st parameter | |
|
168 | |
169 | munmap(p, st.st_size); |
| 48 | | Use of memory after it is freed |
|
170 | |
171 | done: |
172 | close(fd); |
173 | return error; |
174 | } |
175 | |
176 | const char * |
177 | elf_idx2sym(size_t *idx, uint8_t type) |
178 | { |
179 | GElf_Sym sym; |
180 | Elf_Data *data; |
181 | char *name; |
182 | size_t i; |
183 | |
184 | if (scnsymtab == NULL || strtabndx == 0) |
185 | return NULL; |
186 | |
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; |
199 | |
200 | *idx = i; |
201 | return name; |
202 | } |
203 | } |
204 | |
205 | return NULL; |
206 | } |
207 | |
208 | int |
209 | elf_dump(uint8_t flags) |
210 | { |
211 | GElf_Shdr shdr; |
212 | Elf_Scn *scn, *scnctf; |
213 | Elf_Data *data; |
214 | char *name; |
215 | size_t shstrndx; |
216 | int error = 0; |
217 | |
218 | if (elf_getshdrstrndx(e, &shstrndx) != 0) { |
219 | warnx("elf_getshdrstrndx: %s", elf_errmsg(-1)); |
220 | return 1; |
221 | } |
222 | |
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 1; |
228 | } |
229 | |
230 | if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) { |
231 | warnx("elf_strptr: %s", elf_errmsg(-1)); |
232 | return 1; |
233 | } |
234 | |
235 | if (strcmp(name, ELF_CTF) == 0) |
236 | scnctf = scn; |
237 | |
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 | } |
243 | |
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 1; |
254 | } |
255 | |
256 | if (scnsymtab == NULL) |
257 | warnx("symbol table not found"); |
258 | |
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 1; |
264 | } |
265 | |
266 | if (isctf(data->d_buf, data->d_size)) |
267 | error |= ctf_dump(data->d_buf, data->d_size, flags); |
268 | } |
269 | |
270 | return error; |
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 | |
287 | dlen = (off_t)cth->cth_stroff + cth->cth_strlen; |
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; |
320 | off_t dlen; |
321 | char *data; |
322 | |
323 | dlen = (off_t)cth->cth_stroff + cth->cth_strlen; |
324 | if (cth->cth_flags & CTF_F_COMPRESS) { |
| 26 | | Assuming the condition is false | |
|
| |
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); |
334 | printf(" cth_version = %u\n", cth->cth_version); |
335 | printf(" cth_flags = 0x%02x\n", cth->cth_flags); |
336 | printf(" cth_parlabel = %s\n", |
337 | ctf_off2name(cth, data, dlen, cth->cth_parlabel)); |
338 | printf(" cth_parname = %s\n", |
339 | ctf_off2name(cth, data, dlen, cth->cth_parname)); |
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); |
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) { |
| 30 | | Assuming 'lbloff' is >= field 'cth_objtoff' | |
|
| 31 | | Loop condition is false. Execution continues on line 361 | |
|
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) { |
| 33 | | Assuming 'objtoff' is >= field 'cth_funcoff' | |
|
| 34 | | Loop condition is false. Execution continues on line 382 | |
|
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; |
387 | uint16_t *fstart, *fend; |
388 | size_t idx = 0, i = -1; |
389 | const char *s; |
390 | int l; |
391 | |
392 | fstart = (uint16_t *)(data + cth->cth_funcoff); |
393 | fend = (uint16_t *)(data + cth->cth_typeoff); |
394 | |
395 | fsp = fstart; |
396 | while (fsp < fend) { |
| 36 | | Assuming 'fsp' is >= 'fend' | |
|
| 37 | | Loop condition is false. Execution continues on line 414 | |
|
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) |
408 | printf("(%s) ", s); |
409 | printf("returns: %u args: (", *fsp++); |
410 | while (vlen-- > 0 && fsp < fend) |
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; |
419 | uint32_t stroff = cth->cth_stroff; |
420 | |
421 | while (offset < stroff) { |
| 39 | | Assuming 'offset' is >= 'stroff' | |
|
| 40 | | Loop condition is false. Execution continues on line 424 | |
|
422 | ctf_dump_type(cth, data, dlen, stroff, &offset, idx++); |
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) { |
| 42 | | Assuming 'offset' is >= field 'cth_strlen' | |
|
| 43 | | Loop condition is false. Execution continues on line 442 | |
|
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) |
| 44 | | Assuming the condition is true | |
|
| |
446 | free(data); |
| |
447 | |
448 | return 0; |
449 | } |
450 | |
451 | void |
452 | ctf_dump_type(struct ctf_header *cth, const char *data, off_t dlen, |
453 | uint32_t stroff, uint32_t *offset, uint32_t idx) |
454 | { |
455 | const char *p = data + *offset; |
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); |
498 | printf(" encoding=%s offset=%u bits=%u", |
499 | ctf_fpenc2name(CTF_FP_ENCODING(eob)), CTF_FP_OFFSET(eob), |
500 | CTF_FP_BITS(eob)); |
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++; |
513 | if ((const char *)argp > data + dlen) |
514 | errx(1, "offset exceeds CTF section"); |
515 | |
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 | |
529 | if (p + toff > data + dlen) |
530 | errx(1, "offset exceeds CTF section"); |
531 | |
532 | if (toff > (stroff - sizeof(*ctm))) |
533 | break; |
534 | |
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; |
546 | |
547 | if (p + toff > data + dlen) |
548 | errx(1, "offset exceeds CTF section"); |
549 | |
550 | if (toff > (stroff - sizeof(*ctlm))) |
551 | break; |
552 | |
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; |
567 | |
568 | if (p + toff > data + dlen) |
569 | errx(1, "offset exceeds CTF section"); |
570 | |
571 | if (toff > (stroff - sizeof(*cte))) |
572 | break; |
573 | |
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: |
590 | errx(1, "incorrect type %u at offset %u", kind, *offset); |
591 | } |
592 | |
593 | printf("\n"); |
594 | |
595 | *offset += toff; |
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 | |
621 | if (enc > 0 && enc <= nitems(enc_name)) |
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) |
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 | } |