| File: | src/usr.bin/ctfdump/ctfdump.c |
| Warning: | line 169, column 2 Use of memory after it is freed |
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
| |||
| 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); | |||
| 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 | } |