int ELFNAMEEND(__fdnlist)(int fd, struct nlist *list) { struct stat st; Elf_Ehdr ehdr; #if defined(_LP64) || ELFSIZE == 32 || defined(ELF64_MACHDEP_ID) #if (ELFSIZE == 32) Elf32_Half nshdr; #elif (ELFSIZE == 64) Elf64_Word nshdr; #endif /* Only support 64+32 mode on LP64 and those that have defined */ /* ELF64_MACHDEP_ID, otherwise no support for 64 mode on ILP32 */ Elf_Ehdr *ehdrp; Elf_Shdr *shdrp, *symshdrp, *symstrshdrp; Elf_Sym *symp; Elf_Off shdr_off; Elf_Word shdr_size; struct nlist *p; char *mappedfile, *strtab; size_t mappedsize, nsyms; int nent; #endif int rv; size_t i; _DIAGASSERT(fd != -1); _DIAGASSERT(list != NULL); rv = -1; /* * If we can't fstat() the file, something bad is going on. */ if (fstat(fd, &st) < 0) BAD; /* * Map the file in its entirety. */ if ((uintmax_t)st.st_size > (uintmax_t)SIZE_T_MAX) { errno = EFBIG; BAD; } /* * Read the elf header of the file. */ if ((ssize_t)(i = pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0)) == -1) BAD; /* * Check that the elf header is correct. */ if (i != sizeof(Elf_Ehdr)) BAD; if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || ehdr.e_ident[EI_CLASS] != ELFCLASS) BAD; switch (ehdr.e_machine) { ELFDEFNNAME(MACHDEP_ID_CASES) default: BAD; } #if defined(_LP64) || ELFSIZE == 32 || defined(ELF64_MACHDEP_ID) symshdrp = symstrshdrp = NULL; /* Only support 64+32 mode on LP64 and those that have defined */ /* ELF64_MACHDEP_ID, otherwise no support for 64 mode on ILP32 */ if (S_ISCHR(st.st_mode)) { const char *nlistname; Elf_Sym sym; /* * Character device; assume /dev/ksyms. */ nent = 0; for (p = list; !ISLAST(p); ++p) { struct ksyms_gsymbol kg; int error; p->n_other = 0; p->n_desc = 0; nlistname = N_NAME(p); if (*nlistname == '_') nlistname++; memset(&kg, 0, sizeof(kg)); kg.kg_name = nlistname; #ifdef OKIOCGSYMBOL struct ksyms_ogsymbol okg; error = ioctl(fd, KIOCGSYMBOL, &kg); if (error == 0) { sym = kg.kg_sym; } else if (error && errno == ENOTTY) { memset(&okg, 0, sizeof(okg)); okg.kg_name = nlistname; okg.kg_sym = &sym; error = ioctl(fd, OKIOCGSYMBOL, &okg); } #else kg.kg_sym = &sym; error = ioctl(fd, KIOCGSYMBOL, &kg); #endif if (error == 0 #if !defined(_LP64) && ELFSIZE == 64 #if __mips__ && (intptr_t)sym.st_value == (intmax_t)sym.st_value #else && (uintptr_t)sym.st_value == sym.st_value #endif #endif && 1) { p->n_value = (uintptr_t)sym.st_value; switch (ELF_ST_TYPE(sym.st_info)) { case STT_NOTYPE: p->n_type = N_UNDF; break; case STT_COMMON: case STT_OBJECT: p->n_type = N_DATA; break; case STT_FUNC: p->n_type = N_TEXT; break; case STT_FILE: p->n_type = N_FN; break; default: p->n_type = 0; /* catch other enumerations for gcc */ break; } if (ELF_ST_BIND(sym.st_info) != STB_LOCAL) p->n_type |= N_EXT; } else { nent++; p->n_value = 0; p->n_type = 0; } } return nent; } mappedsize = (size_t)st.st_size; mappedfile = mmap(NULL, mappedsize, PROT_READ, MAP_PRIVATE|MAP_FILE, fd, (off_t)0); if (mappedfile == (char *)-1) BAD; /* * Make sure we can access the executable's header * directly, and make sure the recognize the executable * as an ELF binary. */ if (check(0, sizeof *ehdrp)) BADUNMAP; ehdrp = (Elf_Ehdr *)(void *)&mappedfile[0]; /* * Find the symbol list and string table. */ nshdr = ehdrp->e_shnum; shdr_off = ehdrp->e_shoff; shdr_size = ehdrp->e_shentsize * nshdr; if (check(shdr_off, shdr_size) || (sizeof *shdrp != ehdrp->e_shentsize)) BADUNMAP; shdrp = (void *)&mappedfile[(size_t)shdr_off]; for (i = 0; i < nshdr; i++) { if (shdrp[i].sh_type == SHT_SYMTAB) { symshdrp = &shdrp[i]; symstrshdrp = &shdrp[shdrp[i].sh_link]; } } /* Make sure we're not stripped. */ if (symshdrp == NULL || symshdrp->sh_offset == 0) BADUNMAP; /* Make sure the symbols and strings are safely mapped. */ if (check(symshdrp->sh_offset, symshdrp->sh_size)) BADUNMAP; if (check(symstrshdrp->sh_offset, symstrshdrp->sh_size)) BADUNMAP; symp = (void *)&mappedfile[(size_t)symshdrp->sh_offset]; nsyms = (size_t)(symshdrp->sh_size / sizeof(*symp)); strtab = &mappedfile[(size_t)symstrshdrp->sh_offset]; /* * Clean out any left-over information for all valid entries. * Type and value are defined to be 0 if not found; historical * versions cleared other and desc as well. * * XXX Clearing anything other than n_type and n_value violates * the semantics given in the man page. */ nent = 0; for (p = list; !ISLAST(p); ++p) { p->n_type = 0; p->n_other = 0; p->n_desc = 0; p->n_value = 0; ++nent; } for (i = 0; i < nsyms; i++) { for (p = list; !ISLAST(p); ++p) { const char *nlistname; char *symtabname; /* This may be incorrect */ nlistname = N_NAME(p); if (*nlistname == '_') nlistname++; symtabname = &strtab[symp[i].st_name]; if (!strcmp(symtabname, nlistname)) { /* * Translate (roughly) from ELF to nlist */ p->n_value = (uintptr_t)symp[i].st_value; switch (ELF_ST_TYPE(symp[i].st_info)) { case STT_NOTYPE: p->n_type = N_UNDF; break; case STT_OBJECT: case STT_COMMON: p->n_type = N_DATA; break; case STT_FUNC: p->n_type = N_TEXT; break; case STT_FILE: p->n_type = N_FN; break; default: /* catch other enumerations for gcc */ break; } if (ELF_ST_BIND(symp[i].st_info) != STB_LOCAL) p->n_type |= N_EXT; p->n_desc = 0; /* XXX */ p->n_other = 0; /* XXX */ if (--nent <= 0) goto done; break; /* into next run of outer loop */ } } } done: rv = nent; unmap: munmap(mappedfile, mappedsize); #endif /* _LP64 || ELFSIZE == 32 || ELF64_MACHDEP_ID */ out: return (rv); }
int __fdnlist_coff(int fd, struct nlist *list) { struct nlist *p; struct coff_filehdr *filehdrp; struct stat st; char *mappedfile; size_t mappedsize; u_long symoff, extstroff; int rv, nent; long i, nesyms; _DIAGASSERT(fd != -1); _DIAGASSERT(list != NULL); rv = -1; /* * If we can't fstat() the file, something bad is going on. */ if (fstat(fd, &st) < 0) goto out; /* * Map the file in its entirety. */ if ((uintmax_t)st.st_size > (uintmax_t)SIZE_T_MAX) { errno = EFBIG; goto out; } mappedsize = (size_t)st.st_size; mappedfile = mmap(NULL, mappedsize, PROT_READ, MAP_PRIVATE|MAP_FILE, fd, 0); if (mappedfile == MAP_FAILED) goto out; /* * Make sure we can access the executable's header * directly, and make sure we recognize the executable * as an COFF binary. */ if (mappedsize < sizeof (struct coff_filehdr)) goto unmap; filehdrp = (void *)&mappedfile[0]; if (COFF_BADMAG(filehdrp)) goto unmap; /* * Find the symbol list. */ symoff = filehdrp->f_symptr; nesyms = filehdrp->f_nsyms; if (symoff + ES_LEN * nesyms > mappedsize) goto unmap; extstroff = symoff + ES_LEN * nesyms; nent = 0; for (p = list; !ISLAST(p); ++p) { p->n_type = 0; p->n_other = 0; p->n_desc = 0; p->n_value = 0; ++nent; } for (i = 0; i < nesyms; i++) { char *symtabname; const char *nlistname; struct coff_extsym esym; char name[10]; memcpy(&esym, &mappedfile[symoff + ES_LEN * i], ES_LEN); if (esym.es_numaux != 0) { i += esym.es_numaux; /* XXX Skip aux entry */ continue; } if (esym.es_zero != 0) { memcpy(name, esym.es_name, 8); name[8] = 0; symtabname = name; } else if (esym.es_offset != 0) symtabname = &mappedfile[extstroff + esym.es_offset]; else continue; for (p = list; !ISLAST(p); p++) { nlistname = N_NAME(p); if (!strcmp(symtabname, nlistname)) { /* * Translate (roughly) from COFF to nlist */ p->n_value = esym.es_value; p->n_type = N_EXT; /* XXX */ p->n_desc = 0; /* XXX */ p->n_other = 0; /* XXX */ if (--nent <= 0) goto done; break; /* into next run of outer loop */ } } } done: rv = nent; unmap: munmap(mappedfile, mappedsize); out: return rv; }