* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "elf_versioning.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "images.h"
static status_t
assert_defined_image_version(image_t* dependentImage, image_t* image,
const elf_version_info& neededVersion, bool weak)
{
if (image->version_definitions == NULL) {
FATAL("%s: No version information available (required by %s)\n",
image->path, dependentImage->path);
return B_OK;
}
elf_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 = (elf_verdef*)((uint8*)definition + definition->vd_next);
}
if (!weak) {
FATAL("%s: version \"%s\" not found (required by %s)\n", image->path,
neededVersion.name, dependentImage->name);
return B_MISSING_SYMBOL;
}
return B_OK;
}
status_t
init_image_version_infos(image_t* image)
{
uint32 maxIndex = 0;
if (image->version_definitions != NULL) {
elf_verdef* definition = image->version_definitions;
for (uint32 i = 0; i < image->num_version_definitions; i++) {
if (definition->vd_version != 1) {
FATAL("%s: Unsupported version definition revision: %u\n",
image->path, definition->vd_version);
return B_BAD_VALUE;
}
uint32 versionIndex = VER_NDX(definition->vd_ndx);
if (versionIndex > maxIndex)
maxIndex = versionIndex;
definition = (elf_verdef*)
((uint8*)definition + definition->vd_next);
}
}
if (image->needed_versions != NULL) {
elf_verneed* needed = image->needed_versions;
for (uint32 i = 0; i < image->num_needed_versions; i++) {
if (needed->vn_version != 1) {
FATAL("%s: Unsupported version needed revision: %u\n",
image->path, needed->vn_version);
return B_BAD_VALUE;
}
elf_vernaux* vernaux
= (elf_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 = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next);
}
needed = (elf_verneed*)((uint8*)needed + needed->vn_next);
}
}
if (maxIndex == 0)
return B_OK;
size_t size = sizeof(elf_version_info) * (maxIndex + 1);
image->versions
= (elf_version_info*)malloc(size);
if (image->versions == NULL) {
FATAL("Memory shortage in init_image_version_infos()");
return B_NO_MEMORY;
}
memset(image->versions, 0, size);
image->num_versions = maxIndex + 1;
if (image->version_definitions != NULL) {
elf_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) {
elf_verdaux* verdaux
= (elf_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);
info.file_name = NULL;
}
definition = (elf_verdef*)
((uint8*)definition + definition->vd_next);
}
}
if (image->needed_versions != NULL) {
elf_verneed* needed = image->needed_versions;
for (uint32 i = 0; i < image->num_needed_versions; i++) {
const char* fileName = STRING(image, needed->vn_file);
elf_vernaux* vernaux
= (elf_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 = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next);
}
needed = (elf_verneed*)((uint8*)needed + needed->vn_next);
}
}
return B_OK;
}
status_t
check_needed_image_versions(image_t* image)
{
if (image->needed_versions == NULL)
return B_OK;
elf_verneed* needed = image->needed_versions;
for (uint32 i = 0; i < image->num_needed_versions; i++) {
const char* fileName = STRING(image, needed->vn_file);
image_t* dependency = find_loaded_image_by_name(fileName,
ALL_IMAGE_TYPES);
if (dependency == NULL) {
FATAL("%s: Version dependency \"%s\" not found", image->path,
fileName);
return B_ENTRY_NOT_FOUND;
}
elf_vernaux* vernaux
= (elf_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 = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next);
}
needed = (elf_verneed*)((uint8*)needed + needed->vn_next);
}
return B_OK;
}