1 /* $NetBSD: dbsym.c,v 1.1 2009/08/18 20:22:20 skrll 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.1 2009/08/18 20:22:20 skrll 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 79 int 80 main(int argc, char **argv) 81 { 82 int ch, kfd; 83 struct stat ksb; 84 size_t symtab_offset; 85 u_int32_t symtab_space, symtabsize; 86 const char *kfile; 87 char *bfdname, *mappedkfile, *symtab; 88 bfd *abfd; 89 90 setprogname(argv[0]); 91 92 bfdname = NULL; 93 while ((ch = getopt(argc, argv, "b:v")) != -1) 94 switch (ch) { 95 case 'b': 96 bfdname = optarg; 97 break; 98 case 'v': 99 verbose = 1; 100 break; 101 case '?': 102 default: 103 usage(); 104 } 105 argc -= optind; 106 argv += optind; 107 108 if (argc != 1) 109 usage(); 110 kfile = argv[0]; 111 112 if ((kfd = open(kfile, O_RDWR, 0)) == -1) 113 err(1, "open %s", kfile); 114 115 bfd_init(); 116 if ((abfd = bfd_fdopenr(kfile, bfdname, kfd)) == NULL) { 117 bfd_perror("open"); 118 exit(1); 119 } 120 if (!bfd_check_format(abfd, bfd_object)) { 121 bfd_perror("check format"); 122 exit(1); 123 } 124 125 if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) 126 errx(1, "no symbol table in %s", kfile); 127 128 if (find_symtab(abfd, db_symtab_symbols) != 0) 129 errx(1, "could not find SYMTAB_SPACE in %s", kfile); 130 if (verbose) 131 fprintf(stderr, "got SYMTAB_SPACE symbols from %s\n", kfile); 132 133 if (load_symtab(abfd, kfd, &symtab, &symtabsize) != 0) 134 errx(1, "could not load symbol table from %s", kfile); 135 if (verbose) 136 fprintf(stderr, "loaded symbol table from %s\n", kfile); 137 138 if (fstat(kfd, &ksb) == -1) 139 err(1, "fstat %s", kfile); 140 if (ksb.st_size != (size_t)ksb.st_size) 141 errx(1, "%s too big to map", kfile); 142 143 if ((mappedkfile = mmap(NULL, ksb.st_size, PROT_READ | PROT_WRITE, 144 MAP_FILE | MAP_SHARED, kfd, 0)) == (caddr_t)-1) 145 err(1, "mmap %s", kfile); 146 if (verbose) 147 fprintf(stderr, "mapped %s\n", kfile); 148 149 symtab_offset = db_symtab_symbols[X_DB_SYMTAB].offset; 150 symtab_space = bfd_get_32(abfd, 151 &mappedkfile[db_symtab_symbols[X_DB_SYMTABSIZE].offset]); 152 153 if (symtabsize > symtab_space) 154 errx(1, "symbol table (%u bytes) too big for buffer (%u bytes)\n" 155 "Increase options SYMTAB_SPACE in your kernel config", 156 symtabsize, symtab_space); 157 158 if (verbose) 159 fprintf(stderr, "symtab size %d, space available %d\n", 160 symtabsize, symtab_space); 161 162 memcpy(mappedkfile + symtab_offset, symtab, symtabsize); 163 164 if (verbose) 165 fprintf(stderr, "done copying image to file offset %#lx\n", 166 (long)db_symtab_symbols[X_DB_SYMTAB].offset); 167 168 bfd_put_32(abfd, symtabsize, 169 &mappedkfile[db_symtab_symbols[X_DB_SYMTABSIZE].offset]); 170 171 munmap(mappedkfile, ksb.st_size); 172 close(kfd); 173 174 if (verbose) 175 fprintf(stderr, "exiting\n"); 176 177 bfd_close_all_done(abfd); 178 exit(0); 179 } 180 181 void 182 usage(void) 183 { 184 const char **list; 185 186 fprintf(stderr, 187 "usage: %s [-b bfdname] [-v] kernel_file\n", 188 getprogname()); 189 fprintf(stderr, "supported targets:"); 190 for (list = bfd_target_list(); *list != NULL; list++) 191 fprintf(stderr, " %s", *list); 192 fprintf(stderr, "\n"); 193 exit(1); 194 } 195 196 int 197 find_symtab(bfd *abfd, struct symbols *symbols) 198 { 199 long i; 200 long storage_needed; 201 long number_of_symbols; 202 asymbol **symbol_table = NULL; 203 struct symbols *s; 204 205 storage_needed = bfd_get_symtab_upper_bound(abfd); 206 if (storage_needed <= 0) 207 return (1); 208 209 if ((symbol_table = (asymbol **)malloc(storage_needed)) == NULL) 210 return (1); 211 212 number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table); 213 if (number_of_symbols <= 0) { 214 free(symbol_table); 215 return (1); 216 } 217 218 for (i = 0; i < number_of_symbols; i++) { 219 for (s = symbols; s->name != NULL; s++) { 220 const char *sym = symbol_table[i]->name; 221 222 /* 223 * match symbol prefix '_' or ''. 224 * XXX: use bfd_get_symbol_leading_char() here? 225 */ 226 if (!strcmp(s->name, sym) || 227 !strcmp(s->name + 1, sym)) { 228 s->offset = (size_t) 229 (symbol_table[i]->section->filepos 230 + symbol_table[i]->value); 231 232 } 233 } 234 } 235 236 free(symbol_table); 237 238 for (s = symbols; s->name != NULL; s++) { 239 if (s->offset == 0) 240 return (1); 241 } 242 243 return (0); 244 } 245 246 /* --------------------------- ELF gunk follows --------------------------- */ 247 248 /* 249 * The format of the symbols loaded by the boot program is: 250 * 251 * Elf exec header 252 * first section header 253 * . . . 254 * . . . 255 * last section header 256 * first symbol or string table section 257 * . . . 258 * . . . 259 * last symbol or string table section 260 */ 261 262 263 /* Note elftype is local to load_symtab()... */ 264 #define ELF_TYPE_64 0x01 265 #define ISELF64 (elftype & ELF_TYPE_64) 266 267 /* 268 * Field sizes for the Elf exec header: 269 * 270 * ELF32 ELF64 271 * 272 * unsigned char e_ident[ELF_NIDENT]; # Id bytes 273 * 16 16 e_type; # file type 274 * 16 16 e_machine; # machine type 275 * 32 32 e_version; # version number 276 * 32 64 e_entry; # entry point 277 * 32 64 e_phoff; # Program hdr offset 278 * 32 64 e_shoff; # Section hdr offset 279 * 32 32 e_flags; # Processor flags 280 * 16 16 e_ehsize; # sizeof ehdr 281 * 16 16 e_phentsize; # Program header entry size 282 * 16 16 e_phnum; # Number of program headers 283 * 16 16 e_shentsize; # Section header entry size 284 * 16 16 e_shnum; # Number of section headers 285 * 16 16 e_shstrndx; # String table index 286 */ 287 288 typedef union { 289 Elf32_External_Ehdr e32hdr; 290 Elf64_External_Ehdr e64hdr; 291 char e_ident[16]; /* XXX MAGIC NUMBER */ 292 } elf_ehdr; 293 294 #define e32_hdr ehdr.e32hdr 295 #define e64_hdr ehdr.e64hdr 296 297 /* 298 * Field sizes for Elf section headers 299 * 300 * ELF32 ELF64 301 * 302 * 32 32 sh_name; # section name (.shstrtab index) 303 * 32 32 sh_type; # section type 304 * 32 64 sh_flags; # section flags 305 * 32 64 sh_addr; # virtual address 306 * 32 64 sh_offset; # file offset 307 * 32 64 sh_size; # section size 308 * 32 32 sh_link; # link to another 309 * 32 32 sh_info; # misc info 310 * 32 64 sh_addralign; # memory alignment 311 * 32 64 sh_entsize; # table entry size 312 */ 313 314 /* Extract a 32 bit field from Elf32_Shdr */ 315 #define SH_E32_32(x, n) bfd_get_32(abfd, s32hdr[(x)].n) 316 317 /* Extract a 32 bit field from Elf64_Shdr */ 318 #define SH_E64_32(x, n) bfd_get_32(abfd, s64hdr[(x)].n) 319 320 /* Extract a 64 bit field from Elf64_Shdr */ 321 #define SH_E64_64(x, n) bfd_get_64(abfd, s64hdr[(x)].n) 322 323 /* Extract a 32 bit field from either size Shdr */ 324 #define SH_E32E32(x, n) (ISELF64 ? SH_E64_32(x, n) : SH_E32_32(x, n)) 325 326 /* Extract a 32 bit field from Elf32_Shdr or 64 bit field from Elf64_Shdr */ 327 #define SH_E32E64(x, n) (ISELF64 ? SH_E64_64(x, n) : SH_E32_32(x, n)) 328 329 #define SH_NAME(x) SH_E32E32(x, sh_name) 330 #define SH_TYPE(x) SH_E32E32(x, sh_type) 331 #define SH_FLAGS(x) SH_E32E64(x, sh_flags) 332 #define SH_ADDR(x) SH_E32E64(x, sh_addr) 333 #define SH_OFFSET(x) SH_E32E64(x, sh_offset) 334 #define SH_SIZE(x) SH_E32E64(x, sh_size) 335 #define SH_LINK(x) SH_E32E32(x, sh_link) 336 #define SH_INFO(x) SH_E32E32(x, sh_info) 337 #define SH_ADDRALIGN(x) SH_E32E64(x, sh_addralign) 338 #define SH_ENTSIZE(x) SH_E32E64(x, sh_entsize) 339 340 int 341 load_symtab(bfd *abfd, int fd, char **symtab, u_int32_t *symtabsize) 342 { 343 elf_ehdr ehdr; 344 Elf32_External_Shdr *s32hdr = NULL; 345 Elf64_External_Shdr *s64hdr = NULL; 346 void *shdr; 347 u_int32_t osymtabsize, sh_offset; 348 int elftype, e_shnum, i, sh_size; 349 off_t e_shoff; 350 351 if (lseek(fd, 0, SEEK_SET) < 0) 352 return (1); 353 if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) 354 return (1); 355 356 /* 357 * Check that we are targetting an Elf binary. 358 */ 359 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || 360 ehdr.e_ident[EI_MAG1] != ELFMAG1 || 361 ehdr.e_ident[EI_MAG2] != ELFMAG2 || 362 ehdr.e_ident[EI_MAG3] != ELFMAG3) 363 return (1); 364 365 /* 366 * Determine Elf size and endianness. 367 */ 368 elftype = 0; 369 if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) 370 elftype |= ELF_TYPE_64; 371 372 /* 373 * Elf exec header. Only need to allocate space for now, 374 * the header is copied into place at the end. 375 */ 376 *symtabsize = ISELF64 ? sizeof(Elf64_External_Ehdr) 377 : sizeof(Elf32_External_Ehdr); 378 *symtab = NULL; 379 380 /* 381 * Section headers. Allocate a temporary copy that will 382 * be copied into place at the end. 383 */ 384 sh_offset = osymtabsize = *symtabsize; 385 e_shnum = (ISELF64 386 ? bfd_get_16(abfd, e64_hdr.e_shnum) 387 : bfd_get_16(abfd, e32_hdr.e_shnum)); 388 sh_size = e_shnum * (ISELF64 ? sizeof(Elf64_External_Shdr) 389 : sizeof(Elf32_External_Shdr)); 390 if ((shdr = malloc(sh_size)) == NULL) 391 return (1); 392 if (ISELF64) 393 s64hdr = shdr; 394 else 395 s32hdr = shdr; 396 397 *symtabsize += roundup(sh_size, ISELF64 ? 8 : 4); 398 399 e_shoff = (ISELF64 400 ? bfd_get_64(abfd, e64_hdr.e_shoff) 401 : bfd_get_32(abfd, e32_hdr.e_shoff)); 402 if (lseek(fd, e_shoff, SEEK_SET) < 0) 403 goto out; 404 if (read(fd, shdr, sh_size) != sh_size) 405 goto out; 406 407 for (i = 0; i < e_shnum; i++) { 408 if (SH_TYPE(i) == SHT_SYMTAB || SH_TYPE(i) == SHT_STRTAB) { 409 osymtabsize = *symtabsize; 410 *symtabsize += roundup(SH_SIZE(i), ISELF64 ? 8 : 4); 411 if ((*symtab = realloc(*symtab, *symtabsize)) == NULL) 412 goto out; 413 414 if (lseek(fd, SH_OFFSET(i), SEEK_SET) < 0) 415 goto out; 416 if (read(fd, *symtab + osymtabsize, SH_SIZE(i)) != 417 SH_SIZE(i)) 418 goto out; 419 if (ISELF64) { 420 bfd_put_64(abfd, osymtabsize, 421 s64hdr[i].sh_offset); 422 } else { 423 bfd_put_32(abfd, osymtabsize, 424 s32hdr[i].sh_offset); 425 } 426 } 427 } 428 429 if (*symtab == NULL) 430 goto out; 431 432 /* 433 * Copy updated section headers. 434 */ 435 memcpy(*symtab + sh_offset, shdr, sh_size); 436 437 /* 438 * Update and copy the exec header. 439 */ 440 if (ISELF64) { 441 bfd_put_64(abfd, 0, e64_hdr.e_phoff); 442 bfd_put_64(abfd, sizeof(Elf64_External_Ehdr), e64_hdr.e_shoff); 443 bfd_put_16(abfd, 0, e64_hdr.e_phentsize); 444 bfd_put_16(abfd, 0, e64_hdr.e_phnum); 445 } else { 446 bfd_put_32(abfd, 0, e32_hdr.e_phoff); 447 bfd_put_32(abfd, sizeof(Elf32_External_Ehdr), e32_hdr.e_shoff); 448 bfd_put_16(abfd, 0, e32_hdr.e_phentsize); 449 bfd_put_16(abfd, 0, e32_hdr.e_phnum); 450 } 451 memcpy(*symtab, &ehdr, sizeof(ehdr)); 452 453 free(shdr); 454 return (0); 455 out: 456 free(shdr); 457 return (1); 458 } 459