* Added GNU style ELF symbol versioning support in the kernel, too.
* Fixed memory leak in insert_preloaded_image() in error case. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30820 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -13,6 +13,9 @@
|
||||
#include <image.h>
|
||||
|
||||
|
||||
struct elf_version_info;
|
||||
|
||||
|
||||
typedef struct elf_region {
|
||||
area_id id;
|
||||
addr_t start;
|
||||
@@ -49,6 +52,15 @@ struct elf_image_info {
|
||||
struct Elf32_Sym *debug_symbols;
|
||||
uint32 num_debug_symbols;
|
||||
const char *debug_string_table;
|
||||
|
||||
// versioning related structures
|
||||
uint32 num_version_definitions;
|
||||
struct Elf32_Verdef *version_definitions;
|
||||
uint32 num_needed_versions;
|
||||
struct Elf32_Verneed *needed_versions;
|
||||
Elf32_Versym *symbol_versions;
|
||||
struct elf_version_info *versions;
|
||||
uint32 num_versions;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+358
-53
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Copyright 2002-2008, Axel Dörfler, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
@@ -61,7 +62,7 @@ static bool sInitialized = false;
|
||||
|
||||
|
||||
static struct Elf32_Sym *elf_find_symbol(struct elf_image_info *image,
|
||||
const char *name);
|
||||
const char *name, const elf_version_info *version, bool lookupDefault);
|
||||
|
||||
|
||||
/*! Calculates hash for an image using its ID */
|
||||
@@ -118,7 +119,7 @@ register_elf_image(struct elf_image_info *image)
|
||||
// Haiku API version
|
||||
imageInfo.api_version = 0;
|
||||
struct Elf32_Sym* symbol = elf_find_symbol(image,
|
||||
B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME);
|
||||
B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME, NULL, true);
|
||||
if (symbol != NULL && symbol->st_shndx != SHN_UNDEF
|
||||
&& symbol->st_value > 0
|
||||
&& ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT
|
||||
@@ -134,7 +135,7 @@ register_elf_image(struct elf_image_info *image)
|
||||
// Haiku ABI
|
||||
imageInfo.abi = 0;
|
||||
symbol = elf_find_symbol(image,
|
||||
B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME);
|
||||
B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME, NULL, true);
|
||||
if (symbol != NULL && symbol->st_shndx != SHN_UNDEF
|
||||
&& symbol->st_value > 0
|
||||
&& ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT
|
||||
@@ -271,6 +272,27 @@ create_image_struct()
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
delete_elf_image(struct elf_image_info *image)
|
||||
{
|
||||
if (image->text_region.id >= 0)
|
||||
delete_area(image->text_region.id);
|
||||
|
||||
if (image->data_region.id >= 0)
|
||||
delete_area(image->data_region.id);
|
||||
|
||||
if (image->vnode)
|
||||
vfs_put_vnode(image->vnode);
|
||||
|
||||
free(image->versions);
|
||||
free(image->debug_symbols);
|
||||
free((void*)image->debug_string_table);
|
||||
free(image->elf_header);
|
||||
free(image->name);
|
||||
free(image);
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
elf_hash(const char *name)
|
||||
{
|
||||
@@ -566,19 +588,105 @@ void dump_symbol(struct elf_image_info *image, struct Elf32_Sym *sym)
|
||||
|
||||
|
||||
static struct Elf32_Sym *
|
||||
elf_find_symbol(struct elf_image_info *image, const char *name)
|
||||
elf_find_symbol(struct elf_image_info *image, const char *name,
|
||||
const elf_version_info *lookupVersion, bool lookupDefault)
|
||||
{
|
||||
if (image->dynamic_section == 0 || HASHTABSIZE(image) == 0)
|
||||
return NULL;
|
||||
|
||||
Elf32_Sym* versionedSymbol = NULL;
|
||||
uint32 versionedSymbolCount = 0;
|
||||
|
||||
uint32 hash = elf_hash(name) % HASHTABSIZE(image);
|
||||
for (uint32 i = HASHBUCKETS(image)[hash]; i != STN_UNDEF;
|
||||
i = HASHCHAINS(image)[i]) {
|
||||
if (!strcmp(SYMNAME(image, &image->syms[i]), name))
|
||||
return &image->syms[i];
|
||||
Elf32_Sym* symbol = &image->syms[i];
|
||||
if (strcmp(SYMNAME(image, symbol), name) != 0)
|
||||
continue;
|
||||
|
||||
// check the version
|
||||
|
||||
// Handle the simple cases -- the image doesn't have version
|
||||
// information -- first.
|
||||
if (image->symbol_versions == NULL) {
|
||||
if (lookupVersion == NULL) {
|
||||
// No specific symbol version was requested either, so the
|
||||
// symbol is just fine.
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// A specific version is requested. Since the only possible
|
||||
// dependency is the kernel itself, the add-on was obviously linked
|
||||
// against a newer kernel.
|
||||
dprintf("Kernel add-on requires version support, but the kernel "
|
||||
"is too old.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The image has version information. Let's see what we've got.
|
||||
uint32 versionID = image->symbol_versions[i];
|
||||
uint32 versionIndex = VER_NDX(versionID);
|
||||
elf_version_info& version = image->versions[versionIndex];
|
||||
|
||||
// skip local versions
|
||||
if (versionIndex == VER_NDX_LOCAL)
|
||||
continue;
|
||||
|
||||
if (lookupVersion != NULL) {
|
||||
// a specific version is requested
|
||||
|
||||
// compare the versions
|
||||
if (version.hash == lookupVersion->hash
|
||||
&& strcmp(version.name, lookupVersion->name) == 0) {
|
||||
// versions match
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// The versions don't match. We're still fine with the
|
||||
// base version, if it is public and we're not looking for
|
||||
// the default version.
|
||||
if ((versionID & VER_NDX_FLAG_HIDDEN) == 0
|
||||
&& versionIndex == VER_NDX_GLOBAL
|
||||
&& !lookupDefault) {
|
||||
// TODO: Revise the default version case! That's how
|
||||
// FreeBSD implements it, but glibc doesn't handle it
|
||||
// specially.
|
||||
return symbol;
|
||||
}
|
||||
} else {
|
||||
// No specific version requested, but the image has version
|
||||
// information. This can happen in either of these cases:
|
||||
//
|
||||
// * The dependent object was linked against an older version
|
||||
// of the now versioned dependency.
|
||||
// * The symbol is looked up via find_image_symbol() or dlsym().
|
||||
//
|
||||
// In the first case we return the base version of the symbol
|
||||
// (VER_NDX_GLOBAL or VER_NDX_INITIAL), or, if that doesn't
|
||||
// exist, the unique, non-hidden versioned symbol.
|
||||
//
|
||||
// In the second case we want to return the public default
|
||||
// version of the symbol. The handling is pretty similar to the
|
||||
// first case, with the exception that we treat VER_NDX_INITIAL
|
||||
// as regular version.
|
||||
|
||||
// VER_NDX_GLOBAL is always good, VER_NDX_INITIAL is fine, if
|
||||
// we don't look for the default version.
|
||||
if (versionIndex == VER_NDX_GLOBAL
|
||||
|| (!lookupDefault && versionIndex == VER_NDX_INITIAL)) {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// If not hidden, remember the version -- we'll return it, if
|
||||
// it is the only one.
|
||||
if ((versionID & VER_NDX_FLAG_HIDDEN) == 0) {
|
||||
versionedSymbolCount++;
|
||||
versionedSymbol = symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return versionedSymbolCount == 1 ? versionedSymbol : NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -639,6 +747,24 @@ elf_parse_dynamic_section(struct elf_image_info *image)
|
||||
case DT_PLTREL:
|
||||
image->pltrel_type = d[i].d_un.d_val;
|
||||
break;
|
||||
case DT_VERSYM:
|
||||
image->symbol_versions = (Elf32_Versym*)
|
||||
(d[i].d_un.d_ptr + image->text_region.delta);
|
||||
break;
|
||||
case DT_VERDEF:
|
||||
image->version_definitions = (Elf32_Verdef*)
|
||||
(d[i].d_un.d_ptr + image->text_region.delta);
|
||||
break;
|
||||
case DT_VERDEFNUM:
|
||||
image->num_version_definitions = d[i].d_un.d_val;
|
||||
break;
|
||||
case DT_VERNEED:
|
||||
image->needed_versions = (Elf32_Verneed*)
|
||||
(d[i].d_un.d_ptr + image->text_region.delta);
|
||||
break;
|
||||
case DT_VERNEEDNUM:
|
||||
image->num_needed_versions = d[i].d_un.d_val;
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
@@ -658,6 +784,185 @@ elf_parse_dynamic_section(struct elf_image_info *image)
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
assert_defined_image_version(elf_image_info* dependentImage,
|
||||
elf_image_info* image, const elf_version_info& neededVersion, bool weak)
|
||||
{
|
||||
// If the image doesn't have version definitions, we print a warning and
|
||||
// succeed. Weird, but that's how glibc does it. Not unlikely we'll fail
|
||||
// later when resolving versioned symbols.
|
||||
if (image->version_definitions == NULL) {
|
||||
dprintf("%s: No version information available (required by %s)\n",
|
||||
image->name, dependentImage->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// iterate through the defined versions to find the given one
|
||||
Elf32_Verdef* definition = image->version_definitions;
|
||||
for (uint32 i = 0; i < image->num_version_definitions; i++) {
|
||||
uint32 versionIndex = VER_NDX(definition->vd_ndx);
|
||||
elf_version_info& info = image->versions[versionIndex];
|
||||
|
||||
if (neededVersion.hash == info.hash
|
||||
&& strcmp(neededVersion.name, info.name) == 0) {
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
definition = (Elf32_Verdef*)
|
||||
((uint8*)definition + definition->vd_next);
|
||||
}
|
||||
|
||||
// version not found -- fail, if not weak
|
||||
if (!weak) {
|
||||
dprintf("%s: version \"%s\" not found (required by %s)\n", image->name,
|
||||
neededVersion.name, dependentImage->name);
|
||||
return B_MISSING_SYMBOL;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
init_image_version_infos(elf_image_info* image)
|
||||
{
|
||||
// First find out how many version infos we need -- i.e. get the greatest
|
||||
// version index from the defined and needed versions (they use the same
|
||||
// index namespace).
|
||||
uint32 maxIndex = 0;
|
||||
|
||||
if (image->version_definitions != NULL) {
|
||||
Elf32_Verdef* definition = image->version_definitions;
|
||||
for (uint32 i = 0; i < image->num_version_definitions; i++) {
|
||||
if (definition->vd_version != 1) {
|
||||
dprintf("Unsupported version definition revision: %u\n",
|
||||
definition->vd_version);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
uint32 versionIndex = VER_NDX(definition->vd_ndx);
|
||||
if (versionIndex > maxIndex)
|
||||
maxIndex = versionIndex;
|
||||
|
||||
definition = (Elf32_Verdef*)
|
||||
((uint8*)definition + definition->vd_next);
|
||||
}
|
||||
}
|
||||
|
||||
if (image->needed_versions != NULL) {
|
||||
Elf32_Verneed* needed = image->needed_versions;
|
||||
for (uint32 i = 0; i < image->num_needed_versions; i++) {
|
||||
if (needed->vn_version != 1) {
|
||||
dprintf("Unsupported version needed revision: %u\n",
|
||||
needed->vn_version);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
Elf32_Vernaux* vernaux
|
||||
= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
|
||||
for (uint32 k = 0; k < needed->vn_cnt; k++) {
|
||||
uint32 versionIndex = VER_NDX(vernaux->vna_other);
|
||||
if (versionIndex > maxIndex)
|
||||
maxIndex = versionIndex;
|
||||
|
||||
vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
|
||||
}
|
||||
|
||||
needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
|
||||
}
|
||||
}
|
||||
|
||||
if (maxIndex == 0)
|
||||
return B_OK;
|
||||
|
||||
// allocate the version infos
|
||||
image->versions
|
||||
= (elf_version_info*)malloc(sizeof(elf_version_info) * (maxIndex + 1));
|
||||
if (image->versions == NULL) {
|
||||
dprintf("Memory shortage in init_image_version_infos()\n");
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
image->num_versions = maxIndex + 1;
|
||||
|
||||
// init the version infos
|
||||
|
||||
// version definitions
|
||||
if (image->version_definitions != NULL) {
|
||||
Elf32_Verdef* definition = image->version_definitions;
|
||||
for (uint32 i = 0; i < image->num_version_definitions; i++) {
|
||||
if (definition->vd_cnt > 0
|
||||
&& (definition->vd_flags & VER_FLG_BASE) == 0) {
|
||||
Elf32_Verdaux* verdaux
|
||||
= (Elf32_Verdaux*)((uint8*)definition + definition->vd_aux);
|
||||
|
||||
uint32 versionIndex = VER_NDX(definition->vd_ndx);
|
||||
elf_version_info& info = image->versions[versionIndex];
|
||||
info.hash = definition->vd_hash;
|
||||
info.name = STRING(image, verdaux->vda_name);
|
||||
}
|
||||
|
||||
definition = (Elf32_Verdef*)
|
||||
((uint8*)definition + definition->vd_next);
|
||||
}
|
||||
}
|
||||
|
||||
// needed versions
|
||||
if (image->needed_versions != NULL) {
|
||||
Elf32_Verneed* needed = image->needed_versions;
|
||||
for (uint32 i = 0; i < image->num_needed_versions; i++) {
|
||||
const char* fileName = STRING(image, needed->vn_file);
|
||||
|
||||
Elf32_Vernaux* vernaux
|
||||
= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
|
||||
for (uint32 k = 0; k < needed->vn_cnt; k++) {
|
||||
uint32 versionIndex = VER_NDX(vernaux->vna_other);
|
||||
elf_version_info& info = image->versions[versionIndex];
|
||||
info.hash = vernaux->vna_hash;
|
||||
info.name = STRING(image, vernaux->vna_name);
|
||||
info.file_name = fileName;
|
||||
|
||||
vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
|
||||
}
|
||||
|
||||
needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
check_needed_image_versions(elf_image_info* image)
|
||||
{
|
||||
if (image->needed_versions == NULL)
|
||||
return B_OK;
|
||||
|
||||
Elf32_Verneed* needed = image->needed_versions;
|
||||
for (uint32 i = 0; i < image->num_needed_versions; i++) {
|
||||
elf_image_info* dependency = sKernelImage;
|
||||
|
||||
Elf32_Vernaux* vernaux
|
||||
= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
|
||||
for (uint32 k = 0; k < needed->vn_cnt; k++) {
|
||||
uint32 versionIndex = VER_NDX(vernaux->vna_other);
|
||||
elf_version_info& info = image->versions[versionIndex];
|
||||
|
||||
status_t error = assert_defined_image_version(image, dependency,
|
||||
info, (vernaux->vna_flags & VER_FLG_WEAK) != 0);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
|
||||
}
|
||||
|
||||
needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*! Resolves the \a symbol by linking against \a sharedImage if necessary.
|
||||
Returns the resolved symbol's address in \a _symbolAddress.
|
||||
*/
|
||||
@@ -671,8 +976,18 @@ elf_resolve_symbol(struct elf_image_info *image, struct Elf32_Sym *symbol,
|
||||
struct Elf32_Sym *newSymbol;
|
||||
const char *symbolName = SYMNAME(image, symbol);
|
||||
|
||||
// get the version info
|
||||
const elf_version_info* versionInfo = NULL;
|
||||
if (image->symbol_versions != NULL) {
|
||||
uint32 index = symbol - image->syms;
|
||||
uint32 versionIndex = VER_NDX(image->symbol_versions[index]);
|
||||
if (versionIndex >= VER_NDX_INITIAL)
|
||||
versionInfo = image->versions + versionIndex;
|
||||
}
|
||||
|
||||
// it's undefined, must be outside this image, try the other image
|
||||
newSymbol = elf_find_symbol(sharedImage, symbolName);
|
||||
newSymbol = elf_find_symbol(sharedImage, symbolName, versionInfo,
|
||||
false);
|
||||
if (newSymbol == NULL) {
|
||||
dprintf("\"%s\": could not resolve symbol '%s'\n",
|
||||
image->name, symbolName);
|
||||
@@ -778,29 +1093,16 @@ verify_eheader(struct Elf32_Ehdr *elfHeader)
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
static void
|
||||
unload_elf_image(struct elf_image_info *image)
|
||||
{
|
||||
if (atomic_add(&image->ref_count, -1) > 1)
|
||||
return B_OK;
|
||||
return;
|
||||
|
||||
TRACE(("unload image %ld, %s\n", image->id, image->name));
|
||||
|
||||
delete_area(image->text_region.id);
|
||||
delete_area(image->data_region.id);
|
||||
|
||||
if (image->vnode)
|
||||
vfs_put_vnode(image->vnode);
|
||||
|
||||
unregister_elf_image(image);
|
||||
|
||||
free(image->debug_symbols);
|
||||
free((void*)image->debug_string_table);
|
||||
free(image->elf_header);
|
||||
free(image->name);
|
||||
free(image);
|
||||
|
||||
return B_NO_ERROR;
|
||||
delete_elf_image(image);
|
||||
}
|
||||
|
||||
|
||||
@@ -910,14 +1212,13 @@ error1:
|
||||
static status_t
|
||||
insert_preloaded_image(struct preloaded_image *preloadedImage, bool kernel)
|
||||
{
|
||||
struct elf_image_info *image;
|
||||
status_t status;
|
||||
|
||||
status = verify_eheader(&preloadedImage->elf_header);
|
||||
if (status < B_OK)
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
image = create_image_struct();
|
||||
elf_image_info *image = create_image_struct();
|
||||
if (image == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
@@ -928,12 +1229,20 @@ insert_preloaded_image(struct preloaded_image *preloadedImage, bool kernel)
|
||||
image->data_region = preloadedImage->data_region;
|
||||
|
||||
status = elf_parse_dynamic_section(image);
|
||||
if (status < B_OK)
|
||||
if (status != B_OK)
|
||||
goto error1;
|
||||
|
||||
status = init_image_version_infos(image);
|
||||
if (status != B_OK)
|
||||
goto error1;
|
||||
|
||||
if (!kernel) {
|
||||
status = check_needed_image_versions(image);
|
||||
if (status != B_OK)
|
||||
goto error1;
|
||||
|
||||
status = elf_relocate(image);
|
||||
if (status < B_OK)
|
||||
if (status != B_OK)
|
||||
goto error1;
|
||||
} else
|
||||
sKernelImage = image;
|
||||
@@ -972,11 +1281,8 @@ insert_preloaded_image(struct preloaded_image *preloadedImage, bool kernel)
|
||||
return B_OK;
|
||||
|
||||
error1:
|
||||
free(image);
|
||||
delete_elf_image(image);
|
||||
|
||||
// clean up preloaded image resources (this image won't be used anymore)
|
||||
delete_area(preloadedImage->text_region.id);
|
||||
delete_area(preloadedImage->data_region.id);
|
||||
preloadedImage->id = -1;
|
||||
|
||||
return status;
|
||||
@@ -1209,7 +1515,7 @@ get_image_symbol(image_id id, const char *name, int32 symbolClass,
|
||||
goto done;
|
||||
}
|
||||
|
||||
symbol = elf_find_symbol(image, name);
|
||||
symbol = elf_find_symbol(image, name, NULL, true);
|
||||
if (symbol == NULL || symbol->st_shndx == SHN_UNDEF) {
|
||||
status = B_ENTRY_NOT_FOUND;
|
||||
goto done;
|
||||
@@ -1657,6 +1963,7 @@ load_kernel_add_on(const char *path)
|
||||
image->vnode = vnode;
|
||||
image->elf_header = elfHeader;
|
||||
image->name = strdup(path);
|
||||
vnode = NULL;
|
||||
|
||||
programHeaders = (struct Elf32_Phdr *)malloc(elfHeader->e_phnum
|
||||
* elfHeader->e_phentsize);
|
||||
@@ -1812,6 +2119,14 @@ load_kernel_add_on(const char *path)
|
||||
if (status < B_OK)
|
||||
goto error5;
|
||||
|
||||
status = init_image_version_infos(image);
|
||||
if (status != B_OK)
|
||||
goto error5;
|
||||
|
||||
status = check_needed_image_versions(image);
|
||||
if (status != B_OK)
|
||||
goto error5;
|
||||
|
||||
status = elf_relocate(image);
|
||||
if (status < B_OK)
|
||||
goto error5;
|
||||
@@ -1842,15 +2157,13 @@ done:
|
||||
return image->id;
|
||||
|
||||
error5:
|
||||
delete_area(image->data_region.id);
|
||||
delete_area(image->text_region.id);
|
||||
error4:
|
||||
vm_unreserve_address_range(vm_kernel_address_space_id(), reservedAddress,
|
||||
reservedSize);
|
||||
error3:
|
||||
free(programHeaders);
|
||||
error2:
|
||||
free(image);
|
||||
delete_elf_image(image);
|
||||
error1:
|
||||
free(elfHeader);
|
||||
error:
|
||||
@@ -1870,22 +2183,15 @@ error0:
|
||||
status_t
|
||||
unload_kernel_add_on(image_id id)
|
||||
{
|
||||
struct elf_image_info *image;
|
||||
status_t status;
|
||||
MutexLocker _(sImageLoadMutex);
|
||||
MutexLocker _2(sImageMutex);
|
||||
|
||||
mutex_lock(&sImageLoadMutex);
|
||||
mutex_lock(&sImageMutex);
|
||||
elf_image_info *image = find_image(id);
|
||||
if (image == NULL)
|
||||
return B_BAD_IMAGE_ID;
|
||||
|
||||
image = find_image(id);
|
||||
if (image != NULL)
|
||||
status = unload_elf_image(image);
|
||||
else
|
||||
status = B_BAD_IMAGE_ID;
|
||||
|
||||
mutex_unlock(&sImageMutex);
|
||||
mutex_unlock(&sImageLoadMutex);
|
||||
|
||||
return status;
|
||||
unload_elf_image(image);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -2059,9 +2365,8 @@ elf_init(kernel_args *args)
|
||||
panic("could not create kernel image.\n");
|
||||
|
||||
// Build image structures for all preloaded images.
|
||||
for (image = args->preloaded_images; image != NULL; image = image->next) {
|
||||
for (image = args->preloaded_images; image != NULL; image = image->next)
|
||||
insert_preloaded_image(image, false);
|
||||
}
|
||||
|
||||
add_debugger_command("ls", &dump_address_info,
|
||||
"lookup symbol for a particular address");
|
||||
|
||||
Reference in New Issue
Block a user