1/* $NetBSD: nlist_coff.c,v 1.7 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_coff.c,v 1.7 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_COFF 61#include <sys/exec_coff.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_coff(name, db) 81 const char *name; 82 DB *db; 83{ 84 struct coff_filehdr *filehdrp; 85 struct coff_aouthdr *aouthdrp; 86 struct stat st; 87 struct nlist nbuf; 88 DBT key, data; 89 char *mappedfile, *symname, *nsymname, *fsymname; 90 size_t mappedsize, symnamesize, fsymnamesize; 91 u_long symhdroff, extrstroff; 92 u_long symhdrsize, i, nesyms; 93 int fd, rv; 94 struct external_syment *syment; 95 u_long soff; 96 u_long val; 97 char snamebuf[16]; 98 99 rv = -1; 100 101 /* 102 * Open and map the whole file. If we can't open/stat it, 103 * something bad is going on so we punt. 104 */ 105 kfile = name; 106 if ((fd = open(name, O_RDONLY, 0)) < 0) { 107 warn("%s", kfile); 108 punt(); 109 } 110 if (fstat(fd, &st) < 0) { 111 warn("%s", kfile); 112 punt(); 113 } 114 if (st.st_size > SIZE_T_MAX) 115 BAD; 116 117 /* 118 * Map the file in its entirety. 119 */ 120 mappedsize = st.st_size; 121 mappedfile = mmap(NULL, mappedsize, PROT_READ, MAP_FILE|MAP_PRIVATE, 122 fd, 0); 123 if (mappedfile == (char *)-1) 124 BAD; 125 126 /* 127 * Make sure we can access the executable's header 128 * directly, and make sure the recognize the executable 129 * as an COFF binary. 130 */ 131 if (check(0, sizeof *filehdrp)) 132 BADUNMAP; 133 filehdrp = (struct coff_filehdr *)&mappedfile[0]; 134 135 if (COFF_BADMAG(filehdrp)) 136 BADUNMAP; 137 138 /* 139 * We've recognized it as an COFF binary. From here 140 * on out, all errors are fatal. 141 */ 142 143 aouthdrp = (struct coff_aouthdr *) 144 &mappedfile[sizeof(struct coff_filehdr)]; 145 146 /* 147 * Find the symbol list and string table. 148 */ 149 symhdroff = filehdrp->f_symptr; 150 symhdrsize = filehdrp->f_nsyms; 151 extrstroff = symhdroff + symhdrsize*COFF_ES_SYMENTSZ; 152 153#ifdef DEGBU 154 printf("sizeof syment = %d\n",sizeof(struct external_syment )); 155 printf("symhdroff = 0x%lx,symhdrsize=%ld,stroff = 0x%lx", 156 symhdroff,symhdrsize, extrstroff); 157#endif 158 159 if (symhdrsize == 0) 160 badfmt("stripped"); 161 162 /* 163 * Set up the data item, pointing to a nlist structure. 164 * which we fill in for each symbol. 165 */ 166 data.data = (u_char *)&nbuf; 167 data.size = sizeof(nbuf); 168 169 /* 170 * Create a buffer (to be expanded later, if necessary) 171 * to hold symbol names after we've added underscores 172 * to them. 173 */ 174 symnamesize = 1024; 175 if ((symname = malloc(symnamesize)) == NULL) { 176 warn("malloc"); 177 punt(); 178 } 179 180 nesyms = filehdrp->f_nsyms; 181 182 /* 183 * Read each symbol and enter it into the database. 184 */ 185 for (i = 0; i < nesyms; i++) { 186 187 /* 188 * Find symbol name, copy it (with added underscore) to 189 * temporary buffer, and prepare the database key for 190 * insertion. 191 */ 192 syment = (struct external_syment *)&mappedfile[symhdroff + 193 COFF_ES_SYMENTSZ*i]; 194 195 if(syment->e_sclass[0] != 2){ 196 continue; 197 } 198 199 if(syment->e.e.e_zeroes[0]){ 200 if( syment->e.e_name[COFF_ES_SYMNMLEN-1] ){ 201 memcpy( snamebuf, syment->e.e_name, 202 COFF_ES_SYMNMLEN); 203 snamebuf[COFF_ES_SYMNMLEN] = '\0'; 204 fsymname = snamebuf; 205 } 206 else{ 207 fsymname = syment->e.e_name ; 208 } 209 fsymnamesize = strlen(fsymname) + 1; 210 211#ifdef DEBUG 212 printf("%s\n",fsymname ); 213#endif 214 } 215 else{ 216 memcpy(&soff, syment->e.e.e_offset, sizeof(long)); 217 fsymname = &mappedfile[extrstroff+soff]; 218 fsymnamesize = strlen(fsymname) + 1; 219 220#ifdef DEBUG 221 printf("*%s\n",fsymname ); 222#endif 223 } 224 225 while (symnamesize < fsymnamesize + 1) { 226 if ((nsymname = realloc(symname, symnamesize * 2)) == NULL){ 227 warn("malloc"); 228 punt(); 229 } 230 symname = nsymname; 231 symnamesize *= 2; 232 } 233#if 0 234 strlcpy(symname, "_", symnamesize); 235 strlcat(symname, fsymname, symnamesize); 236#else 237 strlcpy(symname, fsymname, symnamesize); 238#endif 239 240 key.data = symname; 241 key.size = strlen((char *)key.data); 242 243 /* 244 * Convert the symbol information into an nlist structure, 245 * as best we can. 246 */ 247 memcpy(&val, syment->e_value, sizeof( long )); 248 nbuf.n_value = val; 249 nbuf.n_type = N_EXT; /* XXX */ 250 nbuf.n_desc = 0; /* XXX */ 251 nbuf.n_other = 0; /* XXX */ 252 253 /* 254 * Enter the symbol into the database. 255 */ 256 if (db->put(db, &key, &data, 0)) { 257 warn("record enter"); 258 punt(); 259 } 260 /* 261 * If it's the kernel version string, we've gotta keep 262 * some extra data around. Under a separate key, 263 * we enter the first line (i.e. up to the first newline, 264 * with the newline replaced by a NUL to terminate the 265 * entered string) of the version string. 266 */ 267 if (strcmp((char *)key.data, VRS_SYM) == 0) { 268 unsigned long vma; 269 char *tmpcp; 270 struct coff_scnhdr *sh; 271 int i; 272 273 key.data = (u_char *)VRS_KEY; 274 key.size = sizeof(VRS_KEY) - 1; 275 276 /* Find the version string, relative to start */ 277 vma = nbuf.n_value; 278 279#ifdef DEBUG 280 printf("vma = %lx,tstart = %lx, dstart=%lx\n", 281 vma, aouthdrp->a_tstart, 282 aouthdrp->a_dstart); 283 printf("tsize = %lx, dsize=%lx\n", 284 aouthdrp->a_tsize, 285 aouthdrp->a_dsize); 286#endif 287 if (aouthdrp->a_tstart <= vma && 288 vma < (aouthdrp->a_tstart + aouthdrp->a_tsize)){ 289 for(i=0;i<filehdrp->f_nscns;i++){ 290 sh = (struct coff_scnhdr *) 291 &mappedfile[COFF_HDR_SIZE+ 292 i*sizeof(struct 293 coff_scnhdr)]; 294 if( sh->s_flags == COFF_STYP_TEXT ){ 295 break; 296 } 297 } 298 vma = vma - sh->s_vaddr + sh->s_scnptr; 299 } 300 else if (aouthdrp->a_dstart <= vma && 301 vma < (aouthdrp->a_dstart + aouthdrp->a_dsize)){ 302 for(i=0;i<filehdrp->f_nscns;i++){ 303 sh = (struct coff_scnhdr *) 304 &mappedfile[COFF_HDR_SIZE+ 305 i*sizeof(struct 306 coff_scnhdr)]; 307 if( sh->s_flags == COFF_STYP_DATA ){ 308 break; 309 } 310 } 311 vma = vma - sh->s_vaddr + sh->s_scnptr; 312 } 313 else { 314 warn("version string neither text nor data"); 315 punt(); 316 } 317 data.data = strdup(&mappedfile[vma]); 318 319#ifdef DEBUG 320 printf("vma = %lx,version = %s\n", 321 vma, (char *)data.data); 322#endif 323 324 /* assumes newline terminates version. */ 325 if ((tmpcp = strchr(data.data, '\n')) != NULL) 326 *tmpcp = '\0'; 327 data.size = strlen((char *)data.data); 328 329 if (db->put(db, &key, &data, 0)) { 330 warn("record enter"); 331 punt(); 332 } 333 334 /* free pointer created by strdup(). */ 335 free(data.data); 336 337 /* Restore to original values */ 338 data.data = (u_char *)&nbuf; 339 data.size = sizeof(nbuf); 340 } 341 } /* End of for() */ 342 343 rv = 0; 344 345unmap: 346 munmap(mappedfile, mappedsize); 347out: 348 return (rv); 349} 350 351#endif /* NLIST_COFF */ 352