| 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 | } |