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