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 return B_OK; 824 825 error1: 826 free(image); 827 828 // clean up preloaded image resources (this image won't be used anymore) 829 delete_area(preloadedImage->text_region.id); 830 delete_area(preloadedImage->data_region.id); 831 preloadedImage->id = -1; 832 833 return status; 834 } 835 836 837 // #pragma mark - 838 // public kernel API 839 840 841 status_t 842 get_image_symbol(image_id id, const char *name, int32 sclass, void **_symbol) 843 { 844 struct elf_image_info *image; 845 struct Elf32_Sym *symbol; 846 status_t status = B_OK; 847 848 TRACE(("get_image_symbol(%s)\n", name)); 849 850 mutex_lock(&sImageMutex); 851 852 image = find_image(id); 853 if (image == NULL) { 854 status = B_BAD_IMAGE_ID; 855 goto done; 856 } 857 858 symbol = elf_find_symbol(image, name); 859 if (symbol == NULL || symbol->st_shndx == SHN_UNDEF) { 860 status = B_ENTRY_NOT_FOUND; 861 goto done; 862 } 863 864 // ToDo: support the "sclass" parameter! 865 866 TRACE(("found: %lx (%lx + %lx)\n", symbol->st_value + image->text_region.delta, 867 symbol->st_value, image->text_region.delta)); 868 869 *_symbol = (void *)(symbol->st_value + image->text_region.delta); 870 871 done: 872 mutex_unlock(&sImageMutex); 873 return status; 874 } 875 876 877 // #pragma mark - 878 // kernel private API 879 880 881 /** Looks up a symbol by address in all images loaded in kernel space. 882 * Note, if you need to call this function outside a debugger, make 883 * sure you fix locking and the way it returns its information, first! 884 */ 885 886 status_t 887 elf_debug_lookup_symbol_address(addr_t address, addr_t *_baseAddress, 888 const char **_symbolName, const char **_imageName, bool *_exactMatch) 889 { 890 struct elf_image_info *image; 891 struct Elf32_Sym *symbolFound = NULL; 892 const char *symbolName = NULL; 893 addr_t deltaFound = INT_MAX; 894 bool exactMatch = false; 895 status_t status; 896 897 TRACE(("looking up %p\n", (void *)address)); 898 899 if (!sInitialized) 900 return B_ERROR; 901 902 //mutex_lock(&sImageMutex); 903 904 image = find_image_at_address(address); 905 // get image that may contain the address 906 907 if (image != NULL) { 908 addr_t symbolDelta; 909 uint32 i; 910 int32 j; 911 912 TRACE((" image %p, base = %p, size = %p\n", image, 913 (void *)image->text_region.start, (void *)image->text_region.size)); 914 915 if (image->debug_symbols != NULL) { 916 // search extended debug symbol table (contains static symbols) 917 918 TRACE((" searching debug symbols...\n")); 919 920 for (i = 0; i < image->num_debug_symbols; i++) { 921 struct Elf32_Sym *symbol = &image->debug_symbols[i]; 922 923 if (symbol->st_value == 0 924 || symbol->st_size >= image->text_region.size + image->data_region.size) 925 continue; 926 927 symbolDelta = address - (symbol->st_value + image->text_region.delta); 928 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) 929 exactMatch = true; 930 931 if (exactMatch || symbolDelta < deltaFound) { 932 deltaFound = symbolDelta; 933 symbolFound = symbol; 934 symbolName = image->debug_string_table + symbol->st_name; 935 936 if (exactMatch) 937 break; 938 } 939 } 940 } else { 941 // search standard symbol lookup table 942 943 TRACE((" searching standard symbols...\n")); 944 945 for (i = 0; i < HASHTABSIZE(image); i++) { 946 for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 947 struct Elf32_Sym *symbol = &image->syms[j]; 948 949 if (symbol->st_value == 0 950 || symbol->st_size >= image->text_region.size + image->data_region.size) 951 continue; 952 953 symbolDelta = address - (long)(symbol->st_value + image->text_region.delta); 954 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) 955 exactMatch = true; 956 957 if (exactMatch || symbolDelta < deltaFound) { 958 deltaFound = symbolDelta; 959 symbolFound = symbol; 960 symbolName = SYMNAME(image, symbol); 961 962 if (exactMatch) 963 goto symbol_found; 964 } 965 } 966 } 967 } 968 } 969 symbol_found: 970 971 if (symbolFound != NULL) { 972 if (_symbolName) 973 *_symbolName = symbolName; 974 if (_imageName) 975 *_imageName = image->name; 976 if (_baseAddress) 977 *_baseAddress = symbolFound->st_value + image->text_region.delta; 978 if (_exactMatch) 979 *_exactMatch = exactMatch; 980 981 status = B_OK; 982 } else if (image != NULL) { 983 TRACE(("symbol not found!\n")); 984 985 if (_symbolName) 986 *_symbolName = NULL; 987 if (_imageName) 988 *_imageName = image->name; 989 if (_baseAddress) 990 *_baseAddress = image->text_region.start; 991 if (_exactMatch) 992 *_exactMatch = false; 993 994 status = B_OK; 995 } else { 996 TRACE(("image not found!\n")); 997 status = B_ENTRY_NOT_FOUND; 998 } 999 1000 // Note, theoretically, all information we return back to our caller 1001 // would have to be locked - but since this function is only called 1002 // from the debugger, it's safe to do it this way 1003 1004 //mutex_unlock(&sImageMutex); 1005 1006 return status; 1007 } 1008 1009 1010 status_t 1011 elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entry) 1012 { 1013 struct Elf32_Ehdr elfHeader; 1014 struct Elf32_Phdr *programHeaders = NULL; 1015 char baseName[B_OS_NAME_LENGTH]; 1016 status_t status; 1017 ssize_t length; 1018 int fd; 1019 int i; 1020 1021 TRACE(("elf_load: entry path '%s', team %p\n", path, team)); 1022 1023 fd = _kern_open(-1, path, O_RDONLY, 0); 1024 if (fd < 0) 1025 return fd; 1026 1027 // read and verify the ELF header 1028 1029 length = _kern_read(fd, 0, &elfHeader, sizeof(elfHeader)); 1030 if (length < B_OK) { 1031 status = length; 1032 goto error; 1033 } 1034 1035 if (length != sizeof(elfHeader)) { 1036 // short read 1037 status = B_NOT_AN_EXECUTABLE; 1038 goto error; 1039 } 1040 status = verify_eheader(&elfHeader); 1041 if (status < B_OK) 1042 goto error; 1043 1044 // read program header 1045 1046 programHeaders = (struct Elf32_Phdr *)malloc(elfHeader.e_phnum * elfHeader.e_phentsize); 1047 if (programHeaders == NULL) { 1048 dprintf("error allocating space for program headers\n"); 1049 status = B_NO_MEMORY; 1050 goto error; 1051 } 1052 1053 TRACE(("reading in program headers at 0x%lx, length 0x%x\n", elfHeader.e_phoff, elfHeader.e_phnum * elfHeader.e_phentsize)); 1054 length = _kern_read(fd, elfHeader.e_phoff, programHeaders, elfHeader.e_phnum * elfHeader.e_phentsize); 1055 if (length < B_OK) { 1056 status = length; 1057 dprintf("error reading in program headers\n"); 1058 goto error; 1059 } 1060 if (length != elfHeader.e_phnum * elfHeader.e_phentsize) { 1061 dprintf("short read while reading in program headers\n"); 1062 status = -1; 1063 goto error; 1064 } 1065 1066 // construct a nice name for the region we have to create below 1067 { 1068 int32 length; 1069 1070 const char *leaf = strrchr(path, '/'); 1071 if (leaf == NULL) 1072 leaf = path; 1073 else 1074 leaf++; 1075 1076 length = strlen(leaf); 1077 if (length > B_OS_NAME_LENGTH - 8) 1078 sprintf(baseName, "...%s", leaf + length + 8 - B_OS_NAME_LENGTH); 1079 else 1080 strcpy(baseName, leaf); 1081 } 1082 1083 // map the program's segments into memory 1084 1085 for (i = 0; i < elfHeader.e_phnum; i++) { 1086 char regionName[B_OS_NAME_LENGTH]; 1087 char *regionAddress; 1088 area_id id; 1089 1090 if (programHeaders[i].p_type != PT_LOAD) 1091 continue; 1092 1093 regionAddress = (char *)ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); 1094 if (programHeaders[i].p_flags & PF_WRITE) { 1095 /* 1096 * rw/data segment 1097 */ 1098 uint32 memUpperBound = (programHeaders[i].p_vaddr % B_PAGE_SIZE) + programHeaders[i].p_memsz; 1099 uint32 fileUpperBound = (programHeaders[i].p_vaddr % B_PAGE_SIZE) + programHeaders[i].p_filesz; 1100 1101 memUpperBound = ROUNDUP(memUpperBound, B_PAGE_SIZE); 1102 fileUpperBound = ROUNDUP(fileUpperBound, B_PAGE_SIZE); 1103 1104 sprintf(regionName, "%s_seg%drw", baseName, i); 1105 1106 id = vm_map_file(team->id, regionName, 1107 (void **)®ionAddress, 1108 B_EXACT_ADDRESS, 1109 fileUpperBound, 1110 B_READ_AREA | B_WRITE_AREA, REGION_PRIVATE_MAP, 1111 path, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); 1112 if (id < B_OK) { 1113 dprintf("error mapping file data: %s!\n", strerror(id)); 1114 status = B_NOT_AN_EXECUTABLE; 1115 goto error; 1116 } 1117 1118 // clean garbage brought by mmap (the region behind the file, 1119 // at least parts of it are the bss and have to be zeroed) 1120 { 1121 uint32 start = (uint32)regionAddress 1122 + (programHeaders[i].p_vaddr % B_PAGE_SIZE) 1123 + programHeaders[i].p_filesz; 1124 uint32 amount = fileUpperBound 1125 - (programHeaders[i].p_vaddr % B_PAGE_SIZE) 1126 - (programHeaders[i].p_filesz); 1127 memset((void *)start, 0, amount); 1128 } 1129 1130 // Check if we need extra storage for the bss - we have to do this if 1131 // the above region doesn't already comprise the memory size, too. 1132 1133 if (memUpperBound != fileUpperBound) { 1134 size_t bss_size = memUpperBound - fileUpperBound; 1135 1136 snprintf(regionName, B_OS_NAME_LENGTH, "%s_bss%d", baseName, i); 1137 1138 regionAddress += fileUpperBound; 1139 id = create_area_etc(team, regionName, (void **)®ionAddress, 1140 B_EXACT_ADDRESS, bss_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 1141 if (id < B_OK) { 1142 dprintf("error allocating bss area: %s!\n", strerror(id)); 1143 status = B_NOT_AN_EXECUTABLE; 1144 goto error; 1145 } 1146 } 1147 } else { 1148 /* 1149 * assume ro/text segment 1150 */ 1151 snprintf(regionName, B_OS_NAME_LENGTH, "%s_seg%dro", baseName, i); 1152 1153 id = vm_map_file(team->id, regionName, 1154 (void **)®ionAddress, 1155 B_EXACT_ADDRESS, 1156 ROUNDUP(programHeaders[i].p_memsz + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE), 1157 B_READ_AREA | B_EXECUTE_AREA, REGION_PRIVATE_MAP, 1158 path, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); 1159 if (id < B_OK) { 1160 dprintf("error mapping file text: %s!\n", strerror(id)); 1161 status = B_NOT_AN_EXECUTABLE; 1162 goto error; 1163 } 1164 } 1165 } 1166 1167 TRACE(("elf_load: done!\n")); 1168 1169 *entry = elfHeader.e_entry; 1170 1171 status = B_OK; 1172 1173 error: 1174 if (programHeaders) 1175 free(programHeaders); 1176 _kern_close(fd); 1177 1178 return status; 1179 } 1180 1181 1182 image_id 1183 load_kernel_add_on(const char *path) 1184 { 1185 struct Elf32_Phdr *programHeaders; 1186 struct Elf32_Ehdr *elfHeader; 1187 struct elf_image_info *image; 1188 const char *fileName; 1189 void *vnode = NULL; 1190 void *reservedAddress; 1191 addr_t start; 1192 size_t reservedSize; 1193 status_t status; 1194 int fd; 1195 ssize_t length; 1196 1197 TRACE(("elf_load_kspace: entry path '%s'\n", path)); 1198 1199 fd = _kern_open(-1, path, O_RDONLY, 0); 1200 if (fd < 0) 1201 return fd; 1202 1203 status = vfs_get_vnode_from_fd(fd, true, &vnode); 1204 if (status < B_OK) 1205 goto error0; 1206 1207 // get the file name 1208 fileName = strrchr(path, '/'); 1209 if (fileName == NULL) 1210 fileName = path; 1211 else 1212 fileName++; 1213 1214 // Prevent someone else from trying to load this image 1215 mutex_lock(&sImageLoadMutex); 1216 1217 // make sure it's not loaded already. Search by vnode 1218 image = find_image_by_vnode(vnode); 1219 if (image) { 1220 atomic_add(&image->ref_count, 1); 1221 goto done; 1222 } 1223 1224 elfHeader = (struct Elf32_Ehdr *)malloc(sizeof(*elfHeader)); 1225 if (!elfHeader) { 1226 status = B_NO_MEMORY; 1227 goto error; 1228 } 1229 1230 length = _kern_read(fd, 0, elfHeader, sizeof(*elfHeader)); 1231 if (length < B_OK) { 1232 status = length; 1233 goto error1; 1234 } 1235 if (length != sizeof(*elfHeader)) { 1236 // short read 1237 status = B_NOT_AN_EXECUTABLE; 1238 goto error1; 1239 } 1240 status = verify_eheader(elfHeader); 1241 if (status < B_OK) 1242 goto error1; 1243 1244 image = create_image_struct(); 1245 if (!image) { 1246 status = B_NO_MEMORY; 1247 goto error1; 1248 } 1249 image->vnode = vnode; 1250 image->elf_header = elfHeader; 1251 image->name = strdup(path); 1252 1253 programHeaders = (struct Elf32_Phdr *)malloc(elfHeader->e_phnum * elfHeader->e_phentsize); 1254 if (programHeaders == NULL) { 1255 dprintf("%s: error allocating space for program headers\n", fileName); 1256 status = B_NO_MEMORY; 1257 goto error2; 1258 } 1259 1260 TRACE(("reading in program headers at 0x%lx, length 0x%x\n", elfHeader->e_phoff, elfHeader->e_phnum * elfHeader->e_phentsize)); 1261 length = _kern_read(fd, elfHeader->e_phoff, programHeaders, elfHeader->e_phnum * elfHeader->e_phentsize); 1262 if (length < B_OK) { 1263 status = length; 1264 TRACE(("%s: error reading in program headers\n", fileName)); 1265 goto error3; 1266 } 1267 if (length != elfHeader->e_phnum * elfHeader->e_phentsize) { 1268 TRACE(("%s: short read while reading in program headers\n", fileName)); 1269 status = B_ERROR; 1270 goto error3; 1271 } 1272 1273 // determine how much space we need for all loaded segments 1274 1275 reservedSize = 0; 1276 length = 0; 1277 1278 for (int32 i = 0; i < elfHeader->e_phnum; i++) { 1279 size_t end; 1280 1281 if (programHeaders[i].p_type != PT_LOAD) 1282 continue; 1283 1284 length += ROUNDUP(programHeaders[i].p_memsz + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); 1285 1286 end = ROUNDUP(programHeaders[i].p_memsz + programHeaders[i].p_vaddr, B_PAGE_SIZE); 1287 if (end > reservedSize) 1288 reservedSize = end; 1289 } 1290 1291 // Check whether the segments have an unreasonable amount of unused space 1292 // inbetween. 1293 if ((ssize_t)reservedSize > length + 8 * 1024) { 1294 status = B_BAD_DATA; 1295 goto error1; 1296 } 1297 1298 // reserve that space and allocate the areas from that one 1299 if (vm_reserve_address_range(vm_kernel_address_space_id(), &reservedAddress, 1300 B_ANY_KERNEL_ADDRESS, reservedSize, 0) < B_OK) 1301 goto error3; 1302 1303 start = (addr_t)reservedAddress; 1304 image->data_region.size = 0; 1305 image->text_region.size = 0; 1306 1307 for (int32 i = 0; i < elfHeader->e_phnum; i++) { 1308 char regionName[B_OS_NAME_LENGTH]; 1309 elf_region *region; 1310 1311 TRACE(("looking at program header %d\n", i)); 1312 1313 switch (programHeaders[i].p_type) { 1314 case PT_LOAD: 1315 break; 1316 case PT_DYNAMIC: 1317 image->dynamic_section = programHeaders[i].p_vaddr; 1318 continue; 1319 default: 1320 dprintf("%s: unhandled pheader type 0x%lx\n", fileName, programHeaders[i].p_type); 1321 continue; 1322 } 1323 1324 // we're here, so it must be a PT_LOAD segment 1325 if (programHeaders[i].IsReadWrite()) { 1326 // this is the writable segment 1327 if (image->data_region.size != 0) { 1328 // we've already created this segment 1329 continue; 1330 } 1331 region = &image->data_region; 1332 1333 snprintf(regionName, B_OS_NAME_LENGTH, "%s_data", fileName); 1334 } else if (programHeaders[i].IsExecutable()) { 1335 // this is the non-writable segment 1336 if (image->text_region.size != 0) { 1337 // we've already created this segment 1338 continue; 1339 } 1340 region = &image->text_region; 1341 1342 snprintf(regionName, B_OS_NAME_LENGTH, "%s_text", fileName); 1343 } else { 1344 dprintf("%s: weird program header flags 0x%lx\n", fileName, 1345 programHeaders[i].p_flags); 1346 continue; 1347 } 1348 1349 region->start = (addr_t)reservedAddress + ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); 1350 region->size = ROUNDUP(programHeaders[i].p_memsz 1351 + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); 1352 region->id = create_area(regionName, (void **)®ion->start, B_EXACT_ADDRESS, 1353 region->size, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 1354 if (region->id < B_OK) { 1355 dprintf("%s: error allocating area: %s\n", fileName, strerror(region->id)); 1356 status = B_NOT_AN_EXECUTABLE; 1357 goto error4; 1358 } 1359 region->delta = -ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); 1360 1361 TRACE(("elf_load_kspace: created area \"%s\" at %p\n", 1362 regionName, (void *)region->start)); 1363 1364 length = _kern_read(fd, programHeaders[i].p_offset, 1365 (void *)(region->start + (programHeaders[i].p_vaddr % B_PAGE_SIZE)), 1366 programHeaders[i].p_filesz); 1367 if (length < B_OK) { 1368 status = length; 1369 dprintf("%s: error reading in segment %ld\n", fileName, i); 1370 goto error5; 1371 } 1372 } 1373 1374 // get the segment order 1375 elf_region *firstRegion; 1376 elf_region *secondRegion; 1377 if (image->text_region.start < image->data_region.start) { 1378 firstRegion = &image->text_region; 1379 secondRegion = &image->data_region; 1380 } else { 1381 firstRegion = &image->data_region; 1382 secondRegion = &image->text_region; 1383 } 1384 1385 image->data_region.delta += image->data_region.start; 1386 image->text_region.delta += image->text_region.start; 1387 1388 // modify the dynamic ptr by the delta of the regions 1389 image->dynamic_section += image->text_region.delta; 1390 1391 status = elf_parse_dynamic_section(image); 1392 if (status < B_OK) 1393 goto error5; 1394 1395 status = elf_relocate(image, ""); 1396 if (status < B_OK) 1397 goto error5; 1398 1399 // We needed to read in the contents of the "text" area, but 1400 // now we can protect it read-only/execute 1401 set_area_protection(image->text_region.id, B_KERNEL_READ_AREA | B_KERNEL_EXECUTE_AREA); 1402 1403 // There might be a hole between the two segments, and we don't need to 1404 // reserve this any longer 1405 vm_unreserve_address_range(vm_kernel_address_space_id(), reservedAddress, reservedSize); 1406 1407 // ToDo: this should be enabled by kernel settings! 1408 if (1) 1409 load_elf_symbol_table(fd, image); 1410 1411 free(programHeaders); 1412 register_elf_image(image); 1413 1414 done: 1415 _kern_close(fd); 1416 mutex_unlock(&sImageLoadMutex); 1417 1418 return image->id; 1419 1420 error5: 1421 delete_area(image->data_region.id); 1422 delete_area(image->text_region.id); 1423 error4: 1424 vm_unreserve_address_range(vm_kernel_address_space_id(), reservedAddress, reservedSize); 1425 error3: 1426 free(programHeaders); 1427 error2: 1428 free(image); 1429 error1: 1430 free(elfHeader); 1431 error: 1432 mutex_unlock(&sImageLoadMutex); 1433 error0: 1434 if (vnode) 1435 vfs_put_vnode(vnode); 1436 _kern_close(fd); 1437 1438 return status; 1439 } 1440 1441 1442 status_t 1443 unload_kernel_add_on(image_id id) 1444 { 1445 struct elf_image_info *image; 1446 status_t status; 1447 1448 mutex_lock(&sImageMutex); 1449 1450 image = find_image(id); 1451 if (image != NULL) { 1452 mutex_lock(&sImageLoadMutex); 1453 1454 status = unload_elf_image(image); 1455 1456 mutex_unlock(&sImageLoadMutex); 1457 } else 1458 status = B_BAD_IMAGE_ID; 1459 1460 mutex_unlock(&sImageMutex); 1461 return status; 1462 } 1463 1464 1465 status_t 1466 elf_init(kernel_args *args) 1467 { 1468 struct preloaded_image *image; 1469 1470 image_init(); 1471 1472 mutex_init(&sImageMutex, "kimages_lock"); 1473 mutex_init(&sImageLoadMutex, "kimages_load_lock"); 1474 1475 sImagesHash = hash_init(IMAGE_HASH_SIZE, 0, image_compare, image_hash); 1476 if (sImagesHash == NULL) 1477 return B_NO_MEMORY; 1478 1479 // Build a image structure for the kernel, which has already been loaded. 1480 // The preloaded_images were already prepared by the VM. 1481 if (insert_preloaded_image(&args->kernel_image, true) < B_OK) 1482 panic("could not create kernel image.\n"); 1483 1484 // Build image structures for all preloaded images. 1485 for (image = args->preloaded_images; image != NULL; image = image->next) { 1486 insert_preloaded_image(image, false); 1487 } 1488 1489 add_debugger_command("ls", &dump_address_info, "lookup symbol for a particular address"); 1490 add_debugger_command("symbols", &dump_symbols, "dump symbols for image"); 1491 add_debugger_command("image", &dump_image, "dump image info"); 1492 1493 sInitialized = true; 1494 return B_OK; 1495 } 1496 1497