headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / runtime_loader / elf_versioning.cpp
blob9785d1d9f36b6de9cc7d7d2488a02a758b007898
1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
6 #include "elf_versioning.h"
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include "images.h"
15 static status_t
16 assert_defined_image_version(image_t* dependentImage, image_t* image,
17 const elf_version_info& neededVersion, bool weak)
19 // If the image doesn't have version definitions, we print a warning and
20 // succeed. Weird, but that's how glibc does it. Not unlikely we'll fail
21 // later when resolving versioned symbols.
22 if (image->version_definitions == NULL) {
23 FATAL("%s: No version information available (required by %s)\n",
24 image->path, dependentImage->path);
25 return B_OK;
28 // iterate through the defined versions to find the given one
29 elf_verdef* definition = image->version_definitions;
30 for (uint32 i = 0; i < image->num_version_definitions; i++) {
31 uint32 versionIndex = VER_NDX(definition->vd_ndx);
32 elf_version_info& info = image->versions[versionIndex];
34 if (neededVersion.hash == info.hash
35 && strcmp(neededVersion.name, info.name) == 0) {
36 return B_OK;
39 definition = (elf_verdef*)((uint8*)definition + definition->vd_next);
42 // version not found -- fail, if not weak
43 if (!weak) {
44 FATAL("%s: version \"%s\" not found (required by %s)\n", image->path,
45 neededVersion.name, dependentImage->name);
46 return B_MISSING_SYMBOL;
49 return B_OK;
53 // #pragma mark -
56 status_t
57 init_image_version_infos(image_t* image)
59 // First find out how many version infos we need -- i.e. get the greatest
60 // version index from the defined and needed versions (they use the same
61 // index namespace).
62 uint32 maxIndex = 0;
64 if (image->version_definitions != NULL) {
65 elf_verdef* definition = image->version_definitions;
66 for (uint32 i = 0; i < image->num_version_definitions; i++) {
67 if (definition->vd_version != 1) {
68 FATAL("%s: Unsupported version definition revision: %u\n",
69 image->path, definition->vd_version);
70 return B_BAD_VALUE;
73 uint32 versionIndex = VER_NDX(definition->vd_ndx);
74 if (versionIndex > maxIndex)
75 maxIndex = versionIndex;
77 definition = (elf_verdef*)
78 ((uint8*)definition + definition->vd_next);
82 if (image->needed_versions != NULL) {
83 elf_verneed* needed = image->needed_versions;
84 for (uint32 i = 0; i < image->num_needed_versions; i++) {
85 if (needed->vn_version != 1) {
86 FATAL("%s: Unsupported version needed revision: %u\n",
87 image->path, needed->vn_version);
88 return B_BAD_VALUE;
91 elf_vernaux* vernaux
92 = (elf_vernaux*)((uint8*)needed + needed->vn_aux);
93 for (uint32 k = 0; k < needed->vn_cnt; k++) {
94 uint32 versionIndex = VER_NDX(vernaux->vna_other);
95 if (versionIndex > maxIndex)
96 maxIndex = versionIndex;
98 vernaux = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next);
101 needed = (elf_verneed*)((uint8*)needed + needed->vn_next);
105 if (maxIndex == 0)
106 return B_OK;
108 // allocate the version infos
109 image->versions
110 = (elf_version_info*)malloc(sizeof(elf_version_info) * (maxIndex + 1));
111 if (image->versions == NULL) {
112 FATAL("Memory shortage in init_image_version_infos()");
113 return B_NO_MEMORY;
115 image->num_versions = maxIndex + 1;
117 // init the version infos
119 // version definitions
120 if (image->version_definitions != NULL) {
121 elf_verdef* definition = image->version_definitions;
122 for (uint32 i = 0; i < image->num_version_definitions; i++) {
123 if (definition->vd_cnt > 0
124 && (definition->vd_flags & VER_FLG_BASE) == 0) {
125 elf_verdaux* verdaux
126 = (elf_verdaux*)((uint8*)definition + definition->vd_aux);
128 uint32 versionIndex = VER_NDX(definition->vd_ndx);
129 elf_version_info& info = image->versions[versionIndex];
130 info.hash = definition->vd_hash;
131 info.name = STRING(image, verdaux->vda_name);
132 info.file_name = NULL;
135 definition = (elf_verdef*)
136 ((uint8*)definition + definition->vd_next);
140 // needed versions
141 if (image->needed_versions != NULL) {
142 elf_verneed* needed = image->needed_versions;
143 for (uint32 i = 0; i < image->num_needed_versions; i++) {
144 const char* fileName = STRING(image, needed->vn_file);
146 elf_vernaux* vernaux
147 = (elf_vernaux*)((uint8*)needed + needed->vn_aux);
148 for (uint32 k = 0; k < needed->vn_cnt; k++) {
149 uint32 versionIndex = VER_NDX(vernaux->vna_other);
150 elf_version_info& info = image->versions[versionIndex];
151 info.hash = vernaux->vna_hash;
152 info.name = STRING(image, vernaux->vna_name);
153 info.file_name = fileName;
155 vernaux = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next);
158 needed = (elf_verneed*)((uint8*)needed + needed->vn_next);
162 return B_OK;
166 status_t
167 check_needed_image_versions(image_t* image)
169 if (image->needed_versions == NULL)
170 return B_OK;
172 elf_verneed* needed = image->needed_versions;
173 for (uint32 i = 0; i < image->num_needed_versions; i++) {
174 const char* fileName = STRING(image, needed->vn_file);
175 image_t* dependency = find_loaded_image_by_name(fileName,
176 ALL_IMAGE_TYPES);
177 if (dependency == NULL) {
178 // This can't really happen, unless the object file is broken, since
179 // the file should also appear in DT_NEEDED.
180 FATAL("%s: Version dependency \"%s\" not found", image->path,
181 fileName);
182 return B_FILE_NOT_FOUND;
185 elf_vernaux* vernaux
186 = (elf_vernaux*)((uint8*)needed + needed->vn_aux);
187 for (uint32 k = 0; k < needed->vn_cnt; k++) {
188 uint32 versionIndex = VER_NDX(vernaux->vna_other);
189 elf_version_info& info = image->versions[versionIndex];
191 status_t error = assert_defined_image_version(image, dependency,
192 info, (vernaux->vna_flags & VER_FLG_WEAK) != 0);
193 if (error != B_OK)
194 return error;
196 vernaux = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next);
199 needed = (elf_verneed*)((uint8*)needed + needed->vn_next);
202 return B_OK;