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