void analyze_image_haiku_version_and_abi(int fd, image_t* image, elf_ehdr& eheader, int32 sheaderSize, char* buffer, size_t bufferSize) { // Haiku API version elf_sym* symbol = find_symbol(image, SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME, B_SYMBOL_TYPE_DATA, true)); if (symbol != NULL && symbol->st_shndx != SHN_UNDEF && symbol->st_value > 0 && symbol->st_size >= sizeof(uint32)) { image->api_version = *(uint32*)(symbol->st_value + image->regions[0].delta); } else image->api_version = 0; // Haiku ABI symbol = find_symbol(image, SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME, B_SYMBOL_TYPE_DATA)); if (symbol != NULL && symbol->st_shndx != SHN_UNDEF && symbol->st_value > 0 && symbol->Type() == STT_OBJECT && symbol->st_size >= sizeof(uint32)) { image->abi = *(uint32*)(symbol->st_value + image->regions[0].delta); } else image->abi = 0; if (image->abi == 0) { // No ABI version in the shared object, i.e. it has been built before // that was introduced in Haiku. We have to try and analyze the gcc // version. if (!analyze_object_gcc_version(fd, image, eheader, sheaderSize, buffer, bufferSize)) { FATAL("%s: Failed to get gcc version.\n", image->path); // not really fatal, actually // assume ancient BeOS image->abi = B_HAIKU_ABI_GCC_2_ANCIENT; } } // guess the API version, if we couldn't figure it out yet if (image->api_version == 0) { image->api_version = image->abi > B_HAIKU_ABI_GCC_2_BEOS ? HAIKU_VERSION_PRE_GLUE_CODE : B_HAIKU_VERSION_BEOS; } }
image_id preload_image(char const* path) { if (path == NULL) return B_BAD_VALUE; KTRACE("rld: preload_image(\"%s\")", path); image_t *image = NULL; status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, &image); if (status < B_OK) { KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path, strerror(status)); return status; } if (image->find_undefined_symbol == NULL) image->find_undefined_symbol = find_undefined_symbol_global; status = load_dependencies(image); if (status < B_OK) goto err; set_image_flags_recursively(image, RTLD_GLOBAL); status = relocate_dependencies(image); if (status < B_OK) goto err; status = add_preloaded_image(image); if (status < B_OK) goto err; inject_runtime_loader_api(image); remap_images(); init_dependencies(image, true); // if the image contains an add-on, register it runtime_loader_add_on* addOnStruct; if (find_symbol(image, SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA), (void**)&addOnStruct) == B_OK) { add_add_on(image, addOnStruct); } KTRACE("rld: preload_image(\"%s\") done: id: %" B_PRId32, path, image->id); return image->id; err: KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status)); dequeue_loaded_image(image); delete_image(image); return status; }
status_t get_symbol(image_id imageID, char const *symbolName, int32 symbolType, bool recursive, image_id *_inImage, void **_location) { status_t status = B_OK; image_t *image; if (imageID < B_OK) return B_BAD_IMAGE_ID; if (symbolName == NULL) return B_BAD_VALUE; rld_lock(); // for now, just do stupid simple global locking // get the image from those who have been already initialized image = find_loaded_image_by_id(imageID, false); if (image != NULL) { if (recursive) { // breadth-first search in the given image and its dependencies status = find_symbol_breadth_first(image, SymbolLookupInfo(symbolName, symbolType, NULL, LOOKUP_FLAG_DEFAULT_VERSION), &image, _location); } else { status = find_symbol(image, SymbolLookupInfo(symbolName, symbolType, NULL, LOOKUP_FLAG_DEFAULT_VERSION), _location); } if (status == B_OK && _inImage != NULL) *_inImage = image->id; } else status = B_BAD_IMAGE_ID; rld_unlock(); return status; }
static void inject_runtime_loader_api(image_t* rootImage) { // We patch any exported __gRuntimeLoader symbols to point to our private // API. image_t* image; void* _export; if (find_symbol_breadth_first(rootImage, SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image, &_export) == B_OK) { *(void**)_export = &gRuntimeLoader; } }
status_t get_library_symbol(void* handle, void* caller, const char* symbolName, void **_location) { status_t status = B_ENTRY_NOT_FOUND; if (symbolName == NULL) return B_BAD_VALUE; rld_lock(); // for now, just do stupid simple global locking if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) { // look in the default scope image_t* image; elf_sym* symbol = find_undefined_symbol_global(gProgramImage, gProgramImage, SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, LOOKUP_FLAG_DEFAULT_VERSION), &image); if (symbol != NULL) { *_location = (void*)(symbol->st_value + image->regions[0].delta); int32 symbolType = symbol->Type() == STT_FUNC ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; patch_defined_symbol(image, symbolName, _location, &symbolType); status = B_OK; } } else if (handle == RTLD_NEXT) { // Look in the default scope, but also in the dependencies of the // calling image. Return the next after the caller symbol. // First of all, find the caller image. image_t* callerImage = get_loaded_images().head; for (; callerImage != NULL; callerImage = callerImage->next) { elf_region_t& text = callerImage->regions[0]; if ((addr_t)caller >= text.vmstart && (addr_t)caller < text.vmstart + text.vmsize) { // found the image break; } } if (callerImage != NULL) { // found the caller -- now search the global scope until we find // the next symbol bool hitCallerImage = false; set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); elf_sym* candidateSymbol = NULL; image_t* candidateImage = NULL; image_t* image = get_loaded_images().head; for (; image != NULL; image = image->next) { // skip the caller image if (image == callerImage) { hitCallerImage = true; continue; } // skip all images up to the caller image; also skip add-on // images and those not marked above for resolution if (!hitCallerImage || image->type == B_ADD_ON_IMAGE || (image->flags & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) { continue; } elf_sym *symbol = find_symbol(image, SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL, LOOKUP_FLAG_DEFAULT_VERSION)); if (symbol == NULL) continue; // found a symbol bool isWeak = symbol->Bind() == STB_WEAK; if (candidateImage == NULL || !isWeak) { candidateSymbol = symbol; candidateImage = image; if (!isWeak) break; } // symbol is weak, so we need to continue } if (candidateSymbol != NULL) { // found the symbol *_location = (void*)(candidateSymbol->st_value + candidateImage->regions[0].delta); int32 symbolType = B_SYMBOL_TYPE_TEXT; patch_defined_symbol(candidateImage, symbolName, _location, &symbolType); status = B_OK; } clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); } } else { // breadth-first search in the given image and its dependencies image_t* inImage; status = find_symbol_breadth_first((image_t*)handle, SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, LOOKUP_FLAG_DEFAULT_VERSION), &inImage, _location); } rld_unlock(); return status; }
image_id load_program(char const *path, void **_entry) { status_t status; image_t *image; KTRACE("rld: load_program(\"%s\")", path); rld_lock(); // for now, just do stupid simple global locking preload_images(); TRACE(("rld: load %s\n", path)); status = load_image(path, B_APP_IMAGE, NULL, NULL, &gProgramImage); if (status < B_OK) goto err; if (gProgramImage->find_undefined_symbol == NULL) gProgramImage->find_undefined_symbol = find_undefined_symbol_global; status = load_dependencies(gProgramImage); if (status < B_OK) goto err; // Set RTLD_GLOBAL on all libraries including the program. // This results in the desired symbol resolution for dlopen()ed libraries. set_image_flags_recursively(gProgramImage, RTLD_GLOBAL); status = relocate_dependencies(gProgramImage); if (status < B_OK) goto err; inject_runtime_loader_api(gProgramImage); remap_images(); init_dependencies(gProgramImage, true); // Since the images are initialized now, we no longer should use our // getenv(), but use the one from libroot.so find_symbol_breadth_first(gProgramImage, SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image, (void**)&gGetEnv); if (gProgramImage->entry_point == 0) { status = B_NOT_AN_EXECUTABLE; goto err; } *_entry = (void *)(gProgramImage->entry_point); rld_unlock(); gProgramLoaded = true; KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %" B_PRId32 , path, *_entry, gProgramImage->id); return gProgramImage->id; err: KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status)); delete_image(gProgramImage); if (report_errors()) { // send error message gErrorMessage.AddInt32("error", status); gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, -1, 0, find_thread(NULL)); _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0); } _kern_loading_app_failed(status); rld_unlock(); return status; }