| 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.24 2019/09/03 10:32:15 mpi 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 *, 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_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
| |||
| 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 = (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_MAGIC0xcff1 || cth->cth_version != CTF_VERSION2) | |||
| 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(1 << 0))) { | |||
| 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(1 << 0)) { | |||
| 325 | data = decompress(p + sizeof(*cth), size - sizeof(*cth), dlen); | |||
| 326 | if (data == NULL((void*)0)) | |||
| 327 | return 1; | |||
| 328 | } else { | |||
| 329 | data = (char *)p + sizeof(*cth); | |||
| 330 | } | |||
| 331 | ||||
| 332 | if (flags & DUMP_HEADER(1 << 2)) { | |||
| 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(1 << 3)) { | |||
| 350 | uint32_t lbloff = cth->cth_lbloff; | |||
| 351 | struct ctf_lblent *ctl; | |||
| 352 | ||||
| 353 | while (lbloff < cth->cth_objtoff) { | |||
| 354 | ctl = (struct ctf_lblent *)(data + lbloff); | |||
| 355 | ||||
| 356 | printf(" %5u %s\n", ctl->ctl_typeidx, | |||
| 357 | ctf_off2name(cth, data, dlen, ctl->ctl_label)); | |||
| 358 | ||||
| 359 | lbloff += sizeof(*ctl); | |||
| 360 | } | |||
| 361 | printf("\n"); | |||
| 362 | } | |||
| 363 | ||||
| 364 | if (flags & DUMP_OBJECT(1 << 0)) { | |||
| 365 | uint32_t objtoff = cth->cth_objtoff; | |||
| 366 | size_t idx = 0, i = 0; | |||
| 367 | uint16_t *dsp; | |||
| 368 | const char *s; | |||
| 369 | int l; | |||
| 370 | ||||
| 371 | while (objtoff < cth->cth_funcoff) { | |||
| 372 | dsp = (uint16_t *)(data + objtoff); | |||
| 373 | ||||
| 374 | l = printf(" [%zu] %u", i++, *dsp); | |||
| 375 | if ((s = elf_idx2sym(&idx, STT_OBJECT1)) != NULL((void*)0)) | |||
| 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(1 << 1)) { | |||
| 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) { | |||
| 397 | kind = CTF_INFO_KIND(*fsp)(((*fsp) & 0xf800) >> 11); | |||
| 398 | vlen = CTF_INFO_VLEN(*fsp)(((*fsp) & 0x03ff)); | |||
| 399 | s = elf_idx2sym(&idx, STT_FUNC2); | |||
| 400 | fsp++; | |||
| 401 | i++; | |||
| 402 | ||||
| 403 | if (kind == CTF_K_UNKNOWN0 && vlen == 0) | |||
| 404 | continue; | |||
| 405 | ||||
| 406 | l = printf(" [%zu] FUNC ", i); | |||
| 407 | if (s != NULL((void*)0)) | |||
| 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(1 << 6)) { | |||
| 418 | uint32_t idx = 1, offset = cth->cth_typeoff; | |||
| 419 | uint32_t stroff = cth->cth_stroff; | |||
| 420 | ||||
| 421 | while (offset < stroff) { | |||
| 422 | ctf_dump_type(cth, data, dlen, stroff, &offset, idx++); | |||
| 423 | } | |||
| 424 | printf("\n"); | |||
| 425 | } | |||
| 426 | ||||
| 427 | if (flags & DUMP_STRTAB(1 << 4)) { | |||
| 428 | uint32_t offset = 0; | |||
| 429 | const char *str; | |||
| 430 | ||||
| 431 | while (offset < cth->cth_strlen) { | |||
| 432 | str = ctf_off2name(cth, data, dlen, offset); | |||
| 433 | ||||
| 434 | printf(" [%u] ", offset); | |||
| 435 | if (strcmp(str, "(anon)")) | |||
| 436 | offset += printf("%s\n", str); | |||
| 437 | else { | |||
| 438 | printf("\\0\n"); | |||
| 439 | offset++; | |||
| 440 | } | |||
| 441 | } | |||
| 442 | printf("\n"); | |||
| 443 | } | |||
| 444 | ||||
| 445 | if (cth->cth_flags & CTF_F_COMPRESS(1 << 0)) | |||
| 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)(((ctt->_ctt_stype.cts_info) & 0xf800) >> 11); | |||
| 464 | vlen = CTF_INFO_VLEN(ctt->ctt_info)(((ctt->_ctt_stype.cts_info) & 0x03ff)); | |||
| 465 | root = CTF_INFO_ISROOT(ctt->ctt_info)(((ctt->_ctt_stype.cts_info) & 0x0400) >> 10); | |||
| 466 | name = ctf_off2name(cth, data, dlen, ctt->ctt_name_ctt_stype.cts_name); | |||
| 467 | ||||
| 468 | if (root) | |||
| 469 | printf(" <%u> ", idx); | |||
| 470 | else | |||
| 471 | printf(" [%u] ", idx); | |||
| 472 | ||||
| 473 | if ((kname = ctf_kind2name(kind)) != NULL((void*)0)) | |||
| 474 | printf("%s %s", kname, name); | |||
| 475 | ||||
| 476 | if (ctt->ctt_size_ctt_stype._ST._size <= CTF_MAX_SIZE0xfffe) { | |||
| 477 | size = ctt->ctt_size_ctt_stype._ST._size; | |||
| 478 | toff = sizeof(struct ctf_stype); | |||
| 479 | } else { | |||
| 480 | size = CTF_TYPE_LSIZE(ctt)(((uint64_t)(ctt)->ctt_lsizehi) << 32 | (ctt)->ctt_lsizelo ); | |||
| 481 | toff = sizeof(struct ctf_type); | |||
| 482 | } | |||
| 483 | ||||
| 484 | switch (kind) { | |||
| 485 | case CTF_K_UNKNOWN0: | |||
| 486 | case CTF_K_FORWARD9: | |||
| 487 | break; | |||
| 488 | case CTF_K_INTEGER1: | |||
| 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)(((eob) & 0xff000000) >> 24)), CTF_INT_OFFSET(eob)(((eob) & 0x00ff0000) >> 16), | |||
| 493 | CTF_INT_BITS(eob)(((eob) & 0x0000ffff))); | |||
| 494 | break; | |||
| 495 | case CTF_K_FLOAT2: | |||
| 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)(((eob) & 0xff000000) >> 24)), CTF_FP_OFFSET(eob)(((eob) & 0x00ff0000) >> 16), | |||
| 500 | CTF_FP_BITS(eob)(((eob) & 0x0000ffff))); | |||
| 501 | break; | |||
| 502 | case CTF_K_ARRAY4: | |||
| 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_FUNCTION5: | |||
| 509 | argp = (uint16_t *)(p + toff); | |||
| 510 | printf(" returns: %u args: (%u", ctt->ctt_type_ctt_stype._ST._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_STRUCT6: | |||
| 522 | case CTF_K_UNION7: | |||
| 523 | printf(" (%llu bytes)\n", size); | |||
| 524 | ||||
| 525 | if (size < CTF_LSTRUCT_THRESH8192) { | |||
| 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_ctlm_member.ctm_name), | |||
| 559 | ctlm->ctlm_type_ctlm_member.ctm_type, CTF_LMEM_OFFSET(ctlm)(((uint64_t)(ctlm)->ctlm_offsethi) << 32 | (ctlm)-> ctlm_offsetlo)); | |||
| 560 | } | |||
| 561 | } | |||
| 562 | break; | |||
| 563 | case CTF_K_ENUM8: | |||
| 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_POINTER3: | |||
| 583 | case CTF_K_TYPEDEF10: | |||
| 584 | case CTF_K_VOLATILE11: | |||
| 585 | case CTF_K_CONST12: | |||
| 586 | case CTF_K_RESTRICT13: | |||
| 587 | printf(" refers to %u", ctt->ctt_type_ctt_stype._ST._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((void*)0), "INTEGER", "FLOAT", "POINTER", | |||
| 602 | "ARRAY", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD", | |||
| 603 | "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" }; | |||
| 604 | ||||
| 605 | if (kind >= nitems(kind_name)(sizeof((kind_name)) / sizeof((kind_name)[0]))) | |||
| 606 | return NULL((void*)0); | |||
| 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(1 << 3)) | |||
| 619 | return "VARARGS"; | |||
| 620 | ||||
| 621 | if (enc > 0 && enc <= nitems(enc_name)(sizeof((enc_name)) / sizeof((enc_name)[0]))) | |||
| 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((void*)0), NULL((void*)0), | |||
| 632 | NULL((void*)0), "LDOUBLE" }; | |||
| 633 | static char invalid[7]; | |||
| 634 | ||||
| 635 | if (enc > 0 && enc <= nitems(enc_name)(sizeof((enc_name)) / sizeof((enc_name)[0])) && enc_name[enc - 1] != NULL((void*)0)) | |||
| 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)((offset) >> 31) != CTF_STRTAB_00) | |||
| 649 | return "external"; | |||
| 650 | ||||
| 651 | if (CTF_NAME_OFFSET(offset)((offset) & 0x7fffffff) >= cth->cth_strlen) | |||
| 652 | return "exceeds strlab"; | |||
| 653 | ||||
| 654 | if (cth->cth_stroff + CTF_NAME_OFFSET(offset)((offset) & 0x7fffffff) >= dlen) | |||
| 655 | return "invalid"; | |||
| 656 | ||||
| 657 | name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset)((offset) & 0x7fffffff); | |||
| 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 ZLIB1 | |||
| 668 | z_stream stream; | |||
| 669 | char *data; | |||
| 670 | int error; | |||
| 671 | ||||
| 672 | data = malloc(len); | |||
| 673 | if (data == NULL((void*)0)) { | |||
| 674 | warn(NULL((void*)0)); | |||
| 675 | return NULL((void*)0); | |||
| 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)inflateInit_((&stream), "1.2.11", (int)sizeof(z_stream))) != Z_OK0) { | |||
| 685 | warnx("zlib inflateInit failed: %s", zError(error)); | |||
| 686 | goto exit; | |||
| 687 | } | |||
| 688 | ||||
| 689 | if ((error = inflate(&stream, Z_FINISH4)) != Z_STREAM_END1) { | |||
| 690 | warnx("zlib inflate failed: %s", zError(error)); | |||
| 691 | inflateEnd(&stream); | |||
| 692 | goto exit; | |||
| 693 | } | |||
| 694 | ||||
| 695 | if ((error = inflateEnd(&stream)) != Z_OK0) { | |||
| 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((void*)0); | |||
| 712 | } | |||
| 713 | ||||
| 714 | __dead__attribute__((__noreturn__)) void | |||
| 715 | usage(void) | |||
| 716 | { | |||
| 717 | fprintf(stderr(&__sF[2]), "usage: %s [-dfhlst] file ...\n", | |||
| 718 | getprogname()); | |||
| 719 | exit(1); | |||
| 720 | } |