1 /* $NetBSD: nlist_ecoff.c,v 1.3 1996/10/03 23:14:23 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 #ifndef lint 34 static char *rcsid = "$NetBSD: nlist_ecoff.c,v 1.3 1996/10/03 23:14:23 cgd Exp $"; 35 #endif /* not lint */ 36 37 #include <sys/param.h> 38 #include <sys/mman.h> 39 #include <sys/stat.h> 40 41 #include <a.out.h> 42 #include <db.h> 43 #include <err.h> 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <kvm.h> 47 #include <limits.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include "extern.h" 54 55 #ifdef NLIST_ECOFF 56 #include <sys/exec_ecoff.h> 57 58 typedef struct nlist NLIST; 59 #define _strx n_un.n_strx 60 #define _name n_un.n_name 61 62 #define badfmt(str) \ 63 do { \ 64 warnx("%s: %s: %s", kfile, str, strerror(EFTYPE)); \ 65 punt(); \ 66 } while (0) 67 68 #define check(off, size) ((off < 0) || (off + size > mappedsize)) 69 #define BAD do { rv = -1; goto out; } while (0) 70 #define BADUNMAP do { rv = -1; goto unmap; } while (0) 71 72 static const char *kfile; 73 74 int 75 create_knlist_ecoff(name, db) 76 const char *name; 77 DB *db; 78 { 79 struct ecoff_exechdr *exechdrp; 80 struct ecoff_symhdr *symhdrp; 81 struct ecoff_extsym *esyms; 82 struct stat st; 83 struct nlist nbuf; 84 DBT key, data; 85 char *mappedfile, *symname, *fsymname, *tmpcp; 86 size_t mappedsize, symnamesize, fsymnamesize; 87 u_long symhdroff, extrstroff; 88 u_long symhdrsize, i, nesyms; 89 int fd, rv; 90 91 rv = -1; 92 93 /* 94 * Open and map the whole file. If we can't open/stat it, 95 * something bad is going on so we punt. 96 */ 97 kfile = name; 98 if ((fd = open(name, O_RDONLY, 0)) < 0) { 99 warn("%s", kfile); 100 punt(); 101 } 102 if (fstat(fd, &st) < 0) { 103 warn("%s", kfile); 104 punt(); 105 } 106 if (st.st_size > SIZE_T_MAX) 107 BAD; 108 109 /* 110 * Map the file in its entirety. 111 */ 112 mappedsize = st.st_size; 113 mappedfile = mmap(NULL, mappedsize, PROT_READ, 0, fd, 0); 114 if (mappedfile == (char *)-1) 115 BAD; 116 117 /* 118 * Make sure we can access the executable's header 119 * directly, and make sure the recognize the executable 120 * as an ECOFF binary. 121 */ 122 if (check(0, sizeof *exechdrp)) 123 BADUNMAP; 124 exechdrp = (struct ecoff_exechdr *)&mappedfile[0]; 125 126 if (ECOFF_BADMAG(exechdrp)) 127 BADUNMAP; 128 129 /* 130 * We've recognized it as an ECOFF binary. From here 131 * on out, all errors are fatal. 132 */ 133 134 /* 135 * Find the symbol list and string table. 136 */ 137 symhdroff = exechdrp->f.f_symptr; 138 symhdrsize = exechdrp->f.f_nsyms; 139 140 if (symhdrsize == 0) 141 badfmt("stripped"); 142 if (check(symhdroff, sizeof *symhdrp) || sizeof *symhdrp != symhdrsize) 143 badfmt("bogus symbol table"); 144 symhdrp = (struct ecoff_symhdr *)&mappedfile[symhdroff]; 145 146 nesyms = symhdrp->esymMax; 147 if (check(symhdrp->cbExtOffset, nesyms * sizeof *esyms)) 148 badfmt("bogus external symbol list"); 149 esyms = (struct ecoff_extsym *)&mappedfile[symhdrp->cbExtOffset]; 150 extrstroff = symhdrp->cbSsExtOffset; 151 152 /* 153 * Set up the data item, pointing to a nlist structure. 154 * which we fill in for each symbol. 155 */ 156 data.data = (u_char *)&nbuf; 157 data.size = sizeof(nbuf); 158 159 /* 160 * Create a buffer (to be expanded later, if necessary) 161 * to hold symbol names after we've added underscores 162 * to them. 163 */ 164 symnamesize = 1024; 165 if ((symname = malloc(symnamesize)) == NULL) { 166 warn("malloc"); 167 punt(); 168 } 169 170 /* 171 * Read each symbol and enter it into the database. 172 */ 173 for (i = 0; i < nesyms; i++) { 174 175 /* 176 * Find symbol name, copy it (with added underscore) to 177 * temporary buffer, and prepare the database key for 178 * insertion. 179 */ 180 fsymname = &mappedfile[extrstroff + esyms[i].es_strindex]; 181 fsymnamesize = strlen(fsymname) + 1; 182 while (symnamesize < fsymnamesize + 1) { 183 symnamesize *= 2; 184 if ((symname = realloc(symname, symnamesize)) == NULL) { 185 warn("malloc"); 186 punt(); 187 } 188 } 189 strcpy(symname, "_"); 190 strcat(symname, fsymname); 191 192 key.data = symname; 193 key.size = strlen((char *)key.data); 194 195 /* 196 * Convert the symbol information into an nlist structure, 197 * as best we can. 198 */ 199 nbuf.n_value = esyms[i].es_value; 200 nbuf.n_type = N_EXT; /* XXX */ 201 nbuf.n_desc = 0; /* XXX */ 202 nbuf.n_other = 0; /* XXX */ 203 204 /* 205 * Enter the symbol into the database. 206 */ 207 if (db->put(db, &key, &data, 0)) { 208 warn("record enter"); 209 punt(); 210 } 211 212 /* 213 * If it's the kernel version string, we've gotta keep 214 * some extra data around. Under a seperate key, 215 * we enter the first line (i.e. up to the first newline, 216 * with the newline replaced by a NUL to terminate the 217 * entered string) of the version string. 218 */ 219 if (strcmp((char *)key.data, VRS_SYM) == 0) { 220 unsigned long vma; 221 222 key.data = (u_char *)VRS_KEY; 223 key.size = sizeof(VRS_KEY) - 1; 224 225 /* Find the version string, relative to start */ 226 vma = nbuf.n_value; 227 if (exechdrp->a.text_start <= vma && 228 vma < (exechdrp->a.text_start + exechdrp->a.tsize)) 229 vma = vma - exechdrp->a.text_start + 230 ECOFF_TXTOFF(exechdrp); 231 else if (exechdrp->a.data_start <= vma && 232 vma < (exechdrp->a.data_start + exechdrp->a.dsize)) 233 vma = vma - exechdrp->a.data_start + 234 ECOFF_DATOFF(exechdrp); 235 else { 236 warn("version string neither text nor data"); 237 punt(); 238 } 239 data.data = strdup(&mappedfile[vma]); 240 241 /* assumes newline terminates version. */ 242 if ((tmpcp = strchr(data.data, '\n')) != NULL) 243 *tmpcp = '\0'; 244 data.size = strlen((char *)data.data); 245 246 if (db->put(db, &key, &data, 0)) { 247 warn("record enter"); 248 punt(); 249 } 250 251 /* free pointer created by strdup(). */ 252 free(data.data); 253 254 /* Restore to original values */ 255 data.data = (u_char *)&nbuf; 256 data.size = sizeof(nbuf); 257 } 258 } 259 260 rv = 0; 261 262 unmap: 263 munmap(mappedfile, mappedsize); 264 out: 265 return (rv); 266 } 267 268 #endif /* NLIST_ECOFF */ 269