1 /* 2 * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 /* Contains the ELF loader */ 10 11 #include <elf.h> 12 13 #include <OS.h> 14 15 #include <unistd.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <stdio.h> 19 #include <ctype.h> 20 21 #include <debug.h> 22 #include <kimage.h> 23 #include <syscalls.h> 24 #include <team.h> 25 #include <thread.h> 26 #include <util/khash.h> 27 #include <vfs.h> 28 #include <vm.h> 29 #include <vm_address_space.h> 30 31 #include <arch/cpu.h> 32 #include <arch/elf.h> 33 #include <elf_priv.h> 34 #include <boot/elf.h> 35 36 //#define TRACE_ELF 37 #ifdef TRACE_ELF 38 # define TRACE(x) dprintf x 39 #else 40 # define TRACE(x) ; 41 #endif 42 43 44 // ToDo: this shall contain a list of linked images (one day) 45 // this is a preparation for shared libraries in the kernel 46 // and not yet used. 47 #if 0 48 typedef struct elf_linked_image { 49 struct elf_linked_image *next; 50 struct elf_image_info *image; 51 } elf_linked_image; 52 #endif 53 54 #define IMAGE_HASH_SIZE 16 55 56 static hash_table *sImagesHash; 57 58 static struct elf_image_info *sKernelImage = NULL; 59 static mutex sImageMutex; // guards sImagesHash 60 static mutex sImageLoadMutex; // serializes loading/unloading add-ons 61 // locking order sImageLoadMutex -> sImageMutex 62 static bool sInitialized = false; 63 64 65 /** calculates hash for an image using its ID */ 66 67 static uint32 68 image_hash(void *_image, const void *_key, uint32 range) 69 { 70 struct elf_image_info *image = (struct elf_image_info *)_image; 71 image_id id = (image_id)_key; 72 73 if (image != NULL) 74 return image->id % range; 75 76 return (uint32)id % range; 77 } 78 79 80 /** compares an image to a given ID */ 81 82 static int 83 image_compare(void *_image, const void *_key) 84 { 85 struct elf_image_info *image = (struct elf_image_info *)_image; 86 image_id id = (image_id)_key; 87 88 return id - image->id; 89 } 90 91 92 static void 93 unregister_elf_image(struct elf_image_info *image) 94 { 95 unregister_image(team_get_kernel_team(), image->id); 96 hash_remove(sImagesHash, image); 97 } 98 99 100 static void 101 register_elf_image(struct elf_image_info *image) 102 { 103 image_info imageInfo; 104 105 memset(&imageInfo, 0, sizeof(image_info)); 106 imageInfo.id = image->id; 107 imageInfo.type = B_SYSTEM_IMAGE; 108 strlcpy(imageInfo.name, image->name, sizeof(imageInfo.name)); 109 110 imageInfo.text = (void *)image->text_region.start; 111 imageInfo.text_size = image->text_region.size; 112 imageInfo.data = (void *)image->data_region.start; 113 imageInfo.data_size = image->data_region.size; 114 115 image->id = register_image(team_get_kernel_team(), &imageInfo, sizeof(image_info)); 116 hash_insert(sImagesHash, image); 117 } 118 119 120 /** Note, you must lock the image mutex when you call this function. */ 121 122 static struct elf_image_info * 123 find_image_at_address(addr_t address) 124 { 125 struct hash_iterator iterator; 126 struct elf_image_info *image; 127 128 ASSERT_LOCKED_MUTEX(&sImageMutex); 129 130 hash_open(sImagesHash, &iterator); 131 132 // get image that may contain the address 133 134 while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { 135 if ((address >= image->text_region.start 136 && address <= (image->text_region.start + image->text_region.size)) 137 || (address >= image->data_region.start 138 && address <= (image->data_region.start + image->data_region.size))) 139 break; 140 } 141 142 hash_close(sImagesHash, &iterator, false); 143 return image; 144 } 145 146 147 static int 148 dump_address_info(int argc, char **argv) 149 { 150 const char *symbol, *imageName; 151 bool exactMatch; 152 addr_t address, baseAddress; 153 154 if (argc < 2) { 155 kprintf("usage: ls <address>\n"); 156 return 0; 157 } 158 159 address = strtoul(argv[1], NULL, 16); 160 161 if (elf_debug_lookup_symbol_address(address, &baseAddress, &symbol, 162 &imageName, &exactMatch) == B_OK) { 163 kprintf("%p = %s + 0x%lx (%s)%s\n", (void *)address, symbol, 164 address - baseAddress, imageName, exactMatch ? "" : " (nearest)"); 165 } else 166 kprintf("There is no image loaded at this address!\n"); 167 168 return 0; 169 } 170 171 172 static struct elf_image_info * 173 find_image(image_id id) 174 { 175 return (elf_image_info *)hash_lookup(sImagesHash, (void *)id); 176 } 177 178 179 static struct elf_image_info * 180 find_image_by_vnode(void *vnode) 181 { 182 struct hash_iterator iterator; 183 struct elf_image_info *image; 184 185 mutex_lock(&sImageMutex); 186 hash_open(sImagesHash, &iterator); 187 188 while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { 189 if (image->vnode == vnode) 190 break; 191 } 192 193 hash_close(sImagesHash, &iterator, false); 194 mutex_unlock(&sImageMutex); 195 196 return image; 197 } 198 199 200 static struct elf_image_info * 201 create_image_struct() 202 { 203 struct elf_image_info *image = (struct elf_image_info *)malloc(sizeof(struct elf_image_info)); 204 if (image == NULL) 205 return NULL; 206 207 memset(image, 0, sizeof(struct elf_image_info)); 208 209 image->text_region.id = -1; 210 image->data_region.id = -1; 211 image->ref_count = 1; 212 213 return image; 214 } 215 216 217 static uint32 218 elf_hash(const char *name) 219 { 220 uint32 hash = 0; 221 uint32 temp; 222 223 while (*name) { 224 hash = (hash << 4) + (uint8)*name++; 225 if ((temp = hash & 0xf0000000) != 0) 226 hash ^= temp >> 24; 227 hash &= ~temp; 228 } 229 return hash; 230 } 231 232 233 static const char * 234 get_symbol_type_string(struct Elf32_Sym *symbol) 235 { 236 switch (ELF32_ST_TYPE(symbol->st_info)) { 237 case STT_FUNC: 238 return "func"; 239 case STT_OBJECT: 240 return " obj"; 241 case STT_FILE: 242 return "file"; 243 default: 244 return "----"; 245 } 246 } 247 248 249 static const char * 250 get_symbol_bind_string(struct Elf32_Sym *symbol) 251 { 252 switch (ELF32_ST_BIND(symbol->st_info)) { 253 case STB_LOCAL: 254 return "loc "; 255 case STB_GLOBAL: 256 return "glob"; 257 case STB_WEAK: 258 return "weak"; 259 default: 260 return "----"; 261 } 262 } 263 264 265 static int 266 dump_symbols(int argc, char **argv) 267 { 268 struct elf_image_info *image = NULL; 269 struct hash_iterator iterator; 270 uint32 i; 271 272 // if the argument looks like a hex number, treat it as such 273 if (argc > 1) { 274 if (isdigit(argv[1][0])) { 275 uint32 num = strtoul(argv[1], NULL, 0); 276 277 if (IS_KERNEL_ADDRESS(num)) { 278 // find image at address 279 280 hash_open(sImagesHash, &iterator); 281 while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { 282 if (image->text_region.start <= num 283 && image->text_region.start + image->text_region.size >= num) 284 break; 285 } 286 hash_close(sImagesHash, &iterator, false); 287 288 if (image == NULL) 289 kprintf("No image covers 0x%lx in the kernel!\n", num); 290 } else { 291 image = (elf_image_info *)hash_lookup(sImagesHash, (void *)num); 292 if (image == NULL) 293 kprintf("image 0x%lx doesn't exist in the kernel!\n", num); 294 } 295 } else { 296 // look for image by name 297 hash_open(sImagesHash, &iterator); 298 while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { 299 if (!strcmp(image->name, argv[1])) 300 break; 301 } 302 hash_close(sImagesHash, &iterator, false); 303 304 if (image == NULL) 305 kprintf("No image \"%s\" found in kernel!\n", argv[1]); 306 } 307 } else { 308 kprintf("usage: %s image_name/image_id/address_in_image\n", argv[0]); 309 return 0; 310 } 311 312 if (image == NULL) 313 return -1; 314 315 // dump symbols 316 317 kprintf("Symbols of image %ld \"%s\":\nAddress Type Size Name\n", image->id, image->name); 318 319 if (image->num_debug_symbols > 0) { 320 // search extended debug symbol table (contains static symbols) 321 for (i = 0; i < image->num_debug_symbols; i++) { 322 struct Elf32_Sym *symbol = &image->debug_symbols[i]; 323 324 if (symbol->st_value == 0 325 || symbol->st_size >= image->text_region.size + image->data_region.size) 326 continue; 327 328 kprintf("%08lx %s/%s %5ld %s\n", symbol->st_value + image->text_region.delta, 329 get_symbol_type_string(symbol), get_symbol_bind_string(symbol), symbol->st_size, 330 image->debug_string_table + symbol->st_name); 331 } 332 } else { 333 int32 j; 334 335 // search standard symbol lookup table 336 for (i = 0; i < HASHTABSIZE(image); i++) { 337 for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 338 struct Elf32_Sym *symbol = &image->syms[j]; 339 340 if (symbol->st_value == 0 341 || symbol->st_size >= image->text_region.size + image->data_region.size) 342 continue; 343 344 kprintf("%08lx %s/%s %5ld %s\n", symbol->st_value + image->text_region.delta, 345 get_symbol_type_string(symbol), get_symbol_bind_string(symbol), 346 symbol->st_size, SYMNAME(image, symbol)); 347 } 348 } 349 } 350 351 return 0; 352 } 353 354 355 static void 356 dump_elf_region(struct elf_region *region, const char *name) 357 { 358 kprintf(" %s.id 0x%lx\n", name, region->id); 359 kprintf(" %s.start 0x%lx\n", name, region->start); 360 kprintf(" %s.size 0x%lx\n", name, region->size); 361 kprintf(" %s.delta %ld\n", name, region->delta); 362 } 363 364 365 static void 366 dump_image_info(struct elf_image_info *image) 367 { 368 kprintf("elf_image_info at %p:\n", image); 369 kprintf(" next %p\n", image->next); 370 kprintf(" id 0x%lx\n", image->id); 371 dump_elf_region(&image->text_region, "text"); 372 dump_elf_region(&image->data_region, "data"); 373 kprintf(" dynamic_section 0x%lx\n", image->dynamic_section); 374 kprintf(" needed %p\n", image->needed); 375 kprintf(" symhash %p\n", image->symhash); 376 kprintf(" syms %p\n", image->syms); 377 kprintf(" strtab %p\n", image->strtab); 378 kprintf(" rel %p\n", image->rel); 379 kprintf(" rel_len 0x%x\n", image->rel_len); 380 kprintf(" rela %p\n", image->rela); 381 kprintf(" rela_len 0x%x\n", image->rela_len); 382 kprintf(" pltrel %p\n", image->pltrel); 383 kprintf(" pltrel_len 0x%x\n", image->pltrel_len); 384 385 kprintf(" debug_symbols %p (%ld)\n", image->debug_symbols, image->num_debug_symbols); 386 } 387 388 389 static int 390 dump_image(int argc, char **argv) 391 { 392 struct hash_iterator iterator; 393 struct elf_image_info *image; 394 395 // if the argument looks like a hex number, treat it as such 396 if (argc > 1) { 397 uint32 num = strtoul(argv[1], NULL, 0); 398 399 if (IS_KERNEL_ADDRESS(num)) { 400 // semi-hack 401 dump_image_info((struct elf_image_info *)num); 402 } else { 403 image = (elf_image_info *)hash_lookup(sImagesHash, (void *)num); 404 if (image == NULL) 405 kprintf("image 0x%lx doesn't exist in the kernel!\n", num); 406 else 407 dump_image_info(image); 408 } 409 return 0; 410 } 411 412 kprintf("loaded kernel images:\n"); 413 414 hash_open(sImagesHash, &iterator); 415 416 while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { 417 kprintf("%p (%ld) %s\n", image, image->id, image->name); 418 } 419 420 hash_close(sImagesHash, &iterator, false); 421 return 0; 422 } 423 424 425 // Currently unused 426 #if 0 427 static 428 void dump_symbol(struct elf_image_info *image, struct Elf32_Sym *sym) 429 { 430 431 kprintf("symbol at %p, in image %p\n", sym, image); 432 433 kprintf(" name index %d, '%s'\n", sym->st_name, SYMNAME(image, sym)); 434 kprintf(" st_value 0x%x\n", sym->st_value); 435 kprintf(" st_size %d\n", sym->st_size); 436 kprintf(" st_info 0x%x\n", sym->st_info); 437 kprintf(" st_other 0x%x\n", sym->st_other); 438 kprintf(" st_shndx %d\n", sym->st_shndx); 439 } 440 #endif 441 442 443 static struct Elf32_Sym * 444 elf_find_symbol(struct elf_image_info *image, const char *name) 445 { 446 uint32 hash; 447 uint32 i; 448 449 if (!image->dynamic_section) 450 return NULL; 451 452 hash = elf_hash(name) % HASHTABSIZE(image); 453 for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) { 454 if (!strcmp(SYMNAME(image, &image->syms[i]), name)) 455 return &image->syms[i]; 456 } 457 458 return NULL; 459 } 460 461 462 static status_t 463 elf_parse_dynamic_section(struct elf_image_info *image) 464 { 465 struct Elf32_Dyn *d; 466 int32 neededOffset = -1; 467 468 TRACE(("top of elf_parse_dynamic_section\n")); 469 470 image->symhash = 0; 471 image->syms = 0; 472 image->strtab = 0; 473 474 d = (struct Elf32_Dyn *)image->dynamic_section; 475 if (!d) 476 return B_ERROR; 477 478 for (int32 i = 0; d[i].d_tag != DT_NULL; i++) { 479 switch (d[i].d_tag) { 480 case DT_NEEDED: 481 neededOffset = d[i].d_un.d_ptr + image->text_region.delta; 482 break; 483 case DT_HASH: 484 image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->text_region.delta); 485 break; 486 case DT_STRTAB: 487 image->strtab = (char *)(d[i].d_un.d_ptr + image->text_region.delta); 488 break; 489 case DT_SYMTAB: 490 image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->text_region.delta); 491 break; 492 case DT_REL: 493 image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->text_region.delta); 494 break; 495 case DT_RELSZ: 496 image->rel_len = d[i].d_un.d_val; 497 break; 498 case DT_RELA: 499 image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->text_region.delta); 500 break; 501 case DT_RELASZ: 502 image->rela_len = d[i].d_un.d_val; 503 break; 504 case DT_JMPREL: 505 image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->text_region.delta); 506 break; 507 case DT_PLTRELSZ: 508 image->pltrel_len = d[i].d_un.d_val; 509 break; 510 case DT_PLTREL: 511 image->pltrel_type = d[i].d_un.d_val; 512 break; 513 514 default: 515 continue; 516 } 517 } 518 519 // lets make sure we found all the required sections 520 if (!image->symhash || !image->syms || !image->strtab) 521 return B_ERROR; 522 523 TRACE(("needed_offset = %d\n", neededOffset)); 524 525 if (neededOffset >= 0) 526 image->needed = STRING(image, neededOffset); 527 528 return B_OK; 529 } 530 531 532 /** this function first tries to see if the first image and it's already resolved symbol is okay, otherwise 533 * it tries to link against the shared_image 534 * XXX gross hack and needs to be done better 535 */ 536 537 status_t 538 elf_resolve_symbol(struct elf_image_info *image, struct Elf32_Sym *sym, 539 struct elf_image_info *shared_image, const char *sym_prepend, addr_t *sym_addr) 540 { 541 struct Elf32_Sym *sym2; 542 char new_symname[512]; 543 544 switch (sym->st_shndx) { 545 case SHN_UNDEF: 546 // patch the symbol name 547 strlcpy(new_symname, sym_prepend, sizeof(new_symname)); 548 strlcat(new_symname, SYMNAME(image, sym), sizeof(new_symname)); 549 550 // it's undefined, must be outside this image, try the other image 551 sym2 = elf_find_symbol(shared_image, new_symname); 552 if (!sym2) { 553 dprintf("\"%s\": could not resolve symbol '%s'\n", 554 image->name, new_symname); 555 return B_MISSING_SYMBOL; 556 } 557 558 // make sure they're the same type 559 if (ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) { 560 dprintf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", new_symname); 561 return B_MISSING_SYMBOL; 562 } 563 564 if (ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL && ELF32_ST_BIND(sym2->st_info) != STB_WEAK) { 565 TRACE(("elf_resolve_symbol: found symbol '%s' but not exported\n", new_symname)); 566 return B_MISSING_SYMBOL; 567 } 568 569 *sym_addr = sym2->st_value + shared_image->text_region.delta; 570 return B_NO_ERROR; 571 case SHN_ABS: 572 *sym_addr = sym->st_value; 573 return B_NO_ERROR; 574 case SHN_COMMON: 575 // ToDo: finish this 576 TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n")); 577 return B_ERROR; 578 default: 579 // standard symbol 580 *sym_addr = sym->st_value + image->text_region.delta; 581 return B_NO_ERROR; 582 } 583 } 584 585 586 /** Until we have shared library support, just links against the kernel */ 587 588 static int 589 elf_relocate(struct elf_image_info *image, const char *sym_prepend) 590 { 591 int status = B_NO_ERROR; 592 593 TRACE(("top of elf_relocate\n")); 594 595 // deal with the rels first 596 if (image->rel) { 597 TRACE(("total %i relocs\n", image->rel_len / (int)sizeof(struct Elf32_Rel))); 598 599 status = arch_elf_relocate_rel(image, sym_prepend, sKernelImage, image->rel, image->rel_len); 600 if (status < B_OK) 601 return status; 602 } 603 604 if (image->pltrel) { 605 TRACE(("total %i plt-relocs\n", image->pltrel_len / (int)sizeof(struct Elf32_Rel))); 606 607 if (image->pltrel_type == DT_REL) 608 status = arch_elf_relocate_rel(image, sym_prepend, sKernelImage, image->pltrel, image->pltrel_len); 609 else 610 status = arch_elf_relocate_rela(image, sym_prepend, sKernelImage, (struct Elf32_Rela *)image->pltrel, image->pltrel_len); 611 if (status < B_OK) 612 return status; 613 } 614 615 if (image->rela) { 616 status = arch_elf_relocate_rela(image, sym_prepend, sKernelImage, image->rela, image->rela_len); 617 if (status < B_OK) 618 return status; 619 } 620 621 return status; 622 } 623 624 625 static int 626 verify_eheader(struct Elf32_Ehdr *elfHeader) 627 { 628 if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0) 629 return B_NOT_AN_EXECUTABLE; 630 631 if (elfHeader->e_ident[4] != ELFCLASS32) 632 return B_NOT_AN_EXECUTABLE; 633 634 if (elfHeader->e_phoff == 0) 635 return B_NOT_AN_EXECUTABLE; 636 637 if (elfHeader->e_phentsize < sizeof(struct Elf32_Phdr)) 638 return B_NOT_AN_EXECUTABLE; 639 640 return 0; 641 } 642 643 644 #if 0 645 static int 646 elf_unlink_relocs(struct elf_image_info *image) 647 { 648 elf_linked_image *link, *next_link; 649 650 for (link = image->linked_images; link; link = next_link) { 651 next_link = link->next; 652 elf_unload_image(link->image); 653 free(link); 654 } 655 656 return B_NO_ERROR; 657 } 658 #endif 659 660 661 static status_t 662 unload_elf_image(struct elf_image_info *image) 663 { 664 if (atomic_add(&image->ref_count, -1) > 0) 665 return B_NO_ERROR; 666 667 //elf_unlink_relocs(image); 668 // not yet used 669 670 delete_area(image->text_region.id); 671 delete_area(image->data_region.id); 672 673 if (image->vnode) 674 vfs_put_vnode(image->vnode); 675 676 unregister_elf_image(image); 677 678 free(image->elf_header); 679 free(image->name); 680 free(image); 681 682 return B_NO_ERROR; 683 } 684 685 686 static status_t 687 load_elf_symbol_table(int fd, struct elf_image_info *image) 688 { 689 struct Elf32_Ehdr *elfHeader = image->elf_header; 690 struct Elf32_Sym *symbolTable = NULL; 691 struct Elf32_Shdr *stringHeader = NULL; 692 uint32 numSymbols = 0; 693 char *stringTable; 694 status_t status; 695 ssize_t length; 696 int32 i; 697 698 // get section headers 699 700 ssize_t size = elfHeader->e_shnum * elfHeader->e_shentsize; 701 struct Elf32_Shdr *sectionHeaders = (struct Elf32_Shdr *)malloc(size); 702 if (sectionHeaders == NULL) { 703 dprintf("error allocating space for section headers\n"); 704 return B_NO_MEMORY; 705 } 706 707 length = read_pos(fd, elfHeader->e_shoff, sectionHeaders, size); 708 if (length < size) { 709 TRACE(("error reading in program headers\n")); 710 status = B_ERROR; 711 goto error1; 712 } 713 714 // find symbol table in section headers 715 716 for (i = 0; i < elfHeader->e_shnum; i++) { 717 if (sectionHeaders[i].sh_type == SHT_SYMTAB) { 718 stringHeader = §ionHeaders[sectionHeaders[i].sh_link]; 719 720 if (stringHeader->sh_type != SHT_STRTAB) { 721 TRACE(("doesn't link to string table\n")); 722 status = B_BAD_DATA; 723 goto error1; 724 } 725 726 // read in symbol table 727 symbolTable = (struct Elf32_Sym *)malloc(size = sectionHeaders[i].sh_size); 728 if (symbolTable == NULL) { 729 status = B_NO_MEMORY; 730 goto error1; 731 } 732 733 length = read_pos(fd, sectionHeaders[i].sh_offset, symbolTable, size); 734 if (length < size) { 735 TRACE(("error reading in symbol table\n")); 736 status = B_ERROR; 737 goto error1; 738 } 739 740 numSymbols = size / sizeof(struct Elf32_Sym); 741 break; 742 } 743 } 744 745 if (symbolTable == NULL) { 746 TRACE(("no symbol table\n")); 747 status = B_BAD_VALUE; 748 goto error1; 749 } 750 751 // read in string table 752 753 stringTable = (char *)malloc(size = stringHeader->sh_size); 754 if (stringTable == NULL) { 755 status = B_NO_MEMORY; 756 goto error2; 757 } 758 759 length = read_pos(fd, stringHeader->sh_offset, stringTable, size); 760 if (length < size) { 761 TRACE(("error reading in string table\n")); 762 status = B_ERROR; 763 goto error3; 764 } 765 766 TRACE(("loaded debug %ld symbols\n", numSymbols)); 767 768 // insert tables into image 769 image->debug_symbols = symbolTable; 770 image->num_debug_symbols = numSymbols; 771 image->debug_string_table = stringTable; 772 773 free(sectionHeaders); 774 return B_OK; 775 776 error3: 777 free(stringTable); 778 error2: 779 free(symbolTable); 780 error1: 781 free(sectionHeaders); 782 783 return status; 784 } 785 786 787 static status_t 788 insert_preloaded_image(struct preloaded_image *preloadedImage, bool kernel) 789 { 790 struct elf_image_info *image; 791 status_t status; 792 793 status = verify_eheader(&preloadedImage->elf_header); 794 if (status < B_OK) 795 return status; 796 797 image = create_image_struct(); 798 if (image == NULL) 799 return B_NO_MEMORY; 800 801 image->name = strdup(preloadedImage->name); 802 image->dynamic_section = preloadedImage->dynamic_section.start; 803 804 image->text_region = preloadedImage->text_region; 805 image->data_region = preloadedImage->data_region; 806 807 status = elf_parse_dynamic_section(image); 808 if (status < B_OK) 809 goto error1; 810 811 if (!kernel) { 812 status = elf_relocate(image, ""); 813 if (status < B_OK) 814 goto error1; 815 } else 816 sKernelImage = image; 817 818 image->debug_symbols = preloadedImage->debug_symbols; 819 image->num_debug_symbols = preloadedImage->num_debug_symbols; 820 image->debug_string_table = preloadedImage->debug_string_table; 821 822 register_elf_image(image); 823 preloadedImage->id = image->id; 824 // modules_init() uses this information to get the preloaded images 825 826 // we now no longer need to write to the text area anymore 827 set_area_protection(image->text_region.id, 828 B_KERNEL_READ_AREA | B_KERNEL_EXECUTE_AREA); 829 830 return B_OK; 831 832 error1: 833 free(image); 834 835 // clean up preloaded image resources (this image won't be used anymore) 836 delete_area(preloadedImage->text_region.id); 837 delete_area(preloadedImage->data_region.id); 838 preloadedImage->id = -1; 839 840 return status; 841 } 842 843 844 // #pragma mark - 845 // public kernel API 846 847 848 status_t 849 get_image_symbol(image_id id, const char *name, int32 sclass, void **_symbol) 850 { 851 struct elf_image_info *image; 852 struct Elf32_Sym *symbol; 853 status_t status = B_OK; 854 855 TRACE(("get_image_symbol(%s)\n", name)); 856 857 mutex_lock(&sImageMutex); 858 859 image = find_image(id); 860 if (image == NULL) { 861 status = B_BAD_IMAGE_ID; 862 goto done; 863 } 864 865 symbol = elf_find_symbol(image, name); 866 if (symbol == NULL || symbol->st_shndx == SHN_UNDEF) { 867 status = B_ENTRY_NOT_FOUND; 868 goto done; 869 } 870 871 // ToDo: support the "sclass" parameter! 872 873 TRACE(("found: %lx (%lx + %lx)\n", symbol->st_value + image->text_region.delta, 874 symbol->st_value, image->text_region.delta)); 875 876 *_symbol = (void *)(symbol->st_value + image->text_region.delta); 877 878 done: 879 mutex_unlock(&sImageMutex); 880 return status; 881 } 882 883 884 // #pragma mark - 885 // kernel private API 886 887 888 /** Looks up a symbol by address in all images loaded in kernel space. 889 * Note, if you need to call this function outside a debugger, make 890 * sure you fix locking and the way it returns its information, first! 891 */ 892 893 status_t 894 elf_debug_lookup_symbol_address(addr_t address, addr_t *_baseAddress, 895 const char **_symbolName, const char **_imageName, bool *_exactMatch) 896 { 897 struct elf_image_info *image; 898 struct Elf32_Sym *symbolFound = NULL; 899 const char *symbolName = NULL; 900 addr_t deltaFound = INT_MAX; 901 bool exactMatch = false; 902 status_t status; 903 904 TRACE(("looking up %p\n", (void *)address)); 905 906 if (!sInitialized) 907 return B_ERROR; 908 909 //mutex_lock(&sImageMutex); 910 911 image = find_image_at_address(address); 912 // get image that may contain the address 913 914 if (image != NULL) { 915 addr_t symbolDelta; 916 uint32 i; 917 int32 j; 918 919 TRACE((" image %p, base = %p, size = %p\n", image, 920 (void *)image->text_region.start, (void *)image->text_region.size)); 921 922 if (image->debug_symbols != NULL) { 923 // search extended debug symbol table (contains static symbols) 924 925 TRACE((" searching debug symbols...\n")); 926 927 for (i = 0; i < image->num_debug_symbols; i++) { 928 struct Elf32_Sym *symbol = &image->debug_symbols[i]; 929 930 if (symbol->st_value == 0 931 || symbol->st_size >= image->text_region.size + image->data_region.size) 932 continue; 933 934 symbolDelta = address - (symbol->st_value + image->text_region.delta); 935 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) 936 exactMatch = true; 937 938 if (exactMatch || symbolDelta < deltaFound) { 939 deltaFound = symbolDelta; 940 symbolFound = symbol; 941 symbolName = image->debug_string_table + symbol->st_name; 942 943 if (exactMatch) 944 break; 945 } 946 } 947 } else { 948 // search standard symbol lookup table 949 950 TRACE((" searching standard symbols...\n")); 951 952 for (i = 0; i < HASHTABSIZE(image); i++) { 953 for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 954 struct Elf32_Sym *symbol = &image->syms[j]; 955 956 if (symbol->st_value == 0 957 || symbol->st_size >= image->text_region.size + image->data_region.size) 958 continue; 959 960 symbolDelta = address - (long)(symbol->st_value + image->text_region.delta); 961 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) 962 exactMatch = true; 963 964 if (exactMatch || symbolDelta < deltaFound) { 965 deltaFound = symbolDelta; 966 symbolFound = symbol; 967 symbolName = SYMNAME(image, symbol); 968 969 if (exactMatch) 970 goto symbol_found; 971 } 972 } 973 } 974 } 975 } 976 symbol_found: 977 978 if (symbolFound != NULL) { 979 if (_symbolName) 980 *_symbolName = symbolName; 981 if (_imageName) 982 *_imageName = image->name; 983 if (_baseAddress) 984 *_baseAddress = symbolFound->st_value + image->text_region.delta; 985 if (_exactMatch) 986 *_exactMatch = exactMatch; 987 988 status = B_OK; 989 } else if (image != NULL) { 990 TRACE(("symbol not found!\n")); 991 992 if (_symbolName) 993 *_symbolName = NULL; 994 if (_imageName) 995 *_imageName = image->name; 996 if (_baseAddress) 997 *_baseAddress = image->text_region.start; 998 if (_exactMatch) 999 *_exactMatch = false; 1000 1001 status = B_OK; 1002 } else { 1003 TRACE(("image not found!\n")); 1004 status = B_ENTRY_NOT_FOUND; 1005 } 1006 1007 // Note, theoretically, all information we return back to our caller 1008 // would have to be locked - but since this function is only called 1009 // from the debugger, it's safe to do it this way 1010 1011 //mutex_unlock(&sImageMutex); 1012 1013 return status; 1014 } 1015 1016 1017 status_t 1018 elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entry) 1019 { 1020 struct Elf32_Ehdr elfHeader; 1021 struct Elf32_Phdr *programHeaders = NULL; 1022 char baseName[B_OS_NAME_LENGTH]; 1023 status_t status; 1024 ssize_t length; 1025 int fd; 1026 int i; 1027 1028 TRACE(("elf_load: entry path '%s', team %p\n", path, team)); 1029 1030 fd = _kern_open(-1, path, O_RDONLY, 0); 1031 if (fd < 0) 1032 return fd; 1033 1034 // read and verify the ELF header 1035 1036 length = _kern_read(fd, 0, &elfHeader, sizeof(elfHeader)); 1037 if (length < B_OK) { 1038 status = length; 1039 goto error; 1040 } 1041 1042 if (length != sizeof(elfHeader)) { 1043 // short read 1044 status = B_NOT_AN_EXECUTABLE; 1045 goto error; 1046 } 1047 status = verify_eheader(&elfHeader); 1048 if (status < B_OK) 1049 goto error; 1050 1051 // read program header 1052 1053 programHeaders = (struct Elf32_Phdr *)malloc(elfHeader.e_phnum * elfHeader.e_phentsize); 1054 if (programHeaders == NULL) { 1055 dprintf("error allocating space for program headers\n"); 1056 status = B_NO_MEMORY; 1057 goto error; 1058 } 1059 1060 TRACE(("reading in program headers at 0x%lx, length 0x%x\n", elfHeader.e_phoff, elfHeader.e_phnum * elfHeader.e_phentsize)); 1061 length = _kern_read(fd, elfHeader.e_phoff, programHeaders, elfHeader.e_phnum * elfHeader.e_phentsize); 1062 if (length < B_OK) { 1063 status = length; 1064 dprintf("error reading in program headers\n"); 1065 goto error; 1066 } 1067 if (length != elfHeader.e_phnum * elfHeader.e_phentsize) { 1068 dprintf("short read while reading in program headers\n"); 1069 status = -1; 1070 goto error; 1071 } 1072 1073 // construct a nice name for the region we have to create below 1074 { 1075 int32 length; 1076 1077 const char *leaf = strrchr(path, '/'); 1078 if (leaf == NULL) 1079 leaf = path; 1080 else 1081 leaf++; 1082 1083 length = strlen(leaf); 1084 if (length > B_OS_NAME_LENGTH - 8) 1085 sprintf(baseName, "...%s", leaf + length + 8 - B_OS_NAME_LENGTH); 1086 else 1087 strcpy(baseName, leaf); 1088 } 1089 1090 // map the program's segments into memory 1091 1092 for (i = 0; i < elfHeader.e_phnum; i++) { 1093 char regionName[B_OS_NAME_LENGTH]; 1094 char *regionAddress; 1095 area_id id; 1096 1097 if (programHeaders[i].p_type != PT_LOAD) 1098 continue; 1099 1100 regionAddress = (char *)ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); 1101 if (programHeaders[i].p_flags & PF_WRITE) { 1102 /* 1103 * rw/data segment 1104 */ 1105 uint32 memUpperBound = (programHeaders[i].p_vaddr % B_PAGE_SIZE) + programHeaders[i].p_memsz; 1106 uint32 fileUpperBound = (programHeaders[i].p_vaddr % B_PAGE_SIZE) + programHeaders[i].p_filesz; 1107 1108 memUpperBound = ROUNDUP(memUpperBound, B_PAGE_SIZE); 1109 fileUpperBound = ROUNDUP(fileUpperBound, B_PAGE_SIZE); 1110 1111 sprintf(regionName, "%s_seg%drw", baseName, i); 1112 1113 id = vm_map_file(team->id, regionName, 1114 (void **)®ionAddress, 1115 B_EXACT_ADDRESS, 1116 fileUpperBound, 1117 B_READ_AREA | B_WRITE_AREA, REGION_PRIVATE_MAP, 1118 path, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); 1119 if (id < B_OK) { 1120 dprintf("error mapping file data: %s!\n", strerror(id)); 1121 status = B_NOT_AN_EXECUTABLE; 1122 goto error; 1123 } 1124 1125 // clean garbage brought by mmap (the region behind the file, 1126 // at least parts of it are the bss and have to be zeroed) 1127 { 1128 uint32 start = (uint32)regionAddress 1129 + (programHeaders[i].p_vaddr % B_PAGE_SIZE) 1130 + programHeaders[i].p_filesz; 1131 uint32 amount = fileUpperBound 1132 - (programHeaders[i].p_vaddr % B_PAGE_SIZE) 1133 - (programHeaders[i].p_filesz); 1134 memset((void *)start, 0, amount); 1135 } 1136 1137 // Check if we need extra storage for the bss - we have to do this if 1138 // the above region doesn't already comprise the memory size, too. 1139 1140 if (memUpperBound != fileUpperBound) { 1141 size_t bss_size = memUpperBound - fileUpperBound; 1142 1143 snprintf(regionName, B_OS_NAME_LENGTH, "%s_bss%d", baseName, i); 1144 1145 regionAddress += fileUpperBound; 1146 id = create_area_etc(team, regionName, (void **)®ionAddress, 1147 B_EXACT_ADDRESS, bss_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 1148 if (id < B_OK) { 1149 dprintf("error allocating bss area: %s!\n", strerror(id)); 1150 status = B_NOT_AN_EXECUTABLE; 1151 goto error; 1152 } 1153 } 1154 } else { 1155 /* 1156 * assume ro/text segment 1157 */ 1158 snprintf(regionName, B_OS_NAME_LENGTH, "%s_seg%dro", baseName, i); 1159 1160 id = vm_map_file(team->id, regionName, 1161 (void **)®ionAddress, 1162 B_EXACT_ADDRESS, 1163 ROUNDUP(programHeaders[i].p_memsz + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE), 1164 B_READ_AREA | B_EXECUTE_AREA, REGION_PRIVATE_MAP, 1165 path, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); 1166 if (id < B_OK) { 1167 dprintf("error mapping file text: %s!\n", strerror(id)); 1168 status = B_NOT_AN_EXECUTABLE; 1169 goto error; 1170 } 1171 } 1172 } 1173 1174 TRACE(("elf_load: done!\n")); 1175 1176 *entry = elfHeader.e_entry; 1177 1178 status = B_OK; 1179 1180 error: 1181 if (programHeaders) 1182 free(programHeaders); 1183 _kern_close(fd); 1184 1185 return status; 1186 } 1187 1188 1189 image_id 1190 load_kernel_add_on(const char *path) 1191 { 1192 struct Elf32_Phdr *programHeaders; 1193 struct Elf32_Ehdr *elfHeader; 1194 struct elf_image_info *image; 1195 const char *fileName; 1196 void *reservedAddress; 1197 addr_t start; 1198 size_t reservedSize; 1199 status_t status; 1200 ssize_t length; 1201 1202 TRACE(("elf_load_kspace: entry path '%s'\n", path)); 1203 1204 int fd = _kern_open(-1, path, O_RDONLY, 0); 1205 if (fd < 0) 1206 return fd; 1207 1208 struct vnode *vnode; 1209 status = vfs_get_vnode_from_fd(fd, true, &vnode); 1210 if (status < B_OK) 1211 goto error0; 1212 1213 // get the file name 1214 fileName = strrchr(path, '/'); 1215 if (fileName == NULL) 1216 fileName = path; 1217 else 1218 fileName++; 1219 1220 // Prevent someone else from trying to load this image 1221 mutex_lock(&sImageLoadMutex); 1222 1223 // make sure it's not loaded already. Search by vnode 1224 image = find_image_by_vnode(vnode); 1225 if (image) { 1226 atomic_add(&image->ref_count, 1); 1227 goto done; 1228 } 1229 1230 elfHeader = (struct Elf32_Ehdr *)malloc(sizeof(*elfHeader)); 1231 if (!elfHeader) { 1232 status = B_NO_MEMORY; 1233 goto error; 1234 } 1235 1236 length = _kern_read(fd, 0, elfHeader, sizeof(*elfHeader)); 1237 if (length < B_OK) { 1238 status = length; 1239 goto error1; 1240 } 1241 if (length != sizeof(*elfHeader)) { 1242 // short read 1243 status = B_NOT_AN_EXECUTABLE; 1244 goto error1; 1245 } 1246 status = verify_eheader(elfHeader); 1247 if (status < B_OK) 1248 goto error1; 1249 1250 image = create_image_struct(); 1251 if (!image) { 1252 status = B_NO_MEMORY; 1253 goto error1; 1254 } 1255 image->vnode = vnode; 1256 image->elf_header = elfHeader; 1257 image->name = strdup(path); 1258 1259 programHeaders = (struct Elf32_Phdr *)malloc(elfHeader->e_phnum * elfHeader->e_phentsize); 1260 if (programHeaders == NULL) { 1261 dprintf("%s: error allocating space for program headers\n", fileName); 1262 status = B_NO_MEMORY; 1263 goto error2; 1264 } 1265 1266 TRACE(("reading in program headers at 0x%lx, length 0x%x\n", elfHeader->e_phoff, elfHeader->e_phnum * elfHeader->e_phentsize)); 1267 length = _kern_read(fd, elfHeader->e_phoff, programHeaders, elfHeader->e_phnum * elfHeader->e_phentsize); 1268 if (length < B_OK) { 1269 status = length; 1270 TRACE(("%s: error reading in program headers\n", fileName)); 1271 goto error3; 1272 } 1273 if (length != elfHeader->e_phnum * elfHeader->e_phentsize) { 1274 TRACE(("%s: short read while reading in program headers\n", fileName)); 1275 status = B_ERROR; 1276 goto error3; 1277 } 1278 1279 // determine how much space we need for all loaded segments 1280 1281 reservedSize = 0; 1282 length = 0; 1283 1284 for (int32 i = 0; i < elfHeader->e_phnum; i++) { 1285 size_t end; 1286 1287 if (programHeaders[i].p_type != PT_LOAD) 1288 continue; 1289 1290 length += ROUNDUP(programHeaders[i].p_memsz + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); 1291 1292 end = ROUNDUP(programHeaders[i].p_memsz + programHeaders[i].p_vaddr, B_PAGE_SIZE); 1293 if (end > reservedSize) 1294 reservedSize = end; 1295 } 1296 1297 // Check whether the segments have an unreasonable amount of unused space 1298 // inbetween. 1299 if ((ssize_t)reservedSize > length + 8 * 1024) { 1300 status = B_BAD_DATA; 1301 goto error1; 1302 } 1303 1304 // reserve that space and allocate the areas from that one 1305 if (vm_reserve_address_range(vm_kernel_address_space_id(), &reservedAddress, 1306 B_ANY_KERNEL_ADDRESS, reservedSize, 0) < B_OK) 1307 goto error3; 1308 1309 start = (addr_t)reservedAddress; 1310 image->data_region.size = 0; 1311 image->text_region.size = 0; 1312 1313 for (int32 i = 0; i < elfHeader->e_phnum; i++) { 1314 char regionName[B_OS_NAME_LENGTH]; 1315 elf_region *region; 1316 1317 TRACE(("looking at program header %d\n", i)); 1318 1319 switch (programHeaders[i].p_type) { 1320 case PT_LOAD: 1321 break; 1322 case PT_DYNAMIC: 1323 image->dynamic_section = programHeaders[i].p_vaddr; 1324 continue; 1325 default: 1326 dprintf("%s: unhandled pheader type 0x%lx\n", fileName, programHeaders[i].p_type); 1327 continue; 1328 } 1329 1330 // we're here, so it must be a PT_LOAD segment 1331 if (programHeaders[i].IsReadWrite()) { 1332 // this is the writable segment 1333 if (image->data_region.size != 0) { 1334 // we've already created this segment 1335 continue; 1336 } 1337 region = &image->data_region; 1338 1339 snprintf(regionName, B_OS_NAME_LENGTH, "%s_data", fileName); 1340 } else if (programHeaders[i].IsExecutable()) { 1341 // this is the non-writable segment 1342 if (image->text_region.size != 0) { 1343 // we've already created this segment 1344 continue; 1345 } 1346 region = &image->text_region; 1347 1348 snprintf(regionName, B_OS_NAME_LENGTH, "%s_text", fileName); 1349 } else { 1350 dprintf("%s: weird program header flags 0x%lx\n", fileName, 1351 programHeaders[i].p_flags); 1352 continue; 1353 } 1354 1355 region->start = (addr_t)reservedAddress + ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); 1356 region->size = ROUNDUP(programHeaders[i].p_memsz 1357 + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); 1358 region->id = create_area(regionName, (void **)®ion->start, B_EXACT_ADDRESS, 1359 region->size, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 1360 if (region->id < B_OK) { 1361 dprintf("%s: error allocating area: %s\n", fileName, strerror(region->id)); 1362 status = B_NOT_AN_EXECUTABLE; 1363 goto error4; 1364 } 1365 region->delta = -ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); 1366 1367 TRACE(("elf_load_kspace: created area \"%s\" at %p\n", 1368 regionName, (void *)region->start)); 1369 1370 length = _kern_read(fd, programHeaders[i].p_offset, 1371 (void *)(region->start + (programHeaders[i].p_vaddr % B_PAGE_SIZE)), 1372 programHeaders[i].p_filesz); 1373 if (length < B_OK) { 1374 status = length; 1375 dprintf("%s: error reading in segment %ld\n", fileName, i); 1376 goto error5; 1377 } 1378 } 1379 1380 // get the segment order 1381 elf_region *firstRegion; 1382 elf_region *secondRegion; 1383 if (image->text_region.start < image->data_region.start) { 1384 firstRegion = &image->text_region; 1385 secondRegion = &image->data_region; 1386 } else { 1387 firstRegion = &image->data_region; 1388 secondRegion = &image->text_region; 1389 } 1390 1391 image->data_region.delta += image->data_region.start; 1392 image->text_region.delta += image->text_region.start; 1393 1394 // modify the dynamic ptr by the delta of the regions 1395 image->dynamic_section += image->text_region.delta; 1396 1397 status = elf_parse_dynamic_section(image); 1398 if (status < B_OK) 1399 goto error5; 1400 1401 status = elf_relocate(image, ""); 1402 if (status < B_OK) 1403 goto error5; 1404 1405 // We needed to read in the contents of the "text" area, but 1406 // now we can protect it read-only/execute 1407 set_area_protection(image->text_region.id, B_KERNEL_READ_AREA | B_KERNEL_EXECUTE_AREA); 1408 1409 // There might be a hole between the two segments, and we don't need to 1410 // reserve this any longer 1411 vm_unreserve_address_range(vm_kernel_address_space_id(), reservedAddress, reservedSize); 1412 1413 // ToDo: this should be enabled by kernel settings! 1414 if (1) 1415 load_elf_symbol_table(fd, image); 1416 1417 free(programHeaders); 1418 register_elf_image(image); 1419 1420 done: 1421 _kern_close(fd); 1422 mutex_unlock(&sImageLoadMutex); 1423 1424 return image->id; 1425 1426 error5: 1427 delete_area(image->data_region.id); 1428 delete_area(image->text_region.id); 1429 error4: 1430 vm_unreserve_address_range(vm_kernel_address_space_id(), reservedAddress, reservedSize); 1431 error3: 1432 free(programHeaders); 1433 error2: 1434 free(image); 1435 error1: 1436 free(elfHeader); 1437 error: 1438 mutex_unlock(&sImageLoadMutex); 1439 error0: 1440 if (vnode) 1441 vfs_put_vnode(vnode); 1442 _kern_close(fd); 1443 1444 return status; 1445 } 1446 1447 1448 status_t 1449 unload_kernel_add_on(image_id id) 1450 { 1451 struct elf_image_info *image; 1452 status_t status; 1453 1454 mutex_lock(&sImageLoadMutex); 1455 mutex_lock(&sImageMutex); 1456 1457 image = find_image(id); 1458 if (image != NULL) 1459 status = unload_elf_image(image); 1460 else 1461 status = B_BAD_IMAGE_ID; 1462 1463 mutex_unlock(&sImageMutex); 1464 mutex_unlock(&sImageLoadMutex); 1465 1466 return status; 1467 } 1468 1469 1470 status_t 1471 elf_init(kernel_args *args) 1472 { 1473 struct preloaded_image *image; 1474 1475 image_init(); 1476 1477 mutex_init(&sImageMutex, "kimages_lock"); 1478 mutex_init(&sImageLoadMutex, "kimages_load_lock"); 1479 1480 sImagesHash = hash_init(IMAGE_HASH_SIZE, 0, image_compare, image_hash); 1481 if (sImagesHash == NULL) 1482 return B_NO_MEMORY; 1483 1484 // Build a image structure for the kernel, which has already been loaded. 1485 // The preloaded_images were already prepared by the VM. 1486 if (insert_preloaded_image(&args->kernel_image, true) < B_OK) 1487 panic("could not create kernel image.\n"); 1488 1489 // Build image structures for all preloaded images. 1490 for (image = args->preloaded_images; image != NULL; image = image->next) { 1491 insert_preloaded_image(image, false); 1492 } 1493 1494 add_debugger_command("ls", &dump_address_info, "lookup symbol for a particular address"); 1495 add_debugger_command("symbols", &dump_symbols, "dump symbols for image"); 1496 add_debugger_command("image", &dump_image, "dump image info"); 1497 1498 sInitialized = true; 1499 return B_OK; 1500 } 1501 1502