int coff_syms(FILE *in) { struct coff_header hdr; char *strtab; uint8_t *symtab; int strtab_len; int i; int ret = 0; if (read_header(in, &hdr) < 0) return -1; strtab_len = read_strtab(in, &hdr, &strtab); if (strtab_len < 0) return -1; if (read_symtab(in, &hdr, &symtab) < 0) { if (strtab) free(strtab); return -1; } for (i = 0; i < hdr.stab_count; i++) { uint8_t *entry = symtab + i * STAB_ENTRY_SIZE; uint32_t value = LE_LONG(entry, 8); int storage_class = entry[16]; char namebuf[9]; const char *name = NULL; if (LE_LONG(entry, 0)) { memcpy(namebuf, entry, 8); namebuf[8] = 0; name = namebuf; } else { uint32_t offset = LE_LONG(entry, 4); if (offset >= 4 && offset < strtab_len) name = strtab + offset; } if (name && (storage_class == C_EXT || storage_class == C_LABEL) && stab_set(name, value) < 0) { printc_err("coff: failed to insert symbol\n"); ret = -1; break; } /* Skip auxiliary entries */ i += entry[17]; } if (symtab) free(symtab); if (strtab) free(strtab); return ret; }
int main(int argc, char *argv[]) { const char *filename = NULL; const char *ufile = NULL; int error = 0; int c, fd, ufd; ctf_data_t cd; const ctf_preamble_t *pp; ctf_header_t *hp; Elf *elf; GElf_Ehdr ehdr; (void) elf_version(EV_CURRENT); for (opterr = 0; optind < argc; optind++) { while ((c = getopt(argc, argv, "dfhlsStu:")) != (int)EOF) { switch (c) { case 'd': flags |= F_DATA; break; case 'f': flags |= F_FUNC; break; case 'h': flags |= F_HDR; break; case 'l': flags |= F_LABEL; break; case 's': flags |= F_STR; break; case 'S': flags |= F_STATS; break; case 't': flags |= F_TYPES; break; case 'u': ufile = optarg; break; default: if (optopt == '?') return (print_usage(stdout, 1)); warn("illegal option -- %c\n", optopt); return (print_usage(stderr, 0)); } } if (optind < argc) { if (filename != NULL) return (print_usage(stderr, 0)); filename = argv[optind]; } } if (filename == NULL) return (print_usage(stderr, 0)); if (flags == 0 && ufile == NULL) flags = F_ALLMSK; if ((fd = open(filename, O_RDONLY)) == -1) die("failed to open %s", filename); if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL && gelf_getehdr(elf, &ehdr) != NULL) { Elf_Data *dp; Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf"); Elf_Scn *symscn; GElf_Shdr ctfshdr; if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL) die("%s does not contain .SUNW_ctf data\n", filename); cd.cd_ctfdata = dp->d_buf; cd.cd_ctflen = dp->d_size; /* * If the sh_link field of the CTF section header is non-zero * it indicates which section contains the symbol table that * should be used. We default to the .symtab section if sh_link * is zero or if there's an error reading the section header. */ if (gelf_getshdr(ctfscn, &ctfshdr) != NULL && ctfshdr.sh_link != 0) { symscn = elf_getscn(elf, ctfshdr.sh_link); } else { symscn = findelfscn(elf, &ehdr, ".symtab"); } /* If we found a symbol table, find the corresponding strings */ if (symscn != NULL) { GElf_Shdr shdr; Elf_Scn *symstrscn; if (gelf_getshdr(symscn, &shdr) != NULL) { symstrscn = elf_getscn(elf, shdr.sh_link); cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize; cd.cd_symdata = elf_getdata(symscn, NULL); cd.cd_strdata = elf_getdata(symstrscn, NULL); } } } else { struct stat st; if (fstat(fd, &st) == -1) die("failed to fstat %s", filename); cd.cd_ctflen = st.st_size; cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ, MAP_PRIVATE, fd, 0); if (cd.cd_ctfdata == MAP_FAILED) die("failed to mmap %s", filename); } /* * Get a pointer to the CTF data buffer and interpret the first portion * as a ctf_header_t. Validate the magic number and size. */ if (cd.cd_ctflen < sizeof (ctf_preamble_t)) die("%s does not contain a CTF preamble\n", filename); /* LINTED - pointer alignment */ pp = (const ctf_preamble_t *)cd.cd_ctfdata; if (pp->ctp_magic != CTF_MAGIC) die("%s does not appear to contain CTF data\n", filename); if (pp->ctp_version == CTF_VERSION) { /* LINTED - pointer alignment */ hp = (ctf_header_t *)cd.cd_ctfdata; cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t); if (cd.cd_ctflen < sizeof (ctf_header_t)) { die("%s does not contain a v%d CTF header\n", filename, CTF_VERSION); } } else { die("%s contains unsupported CTF version %d\n", filename, pp->ctp_version); } /* * If the data buffer is compressed, then malloc a buffer large enough * to hold the decompressed data, and use zlib to decompress it. */ if (hp->cth_flags & CTF_F_COMPRESS) { z_stream zstr; void *buf; int rc; if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL) die("failed to allocate decompression buffer"); bzero(&zstr, sizeof (z_stream)); zstr.next_in = (void *)cd.cd_ctfdata; zstr.avail_in = cd.cd_ctflen; zstr.next_out = buf; zstr.avail_out = hp->cth_stroff + hp->cth_strlen; if ((rc = inflateInit(&zstr)) != Z_OK) die("failed to initialize zlib: %s\n", zError(rc)); if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END) die("failed to decompress CTF data: %s\n", zError(rc)); if ((rc = inflateEnd(&zstr)) != Z_OK) die("failed to finish decompression: %s\n", zError(rc)); if (zstr.total_out != hp->cth_stroff + hp->cth_strlen) die("CTF data is corrupt -- short decompression\n"); cd.cd_ctfdata = buf; cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen; } if (flags & F_HDR) error |= print_header(hp, &cd); if (flags & (F_LABEL)) error |= print_labeltable(hp, &cd); if (flags & (F_DATA | F_STATS)) error |= read_data(hp, &cd); if (flags & (F_FUNC | F_STATS)) error |= read_funcs(hp, &cd); if (flags & (F_TYPES | F_STATS)) error |= read_types(hp, &cd); if (flags & (F_STR | F_STATS)) error |= read_strtab(hp, &cd); if (flags & F_STATS) error |= print_stats(); /* * If the -u option is specified, write the uncompressed CTF data to a * raw CTF file. CTF data can already be extracted compressed by * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother. */ if (ufile != NULL) { ctf_header_t h; bcopy(hp, &h, sizeof (h)); h.cth_flags &= ~CTF_F_COMPRESS; if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 || write(ufd, &h, sizeof (h)) != sizeof (h) || write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != cd.cd_ctflen) { warn("failed to write CTF data to '%s'", ufile); error |= E_ERROR; } (void) close(ufd); } if (elf != NULL) (void) elf_end(elf); (void) close(fd); return (error); }