xref: /haiku/src/system/runtime_loader/elf_versioning.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "elf_versioning.h"
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "images.h"
13 
14 
15 static status_t
16 assert_defined_image_version(image_t* dependentImage, image_t* image,
17 	const elf_version_info& neededVersion, bool weak)
18 {
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;
26 	}
27 
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];
33 
34 		if (neededVersion.hash == info.hash
35 			&& strcmp(neededVersion.name, info.name) == 0) {
36 			return B_OK;
37 		}
38 
39 		definition = (elf_verdef*)((uint8*)definition + definition->vd_next);
40 	}
41 
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;
47 	}
48 
49 	return B_OK;
50 }
51 
52 
53 // #pragma mark -
54 
55 
56 status_t
57 init_image_version_infos(image_t* image)
58 {
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;
63 
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;
71 			}
72 
73 			uint32 versionIndex = VER_NDX(definition->vd_ndx);
74 			if (versionIndex > maxIndex)
75 				maxIndex = versionIndex;
76 
77 			definition = (elf_verdef*)
78 				((uint8*)definition + definition->vd_next);
79 		}
80 	}
81 
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;
89 			}
90 
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;
97 
98 				vernaux = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next);
99 			}
100 
101 			needed = (elf_verneed*)((uint8*)needed + needed->vn_next);
102 		}
103 	}
104 
105 	if (maxIndex == 0)
106 		return B_OK;
107 
108 	// allocate the version infos
109 	size_t size = sizeof(elf_version_info) * (maxIndex + 1);
110 	image->versions
111 		= (elf_version_info*)malloc(size);
112 	if (image->versions == NULL) {
113 		FATAL("Memory shortage in init_image_version_infos()");
114 		return B_NO_MEMORY;
115 	}
116 	memset(image->versions, 0, size);
117 	image->num_versions = maxIndex + 1;
118 
119 	// init the version infos
120 
121 	// version definitions
122 	if (image->version_definitions != NULL) {
123 		elf_verdef* definition = image->version_definitions;
124 		for (uint32 i = 0; i < image->num_version_definitions; i++) {
125 			if (definition->vd_cnt > 0
126 				&& (definition->vd_flags & VER_FLG_BASE) == 0) {
127 				elf_verdaux* verdaux
128 					= (elf_verdaux*)((uint8*)definition + definition->vd_aux);
129 
130 				uint32 versionIndex = VER_NDX(definition->vd_ndx);
131 				elf_version_info& info = image->versions[versionIndex];
132 				info.hash = definition->vd_hash;
133 				info.name = STRING(image, verdaux->vda_name);
134 				info.file_name = NULL;
135 			}
136 
137 			definition = (elf_verdef*)
138 				((uint8*)definition + definition->vd_next);
139 		}
140 	}
141 
142 	// needed versions
143 	if (image->needed_versions != NULL) {
144 		elf_verneed* needed = image->needed_versions;
145 		for (uint32 i = 0; i < image->num_needed_versions; i++) {
146 			const char* fileName = STRING(image, needed->vn_file);
147 
148 			elf_vernaux* vernaux
149 				= (elf_vernaux*)((uint8*)needed + needed->vn_aux);
150 			for (uint32 k = 0; k < needed->vn_cnt; k++) {
151 				uint32 versionIndex = VER_NDX(vernaux->vna_other);
152 				elf_version_info& info = image->versions[versionIndex];
153 				info.hash = vernaux->vna_hash;
154 				info.name = STRING(image, vernaux->vna_name);
155 				info.file_name = fileName;
156 
157 				vernaux = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next);
158 			}
159 
160 			needed = (elf_verneed*)((uint8*)needed + needed->vn_next);
161 		}
162 	}
163 
164 	return B_OK;
165 }
166 
167 
168 status_t
169 check_needed_image_versions(image_t* image)
170 {
171 	if (image->needed_versions == NULL)
172 		return B_OK;
173 
174 	elf_verneed* needed = image->needed_versions;
175 	for (uint32 i = 0; i < image->num_needed_versions; i++) {
176 		const char* fileName = STRING(image, needed->vn_file);
177 		image_t* dependency = find_loaded_image_by_name(fileName,
178 			ALL_IMAGE_TYPES);
179 		if (dependency == NULL) {
180 			// This can't really happen, unless the object file is broken, since
181 			// the file should also appear in DT_NEEDED.
182 			FATAL("%s: Version dependency \"%s\" not found", image->path,
183 				fileName);
184 			return B_ENTRY_NOT_FOUND;
185 		}
186 
187 		elf_vernaux* vernaux
188 			= (elf_vernaux*)((uint8*)needed + needed->vn_aux);
189 		for (uint32 k = 0; k < needed->vn_cnt; k++) {
190 			uint32 versionIndex = VER_NDX(vernaux->vna_other);
191 			elf_version_info& info = image->versions[versionIndex];
192 
193 			status_t error = assert_defined_image_version(image, dependency,
194 				info, (vernaux->vna_flags & VER_FLG_WEAK) != 0);
195 			if (error != B_OK)
196 				return error;
197 
198 			vernaux = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next);
199 		}
200 
201 		needed = (elf_verneed*)((uint8*)needed + needed->vn_next);
202 	}
203 
204 	return B_OK;
205 }
206