1*ccd92e6dSuwe /* $OpenBSD: ctfdump.c,v 1.7 2017/09/23 12:24:31 uwe Exp $ */ 27047d4c7Sjasper 326d55b61Smpi /* 426d55b61Smpi * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org> 526d55b61Smpi * 626d55b61Smpi * Permission to use, copy, modify, and distribute this software for any 726d55b61Smpi * purpose with or without fee is hereby granted, provided that the above 826d55b61Smpi * copyright notice and this permission notice appear in all copies. 926d55b61Smpi * 1026d55b61Smpi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1126d55b61Smpi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1226d55b61Smpi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1326d55b61Smpi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1426d55b61Smpi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1526d55b61Smpi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1626d55b61Smpi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1726d55b61Smpi */ 1826d55b61Smpi 1926d55b61Smpi #include <sys/types.h> 2026d55b61Smpi #include <sys/stat.h> 2126d55b61Smpi #include <sys/exec_elf.h> 2226d55b61Smpi #include <sys/mman.h> 2326d55b61Smpi #include <sys/ctf.h> 2426d55b61Smpi 2526d55b61Smpi #include <err.h> 2626d55b61Smpi #include <fcntl.h> 2726d55b61Smpi #include <locale.h> 2826d55b61Smpi #include <stdio.h> 2926d55b61Smpi #include <stdint.h> 3026d55b61Smpi #include <stdlib.h> 3126d55b61Smpi #include <string.h> 3226d55b61Smpi #include <unistd.h> 3326d55b61Smpi 3426d55b61Smpi #ifdef ZLIB 3526d55b61Smpi #include <zlib.h> 3626d55b61Smpi #endif /* ZLIB */ 3726d55b61Smpi 3826d55b61Smpi #ifndef nitems 3926d55b61Smpi #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 4026d55b61Smpi #endif 4126d55b61Smpi 4226d55b61Smpi #define DUMP_OBJECT (1 << 0) 4326d55b61Smpi #define DUMP_FUNCTION (1 << 1) 4426d55b61Smpi #define DUMP_HEADER (1 << 2) 4526d55b61Smpi #define DUMP_LABEL (1 << 3) 4626d55b61Smpi #define DUMP_STRTAB (1 << 4) 4726d55b61Smpi #define DUMP_STATISTIC (1 << 5) 4826d55b61Smpi #define DUMP_TYPE (1 << 6) 4926d55b61Smpi 5026d55b61Smpi int dump(const char *, uint8_t); 5126d55b61Smpi int isctf(const char *, size_t); 5226d55b61Smpi __dead void usage(void); 5326d55b61Smpi 5426d55b61Smpi int ctf_dump(const char *, size_t, uint8_t); 5526d55b61Smpi uint32_t ctf_dump_type(struct ctf_header *, const char *, off_t, 5626d55b61Smpi uint32_t, uint32_t); 5726d55b61Smpi const char *ctf_kind2name(uint16_t); 5826d55b61Smpi const char *ctf_enc2name(uint16_t); 59*ccd92e6dSuwe const char *ctf_fpenc2name(uint16_t); 6026d55b61Smpi const char *ctf_off2name(struct ctf_header *, const char *, off_t, 6126d55b61Smpi uint32_t); 6226d55b61Smpi 6326d55b61Smpi int elf_dump(char *, size_t, uint8_t); 6426d55b61Smpi const char *elf_idx2sym(size_t *, uint8_t); 6526d55b61Smpi 6626d55b61Smpi /* elf.c */ 6726d55b61Smpi int iself(const char *, size_t); 6826d55b61Smpi int elf_getshstab(const char *, size_t, const char **, size_t *); 6926d55b61Smpi ssize_t elf_getsymtab(const char *, const char *, size_t, 7026d55b61Smpi const Elf_Sym **, size_t *); 7126d55b61Smpi ssize_t elf_getsection(char *, const char *, const char *, 7226d55b61Smpi size_t, const char **, size_t *); 7326d55b61Smpi 7426d55b61Smpi char *decompress(const char *, size_t, off_t); 7526d55b61Smpi 7626d55b61Smpi int 7726d55b61Smpi main(int argc, char *argv[]) 7826d55b61Smpi { 7926d55b61Smpi const char *filename; 8026d55b61Smpi uint8_t flags = 0; 8126d55b61Smpi int ch, error = 0; 8226d55b61Smpi 8326e2f886Sjasper setlocale(LC_ALL, ""); 8426e2f886Sjasper 85933e960dSjasper if (pledge("stdio rpath", NULL) == -1) 86933e960dSjasper err(1, "pledge"); 87933e960dSjasper 8826d55b61Smpi while ((ch = getopt(argc, argv, "dfhlst")) != -1) { 8926d55b61Smpi switch (ch) { 9026d55b61Smpi case 'd': 9126d55b61Smpi flags |= DUMP_OBJECT; 9226d55b61Smpi break; 9326d55b61Smpi case 'f': 9426d55b61Smpi flags |= DUMP_FUNCTION; 9526d55b61Smpi break; 9626d55b61Smpi case 'h': 9726d55b61Smpi flags |= DUMP_HEADER; 9826d55b61Smpi break; 9926d55b61Smpi case 'l': 10026d55b61Smpi flags |= DUMP_LABEL; 10126d55b61Smpi break; 10226d55b61Smpi case 's': 10326d55b61Smpi flags |= DUMP_STRTAB; 10426d55b61Smpi break; 10526d55b61Smpi case 't': 10626d55b61Smpi flags |= DUMP_TYPE; 10726d55b61Smpi break; 10826d55b61Smpi default: 10926d55b61Smpi usage(); 11026d55b61Smpi } 11126d55b61Smpi } 11226d55b61Smpi 11326d55b61Smpi argc -= optind; 11426d55b61Smpi argv += optind; 11526d55b61Smpi 11626d55b61Smpi if (argc <= 0) 11726d55b61Smpi usage(); 11826d55b61Smpi 11926d55b61Smpi /* Dump everything by default */ 12026d55b61Smpi if (flags == 0) 12126d55b61Smpi flags = 0xff; 12226d55b61Smpi 12326d55b61Smpi while ((filename = *argv++) != NULL) 12426d55b61Smpi error |= dump(filename, flags); 12526d55b61Smpi 12626d55b61Smpi return error; 12726d55b61Smpi } 12826d55b61Smpi 12926d55b61Smpi int 13026d55b61Smpi dump(const char *path, uint8_t flags) 13126d55b61Smpi { 13226d55b61Smpi struct stat st; 13326d55b61Smpi int fd, error = 1; 13426d55b61Smpi char *p; 13526d55b61Smpi 13626d55b61Smpi fd = open(path, O_RDONLY); 13726d55b61Smpi if (fd == -1) { 13826d55b61Smpi warn("open"); 13926d55b61Smpi return 1; 14026d55b61Smpi } 14126d55b61Smpi if (fstat(fd, &st) == -1) { 14226d55b61Smpi warn("fstat"); 143c8f519c3Sjsg close(fd); 14426d55b61Smpi return 1; 14526d55b61Smpi } 14626d55b61Smpi if ((uintmax_t)st.st_size > SIZE_MAX) { 14726d55b61Smpi warnx("file too big to fit memory"); 148c8f519c3Sjsg close(fd); 14926d55b61Smpi return 1; 15026d55b61Smpi } 15126d55b61Smpi 15226d55b61Smpi p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 15326d55b61Smpi if (p == MAP_FAILED) 15426d55b61Smpi err(1, "mmap"); 15526d55b61Smpi 15626d55b61Smpi if (iself(p, st.st_size)) { 15726d55b61Smpi error = elf_dump(p, st.st_size, flags); 15826d55b61Smpi } else if (isctf(p, st.st_size)) { 15926d55b61Smpi error = ctf_dump(p, st.st_size, flags); 16026d55b61Smpi } 16126d55b61Smpi 16226d55b61Smpi munmap(p, st.st_size); 16326d55b61Smpi close(fd); 16426d55b61Smpi 16526d55b61Smpi return error; 16626d55b61Smpi } 16726d55b61Smpi 16826d55b61Smpi const char *strtab; 16926d55b61Smpi const Elf_Sym *symtab; 17026d55b61Smpi size_t strtabsz, nsymb; 17126d55b61Smpi 17226d55b61Smpi const char * 17326d55b61Smpi elf_idx2sym(size_t *idx, uint8_t type) 17426d55b61Smpi { 17526d55b61Smpi const Elf_Sym *st; 17626d55b61Smpi size_t i; 17726d55b61Smpi 17826d55b61Smpi for (i = *idx + 1; i < nsymb; i++) { 17926d55b61Smpi st = &symtab[i]; 18026d55b61Smpi 18126d55b61Smpi if (ELF_ST_TYPE(st->st_info) != type) 18226d55b61Smpi continue; 18326d55b61Smpi 18426d55b61Smpi *idx = i; 18526d55b61Smpi return strtab + st->st_name; 18626d55b61Smpi } 18726d55b61Smpi 18826d55b61Smpi return NULL; 18926d55b61Smpi } 19026d55b61Smpi 19126d55b61Smpi int 19226d55b61Smpi elf_dump(char *p, size_t filesize, uint8_t flags) 19326d55b61Smpi { 19426d55b61Smpi Elf_Ehdr *eh = (Elf_Ehdr *)p; 19526d55b61Smpi Elf_Shdr *sh; 19626d55b61Smpi const char *shstab; 19726d55b61Smpi size_t i, shstabsz; 19826d55b61Smpi 19926d55b61Smpi /* Find section header string table location and size. */ 20026d55b61Smpi if (elf_getshstab(p, filesize, &shstab, &shstabsz)) 20126d55b61Smpi return 1; 20226d55b61Smpi 20326d55b61Smpi /* Find symbol table location and number of symbols. */ 20426d55b61Smpi if (elf_getsymtab(p, shstab, shstabsz, &symtab, &nsymb) == -1) 20526d55b61Smpi warnx("symbol table not found"); 20626d55b61Smpi 20726d55b61Smpi /* Find string table location and size. */ 20826d55b61Smpi if (elf_getsection(p, ELF_STRTAB, shstab, shstabsz, &strtab, 20926d55b61Smpi &strtabsz) == -1) 21026d55b61Smpi warnx("string table not found"); 21126d55b61Smpi 21226d55b61Smpi /* Find CTF section and dump it. */ 21326d55b61Smpi for (i = 0; i < eh->e_shnum; i++) { 21426d55b61Smpi sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize); 21526d55b61Smpi 21626d55b61Smpi if ((sh->sh_link >= eh->e_shnum) || 21726d55b61Smpi (sh->sh_name >= shstabsz)) 21826d55b61Smpi continue; 21926d55b61Smpi 22026d55b61Smpi if (strncmp(shstab + sh->sh_name, ELF_CTF, strlen(ELF_CTF))) 22126d55b61Smpi continue; 22226d55b61Smpi 22326d55b61Smpi if (!isctf(p + sh->sh_offset, sh->sh_size)) 22426d55b61Smpi break; 22526d55b61Smpi 22626d55b61Smpi return ctf_dump(p + sh->sh_offset, sh->sh_size, flags); 22726d55b61Smpi } 22826d55b61Smpi 22926d55b61Smpi warnx("%s section not found", ELF_CTF); 23026d55b61Smpi return 1; 23126d55b61Smpi } 23226d55b61Smpi 23326d55b61Smpi int 23426d55b61Smpi isctf(const char *p, size_t filesize) 23526d55b61Smpi { 23626d55b61Smpi struct ctf_header *cth = (struct ctf_header *)p; 23726d55b61Smpi off_t dlen; 23826d55b61Smpi 23926d55b61Smpi if (filesize < sizeof(struct ctf_header)) { 24026d55b61Smpi warnx("file too small to be CTF"); 24126d55b61Smpi return 0; 24226d55b61Smpi } 24326d55b61Smpi 24426d55b61Smpi if (cth->cth_magic != CTF_MAGIC || cth->cth_version != CTF_VERSION) 24526d55b61Smpi return 0; 24626d55b61Smpi 24726d55b61Smpi dlen = cth->cth_stroff + cth->cth_strlen; 24826d55b61Smpi if (dlen > (off_t)filesize && !(cth->cth_flags & CTF_F_COMPRESS)) { 24926d55b61Smpi warnx("bogus file size"); 25026d55b61Smpi return 0; 25126d55b61Smpi } 25226d55b61Smpi 25326d55b61Smpi if ((cth->cth_lbloff & 3) || (cth->cth_objtoff & 1) || 25426d55b61Smpi (cth->cth_funcoff & 1) || (cth->cth_typeoff & 3)) { 25526d55b61Smpi warnx("wrongly aligned offset"); 25626d55b61Smpi return 0; 25726d55b61Smpi } 25826d55b61Smpi 25926d55b61Smpi if ((cth->cth_lbloff >= dlen) || (cth->cth_objtoff >= dlen) || 26026d55b61Smpi (cth->cth_funcoff >= dlen) || (cth->cth_typeoff >= dlen)) { 26126d55b61Smpi warnx("truncated file"); 26226d55b61Smpi return 0; 26326d55b61Smpi } 26426d55b61Smpi 26526d55b61Smpi if ((cth->cth_lbloff > cth->cth_objtoff) || 26626d55b61Smpi (cth->cth_objtoff > cth->cth_funcoff) || 26726d55b61Smpi (cth->cth_funcoff > cth->cth_typeoff) || 26826d55b61Smpi (cth->cth_typeoff > cth->cth_stroff)) { 26926d55b61Smpi warnx("corrupted file"); 27026d55b61Smpi return 0; 27126d55b61Smpi } 27226d55b61Smpi 27326d55b61Smpi return 1; 27426d55b61Smpi } 27526d55b61Smpi 27626d55b61Smpi int 27726d55b61Smpi ctf_dump(const char *p, size_t size, uint8_t flags) 27826d55b61Smpi { 27926d55b61Smpi struct ctf_header *cth = (struct ctf_header *)p; 28026d55b61Smpi off_t dlen = cth->cth_stroff + cth->cth_strlen; 28126d55b61Smpi char *data; 28226d55b61Smpi 28326d55b61Smpi if (cth->cth_flags & CTF_F_COMPRESS) { 28426d55b61Smpi data = decompress(p + sizeof(*cth), size - sizeof(*cth), dlen); 28526d55b61Smpi if (data == NULL) 28626d55b61Smpi return 1; 28726d55b61Smpi } else { 28826d55b61Smpi data = (char *)p + sizeof(*cth); 28926d55b61Smpi } 29026d55b61Smpi 29126d55b61Smpi if (flags & DUMP_HEADER) { 29226d55b61Smpi printf(" cth_magic = 0x%04x\n", cth->cth_magic); 29326d55b61Smpi printf(" cth_version = %d\n", cth->cth_version); 29426d55b61Smpi printf(" cth_flags = 0x%02x\n", cth->cth_flags); 29526d55b61Smpi printf(" cth_parlabel = %s\n", 29626d55b61Smpi ctf_off2name(cth, data, dlen, cth->cth_parname)); 29726d55b61Smpi printf(" cth_parname = %s\n", 29826d55b61Smpi ctf_off2name(cth, data, dlen, cth->cth_parname)); 29926d55b61Smpi printf(" cth_lbloff = %d\n", cth->cth_lbloff); 30026d55b61Smpi printf(" cth_objtoff = %d\n", cth->cth_objtoff); 30126d55b61Smpi printf(" cth_funcoff = %d\n", cth->cth_funcoff); 30226d55b61Smpi printf(" cth_typeoff = %d\n", cth->cth_typeoff); 30326d55b61Smpi printf(" cth_stroff = %d\n", cth->cth_stroff); 30426d55b61Smpi printf(" cth_strlen = %d\n", cth->cth_strlen); 30526d55b61Smpi printf("\n"); 30626d55b61Smpi } 30726d55b61Smpi 30826d55b61Smpi if (flags & DUMP_LABEL) { 30926d55b61Smpi uint32_t lbloff = cth->cth_lbloff; 31026d55b61Smpi struct ctf_lblent *ctl; 31126d55b61Smpi 31226d55b61Smpi while (lbloff < cth->cth_objtoff) { 31326d55b61Smpi ctl = (struct ctf_lblent *)(data + lbloff); 31426d55b61Smpi 31526d55b61Smpi printf(" %5u %s\n", ctl->ctl_typeidx, 31626d55b61Smpi ctf_off2name(cth, data, dlen, ctl->ctl_label)); 31726d55b61Smpi 31826d55b61Smpi lbloff += sizeof(*ctl); 31926d55b61Smpi } 32026d55b61Smpi printf("\n"); 32126d55b61Smpi } 32226d55b61Smpi 32326d55b61Smpi if (flags & DUMP_OBJECT) { 32426d55b61Smpi uint32_t objtoff = cth->cth_objtoff; 32526d55b61Smpi size_t idx = 0, i = 0; 32626d55b61Smpi uint16_t *dsp; 32726d55b61Smpi const char *s; 32826d55b61Smpi int l; 32926d55b61Smpi 33026d55b61Smpi while (objtoff < cth->cth_funcoff) { 33126d55b61Smpi dsp = (uint16_t *)(data + objtoff); 33226d55b61Smpi 33326d55b61Smpi l = printf(" [%zu] %u", i++, *dsp); 33426d55b61Smpi if ((s = elf_idx2sym(&idx, STT_OBJECT)) != NULL) 33526d55b61Smpi printf("%*s %s (%zu)\n", (14 - l), "", s, idx); 33626d55b61Smpi else 33726d55b61Smpi printf("\n"); 33826d55b61Smpi 33926d55b61Smpi objtoff += sizeof(*dsp); 34026d55b61Smpi } 34126d55b61Smpi printf("\n"); 34226d55b61Smpi } 34326d55b61Smpi 34426d55b61Smpi if (flags & DUMP_FUNCTION) { 34526d55b61Smpi uint16_t *fsp, kind, vlen; 34626d55b61Smpi size_t idx = 0, i = -1; 34726d55b61Smpi const char *s; 34826d55b61Smpi int l; 34926d55b61Smpi 35026d55b61Smpi fsp = (uint16_t *)(data + cth->cth_funcoff); 35126d55b61Smpi while (fsp < (uint16_t *)(data + cth->cth_typeoff)) { 35226d55b61Smpi kind = CTF_INFO_KIND(*fsp); 35326d55b61Smpi vlen = CTF_INFO_VLEN(*fsp); 35426d55b61Smpi s = elf_idx2sym(&idx, STT_FUNC); 35526d55b61Smpi fsp++; 35626d55b61Smpi i++; 35726d55b61Smpi 35826d55b61Smpi if (kind == CTF_K_UNKNOWN && vlen == 0) 35926d55b61Smpi continue; 36026d55b61Smpi 36126d55b61Smpi l = printf(" [%zu] FUNC ", i); 36226d55b61Smpi if (s != NULL) 36326d55b61Smpi printf("(%s)", s); 36426d55b61Smpi printf(" returns: %u args: (", *fsp++); 36526d55b61Smpi while (vlen-- > 0) 36626d55b61Smpi printf("%u%s", *fsp++, (vlen > 0) ? ", " : ""); 36726d55b61Smpi printf(")\n"); 36826d55b61Smpi } 36926d55b61Smpi printf("\n"); 37026d55b61Smpi } 37126d55b61Smpi 37226d55b61Smpi if (flags & DUMP_TYPE) { 37326d55b61Smpi uint32_t idx = 1, offset = cth->cth_typeoff; 37426d55b61Smpi 37526d55b61Smpi while (offset < cth->cth_stroff) { 37626d55b61Smpi offset += ctf_dump_type(cth, data, dlen, offset, idx++); 37726d55b61Smpi } 37826d55b61Smpi printf("\n"); 37926d55b61Smpi } 38026d55b61Smpi 38126d55b61Smpi if (flags & DUMP_STRTAB) { 38226d55b61Smpi uint32_t offset = 0; 38326d55b61Smpi const char *str; 38426d55b61Smpi 38526d55b61Smpi while (offset < cth->cth_strlen) { 38626d55b61Smpi str = ctf_off2name(cth, data, dlen, offset); 38726d55b61Smpi 38826d55b61Smpi printf(" [%u] ", offset); 38926d55b61Smpi if (strcmp(str, "(anon)")) 39026d55b61Smpi offset += printf("%s\n", str); 39126d55b61Smpi else { 39226d55b61Smpi printf("\\0\n"); 39326d55b61Smpi offset++; 39426d55b61Smpi } 39526d55b61Smpi } 39626d55b61Smpi printf("\n"); 39726d55b61Smpi } 39826d55b61Smpi 39926d55b61Smpi if (cth->cth_flags & CTF_F_COMPRESS) 40026d55b61Smpi free(data); 40126d55b61Smpi 40226d55b61Smpi return 0; 40326d55b61Smpi } 40426d55b61Smpi 40526d55b61Smpi uint32_t 40626d55b61Smpi ctf_dump_type(struct ctf_header *cth, const char *data, off_t dlen, 40726d55b61Smpi uint32_t offset, uint32_t idx) 40826d55b61Smpi { 40926d55b61Smpi const char *p = data + offset; 41026d55b61Smpi const struct ctf_type *ctt = (struct ctf_type *)p; 41126d55b61Smpi const struct ctf_array *cta; 41226d55b61Smpi uint16_t *argp, i, kind, vlen, root; 41326d55b61Smpi uint32_t eob, toff; 41426d55b61Smpi uint64_t size; 41526d55b61Smpi const char *name, *kname; 41626d55b61Smpi 41726d55b61Smpi kind = CTF_INFO_KIND(ctt->ctt_info); 41826d55b61Smpi vlen = CTF_INFO_VLEN(ctt->ctt_info); 41926d55b61Smpi root = CTF_INFO_ISROOT(ctt->ctt_info); 42026d55b61Smpi name = ctf_off2name(cth, data, dlen, ctt->ctt_name); 42126d55b61Smpi 42226d55b61Smpi if (root) 42326d55b61Smpi printf(" <%u> ", idx); 42426d55b61Smpi else 42526d55b61Smpi printf(" [%u] ", idx); 42626d55b61Smpi 42726d55b61Smpi if ((kname = ctf_kind2name(kind)) != NULL) 42826d55b61Smpi printf("%s %s", kname, name); 42926d55b61Smpi 43026d55b61Smpi if (ctt->ctt_size <= CTF_MAX_SIZE) { 43126d55b61Smpi size = ctt->ctt_size; 43226d55b61Smpi toff = sizeof(struct ctf_stype); 43326d55b61Smpi } else { 43426d55b61Smpi size = CTF_TYPE_LSIZE(ctt); 43526d55b61Smpi toff = sizeof(struct ctf_type); 43626d55b61Smpi } 43726d55b61Smpi 43826d55b61Smpi switch (kind) { 43926d55b61Smpi case CTF_K_UNKNOWN: 44026d55b61Smpi case CTF_K_FORWARD: 44126d55b61Smpi break; 44226d55b61Smpi case CTF_K_INTEGER: 44326d55b61Smpi eob = *((uint32_t *)(p + toff)); 44426d55b61Smpi toff += sizeof(uint32_t); 44526d55b61Smpi printf(" encoding=%s offset=%u bits=%u", 44626d55b61Smpi ctf_enc2name(CTF_INT_ENCODING(eob)), CTF_INT_OFFSET(eob), 44726d55b61Smpi CTF_INT_BITS(eob)); 44826d55b61Smpi break; 44926d55b61Smpi case CTF_K_FLOAT: 45026d55b61Smpi eob = *((uint32_t *)(p + toff)); 45126d55b61Smpi toff += sizeof(uint32_t); 452*ccd92e6dSuwe printf(" encoding=%s offset=%u bits=%u", 453*ccd92e6dSuwe ctf_fpenc2name(CTF_FP_ENCODING(eob)), CTF_FP_OFFSET(eob), 454*ccd92e6dSuwe CTF_FP_BITS(eob)); 45526d55b61Smpi break; 45626d55b61Smpi case CTF_K_ARRAY: 45726d55b61Smpi cta = (struct ctf_array *)(p + toff); 45826d55b61Smpi printf(" content: %u index: %u nelems: %u\n", cta->cta_contents, 45926d55b61Smpi cta->cta_index, cta->cta_nelems); 46026d55b61Smpi toff += sizeof(struct ctf_array); 46126d55b61Smpi break; 46226d55b61Smpi case CTF_K_FUNCTION: 46326d55b61Smpi argp = (uint16_t *)(p + toff); 46426d55b61Smpi printf(" returns: %u args: (%u", ctt->ctt_type, *argp); 46526d55b61Smpi for (i = 1; i < vlen; i++) { 46626d55b61Smpi argp++; 46726d55b61Smpi printf(", %u", *argp); 46826d55b61Smpi } 46926d55b61Smpi printf(")"); 47026d55b61Smpi toff += (vlen + (vlen & 1)) * sizeof(uint16_t); 47126d55b61Smpi break; 47226d55b61Smpi case CTF_K_STRUCT: 47326d55b61Smpi case CTF_K_UNION: 47426d55b61Smpi printf(" (%llu bytes)\n", size); 47526d55b61Smpi 47626d55b61Smpi if (size < CTF_LSTRUCT_THRESH) { 47726d55b61Smpi for (i = 0; i < vlen; i++) { 47826d55b61Smpi struct ctf_member *ctm; 47926d55b61Smpi 48026d55b61Smpi ctm = (struct ctf_member *)(p + toff); 48126d55b61Smpi toff += sizeof(struct ctf_member); 48226d55b61Smpi 48326d55b61Smpi printf("\t%s type=%u off=%u\n", 48426d55b61Smpi ctf_off2name(cth, data, dlen, 48526d55b61Smpi ctm->ctm_name), 48626d55b61Smpi ctm->ctm_type, ctm->ctm_offset); 48726d55b61Smpi } 48826d55b61Smpi } else { 48926d55b61Smpi for (i = 0; i < vlen; i++) { 49026d55b61Smpi struct ctf_lmember *ctlm; 49126d55b61Smpi 49226d55b61Smpi ctlm = (struct ctf_lmember *)(p + toff); 49326d55b61Smpi toff += sizeof(struct ctf_lmember); 49426d55b61Smpi 49526d55b61Smpi printf("\t%s type=%u off=%llu\n", 49626d55b61Smpi ctf_off2name(cth, data, dlen, 49726d55b61Smpi ctlm->ctlm_name), 49826d55b61Smpi ctlm->ctlm_type, CTF_LMEM_OFFSET(ctlm)); 49926d55b61Smpi } 50026d55b61Smpi } 50126d55b61Smpi break; 50226d55b61Smpi case CTF_K_ENUM: 50326d55b61Smpi printf("\n"); 50426d55b61Smpi for (i = 0; i < vlen; i++) { 50526d55b61Smpi struct ctf_enum *cte; 50626d55b61Smpi 50726d55b61Smpi cte = (struct ctf_enum *)(p + toff); 50826d55b61Smpi toff += sizeof(struct ctf_enum); 50926d55b61Smpi 51026d55b61Smpi printf("\t%s = %d\n", 51126d55b61Smpi ctf_off2name(cth, data, dlen, cte->cte_name), 51226d55b61Smpi cte->cte_value); 51326d55b61Smpi } 51426d55b61Smpi break; 51526d55b61Smpi case CTF_K_POINTER: 51626d55b61Smpi case CTF_K_TYPEDEF: 51726d55b61Smpi case CTF_K_VOLATILE: 51826d55b61Smpi case CTF_K_CONST: 51926d55b61Smpi case CTF_K_RESTRICT: 52026d55b61Smpi printf(" refers to %u", ctt->ctt_type); 52126d55b61Smpi break; 52226d55b61Smpi default: 52326d55b61Smpi errx(1, "incorrect type %u at offset %u", kind, offset); 52426d55b61Smpi } 52526d55b61Smpi 52626d55b61Smpi printf("\n"); 52726d55b61Smpi 52826d55b61Smpi return toff; 52926d55b61Smpi } 53026d55b61Smpi 53126d55b61Smpi const char * 53226d55b61Smpi ctf_kind2name(uint16_t kind) 53326d55b61Smpi { 53426d55b61Smpi static const char *kind_name[] = { NULL, "INTEGER", "FLOAT", "POINTER", 53526d55b61Smpi "ARRAY", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD", 53626d55b61Smpi "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" }; 53726d55b61Smpi 53826d55b61Smpi if (kind >= nitems(kind_name)) 53926d55b61Smpi return NULL; 54026d55b61Smpi 54126d55b61Smpi return kind_name[kind]; 54226d55b61Smpi } 54326d55b61Smpi 54426d55b61Smpi const char * 54526d55b61Smpi ctf_enc2name(uint16_t enc) 54626d55b61Smpi { 54726d55b61Smpi static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR", 54826d55b61Smpi "BOOL", "SIGNED BOOL" }; 54926d55b61Smpi static char invalid[7]; 55026d55b61Smpi 55126d55b61Smpi if (enc == CTF_INT_VARARGS) 55226d55b61Smpi return "VARARGS"; 55326d55b61Smpi 55426d55b61Smpi if (enc > 0 && enc < nitems(enc_name)) 55526d55b61Smpi return enc_name[enc - 1]; 55626d55b61Smpi 55726d55b61Smpi snprintf(invalid, sizeof(invalid), "0x%x", enc); 55826d55b61Smpi return invalid; 55926d55b61Smpi } 56026d55b61Smpi 56126d55b61Smpi const char * 562*ccd92e6dSuwe ctf_fpenc2name(uint16_t enc) 563*ccd92e6dSuwe { 564*ccd92e6dSuwe static const char *enc_name[] = { "SINGLE", "DOUBLE", NULL, NULL, 565*ccd92e6dSuwe NULL, "LDOUBLE" }; 566*ccd92e6dSuwe static char invalid[7]; 567*ccd92e6dSuwe 568*ccd92e6dSuwe if (enc > 0 && enc <= nitems(enc_name) && enc_name[enc - 1] != NULL) 569*ccd92e6dSuwe return enc_name[enc - 1]; 570*ccd92e6dSuwe 571*ccd92e6dSuwe snprintf(invalid, sizeof(invalid), "0x%x", enc); 572*ccd92e6dSuwe return invalid; 573*ccd92e6dSuwe } 574*ccd92e6dSuwe 575*ccd92e6dSuwe const char * 57626d55b61Smpi ctf_off2name(struct ctf_header *cth, const char *data, off_t dlen, 57726d55b61Smpi uint32_t offset) 57826d55b61Smpi { 57926d55b61Smpi const char *name; 58026d55b61Smpi 58126d55b61Smpi if (CTF_NAME_STID(offset) != CTF_STRTAB_0) 58226d55b61Smpi return "external"; 58326d55b61Smpi 58426d55b61Smpi if (CTF_NAME_OFFSET(offset) >= cth->cth_strlen) 58526d55b61Smpi return "exceeds strlab"; 58626d55b61Smpi 58726d55b61Smpi if (cth->cth_stroff + CTF_NAME_OFFSET(offset) >= dlen) 58826d55b61Smpi return "invalid"; 58926d55b61Smpi 59026d55b61Smpi name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset); 59126d55b61Smpi if (*name == '\0') 59226d55b61Smpi return "(anon)"; 59326d55b61Smpi 59426d55b61Smpi return name; 59526d55b61Smpi } 59626d55b61Smpi 59726d55b61Smpi char * 59826d55b61Smpi decompress(const char *buf, size_t size, off_t len) 59926d55b61Smpi { 60026d55b61Smpi #ifdef ZLIB 60126d55b61Smpi z_stream stream; 60226d55b61Smpi char *data; 60326d55b61Smpi int error; 60426d55b61Smpi 60526d55b61Smpi data = malloc(len); 60626d55b61Smpi if (data == NULL) { 60726d55b61Smpi warn(NULL); 60826d55b61Smpi return NULL; 60926d55b61Smpi } 61026d55b61Smpi 61126d55b61Smpi memset(&stream, 0, sizeof(stream)); 61226d55b61Smpi stream.next_in = (void *)buf; 61326d55b61Smpi stream.avail_in = size; 61426d55b61Smpi stream.next_out = (uint8_t *)data; 61526d55b61Smpi stream.avail_out = len; 61626d55b61Smpi 61726d55b61Smpi if ((error = inflateInit(&stream)) != Z_OK) { 61826d55b61Smpi warnx("zlib inflateInit failed: %s", zError(error)); 61926d55b61Smpi goto exit; 62026d55b61Smpi } 62126d55b61Smpi 62226d55b61Smpi if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) { 62326d55b61Smpi warnx("zlib inflate failed: %s", zError(error)); 62426d55b61Smpi inflateEnd(&stream); 62526d55b61Smpi goto exit; 62626d55b61Smpi } 62726d55b61Smpi 62826d55b61Smpi if ((error = inflateEnd(&stream)) != Z_OK) { 62926d55b61Smpi warnx("zlib inflateEnd failed: %s", zError(error)); 63026d55b61Smpi goto exit; 63126d55b61Smpi } 63226d55b61Smpi 63326d55b61Smpi if (stream.total_out != len) { 63426d55b61Smpi warnx("decompression failed: %llu != %llu", 63526d55b61Smpi stream.total_out, len); 63626d55b61Smpi goto exit; 63726d55b61Smpi } 63826d55b61Smpi 63926d55b61Smpi return data; 64026d55b61Smpi 64126d55b61Smpi exit: 64226d55b61Smpi free(data); 64326d55b61Smpi #endif /* ZLIB */ 64426d55b61Smpi return NULL; 64526d55b61Smpi } 64626d55b61Smpi 64726d55b61Smpi __dead void 64826d55b61Smpi usage(void) 64926d55b61Smpi { 65026d55b61Smpi fprintf(stderr, "usage: %s [-dfhlst] file ...\n", 65126d55b61Smpi getprogname()); 65226d55b61Smpi exit(1); 65326d55b61Smpi } 654