xref: /haiku/src/system/runtime_loader/elf_versioning.cpp (revision 4466b89c65970de4c7236ac87faa2bee4589f413)
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 	Elf32_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 = (Elf32_Verdef*)
40 			((uint8*)definition + definition->vd_next);
41 	}
42 
43 	// version not found -- fail, if not weak
44 	if (!weak) {
45 		FATAL("%s: version \"%s\" not found (required by %s)\n", image->path,
46 			neededVersion.name, dependentImage->name);
47 		return B_MISSING_SYMBOL;
48 	}
49 
50 	return B_OK;
51 }
52 
53 
54 // #pragma mark -
55 
56 
57 status_t
58 init_image_version_infos(image_t* image)
59 {
60 	// First find out how many version infos we need -- i.e. get the greatest
61 	// version index from the defined and needed versions (they use the same
62 	// index namespace).
63 	uint32 maxIndex = 0;
64 
65 	if (image->version_definitions != NULL) {
66 		Elf32_Verdef* definition = image->version_definitions;
67 		for (uint32 i = 0; i < image->num_version_definitions; i++) {
68 			if (definition->vd_version != 1) {
69 				FATAL("%s: Unsupported version definition revision: %u\n",
70 					image->path, definition->vd_version);
71 				return B_BAD_VALUE;
72 			}
73 
74 			uint32 versionIndex = VER_NDX(definition->vd_ndx);
75 			if (versionIndex > maxIndex)
76 				maxIndex = versionIndex;
77 
78 			definition = (Elf32_Verdef*)
79 				((uint8*)definition	+ definition->vd_next);
80 		}
81 	}
82 
83 	if (image->needed_versions != NULL) {
84 		Elf32_Verneed* needed = image->needed_versions;
85 		for (uint32 i = 0; i < image->num_needed_versions; i++) {
86 			if (needed->vn_version != 1) {
87 				FATAL("%s: Unsupported version needed revision: %u\n",
88 					image->path, needed->vn_version);
89 				return B_BAD_VALUE;
90 			}
91 
92 			Elf32_Vernaux* vernaux
93 				= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
94 			for (uint32 k = 0; k < needed->vn_cnt; k++) {
95 				uint32 versionIndex = VER_NDX(vernaux->vna_other);
96 				if (versionIndex > maxIndex)
97 					maxIndex = versionIndex;
98 
99 				vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
100 			}
101 
102 			needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
103 		}
104 	}
105 
106 	if (maxIndex == 0)
107 		return B_OK;
108 
109 	// allocate the version infos
110 	image->versions
111 		= (elf_version_info*)malloc(sizeof(elf_version_info) * (maxIndex + 1));
112 	if (image->versions == NULL) {
113 		FATAL("Memory shortage in init_image_version_infos()");
114 		return B_NO_MEMORY;
115 	}
116 	image->num_versions = maxIndex + 1;
117 
118 	// init the version infos
119 
120 	// version definitions
121 	if (image->version_definitions != NULL) {
122 		Elf32_Verdef* definition = image->version_definitions;
123 		for (uint32 i = 0; i < image->num_version_definitions; i++) {
124 			if (definition->vd_cnt > 0
125 				&& (definition->vd_flags & VER_FLG_BASE) == 0) {
126 				Elf32_Verdaux* verdaux
127 					= (Elf32_Verdaux*)((uint8*)definition + definition->vd_aux);
128 
129 				uint32 versionIndex = VER_NDX(definition->vd_ndx);
130 				elf_version_info& info = image->versions[versionIndex];
131 				info.hash = definition->vd_hash;
132 				info.name = STRING(image, verdaux->vda_name);
133 				info.file_name = NULL;
134 			}
135 
136 			definition = (Elf32_Verdef*)
137 				((uint8*)definition + definition->vd_next);
138 		}
139 	}
140 
141 	// needed versions
142 	if (image->needed_versions != NULL) {
143 		Elf32_Verneed* needed = image->needed_versions;
144 		for (uint32 i = 0; i < image->num_needed_versions; i++) {
145 			const char* fileName = STRING(image, needed->vn_file);
146 
147 			Elf32_Vernaux* vernaux
148 				= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
149 			for (uint32 k = 0; k < needed->vn_cnt; k++) {
150 				uint32 versionIndex = VER_NDX(vernaux->vna_other);
151 				elf_version_info& info = image->versions[versionIndex];
152 				info.hash = vernaux->vna_hash;
153 				info.name = STRING(image, vernaux->vna_name);
154 				info.file_name = fileName;
155 
156 				vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
157 			}
158 
159 			needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
160 		}
161 	}
162 
163 	return B_OK;
164 }
165 
166 
167 status_t
168 check_needed_image_versions(image_t* image)
169 {
170 	if (image->needed_versions == NULL)
171 		return B_OK;
172 
173 	Elf32_Verneed* needed = image->needed_versions;
174 	for (uint32 i = 0; i < image->num_needed_versions; i++) {
175 		const char* fileName = STRING(image, needed->vn_file);
176 		image_t* dependency = find_loaded_image_by_name(fileName,
177 			ALL_IMAGE_TYPES);
178 		if (dependency == NULL) {
179 			// This can't really happen, unless the object file is broken, since
180 			// the file should also appear in DT_NEEDED.
181 			FATAL("%s: Version dependency \"%s\" not found", image->path,
182 				fileName);
183 			return B_FILE_NOT_FOUND;
184 		}
185 
186 		Elf32_Vernaux* vernaux
187 			= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
188 		for (uint32 k = 0; k < needed->vn_cnt; k++) {
189 			uint32 versionIndex = VER_NDX(vernaux->vna_other);
190 			elf_version_info& info = image->versions[versionIndex];
191 
192 			status_t error = assert_defined_image_version(image, dependency,
193 				info, (vernaux->vna_flags & VER_FLG_WEAK) != 0);
194 			if (error != B_OK)
195 				return error;
196 
197 			vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
198 		}
199 
200 		needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
201 	}
202 
203 	return B_OK;
204 }
205