Пример #1
0
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;
	}
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
	}
}
Пример #5
0
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;
}
Пример #6
0
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;
}