xref: /haiku/src/system/runtime_loader/elf_symbol_lookup.cpp (revision 893988af824e65e49e55f517b157db8386e8002b)
1 /*
2  * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  *
6  * Copyright 2002, Manuel J. Petit. All rights reserved.
7  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
8  * Distributed under the terms of the NewOS License.
9  */
10 
11 #include "elf_symbol_lookup.h"
12 
13 #include <dlfcn.h>
14 #include <stdio.h>
15 #include <string.h>
16 
17 #include "add_ons.h"
18 #include "errors.h"
19 #include "images.h"
20 #include "runtime_loader_private.h"
21 
22 
23 static bool
24 equals_image_name(image_t* image, const char* name)
25 {
26 	const char* lastSlash = strrchr(name, '/');
27 	return strcmp(image->name, lastSlash != NULL ? lastSlash + 1 : name) == 0;
28 }
29 
30 
31 // #pragma mark -
32 
33 
34 uint32
35 elf_hash(const char* _name)
36 {
37 	const uint8* name = (const uint8*)_name;
38 
39 	uint32 hash = 0;
40 	uint32 temp;
41 
42 	while (*name) {
43 		hash = (hash << 4) + *name++;
44 		if ((temp = hash & 0xf0000000)) {
45 			hash ^= temp >> 24;
46 		}
47 		hash &= ~temp;
48 	}
49 	return hash;
50 }
51 
52 
53 void
54 patch_defined_symbol(image_t* image, const char* name, void** symbol,
55 	int32* type)
56 {
57 	RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers;
58 	while (patcher != NULL && *symbol != 0) {
59 		image_t* inImage = image;
60 		patcher->patcher(patcher->cookie, NULL, image, name, &inImage,
61 			symbol, type);
62 		patcher = patcher->next;
63 	}
64 }
65 
66 
67 void
68 patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
69 	image_t** foundInImage, void** symbol, int32* type)
70 {
71 	if (*foundInImage != NULL)
72 		patch_defined_symbol(*foundInImage, name, symbol, type);
73 
74 	RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers;
75 	while (patcher != NULL) {
76 		patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage,
77 			symbol, type);
78 		patcher = patcher->next;
79 	}
80 }
81 
82 
83 Elf32_Sym*
84 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo)
85 {
86 	if (image->dynamic_ptr == 0)
87 		return NULL;
88 
89 	Elf32_Sym* versionedSymbol = NULL;
90 	uint32 versionedSymbolCount = 0;
91 
92 	uint32 bucket = lookupInfo.hash % HASHTABSIZE(image);
93 
94 	for (uint32 i = HASHBUCKETS(image)[bucket]; i != STN_UNDEF;
95 			i = HASHCHAINS(image)[i]) {
96 		Elf32_Sym* symbol = &image->syms[i];
97 
98 		if (symbol->st_shndx != SHN_UNDEF
99 			&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
100 				|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
101 			&& !strcmp(SYMNAME(image, symbol), lookupInfo.name)) {
102 
103 			// check if the type matches
104 			uint32 type = ELF32_ST_TYPE(symbol->st_info);
105 			if ((lookupInfo.type == B_SYMBOL_TYPE_TEXT && type != STT_FUNC)
106 				|| (lookupInfo.type == B_SYMBOL_TYPE_DATA
107 					&& type != STT_OBJECT)) {
108 				continue;
109 			}
110 
111 			// check the version
112 
113 			// Handle the simple cases -- the image doesn't have version
114 			// information -- first.
115 			if (image->symbol_versions == NULL) {
116 				if (lookupInfo.version == NULL) {
117 					// No specific symbol version was requested either, so the
118 					// symbol is just fine.
119 					return symbol;
120 				}
121 
122 				// A specific version is requested. If it's the dependency
123 				// referred to by the requested version, it's apparently an
124 				// older version of the dependency and we're not happy.
125 				if (equals_image_name(image, lookupInfo.version->file_name)) {
126 					// TODO: That should actually be kind of fatal!
127 					return NULL;
128 				}
129 
130 				// This is some other image. We accept the symbol.
131 				return symbol;
132 			}
133 
134 			// The image has version information. Let's see what we've got.
135 			uint32 versionID = image->symbol_versions[i];
136 			uint32 versionIndex = VER_NDX(versionID);
137 			elf_version_info& version = image->versions[versionIndex];
138 
139 			// skip local versions
140 			if (versionIndex == VER_NDX_LOCAL)
141 				continue;
142 
143 			if (lookupInfo.version != NULL) {
144 				// a specific version is requested
145 
146 				// compare the versions
147 				if (version.hash == lookupInfo.version->hash
148 					&& strcmp(version.name, lookupInfo.version->name) == 0) {
149 					// versions match
150 					return symbol;
151 				}
152 
153 				// The versions don't match. We're still fine with the
154 				// base version, if it is public and we're not looking for
155 				// the default version.
156 				if ((versionID & VER_NDX_FLAG_HIDDEN) == 0
157 					&& versionIndex == VER_NDX_GLOBAL
158 					&& (lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION)
159 						== 0) {
160 					// TODO: Revise the default version case! That's how
161 					// FreeBSD implements it, but glibc doesn't handle it
162 					// specially.
163 					return symbol;
164 				}
165 			} else {
166 				// No specific version requested, but the image has version
167 				// information. This can happen in either of these cases:
168 				//
169 				// * The dependent object was linked against an older version
170 				//   of the now versioned dependency.
171 				// * The symbol is looked up via find_image_symbol() or dlsym().
172 				//
173 				// In the first case we return the base version of the symbol
174 				// (VER_NDX_GLOBAL or VER_NDX_INITIAL), or, if that doesn't
175 				// exist, the unique, non-hidden versioned symbol.
176 				//
177 				// In the second case we want to return the public default
178 				// version of the symbol. The handling is pretty similar to the
179 				// first case, with the exception that we treat VER_NDX_INITIAL
180 				// as regular version.
181 
182 				// VER_NDX_GLOBAL is always good, VER_NDX_INITIAL is fine, if
183 				// we don't look for the default version.
184 				if (versionIndex == VER_NDX_GLOBAL
185 					|| ((lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) == 0
186 						&& versionIndex == VER_NDX_INITIAL)) {
187 					return symbol;
188 				}
189 
190 				// If not hidden, remember the version -- we'll return it, if
191 				// it is the only one.
192 				if ((versionID & VER_NDX_FLAG_HIDDEN) == 0) {
193 					versionedSymbolCount++;
194 					versionedSymbol = symbol;
195 				}
196 			}
197 		}
198 	}
199 
200 	return versionedSymbolCount == 1 ? versionedSymbol : NULL;
201 }
202 
203 
204 status_t
205 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo,
206 	void **_location)
207 {
208 	// get the symbol in the image
209 	Elf32_Sym* symbol = find_symbol(image, lookupInfo);
210 	if (symbol == NULL)
211 		return B_ENTRY_NOT_FOUND;
212 
213 	void* location = (void*)(symbol->st_value + image->regions[0].delta);
214 	int32 symbolType = lookupInfo.type;
215 	patch_defined_symbol(image, lookupInfo.name, &location, &symbolType);
216 
217 	if (_location != NULL)
218 		*_location = location;
219 
220 	return B_OK;
221 }
222 
223 
224 status_t
225 find_symbol_breadth_first(image_t* image, const SymbolLookupInfo& lookupInfo,
226 	image_t** _foundInImage, void** _location)
227 {
228 	image_t* queue[count_loaded_images()];
229 	uint32 count = 0;
230 	uint32 index = 0;
231 	queue[count++] = image;
232 	image->flags |= RFLAG_VISITED;
233 
234 	bool found = false;
235 	while (index < count) {
236 		// pop next image
237 		image = queue[index++];
238 
239 		if (find_symbol(image, lookupInfo, _location) == B_OK) {
240 			if (_foundInImage != NULL)
241 				*_foundInImage = image;
242 			found = true;
243 			break;
244 		}
245 
246 		// push needed images
247 		for (uint32 i = 0; i < image->num_needed; i++) {
248 			image_t* needed = image->needed[i];
249 			if ((needed->flags & RFLAG_VISITED) == 0) {
250 				queue[count++] = needed;
251 				needed->flags |= RFLAG_VISITED;
252 			}
253 		}
254 	}
255 
256 	// clear visited flags
257 	for (uint32 i = 0; i < count; i++)
258 		queue[i]->flags &= ~RFLAG_VISITED;
259 
260 	return found ? B_OK : B_ENTRY_NOT_FOUND;
261 }
262 
263 
264 Elf32_Sym*
265 find_undefined_symbol_beos(image_t* rootImage, image_t* image,
266 	const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
267 {
268 	// BeOS style symbol resolution: It is sufficient to check the direct
269 	// dependencies. The linker would have complained, if the symbol wasn't
270 	// there.
271 	for (uint32 i = 0; i < image->num_needed; i++) {
272 		if (image->needed[i]->dynamic_ptr) {
273 			Elf32_Sym *symbol = find_symbol(image->needed[i],
274 				lookupInfo);
275 			if (symbol) {
276 				*foundInImage = image->needed[i];
277 				return symbol;
278 			}
279 		}
280 	}
281 
282 	return NULL;
283 }
284 
285 
286 Elf32_Sym*
287 find_undefined_symbol_global(image_t* rootImage, image_t* image,
288 	const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
289 {
290 	// Global load order symbol resolution: All loaded images are searched for
291 	// the symbol in the order they have been loaded. We skip add-on images and
292 	// RTLD_LOCAL images though.
293 	image_t* otherImage = get_loaded_images().head;
294 	while (otherImage != NULL) {
295 		if (otherImage == rootImage
296 			|| (otherImage->type != B_ADD_ON_IMAGE
297 				&& (otherImage->flags
298 					& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) {
299 			Elf32_Sym *symbol = find_symbol(otherImage, lookupInfo);
300 			if (symbol) {
301 				*foundInImage = otherImage;
302 				return symbol;
303 			}
304 		}
305 		otherImage = otherImage->next;
306 	}
307 
308 	return NULL;
309 }
310 
311 
312 Elf32_Sym*
313 find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
314 	const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
315 {
316 	// Do a breadth-first resolution in the add-on dependency scope,
317 	// skipping the add-on itself.
318 	Elf32_Sym* foundSymbol = NULL;
319 
320 	image_t* queue[count_loaded_images()];
321 	uint32 count = 0;
322 	uint32 index = 0;
323 	queue[count++] = image;
324 	image->flags |= RFLAG_VISITED;
325 
326 	image_t* currentImage;
327 	while (index < count) {
328 		// pop next image
329 		currentImage = queue[index++];
330 
331 		if (currentImage != image) {
332 			foundSymbol = find_symbol(currentImage, lookupInfo);
333 			if (foundSymbol != NULL) {
334 				if (foundInImage != NULL)
335 					*foundInImage = currentImage;
336 				break;
337 			}
338 		}
339 
340 		// push needed images
341 		for (uint32 i = 0; i < currentImage->num_needed; i++) {
342 			image_t* needed = currentImage->needed[i];
343 			if ((needed->flags & RFLAG_VISITED) == 0) {
344 				queue[count++] = needed;
345 				needed->flags |= RFLAG_VISITED;
346 			}
347 		}
348 	}
349 
350 	// clear visited flags
351 	for (uint32 i = 0; i < count; i++)
352 		queue[i]->flags &= ~RFLAG_VISITED;
353 
354 	return foundSymbol;
355 }
356 
357 
358 int
359 resolve_symbol(image_t* rootImage, image_t* image, struct Elf32_Sym* sym,
360 	addr_t* symAddress)
361 {
362 	switch (sym->st_shndx) {
363 		case SHN_UNDEF:
364 		{
365 			struct Elf32_Sym* sharedSym;
366 			image_t* sharedImage;
367 			const char* symName = SYMNAME(image, sym);
368 
369 			// get the version info
370 			const elf_version_info* versionInfo = NULL;
371 			if (image->symbol_versions != NULL) {
372 				uint32 index = sym - image->syms;
373 				uint32 versionIndex = VER_NDX(image->symbol_versions[index]);
374 				if (versionIndex >= VER_NDX_INITIAL)
375 					versionInfo = image->versions + versionIndex;
376 			}
377 
378 			int32 type = B_SYMBOL_TYPE_ANY;
379 			if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC)
380 				type = B_SYMBOL_TYPE_TEXT;
381 			else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT)
382 				type = B_SYMBOL_TYPE_DATA;
383 
384 			// it's undefined, must be outside this image, try the other images
385 			sharedSym = rootImage->find_undefined_symbol(rootImage, image,
386 				SymbolLookupInfo(symName, type, versionInfo), &sharedImage);
387 			void* location = NULL;
388 
389 			enum {
390 				ERROR_NO_SYMBOL,
391 				ERROR_WRONG_TYPE,
392 				ERROR_NOT_EXPORTED,
393 				ERROR_UNPATCHED
394 			};
395 			uint32 lookupError = ERROR_UNPATCHED;
396 
397 			if (sharedSym == NULL) {
398 				// symbol not found at all
399 				lookupError = ERROR_NO_SYMBOL;
400 				sharedImage = NULL;
401 			} else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
402 				&& ELF32_ST_TYPE(sym->st_info)
403 					!= ELF32_ST_TYPE(sharedSym->st_info)) {
404 				// symbol not of the requested type
405 				lookupError = ERROR_WRONG_TYPE;
406 				sharedImage = NULL;
407 			} else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL
408 				&& ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) {
409 				// symbol not exported
410 				lookupError = ERROR_NOT_EXPORTED;
411 				sharedImage = NULL;
412 			} else {
413 				// symbol is fine, get its location
414 				location = (void*)(sharedSym->st_value
415 					+ sharedImage->regions[0].delta);
416 			}
417 
418 			patch_undefined_symbol(rootImage, image, symName, &sharedImage,
419 				&location, &type);
420 
421 			if (location == NULL) {
422 				switch (lookupError) {
423 					case ERROR_NO_SYMBOL:
424 						FATAL("%s: Could not resolve symbol '%s'\n",
425 							image->path, symName);
426 						break;
427 					case ERROR_WRONG_TYPE:
428 						FATAL("%s: Found symbol '%s' in shared image but wrong "
429 							"type\n", image->path, symName);
430 						break;
431 					case ERROR_NOT_EXPORTED:
432 						FATAL("%s: Found symbol '%s', but not exported\n",
433 							image->path, symName);
434 						break;
435 					case ERROR_UNPATCHED:
436 						FATAL("%s: Found symbol '%s', but was hidden by symbol "
437 							"patchers\n", image->path, symName);
438 						break;
439 				}
440 
441 				if (report_errors())
442 					gErrorMessage.AddString("missing symbol", symName);
443 
444 				return B_MISSING_SYMBOL;
445 			}
446 
447 			*symAddress = (addr_t)location;
448 			return B_OK;
449 		}
450 
451 		case SHN_ABS:
452 			*symAddress = sym->st_value + image->regions[0].delta;
453 			return B_NO_ERROR;
454 
455 		case SHN_COMMON:
456 			// TODO: finish this
457 			FATAL("%s: elf_resolve_symbol: COMMON symbol, finish me!\n",
458 				image->path);
459 			return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
460 
461 		default:
462 			// standard symbol
463 			*symAddress = sym->st_value + image->regions[0].delta;
464 			return B_NO_ERROR;
465 	}
466 }
467