1 /* $NetBSD: dbsym.c,v 1.3 2012/03/19 09:14:15 wiz Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Simon Burge (for Wasabi Systems) 5 * Copyright (c) 1996 Christopher G. Demetriou 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>> 31 */ 32 33 #if HAVE_NBTOOL_CONFIG_H 34 #include "nbtool_config.h" 35 #endif 36 37 #include <sys/cdefs.h> 38 #if !defined(lint) 39 __COPYRIGHT("@(#) Copyright (c) 1996 Christopher G. Demetriou.\ 40 Copyright 2001 Simon Burge.\ 41 All rights reserved."); 42 __RCSID("$NetBSD: dbsym.c,v 1.3 2012/03/19 09:14:15 wiz Exp $"); 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/mman.h> 47 #include <sys/stat.h> 48 49 #include <bfd.h> 50 #include <err.h> 51 #include <fcntl.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 57 /* BFD ELF headers */ 58 #include <elf/common.h> 59 #include <elf/external.h> 60 61 struct symbols { 62 char *name; 63 size_t offset; 64 } db_symtab_symbols[] = { 65 #define X_DB_SYMTAB 0 66 { "_db_symtab", 0 }, 67 #define X_DB_SYMTABSIZE 1 68 { "_db_symtabsize", 0 }, 69 { NULL, 0 } 70 }; 71 72 int main(int, char **); 73 void usage(void) __attribute__((noreturn)); 74 int find_symtab(bfd *, struct symbols *); 75 int load_symtab(bfd *, int fd, char **, u_int32_t *); 76 77 int verbose; 78 int printsize; 79 80 int 81 main(int argc, char **argv) 82 { 83 int ch, kfd; 84 struct stat ksb; 85 size_t symtab_offset; 86 u_int32_t symtab_space, symtabsize; 87 const char *kfile; 88 char *bfdname, *mappedkfile, *symtab; 89 bfd *abfd; 90 91 setprogname(argv[0]); 92 93 bfdname = NULL; 94 while ((ch = getopt(argc, argv, "b:pv")) != -1) 95 switch (ch) { 96 case 'b': 97 bfdname = optarg; 98 break; 99 case 'v': 100 verbose = 1; 101 break; 102 case 'p': 103 printsize = 1; 104 break; 105 case '?': 106 default: 107 usage(); 108 } 109 argc -= optind; 110 argv += optind; 111 112 if (argc != 1) 113 usage(); 114 kfile = argv[0]; 115 116 if ((kfd = open(kfile, O_RDWR, 0)) == -1) 117 err(1, "open %s", kfile); 118 119 bfd_init(); 120 if ((abfd = bfd_fdopenr(kfile, bfdname, kfd)) == NULL) { 121 bfd_perror("open"); 122 exit(1); 123 } 124 if (!bfd_check_format(abfd, bfd_object)) { 125 bfd_perror("check format"); 126 exit(1); 127 } 128 129 if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) 130 errx(1, "no symbol table in %s", kfile); 131 132 if (find_symtab(abfd, db_symtab_symbols) != 0) 133 errx(1, "could not find SYMTAB_SPACE in %s", kfile); 134 if (verbose) 135 fprintf(stderr, "got SYMTAB_SPACE symbols from %s\n", kfile); 136 137 if (load_symtab(abfd, kfd, &symtab, &symtabsize) != 0) 138 errx(1, "could not load symbol table from %s", kfile); 139 if (verbose) 140 fprintf(stderr, "loaded symbol table from %s\n", kfile); 141 142 if (fstat(kfd, &ksb) == -1) 143 err(1, "fstat %s", kfile); 144 if (ksb.st_size != (size_t)ksb.st_size) 145 errx(1, "%s too big to map", kfile); 146 147 if ((mappedkfile = mmap(NULL, ksb.st_size, PROT_READ | PROT_WRITE, 148 MAP_FILE | MAP_SHARED, kfd, 0)) == (caddr_t)-1) 149 err(1, "mmap %s", kfile); 150 if (verbose) 151 fprintf(stderr, "mapped %s\n", kfile); 152 153 symtab_offset = db_symtab_symbols[X_DB_SYMTAB].offset; 154 symtab_space = bfd_get_32(abfd, 155 &mappedkfile[db_symtab_symbols[X_DB_SYMTABSIZE].offset]); 156 157 if (printsize) { 158 printf("%d %d\n", symtabsize, symtab_space); 159 goto done; 160 } 161 162 if (symtabsize > symtab_space) 163 errx(1, "symbol table (%u bytes) too big for buffer (%u bytes)\n" 164 "Increase options SYMTAB_SPACE in your kernel config", 165 symtabsize, symtab_space); 166 167 if (verbose) 168 fprintf(stderr, "symtab size %d, space available %d\n", 169 symtabsize, symtab_space); 170 171 memcpy(mappedkfile + symtab_offset, symtab, symtabsize); 172 173 if (verbose) 174 fprintf(stderr, "done copying image to file offset %#lx\n", 175 (long)db_symtab_symbols[X_DB_SYMTAB].offset); 176 177 bfd_put_32(abfd, symtabsize, 178 &mappedkfile[db_symtab_symbols[X_DB_SYMTABSIZE].offset]); 179 180 done: 181 munmap(mappedkfile, ksb.st_size); 182 close(kfd); 183 184 if (verbose) 185 fprintf(stderr, "exiting\n"); 186 187 bfd_close_all_done(abfd); 188 exit(0); 189 } 190 191 void 192 usage(void) 193 { 194 const char **list; 195 196 fprintf(stderr, 197 "usage: %s [-pv] [-b bfdname] kernel\n", 198 getprogname()); 199 fprintf(stderr, "supported targets:"); 200 for (list = bfd_target_list(); *list != NULL; list++) 201 fprintf(stderr, " %s", *list); 202 fprintf(stderr, "\n"); 203 exit(1); 204 } 205 206 int 207 find_symtab(bfd *abfd, struct symbols *symbols) 208 { 209 long i; 210 long storage_needed; 211 long number_of_symbols; 212 asymbol **symbol_table = NULL; 213 struct symbols *s; 214 215 storage_needed = bfd_get_symtab_upper_bound(abfd); 216 if (storage_needed <= 0) 217 return (1); 218 219 if ((symbol_table = (asymbol **)malloc(storage_needed)) == NULL) 220 return (1); 221 222 number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table); 223 if (number_of_symbols <= 0) { 224 free(symbol_table); 225 return (1); 226 } 227 228 for (i = 0; i < number_of_symbols; i++) { 229 for (s = symbols; s->name != NULL; s++) { 230 const char *sym = symbol_table[i]->name; 231 232 /* 233 * match symbol prefix '_' or ''. 234 * XXX: use bfd_get_symbol_leading_char() here? 235 */ 236 if (!strcmp(s->name, sym) || 237 !strcmp(s->name + 1, sym)) { 238 s->offset = (size_t) 239 (symbol_table[i]->section->filepos 240 + symbol_table[i]->value); 241 242 } 243 } 244 } 245 246 free(symbol_table); 247 248 for (s = symbols; s->name != NULL; s++) { 249 if (s->offset == 0) 250 return (1); 251 } 252 253 return (0); 254 } 255 256 /* --------------------------- ELF gunk follows --------------------------- */ 257 258 /* 259 * The format of the symbols loaded by the boot program is: 260 * 261 * Elf exec header 262 * first section header 263 * . . . 264 * . . . 265 * last section header 266 * first symbol or string table section 267 * . . . 268 * . . . 269 * last symbol or string table section 270 */ 271 272 273 /* Note elftype is local to load_symtab()... */ 274 #define ELF_TYPE_64 0x01 275 #define ISELF64 (elftype & ELF_TYPE_64) 276 277 /* 278 * Field sizes for the Elf exec header: 279 * 280 * ELF32 ELF64 281 * 282 * unsigned char e_ident[ELF_NIDENT]; # Id bytes 283 * 16 16 e_type; # file type 284 * 16 16 e_machine; # machine type 285 * 32 32 e_version; # version number 286 * 32 64 e_entry; # entry point 287 * 32 64 e_phoff; # Program hdr offset 288 * 32 64 e_shoff; # Section hdr offset 289 * 32 32 e_flags; # Processor flags 290 * 16 16 e_ehsize; # sizeof ehdr 291 * 16 16 e_phentsize; # Program header entry size 292 * 16 16 e_phnum; # Number of program headers 293 * 16 16 e_shentsize; # Section header entry size 294 * 16 16 e_shnum; # Number of section headers 295 * 16 16 e_shstrndx; # String table index 296 */ 297 298 typedef union { 299 Elf32_External_Ehdr e32hdr; 300 Elf64_External_Ehdr e64hdr; 301 char e_ident[16]; /* XXX MAGIC NUMBER */ 302 } elf_ehdr; 303 304 #define e32_hdr ehdr.e32hdr 305 #define e64_hdr ehdr.e64hdr 306 307 /* 308 * Field sizes for Elf section headers 309 * 310 * ELF32 ELF64 311 * 312 * 32 32 sh_name; # section name (.shstrtab index) 313 * 32 32 sh_type; # section type 314 * 32 64 sh_flags; # section flags 315 * 32 64 sh_addr; # virtual address 316 * 32 64 sh_offset; # file offset 317 * 32 64 sh_size; # section size 318 * 32 32 sh_link; # link to another 319 * 32 32 sh_info; # misc info 320 * 32 64 sh_addralign; # memory alignment 321 * 32 64 sh_entsize; # table entry size 322 */ 323 324 /* Extract a 32 bit field from Elf32_Shdr */ 325 #define SH_E32_32(x, n) bfd_get_32(abfd, s32hdr[(x)].n) 326 327 /* Extract a 32 bit field from Elf64_Shdr */ 328 #define SH_E64_32(x, n) bfd_get_32(abfd, s64hdr[(x)].n) 329 330 /* Extract a 64 bit field from Elf64_Shdr */ 331 #define SH_E64_64(x, n) bfd_get_64(abfd, s64hdr[(x)].n) 332 333 /* Extract a 32 bit field from either size Shdr */ 334 #define SH_E32E32(x, n) (ISELF64 ? SH_E64_32(x, n) : SH_E32_32(x, n)) 335 336 /* Extract a 32 bit field from Elf32_Shdr or 64 bit field from Elf64_Shdr */ 337 #define SH_E32E64(x, n) (ISELF64 ? SH_E64_64(x, n) : SH_E32_32(x, n)) 338 339 #define SH_NAME(x) SH_E32E32(x, sh_name) 340 #define SH_TYPE(x) SH_E32E32(x, sh_type) 341 #define SH_FLAGS(x) SH_E32E64(x, sh_flags) 342 #define SH_ADDR(x) SH_E32E64(x, sh_addr) 343 #define SH_OFFSET(x) SH_E32E64(x, sh_offset) 344 #define SH_SIZE(x) SH_E32E64(x, sh_size) 345 #define SH_LINK(x) SH_E32E32(x, sh_link) 346 #define SH_INFO(x) SH_E32E32(x, sh_info) 347 #define SH_ADDRALIGN(x) SH_E32E64(x, sh_addralign) 348 #define SH_ENTSIZE(x) SH_E32E64(x, sh_entsize) 349 350 int 351 load_symtab(bfd *abfd, int fd, char **symtab, u_int32_t *symtabsize) 352 { 353 elf_ehdr ehdr; 354 Elf32_External_Shdr *s32hdr = NULL; 355 Elf64_External_Shdr *s64hdr = NULL; 356 void *shdr; 357 u_int32_t osymtabsize, sh_offset; 358 int elftype, e_shnum, i, sh_size; 359 off_t e_shoff; 360 361 if (lseek(fd, 0, SEEK_SET) < 0) 362 return (1); 363 if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) 364 return (1); 365 366 /* 367 * Check that we are targetting an Elf binary. 368 */ 369 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || 370 ehdr.e_ident[EI_MAG1] != ELFMAG1 || 371 ehdr.e_ident[EI_MAG2] != ELFMAG2 || 372 ehdr.e_ident[EI_MAG3] != ELFMAG3) 373 return (1); 374 375 /* 376 * Determine Elf size and endianness. 377 */ 378 elftype = 0; 379 if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) 380 elftype |= ELF_TYPE_64; 381 382 /* 383 * Elf exec header. Only need to allocate space for now, 384 * the header is copied into place at the end. 385 */ 386 *symtabsize = ISELF64 ? sizeof(Elf64_External_Ehdr) 387 : sizeof(Elf32_External_Ehdr); 388 *symtab = NULL; 389 390 /* 391 * Section headers. Allocate a temporary copy that will 392 * be copied into place at the end. 393 */ 394 sh_offset = osymtabsize = *symtabsize; 395 e_shnum = (ISELF64 396 ? bfd_get_16(abfd, e64_hdr.e_shnum) 397 : bfd_get_16(abfd, e32_hdr.e_shnum)); 398 sh_size = e_shnum * (ISELF64 ? sizeof(Elf64_External_Shdr) 399 : sizeof(Elf32_External_Shdr)); 400 if ((shdr = malloc(sh_size)) == NULL) 401 return (1); 402 if (ISELF64) 403 s64hdr = shdr; 404 else 405 s32hdr = shdr; 406 407 *symtabsize += roundup(sh_size, ISELF64 ? 8 : 4); 408 409 e_shoff = (ISELF64 410 ? bfd_get_64(abfd, e64_hdr.e_shoff) 411 : bfd_get_32(abfd, e32_hdr.e_shoff)); 412 if (lseek(fd, e_shoff, SEEK_SET) < 0) 413 goto out; 414 if (read(fd, shdr, sh_size) != sh_size) 415 goto out; 416 417 for (i = 0; i < e_shnum; i++) { 418 if (SH_TYPE(i) == SHT_SYMTAB || SH_TYPE(i) == SHT_STRTAB) { 419 osymtabsize = *symtabsize; 420 *symtabsize += roundup(SH_SIZE(i), ISELF64 ? 8 : 4); 421 if ((*symtab = realloc(*symtab, *symtabsize)) == NULL) 422 goto out; 423 424 if (lseek(fd, SH_OFFSET(i), SEEK_SET) < 0) 425 goto out; 426 if (read(fd, *symtab + osymtabsize, SH_SIZE(i)) != 427 SH_SIZE(i)) 428 goto out; 429 if (ISELF64) { 430 bfd_put_64(abfd, osymtabsize, 431 s64hdr[i].sh_offset); 432 } else { 433 bfd_put_32(abfd, osymtabsize, 434 s32hdr[i].sh_offset); 435 } 436 } 437 } 438 439 if (*symtab == NULL) 440 goto out; 441 442 /* 443 * Copy updated section headers. 444 */ 445 memcpy(*symtab + sh_offset, shdr, sh_size); 446 447 /* 448 * Update and copy the exec header. 449 */ 450 if (ISELF64) { 451 bfd_put_64(abfd, 0, e64_hdr.e_phoff); 452 bfd_put_64(abfd, sizeof(Elf64_External_Ehdr), e64_hdr.e_shoff); 453 bfd_put_16(abfd, 0, e64_hdr.e_phentsize); 454 bfd_put_16(abfd, 0, e64_hdr.e_phnum); 455 } else { 456 bfd_put_32(abfd, 0, e32_hdr.e_phoff); 457 bfd_put_32(abfd, sizeof(Elf32_External_Ehdr), e32_hdr.e_shoff); 458 bfd_put_16(abfd, 0, e32_hdr.e_phentsize); 459 bfd_put_16(abfd, 0, e32_hdr.e_phnum); 460 } 461 memcpy(*symtab, &ehdr, sizeof(ehdr)); 462 463 free(shdr); 464 return (0); 465 out: 466 free(shdr); 467 return (1); 468 } 469