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