1/* $NetBSD: nlist_ecoff.c,v 1.10 2003/09/19 06:24:04 itojun 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.10 2003/09/19 06:24:04 itojun 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 63typedef 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 77static const char *kfile; 78 79int 80create_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, *nsymname, *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 if ((nsymname = realloc(symname, symnamesize * 2)) == NULL) { 190 warn("malloc"); 191 punt(); 192 } 193 symname = nsymname; 194 symnamesize *= 2; 195 } 196 strlcpy(symname, "_", symnamesize); 197 strlcat(symname, fsymname, symnamesize); 198 199 key.data = symname; 200 key.size = strlen((char *)key.data); 201 202 /* 203 * Convert the symbol information into an nlist structure, 204 * as best we can. 205 */ 206 nbuf.n_value = esyms[i].es_value; 207 nbuf.n_type = N_EXT; /* XXX */ 208 nbuf.n_desc = 0; /* XXX */ 209 nbuf.n_other = 0; /* XXX */ 210 211 /* 212 * Enter the symbol into the database. 213 */ 214 if (db->put(db, &key, &data, 0)) { 215 warn("record enter"); 216 punt(); 217 } 218 219 /* 220 * If it's the kernel version string, we've gotta keep 221 * some extra data around. Under a separate key, 222 * we enter the first line (i.e. up to the first newline, 223 * with the newline replaced by a NUL to terminate the 224 * entered string) of the version string. 225 */ 226 if (strcmp((char *)key.data, VRS_SYM) == 0) { 227 unsigned long vma; 228 229 key.data = (u_char *)VRS_KEY; 230 key.size = sizeof(VRS_KEY) - 1; 231 232 /* Find the version string, relative to start */ 233 vma = nbuf.n_value; 234 if (exechdrp->a.text_start <= vma && 235 vma < (exechdrp->a.text_start + exechdrp->a.tsize)) 236 vma = vma - exechdrp->a.text_start + 237 ECOFF_TXTOFF(exechdrp); 238 else if (exechdrp->a.data_start <= vma && 239 vma < (exechdrp->a.data_start + exechdrp->a.dsize)) 240 vma = vma - exechdrp->a.data_start + 241 ECOFF_DATOFF(exechdrp); 242 else { 243 warn("version string neither text nor data"); 244 punt(); 245 } 246 data.data = strdup(&mappedfile[vma]); 247 248 /* assumes newline terminates version. */ 249 if ((tmpcp = strchr(data.data, '\n')) != NULL) 250 *tmpcp = '\0'; 251 data.size = strlen((char *)data.data); 252 253 if (db->put(db, &key, &data, 0)) { 254 warn("record enter"); 255 punt(); 256 } 257 258 /* free pointer created by strdup(). */ 259 free(data.data); 260 261 /* Restore to original values */ 262 data.data = (u_char *)&nbuf; 263 data.size = sizeof(nbuf); 264 } 265 } 266 267 rv = 0; 268 269unmap: 270 munmap(mappedfile, mappedsize); 271out: 272 return (rv); 273} 274 275#endif /* NLIST_ECOFF */ 276