Index: head/usr.sbin/kvm_mkdb/nlist.c =================================================================== --- head/usr.sbin/kvm_mkdb/nlist.c (revision 40688) +++ head/usr.sbin/kvm_mkdb/nlist.c (revision 40689) @@ -1,339 +1,368 @@ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD$ */ #ifndef lint #if 0 static char sccsid[] = "@(#)from: nlist.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = - "$Id: nlist.c,v 1.8 1997/09/24 06:44:10 charnier Exp $"; + "$Id: nlist.c,v 1.9 1998/08/17 08:46:46 dfr Exp $"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "extern.h" #ifdef DO_ELF #include #endif typedef struct nlist NLIST; #define _strx n_un.n_strx #define _name n_un.n_name #define badfmt(str) errx(1, "%s: %s: %s", kfile, str, strerror(EFTYPE)) static char *kfile; #if defined(DO_AOUT) int __aout_knlist(name, db) char *name; DB *db; { register int nsyms; struct exec *ebuf; NLIST *nbuf; DBT data, key; int fd; char *strtab; u_char *filep; char *vp; struct stat sst; long cur_off, voff; kfile = name; if ((fd = open(name, O_RDONLY, 0)) < 0) err(1, "%s", name); fstat(fd,&sst); filep = (u_char*)mmap(0, sst.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (filep == (u_char*)MAP_FAILED) err(1, "mmap failed"); /* Read in exec structure. */ ebuf = (struct exec *) filep; /* Check magic number and symbol count. */ if (N_BADMAG(*ebuf)) badfmt("bad magic number"); if (!ebuf->a_syms) badfmt("stripped"); strtab = filep + N_STROFF(*ebuf) + sizeof (int); /* Seek to symbol table. */ cur_off = N_SYMOFF(*ebuf); /* Read each symbol and enter it into the database. */ nsyms = ebuf->a_syms / sizeof(struct nlist); while (nsyms--) { nbuf = (NLIST *)(filep + cur_off); cur_off += sizeof(NLIST); if (!nbuf->_strx || nbuf->n_type&N_STAB) continue; key.data = (u_char *)strtab + nbuf->_strx - sizeof(long); key.size = strlen((char *)key.data); data.data = (u_char *)nbuf; data.size = sizeof(NLIST); if (db->put(db, &key, &data, 0)) err(1, "record enter"); if (1 && strcmp((char *)key.data, VRS_SYM) == 0) { #ifndef KERNTEXTOFF /* * XXX * The FreeBSD bootloader loads the kernel at the a_entry address, meaning * that this is where the kernel starts. (not at KERNBASE) * * This may be introducing an i386 dependency. */ #if defined(__FreeBSD__) #define KERNTEXTOFF ebuf->a_entry #else #define KERNTEXTOFF KERNBASE #endif #endif /* * Calculate offset relative to a normal (non-kernel) * a.out. KERNTEXTOFF is where the kernel is really * loaded; N_TXTADDR is where a normal file is loaded. * From there, locate file offset in text or data. */ voff = nbuf->n_value - KERNTEXTOFF + N_TXTADDR(*ebuf); if ((nbuf->n_type & N_TYPE) == N_TEXT) voff += N_TXTOFF(*ebuf) - N_TXTADDR(*ebuf); else voff += N_DATOFF(*ebuf) - N_DATADDR(*ebuf); vp = filep + voff; key.data = (u_char *)VRS_KEY; key.size = sizeof(VRS_KEY) - 1; data.data = vp; data.size = strchr(vp, '\n') - vp + 1; if (db->put(db, &key, &data, 0)) err(1, "record enter"); /* Restore to original values. */ data.size = sizeof(NLIST); } } return(0); } #endif /* DO_AOUT */ #ifdef DO_ELF +static void elf_sym_to_nlist __P((struct nlist *, Elf_Sym *, Elf_Shdr *, int)); + int __elf_knlist(name, db) char *name; DB *db; { register caddr_t strtab; - register off_t symstroff, symoff; - register u_long symsize; + register off_t symstroff = 0, symoff = 0; + register u_long symsize = 0; register u_long kernvma, kernoffs; register int i; Elf_Sym *sbuf; size_t symstrsize; char *shstr, buf[1024]; Elf_Ehdr *eh; Elf_Shdr *sh = NULL; DBT data, key; NLIST nbuf; int fd; u_char *filep; struct stat sst; kfile = name; if ((fd = open(name, O_RDONLY, 0)) < 0) err(1, "%s", name); fstat(fd, &sst); /* Check for files too large to mmap. */ /* XXX is this really possible? */ if (sst.st_size > SIZE_T_MAX) { badfmt("corrupt file"); } filep = (u_char*)mmap(0, sst.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (filep == (u_char*)MAP_FAILED) err(1, "mmap failed"); /* Read in exec structure. */ eh = (Elf_Ehdr *) filep; if (!IS_ELF(*eh)) return(-1); sh = (Elf_Shdr *)&filep[eh->e_shoff]; shstr = (char *)&filep[sh[eh->e_shstrndx].sh_offset]; for (i = 0; i < eh->e_shnum; i++) { if (strcmp (shstr + sh[i].sh_name, ".strtab") == 0) { symstroff = sh[i].sh_offset; symstrsize = sh[i].sh_size; } else if (strcmp (shstr + sh[i].sh_name, ".symtab") == 0) { symoff = sh[i].sh_offset; symsize = sh[i].sh_size; } else if (strcmp (shstr + sh[i].sh_name, ".text") == 0) { kernvma = sh[i].sh_addr; kernoffs = sh[i].sh_offset; } } + if (symsize == 0) + badfmt("stripped"); strtab = (char *)&filep[symstroff]; data.data = (u_char *)&nbuf; data.size = sizeof(NLIST); /* Read each symbol and enter it into the database. */ for (i = 0; symsize > 0; i++, symsize -= sizeof(Elf_Sym)) { sbuf = (Elf_Sym *)&filep[symoff + i * sizeof(*sbuf)]; if (!sbuf->st_name) continue; - - nbuf.n_value = sbuf->st_value; - - /*XXX type conversion is pretty rude... */ - switch (ELF_ST_TYPE(sbuf->st_info)) { - case STT_NOTYPE: - nbuf.n_type = N_UNDF; - break; - case STT_FUNC: - nbuf.n_type = N_TEXT; - break; - case STT_OBJECT: - nbuf.n_type = N_DATA; - break; - } - if (ELF_ST_BIND(sbuf->st_info) == STB_LOCAL) - nbuf.n_type = N_EXT; - + elf_sym_to_nlist(&nbuf, sbuf, sh, eh->e_shnum); key.data = (u_char *)(strtab + sbuf->st_name); key.size = strlen((char *)key.data); if (db->put(db, &key, &data, 0)) err(1, "record enter"); /* also put in name prefixed with _ */ *buf = '_'; strcpy(buf + 1, strtab + sbuf->st_name); key.data = (u_char *)buf; key.size = strlen((char *)key.data); if (db->put(db, &key, &data, 0)) err(1, "record enter"); /* Special processing for "_version" (depends on above) */ if (strcmp((char *)key.data, VRS_SYM) == 0) { char *vp; key.data = (u_char *)VRS_KEY; key.size = sizeof(VRS_KEY) - 1; /* Find the version string, relative to its section */ data.data = strdup(&filep[nbuf.n_value - sh[sbuf->st_shndx].sh_addr + sh[sbuf->st_shndx].sh_offset]); /* assumes newline terminates version. */ if ((vp = strchr(data.data, '\n')) != NULL) *vp = '\0'; data.size = strlen((char *)data.data); if (db->put(db, &key, &data, 0)) err(1, "record enter"); /* Restore to original values. */ data.data = (u_char *)&nbuf; data.size = sizeof(NLIST); } } munmap(filep, sst.st_size); (void)close(fd); return(0); +} + +/* + * Convert an Elf_Sym into an nlist structure. This fills in only the + * n_value and n_type members. + */ +static void +elf_sym_to_nlist(nl, s, shdr, shnum) + struct nlist *nl; + Elf_Sym *s; + Elf_Shdr *shdr; + int shnum; +{ + nl->n_value = s->st_value; + + switch (s->st_shndx) { + case SHN_UNDEF: + case SHN_COMMON: + nl->n_type = N_UNDF; + break; + case SHN_ABS: + nl->n_type = ELF_ST_TYPE(s->st_info) == STT_FILE ? + N_FN : N_ABS; + break; + default: + if (s->st_shndx >= shnum) + nl->n_type = N_UNDF; + else { + Elf_Shdr *sh = shdr + s->st_shndx; + + nl->n_type = sh->sh_type == SHT_PROGBITS ? + (sh->sh_flags & SHF_WRITE ? N_DATA : N_TEXT) : + (sh->sh_type == SHT_NOBITS ? N_BSS : N_UNDF); + } + break; + } + + if (ELF_ST_BIND(s->st_info) == STB_GLOBAL || + ELF_ST_BIND(s->st_info) == STB_WEAK) + nl->n_type |= N_EXT; } #endif /* DO_ELF */ static struct knlist_handlers { int (*fn) __P((char *name, DB *db)); } nlist_fn[] = { #ifdef DO_ELF { __elf_knlist }, #endif #ifdef DO_AOUT { __aout_knlist }, #endif }; void create_knlist(name, db) char *name; DB *db; { int n, i; for (i = 0; i < sizeof(nlist_fn)/sizeof(nlist_fn[0]); i++) { n = (nlist_fn[i].fn)(name, db); if (n != -1) break; } }