Home | History | Annotate | Line # | Download | only in kvm_mkdb
nlist_ecoff.c revision 1.6
      1 /* $NetBSD: nlist_ecoff.c,v 1.6 2000/06/14 06:49:25 cgd Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *      This product includes software developed by Christopher G. Demetriou
     17  *	for the NetBSD Project.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 #ifndef lint
     35 __RCSID("$NetBSD: nlist_ecoff.c,v 1.6 2000/06/14 06:49:25 cgd Exp $");
     36 #endif /* not lint */
     37 
     38 #include <sys/param.h>
     39 #include <sys/mman.h>
     40 #include <sys/stat.h>
     41 
     42 #include <a.out.h>
     43 #include <db.h>
     44 #include <err.h>
     45 #include <errno.h>
     46 #include <fcntl.h>
     47 #include <kvm.h>
     48 #include <limits.h>
     49 #include <stdio.h>
     50 #include <stdlib.h>
     51 #include <string.h>
     52 #include <unistd.h>
     53 
     54 #include "extern.h"
     55 
     56 #ifdef NLIST_ECOFF
     57 #include <sys/exec_ecoff.h>
     58 
     59 typedef struct nlist NLIST;
     60 #define	_strx	n_un.n_strx
     61 #define	_name	n_un.n_name
     62 
     63 #define	badfmt(str)							\
     64 	do {								\
     65 		warnx("%s: %s: %s", kfile, str, strerror(EFTYPE));	\
     66 		punt();							\
     67 	} while (0)
     68 
     69 #define	check(off, size)	((off < 0) || (off + size > mappedsize))
     70 #define	BAD			do { rv = -1; goto out; } while (0)
     71 #define	BADUNMAP		do { rv = -1; goto unmap; } while (0)
     72 
     73 static const char *kfile;
     74 
     75 int
     76 create_knlist_ecoff(name, db)
     77 	const char *name;
     78 	DB *db;
     79 {
     80 	struct ecoff_exechdr *exechdrp;
     81 	struct ecoff_symhdr *symhdrp;
     82 	struct ecoff_extsym *esyms;
     83 	struct stat st;
     84 	struct nlist nbuf;
     85 	DBT key, data;
     86 	char *mappedfile, *symname, *fsymname, *tmpcp;
     87 	size_t mappedsize, symnamesize, fsymnamesize;
     88 	u_long symhdroff, extrstroff;
     89 	u_long symhdrsize, i, nesyms;
     90 	int fd, rv;
     91 
     92 	rv = -1;
     93 
     94 	/*
     95 	 * Open and map the whole file.  If we can't open/stat it,
     96 	 * something bad is going on so we punt.
     97 	 */
     98 	kfile = name;
     99 	if ((fd = open(name, O_RDONLY, 0)) < 0) {
    100 		warn("%s", kfile);
    101 		punt();
    102 	}
    103 	if (fstat(fd, &st) < 0) {
    104 		warn("%s", kfile);
    105 		punt();
    106 	}
    107 	if (st.st_size > SIZE_T_MAX)
    108 		BAD;
    109 
    110 	/*
    111 	 * Map the file in its entirety.
    112 	 */
    113 	mappedsize = st.st_size;
    114 	mappedfile = mmap(NULL, mappedsize, PROT_READ, MAP_FILE|MAP_PRIVATE,
    115 	    fd, 0);
    116 	if (mappedfile == (char *)-1)
    117 		BAD;
    118 
    119 	/*
    120 	 * Make sure we can access the executable's header
    121 	 * directly, and make sure the recognize the executable
    122 	 * as an ECOFF binary.
    123 	 */
    124 	if (check(0, sizeof *exechdrp))
    125 		BADUNMAP;
    126 	exechdrp = (struct ecoff_exechdr *)&mappedfile[0];
    127 
    128 	if (ECOFF_BADMAG(exechdrp))
    129 		BADUNMAP;
    130 
    131 	/*
    132 	 * We've recognized it as an ECOFF binary.  From here
    133 	 * on out, all errors are fatal.
    134 	 */
    135 
    136 	/*
    137 	 * Find the symbol list and string table.
    138 	 */
    139 	symhdroff = exechdrp->f.f_symptr;
    140 	symhdrsize = exechdrp->f.f_nsyms;
    141 
    142 	if (symhdrsize == 0)
    143 		badfmt("stripped");
    144 	if (check(symhdroff, sizeof *symhdrp) || sizeof *symhdrp != symhdrsize)
    145 		badfmt("bogus symbol table");
    146 	symhdrp = (struct ecoff_symhdr *)&mappedfile[symhdroff];
    147 
    148 	nesyms = symhdrp->esymMax;
    149 	if (check(symhdrp->cbExtOffset, nesyms * sizeof *esyms))
    150 		badfmt("bogus external symbol list");
    151 	esyms = (struct ecoff_extsym *)&mappedfile[symhdrp->cbExtOffset];
    152 	extrstroff = symhdrp->cbSsExtOffset;
    153 
    154 	/*
    155 	 * Set up the data item, pointing to a nlist structure.
    156 	 * which we fill in for each symbol.
    157 	 */
    158 	data.data = (u_char *)&nbuf;
    159 	data.size = sizeof(nbuf);
    160 
    161 	/*
    162 	 * Create a buffer (to be expanded later, if necessary)
    163 	 * to hold symbol names after we've added underscores
    164 	 * to them.
    165 	 */
    166 	symnamesize = 1024;
    167 	if ((symname = malloc(symnamesize)) == NULL) {
    168 		warn("malloc");
    169 		punt();
    170 	}
    171 
    172 	/*
    173 	 * Read each symbol and enter it into the database.
    174 	 */
    175 	for (i = 0; i < nesyms; i++) {
    176 
    177 		/*
    178 		 * Find symbol name, copy it (with added underscore) to
    179 		 * temporary buffer, and prepare the database key for
    180 		 * insertion.
    181 		 */
    182 		fsymname = &mappedfile[extrstroff + esyms[i].es_strindex];
    183 		fsymnamesize = strlen(fsymname) + 1;
    184 		while (symnamesize < fsymnamesize + 1) {
    185 			symnamesize *= 2;
    186 			if ((symname = realloc(symname, symnamesize)) == NULL) {
    187 				warn("malloc");
    188 				punt();
    189 			}
    190 		}
    191 		strcpy(symname, "_");
    192 		strcat(symname, fsymname);
    193 
    194 		key.data = symname;
    195 		key.size = strlen((char *)key.data);
    196 
    197 		/*
    198 		 * Convert the symbol information into an nlist structure,
    199 		 * as best we can.
    200 		 */
    201 		nbuf.n_value = esyms[i].es_value;
    202 		nbuf.n_type = N_EXT;				/* XXX */
    203 		nbuf.n_desc = 0;				/* XXX */
    204 		nbuf.n_other = 0;				/* XXX */
    205 
    206 		/*
    207 		 * Enter the symbol into the database.
    208 		 */
    209 		if (db->put(db, &key, &data, 0)) {
    210 			warn("record enter");
    211 			punt();
    212 		}
    213 
    214 		/*
    215 		 * If it's the kernel version string, we've gotta keep
    216 		 * some extra data around.  Under a seperate key,
    217 		 * we enter the first line (i.e. up to the first newline,
    218 		 * with the newline replaced by a NUL to terminate the
    219 		 * entered string) of the version string.
    220 		 */
    221 		if (strcmp((char *)key.data, VRS_SYM) == 0) {
    222 			unsigned long vma;
    223 
    224 			key.data = (u_char *)VRS_KEY;
    225 			key.size = sizeof(VRS_KEY) - 1;
    226 
    227 			/* Find the version string, relative to start */
    228 			vma = nbuf.n_value;
    229 			if (exechdrp->a.text_start <= vma &&
    230 		            vma < (exechdrp->a.text_start + exechdrp->a.tsize))
    231                 		vma = vma - exechdrp->a.text_start +
    232 				    ECOFF_TXTOFF(exechdrp);
    233 			else if (exechdrp->a.data_start <= vma &&
    234 			    vma < (exechdrp->a.data_start + exechdrp->a.dsize))
    235 				vma = vma - exechdrp->a.data_start +
    236 				    ECOFF_DATOFF(exechdrp);
    237 			else {
    238 				warn("version string neither text nor data");
    239 				punt();
    240 			}
    241 			data.data = strdup(&mappedfile[vma]);
    242 
    243 			/* assumes newline terminates version. */
    244 			if ((tmpcp = strchr(data.data, '\n')) != NULL)
    245 				*tmpcp = '\0';
    246 			data.size = strlen((char *)data.data);
    247 
    248 			if (db->put(db, &key, &data, 0)) {
    249 				warn("record enter");
    250 				punt();
    251 			}
    252 
    253 			/* free pointer created by strdup(). */
    254 			free(data.data);
    255 
    256 			/* Restore to original values */
    257 			data.data = (u_char *)&nbuf;
    258 			data.size = sizeof(nbuf);
    259 		}
    260 	}
    261 
    262 	rv = 0;
    263 
    264 unmap:
    265 	munmap(mappedfile, mappedsize);
    266 out:
    267 	return (rv);
    268 }
    269 
    270 #endif /* NLIST_ECOFF */
    271