File: | src/usr.bin/ctfdump/ctfdump.c |
Warning: | line 408, column 4 Value stored to 'l' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ctfdump.c,v 1.27 2022/08/14 15:01:18 millert Exp $ */ |
2 | |
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> |
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 ZLIB1 |
36 | #include <zlib.h> |
37 | #endif /* ZLIB */ |
38 | |
39 | #ifndef nitems |
40 | #define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0])) |
41 | #endif |
42 | |
43 | #define DUMP_OBJECT(1 << 0) (1 << 0) |
44 | #define DUMP_FUNCTION(1 << 1) (1 << 1) |
45 | #define DUMP_HEADER(1 << 2) (1 << 2) |
46 | #define DUMP_LABEL(1 << 3) (1 << 3) |
47 | #define DUMP_STRTAB(1 << 4) (1 << 4) |
48 | #define DUMP_STATISTIC(1 << 5) (1 << 5) |
49 | #define DUMP_TYPE(1 << 6) (1 << 6) |
50 | |
51 | int dump(const char *, uint8_t); |
52 | int isctf(const char *, size_t); |
53 | __dead__attribute__((__noreturn__)) void usage(void); |
54 | |
55 | int ctf_dump(const char *, size_t, uint8_t); |
56 | void ctf_dump_type(struct ctf_header *, const char *, size_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 *, size_t, |
62 | uint32_t); |
63 | |
64 | char *decompress(const char *, size_t, size_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_ALL0, ""); |
76 | |
77 | if (pledge("stdio rpath", NULL((void *)0)) == -1) |
78 | err(1, "pledge"); |
79 | |
80 | while ((ch = getopt(argc, argv, "dfhlst")) != -1) { |
81 | switch (ch) { |
82 | case 'd': |
83 | flags |= DUMP_OBJECT(1 << 0); |
84 | break; |
85 | case 'f': |
86 | flags |= DUMP_FUNCTION(1 << 1); |
87 | break; |
88 | case 'h': |
89 | flags |= DUMP_HEADER(1 << 2); |
90 | break; |
91 | case 'l': |
92 | flags |= DUMP_LABEL(1 << 3); |
93 | break; |
94 | case 's': |
95 | flags |= DUMP_STRTAB(1 << 4); |
96 | break; |
97 | case 't': |
98 | flags |= DUMP_TYPE(1 << 6); |
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 | |
115 | if (elf_version(EV_CURRENT1) == EV_NONE0) |
116 | errx(1, "elf_version: %s", elf_errmsg(-1)); |
117 | |
118 | while ((filename = *argv++) != NULL((void *)0)) |
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_RDONLY0x0000); |
136 | if (fd == -1) { |
137 | warn("open"); |
138 | return 1; |
139 | } |
140 | |
141 | if ((e = elf_begin(fd, ELF_C_READ, NULL((void *)0))) == NULL((void *)0)) { |
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 | |
153 | if (fstat(fd, &st) == -1) { |
154 | warn("fstat"); |
155 | goto done; |
156 | } |
157 | if ((uintmax_t)st.st_size > SIZE_MAX0xffffffffffffffffUL) { |
158 | warnx("file too big to fit memory"); |
159 | goto done; |
160 | } |
161 | |
162 | p = mmap(NULL((void *)0), st.st_size, PROT_READ0x01, MAP_PRIVATE0x0002, fd, 0); |
163 | if (p == MAP_FAILED((void *)-1)) |
164 | err(1, "mmap"); |
165 | |
166 | if (isctf(p, st.st_size)) |
167 | error = ctf_dump(p, st.st_size, flags); |
168 | |
169 | munmap(p, st.st_size); |
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((void *)0) || strtabndx == 0) |
185 | return NULL((void *)0); |
186 | |
187 | data = NULL((void *)0); |
188 | while ((data = elf_rawdata(scnsymtab, data)) != NULL((void *)0)) { |
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)(((unsigned int) sym.st_info) & 0xf) != type) |
193 | continue; |
194 | if (sym.st_name >= strtabsz) |
195 | break; |
196 | if ((name = elf_strptr(e, strtabndx, |
197 | sym.st_name)) == NULL((void *)0)) |
198 | continue; |
199 | |
200 | *idx = i; |
201 | return name; |
202 | } |
203 | } |
204 | |
205 | return NULL((void *)0); |
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((void *)0); |
224 | while ((scn = elf_nextscn(e, scn)) != NULL((void *)0)) { |
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((void *)0)) { |
231 | warnx("elf_strptr: %s", elf_errmsg(-1)); |
232 | return 1; |
233 | } |
234 | |
235 | if (strcmp(name, ELF_CTF".SUNW_ctf") == 0) |
236 | scnctf = scn; |
237 | |
238 | if (strcmp(name, ELF_SYMTAB".symtab") == 0 && |
239 | shdr.sh_type == SHT_SYMTAB2 && shdr.sh_entsize != 0) { |
240 | scnsymtab = scn; |
241 | nsymb = shdr.sh_size / shdr.sh_entsize; |
242 | } |
243 | |
244 | if (strcmp(name, ELF_STRTAB".strtab") == 0 && |
245 | shdr.sh_type == SHT_STRTAB3) { |
246 | strtabndx = elf_ndxscn(scn); |
247 | strtabsz = shdr.sh_size; |
248 | } |
249 | } |
250 | |
251 | if (scnctf == NULL((void *)0)) { |
252 | warnx("%s section not found", ELF_CTF".SUNW_ctf"); |
253 | return 1; |
254 | } |
255 | |
256 | if (scnsymtab == NULL((void *)0)) |
257 | warnx("symbol table not found"); |
258 | |
259 | data = NULL((void *)0); |
260 | while ((data = elf_rawdata(scnctf, data)) != NULL((void *)0)) { |
261 | if (data->d_buf == NULL((void *)0)) { |
262 | warnx("%s section size is zero", ELF_CTF".SUNW_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; |
277 | size_t dlen; |
278 | |
279 | if (filesize < sizeof(struct ctf_header)) { |
280 | warnx("file too small to be CTF"); |
281 | return 0; |
282 | } |
283 | |
284 | memcpy(&cth, p, sizeof(struct ctf_header)); |
285 | if (cth.cth_magic != CTF_MAGIC0xcff1 || cth.cth_version != CTF_VERSION2) |
286 | return 0; |
287 | |
288 | dlen = cth.cth_stroff + cth.cth_strlen; |
289 | if (dlen > filesize && !(cth.cth_flags & CTF_F_COMPRESS(1 << 0))) { |
290 | warnx("bogus file size"); |
291 | return 0; |
292 | } |
293 | |
294 | if ((cth.cth_lbloff & 3) || (cth.cth_objtoff & 1) || |
295 | (cth.cth_funcoff & 1) || (cth.cth_typeoff & 3)) { |
296 | warnx("wrongly aligned offset"); |
297 | return 0; |
298 | } |
299 | |
300 | if ((cth.cth_lbloff >= dlen) || (cth.cth_objtoff >= dlen) || |
301 | (cth.cth_funcoff >= dlen) || (cth.cth_typeoff >= dlen)) { |
302 | warnx("truncated file"); |
303 | return 0; |
304 | } |
305 | |
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)) { |
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 | { |
320 | struct ctf_header cth; |
321 | size_t dlen; |
322 | char *data; |
323 | |
324 | memcpy(&cth, p, sizeof(struct ctf_header)); |
325 | dlen = cth.cth_stroff + cth.cth_strlen; |
326 | if (cth.cth_flags & CTF_F_COMPRESS(1 << 0)) { |
327 | data = decompress(p + sizeof(cth), size - sizeof(cth), dlen); |
328 | if (data == NULL((void *)0)) |
329 | return 1; |
330 | } else { |
331 | data = (char *)p + sizeof(cth); |
332 | } |
333 | |
334 | if (flags & DUMP_HEADER(1 << 2)) { |
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); |
338 | printf(" cth_parlabel = %s\n", |
339 | ctf_off2name(&cth, data, dlen, cth.cth_parlabel)); |
340 | printf(" cth_parname = %s\n", |
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); |
348 | printf("\n"); |
349 | } |
350 | |
351 | if (flags & DUMP_LABEL(1 << 3)) { |
352 | uint32_t lbloff = cth.cth_lbloff; |
353 | struct ctf_lblent *ctl; |
354 | |
355 | while (lbloff < cth.cth_objtoff) { |
356 | ctl = (struct ctf_lblent *)(data + lbloff); |
357 | |
358 | printf(" %5u %s\n", ctl->ctl_typeidx, |
359 | ctf_off2name(&cth, data, dlen, ctl->ctl_label)); |
360 | |
361 | lbloff += sizeof(*ctl); |
362 | } |
363 | printf("\n"); |
364 | } |
365 | |
366 | if (flags & DUMP_OBJECT(1 << 0)) { |
367 | uint32_t objtoff = cth.cth_objtoff; |
368 | size_t idx = 0, i = 0; |
369 | uint16_t *dsp; |
370 | const char *s; |
371 | int l; |
372 | |
373 | while (objtoff < cth.cth_funcoff) { |
374 | dsp = (uint16_t *)(data + objtoff); |
375 | |
376 | l = printf(" [%zu] %u", i++, *dsp); |
377 | if ((s = elf_idx2sym(&idx, STT_OBJECT1)) != NULL((void *)0)) |
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(1 << 1)) { |
388 | uint16_t *fsp, kind, vlen; |
389 | uint16_t *fstart, *fend; |
390 | size_t idx = 0, i = -1; |
391 | const char *s; |
392 | int l; |
393 | |
394 | fstart = (uint16_t *)(data + cth.cth_funcoff); |
395 | fend = (uint16_t *)(data + cth.cth_typeoff); |
396 | |
397 | fsp = fstart; |
398 | while (fsp < fend) { |
399 | kind = CTF_INFO_KIND(*fsp)(((*fsp) & 0xf800) >> 11); |
400 | vlen = CTF_INFO_VLEN(*fsp)(((*fsp) & 0x03ff)); |
401 | s = elf_idx2sym(&idx, STT_FUNC2); |
402 | fsp++; |
403 | i++; |
404 | |
405 | if (kind == CTF_K_UNKNOWN0 && vlen == 0) |
406 | continue; |
407 | |
408 | l = printf(" [%zu] FUNC ", i); |
Value stored to 'l' is never read | |
409 | if (s != NULL((void *)0)) |
410 | printf("(%s) ", s); |
411 | printf("returns: %u args: (", *fsp++); |
412 | while (vlen-- > 0 && fsp < fend) |
413 | printf("%u%s", *fsp++, (vlen > 0) ? ", " : ""); |
414 | printf(")\n"); |
415 | } |
416 | printf("\n"); |
417 | } |
418 | |
419 | if (flags & DUMP_TYPE(1 << 6)) { |
420 | uint32_t idx = 1, offset = cth.cth_typeoff; |
421 | uint32_t stroff = cth.cth_stroff; |
422 | |
423 | while (offset < stroff) { |
424 | ctf_dump_type(&cth, data, dlen, stroff, &offset, idx++); |
425 | } |
426 | printf("\n"); |
427 | } |
428 | |
429 | if (flags & DUMP_STRTAB(1 << 4)) { |
430 | uint32_t offset = 0; |
431 | const char *str; |
432 | |
433 | while (offset < cth.cth_strlen) { |
434 | str = ctf_off2name(&cth, data, dlen, offset); |
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 | |
447 | if (cth.cth_flags & CTF_F_COMPRESS(1 << 0)) |
448 | free(data); |
449 | |
450 | return 0; |
451 | } |
452 | |
453 | void |
454 | ctf_dump_type(struct ctf_header *cth, const char *data, size_t dlen, |
455 | uint32_t stroff, uint32_t *offset, uint32_t idx) |
456 | { |
457 | const char *p = data + *offset; |
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)(((ctt->_ctt_stype.cts_info) & 0xf800) >> 11); |
466 | vlen = CTF_INFO_VLEN(ctt->ctt_info)(((ctt->_ctt_stype.cts_info) & 0x03ff)); |
467 | root = CTF_INFO_ISROOT(ctt->ctt_info)(((ctt->_ctt_stype.cts_info) & 0x0400) >> 10); |
468 | name = ctf_off2name(cth, data, dlen, ctt->ctt_name_ctt_stype.cts_name); |
469 | |
470 | if (root) |
471 | printf(" <%u> ", idx); |
472 | else |
473 | printf(" [%u] ", idx); |
474 | |
475 | if ((kname = ctf_kind2name(kind)) != NULL((void *)0)) |
476 | printf("%s %s", kname, name); |
477 | |
478 | if (ctt->ctt_size_ctt_stype._ST._size <= CTF_MAX_SIZE0xfffe) { |
479 | size = ctt->ctt_size_ctt_stype._ST._size; |
480 | toff = sizeof(struct ctf_stype); |
481 | } else { |
482 | size = CTF_TYPE_LSIZE(ctt)(((uint64_t)(ctt)->ctt_lsizehi) << 32 | (ctt)->ctt_lsizelo ); |
483 | toff = sizeof(struct ctf_type); |
484 | } |
485 | |
486 | switch (kind) { |
487 | case CTF_K_UNKNOWN0: |
488 | case CTF_K_FORWARD9: |
489 | break; |
490 | case CTF_K_INTEGER1: |
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)(((eob) & 0xff000000) >> 24)), CTF_INT_OFFSET(eob)(((eob) & 0x00ff0000) >> 16), |
495 | CTF_INT_BITS(eob)(((eob) & 0x0000ffff))); |
496 | break; |
497 | case CTF_K_FLOAT2: |
498 | eob = *((uint32_t *)(p + toff)); |
499 | toff += sizeof(uint32_t); |
500 | printf(" encoding=%s offset=%u bits=%u", |
501 | ctf_fpenc2name(CTF_FP_ENCODING(eob)(((eob) & 0xff000000) >> 24)), CTF_FP_OFFSET(eob)(((eob) & 0x00ff0000) >> 16), |
502 | CTF_FP_BITS(eob)(((eob) & 0x0000ffff))); |
503 | break; |
504 | case CTF_K_ARRAY4: |
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_FUNCTION5: |
511 | argp = (uint16_t *)(p + toff); |
512 | printf(" returns: %u args: (%u", ctt->ctt_type_ctt_stype._ST._type, *argp); |
513 | for (i = 1; i < vlen; i++) { |
514 | argp++; |
515 | if ((const char *)argp > data + dlen) |
516 | errx(1, "offset exceeds CTF section"); |
517 | |
518 | printf(", %u", *argp); |
519 | } |
520 | printf(")"); |
521 | toff += (vlen + (vlen & 1)) * sizeof(uint16_t); |
522 | break; |
523 | case CTF_K_STRUCT6: |
524 | case CTF_K_UNION7: |
525 | printf(" (%llu bytes)\n", size); |
526 | |
527 | if (size < CTF_LSTRUCT_THRESH8192) { |
528 | for (i = 0; i < vlen; i++) { |
529 | struct ctf_member *ctm; |
530 | |
531 | if (p + toff > data + dlen) |
532 | errx(1, "offset exceeds CTF section"); |
533 | |
534 | if (toff > (stroff - sizeof(*ctm))) |
535 | break; |
536 | |
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; |
548 | |
549 | if (p + toff > data + dlen) |
550 | errx(1, "offset exceeds CTF section"); |
551 | |
552 | if (toff > (stroff - sizeof(*ctlm))) |
553 | break; |
554 | |
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_ctlm_member.ctm_name), |
561 | ctlm->ctlm_type_ctlm_member.ctm_type, CTF_LMEM_OFFSET(ctlm)(((uint64_t)(ctlm)->ctlm_offsethi) << 32 | (ctlm)-> ctlm_offsetlo)); |
562 | } |
563 | } |
564 | break; |
565 | case CTF_K_ENUM8: |
566 | printf("\n"); |
567 | for (i = 0; i < vlen; i++) { |
568 | struct ctf_enum *cte; |
569 | |
570 | if (p + toff > data + dlen) |
571 | errx(1, "offset exceeds CTF section"); |
572 | |
573 | if (toff > (stroff - sizeof(*cte))) |
574 | break; |
575 | |
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_POINTER3: |
585 | case CTF_K_TYPEDEF10: |
586 | case CTF_K_VOLATILE11: |
587 | case CTF_K_CONST12: |
588 | case CTF_K_RESTRICT13: |
589 | printf(" refers to %u", ctt->ctt_type_ctt_stype._ST._type); |
590 | break; |
591 | default: |
592 | errx(1, "incorrect type %u at offset %u", kind, *offset); |
593 | } |
594 | |
595 | printf("\n"); |
596 | |
597 | *offset += toff; |
598 | } |
599 | |
600 | const char * |
601 | ctf_kind2name(uint16_t kind) |
602 | { |
603 | static const char *kind_name[] = { NULL((void *)0), "INTEGER", "FLOAT", "POINTER", |
604 | "ARRAY", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD", |
605 | "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" }; |
606 | |
607 | if (kind >= nitems(kind_name)(sizeof((kind_name)) / sizeof((kind_name)[0]))) |
608 | return NULL((void *)0); |
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(1 << 3)) |
621 | return "VARARGS"; |
622 | |
623 | if (enc > 0 && enc <= nitems(enc_name)(sizeof((enc_name)) / sizeof((enc_name)[0]))) |
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((void *)0), NULL((void *)0), |
634 | NULL((void *)0), "LDOUBLE" }; |
635 | static char invalid[7]; |
636 | |
637 | if (enc > 0 && enc <= nitems(enc_name)(sizeof((enc_name)) / sizeof((enc_name)[0])) && enc_name[enc - 1] != NULL((void *)0)) |
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, size_t dlen, |
646 | uint32_t offset) |
647 | { |
648 | const char *name; |
649 | |
650 | if (CTF_NAME_STID(offset)((offset) >> 31) != CTF_STRTAB_00) |
651 | return "external"; |
652 | |
653 | if (CTF_NAME_OFFSET(offset)((offset) & 0x7fffffff) >= cth->cth_strlen) |
654 | return "exceeds strlab"; |
655 | |
656 | if (cth->cth_stroff + CTF_NAME_OFFSET(offset)((offset) & 0x7fffffff) >= dlen) |
657 | return "invalid"; |
658 | |
659 | name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset)((offset) & 0x7fffffff); |
660 | if (*name == '\0') |
661 | return "(anon)"; |
662 | |
663 | return name; |
664 | } |
665 | |
666 | char * |
667 | decompress(const char *buf, size_t size, size_t len) |
668 | { |
669 | #ifdef ZLIB1 |
670 | z_stream stream; |
671 | char *data; |
672 | int error; |
673 | |
674 | data = malloc(len); |
675 | if (data == NULL((void *)0)) { |
676 | warn(NULL((void *)0)); |
677 | return NULL((void *)0); |
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)inflateInit_((&stream), "1.3.0.1-motley", (int)sizeof(z_stream ))) != Z_OK0) { |
687 | warnx("zlib inflateInit failed: %s", zError(error)); |
688 | goto exit; |
689 | } |
690 | |
691 | if ((error = inflate(&stream, Z_FINISH4)) != Z_STREAM_END1) { |
692 | warnx("zlib inflate failed: %s", zError(error)); |
693 | inflateEnd(&stream); |
694 | goto exit; |
695 | } |
696 | |
697 | if ((error = inflateEnd(&stream)) != Z_OK0) { |
698 | warnx("zlib inflateEnd failed: %s", zError(error)); |
699 | goto exit; |
700 | } |
701 | |
702 | if (stream.total_out != len) { |
703 | warnx("decompression failed: %lu != %zu", |
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((void *)0); |
714 | } |
715 | |
716 | __dead__attribute__((__noreturn__)) void |
717 | usage(void) |
718 | { |
719 | fprintf(stderr(&__sF[2]), "usage: %s [-dfhlst] file ...\n", |
720 | getprogname()); |
721 | exit(1); |
722 | } |