xref: /haiku/src/system/runtime_loader/elf_symbol_lookup.cpp (revision 4e3137c085bae361922078f123dceb92da700640)
1 /*
2  * Copyright 2008-2011, 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 /*!	Checks whether \a name matches the name of \a image.
24 
25 	It is expected that \a name does not contain directory components. It is
26 	compared with the base name of \a image's name.
27 
28 	\param image The image.
29 	\param name The name to check against. Can be NULL, in which case \c false
30 		is returned.
31 	\return \c true, iff \a name is non-NULL and matches the name of \a image.
32 */
33 static bool
34 equals_image_name(image_t* image, const char* name)
35 {
36 	if (name == NULL)
37 		return false;
38 
39 	const char* lastSlash = strrchr(name, '/');
40 	return strcmp(image->name, lastSlash != NULL ? lastSlash + 1 : name) == 0;
41 }
42 
43 
44 // #pragma mark -
45 
46 
47 uint32
48 elf_hash(const char* _name)
49 {
50 	const uint8* name = (const uint8*)_name;
51 
52 	uint32 hash = 0;
53 	uint32 temp;
54 
55 	while (*name) {
56 		hash = (hash << 4) + *name++;
57 		if ((temp = hash & 0xf0000000)) {
58 			hash ^= temp >> 24;
59 		}
60 		hash &= ~temp;
61 	}
62 	return hash;
63 }
64 
65 
66 void
67 patch_defined_symbol(image_t* image, const char* name, void** symbol,
68 	int32* type)
69 {
70 	RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers;
71 	while (patcher != NULL && *symbol != 0) {
72 		image_t* inImage = image;
73 		patcher->patcher(patcher->cookie, NULL, image, name, &inImage,
74 			symbol, type);
75 		patcher = patcher->next;
76 	}
77 }
78 
79 
80 void
81 patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
82 	image_t** foundInImage, void** symbol, int32* type)
83 {
84 	if (*foundInImage != NULL)
85 		patch_defined_symbol(*foundInImage, name, symbol, type);
86 
87 	RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers;
88 	while (patcher != NULL) {
89 		patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage,
90 			symbol, type);
91 		patcher = patcher->next;
92 	}
93 }
94 
95 
96 elf_sym*
97 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo)
98 {
99 	if (image->dynamic_ptr == 0)
100 		return NULL;
101 
102 	elf_sym* versionedSymbol = NULL;
103 	uint32 versionedSymbolCount = 0;
104 
105 	uint32 bucket = lookupInfo.hash % HASHTABSIZE(image);
106 
107 	for (uint32 i = HASHBUCKETS(image)[bucket]; i != STN_UNDEF;
108 			i = HASHCHAINS(image)[i]) {
109 		elf_sym* symbol = &image->syms[i];
110 
111 		if (symbol->st_shndx != SHN_UNDEF
112 			&& ((symbol->Bind() == STB_GLOBAL)
113 				|| (symbol->Bind() == STB_WEAK))
114 			&& !strcmp(SYMNAME(image, symbol), lookupInfo.name)) {
115 
116 			// check if the type matches
117 			uint32 type = symbol->Type();
118 			if ((lookupInfo.type == B_SYMBOL_TYPE_TEXT && type != STT_FUNC)
119 				|| (lookupInfo.type == B_SYMBOL_TYPE_DATA
120 					&& type != STT_OBJECT)) {
121 				continue;
122 			}
123 
124 			// check the version
125 
126 			// Handle the simple cases -- the image doesn't have version
127 			// information -- first.
128 			if (image->symbol_versions == NULL) {
129 				if (lookupInfo.version == NULL) {
130 					// No specific symbol version was requested either, so the
131 					// symbol is just fine.
132 					return symbol;
133 				}
134 
135 				// A specific version is requested. If it's the dependency
136 				// referred to by the requested version, it's apparently an
137 				// older version of the dependency and we're not happy.
138 				if (equals_image_name(image, lookupInfo.version->file_name)) {
139 					// TODO: That should actually be kind of fatal!
140 					return NULL;
141 				}
142 
143 				// This is some other image. We accept the symbol.
144 				return symbol;
145 			}
146 
147 			// The image has version information. Let's see what we've got.
148 			uint32 versionID = image->symbol_versions[i];
149 			uint32 versionIndex = VER_NDX(versionID);
150 			elf_version_info& version = image->versions[versionIndex];
151 
152 			// skip local versions
153 			if (versionIndex == VER_NDX_LOCAL)
154 				continue;
155 
156 			if (lookupInfo.version != NULL) {
157 				// a specific version is requested
158 
159 				// compare the versions
160 				if (version.hash == lookupInfo.version->hash
161 					&& strcmp(version.name, lookupInfo.version->name) == 0) {
162 					// versions match
163 					return symbol;
164 				}
165 
166 				// The versions don't match. We're still fine with the
167 				// base version, if it is public and we're not looking for
168 				// the default version.
169 				if ((versionID & VER_NDX_FLAG_HIDDEN) == 0
170 					&& versionIndex == VER_NDX_GLOBAL
171 					&& (lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION)
172 						== 0) {
173 					// TODO: Revise the default version case! That's how
174 					// FreeBSD implements it, but glibc doesn't handle it
175 					// specially.
176 					return symbol;
177 				}
178 			} else {
179 				// No specific version requested, but the image has version
180 				// information. This can happen in either of these cases:
181 				//
182 				// * The dependent object was linked against an older version
183 				//   of the now versioned dependency.
184 				// * The symbol is looked up via find_image_symbol() or dlsym().
185 				//
186 				// In the first case we return the base version of the symbol
187 				// (VER_NDX_GLOBAL or VER_NDX_INITIAL), or, if that doesn't
188 				// exist, the unique, non-hidden versioned symbol.
189 				//
190 				// In the second case we want to return the public default
191 				// version of the symbol. The handling is pretty similar to the
192 				// first case, with the exception that we treat VER_NDX_INITIAL
193 				// as regular version.
194 
195 				// VER_NDX_GLOBAL is always good, VER_NDX_INITIAL is fine, if
196 				// we don't look for the default version.
197 				if (versionIndex == VER_NDX_GLOBAL
198 					|| ((lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) == 0
199 						&& versionIndex == VER_NDX_INITIAL)) {
200 					return symbol;
201 				}
202 
203 				// If not hidden, remember the version -- we'll return it, if
204 				// it is the only one.
205 				if ((versionID & VER_NDX_FLAG_HIDDEN) == 0) {
206 					versionedSymbolCount++;
207 					versionedSymbol = symbol;
208 				}
209 			}
210 		}
211 	}
212 
213 	return versionedSymbolCount == 1 ? versionedSymbol : NULL;
214 }
215 
216 
217 status_t
218 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo,
219 	void **_location)
220 {
221 	// get the symbol in the image
222 	elf_sym* symbol = find_symbol(image, lookupInfo);
223 	if (symbol == NULL)
224 		return B_ENTRY_NOT_FOUND;
225 
226 	void* location = (void*)(symbol->st_value + image->regions[0].delta);
227 	int32 symbolType = lookupInfo.type;
228 	patch_defined_symbol(image, lookupInfo.name, &location, &symbolType);
229 
230 	if (_location != NULL)
231 		*_location = location;
232 
233 	return B_OK;
234 }
235 
236 
237 status_t
238 find_symbol_breadth_first(image_t* image, const SymbolLookupInfo& lookupInfo,
239 	image_t** _foundInImage, void** _location)
240 {
241 	image_t* queue[count_loaded_images()];
242 	uint32 count = 0;
243 	uint32 index = 0;
244 	queue[count++] = image;
245 	image->flags |= RFLAG_VISITED;
246 
247 	elf_sym* candidateSymbol = NULL;
248 	image_t* candidateImage = NULL;
249 
250 	while (index < count) {
251 		// pop next image
252 		image = queue[index++];
253 
254 		elf_sym* symbol = find_symbol(image, lookupInfo);
255 		if (symbol != NULL) {
256 			bool isWeak = symbol->Bind() == STB_WEAK;
257 			if (candidateImage == NULL || !isWeak) {
258 				candidateSymbol = symbol;
259 				candidateImage = image;
260 
261 				if (!isWeak)
262 					break;
263 			}
264 		}
265 
266 		// push needed images
267 		for (uint32 i = 0; i < image->num_needed; i++) {
268 			image_t* needed = image->needed[i];
269 			if ((needed->flags & RFLAG_VISITED) == 0) {
270 				queue[count++] = needed;
271 				needed->flags |= RFLAG_VISITED;
272 			}
273 		}
274 	}
275 
276 	// clear visited flags
277 	for (uint32 i = 0; i < count; i++)
278 		queue[i]->flags &= ~RFLAG_VISITED;
279 
280 	if (candidateSymbol == NULL)
281 		return B_ENTRY_NOT_FOUND;
282 
283 	// compute the symbol location
284 	*_location = (void*)(candidateSymbol->st_value
285 		+ candidateImage->regions[0].delta);
286 	int32 symbolType = lookupInfo.type;
287 	patch_defined_symbol(candidateImage, lookupInfo.name, _location,
288 		&symbolType);
289 
290 	if (_foundInImage != NULL)
291 		*_foundInImage = candidateImage;
292 
293 	return B_OK;
294 }
295 
296 
297 elf_sym*
298 find_undefined_symbol_beos(image_t* rootImage, image_t* image,
299 	const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
300 {
301 	// BeOS style symbol resolution: It is sufficient to check the image itself
302 	// and its direct dependencies. The linker would have complained, if the
303 	// symbol wasn't there. First we check whether the requesting symbol is
304 	// defined already -- then we can simply return it, since, due to symbolic
305 	// linking, that's the one we'd find anyway.
306 	if (elf_sym* symbol = lookupInfo.requestingSymbol) {
307 		if (symbol->st_shndx != SHN_UNDEF
308 			&& ((symbol->Bind() == STB_GLOBAL)
309 				|| (symbol->Bind() == STB_WEAK))) {
310 			*foundInImage = image;
311 			return symbol;
312 		}
313 	}
314 
315 	// lookup in image
316 	elf_sym* symbol = find_symbol(image, lookupInfo);
317 	if (symbol != NULL) {
318 		*foundInImage = image;
319 		return symbol;
320 	}
321 
322 	// lookup in dependencies
323 	for (uint32 i = 0; i < image->num_needed; i++) {
324 		if (image->needed[i]->dynamic_ptr) {
325 			symbol = find_symbol(image->needed[i], lookupInfo);
326 			if (symbol != NULL) {
327 				*foundInImage = image->needed[i];
328 				return symbol;
329 			}
330 		}
331 	}
332 
333 	return NULL;
334 }
335 
336 
337 elf_sym*
338 find_undefined_symbol_global(image_t* rootImage, image_t* image,
339 	const SymbolLookupInfo& lookupInfo, image_t** _foundInImage)
340 {
341 	// Global load order symbol resolution: All loaded images are searched for
342 	// the symbol in the order they have been loaded. We skip add-on images and
343 	// RTLD_LOCAL images though.
344 	image_t* candidateImage = NULL;
345 	elf_sym* candidateSymbol = NULL;
346 
347 	// If the requesting image is linked symbolically, look up the symbol there
348 	// first.
349 	bool symbolic = (image->flags & RFLAG_SYMBOLIC) != 0;
350 	if (symbolic) {
351 		candidateSymbol = find_symbol(image, lookupInfo);
352 		if (candidateSymbol != NULL) {
353 			if (candidateSymbol->Bind() != STB_WEAK) {
354 				*_foundInImage = image;
355 				return candidateSymbol;
356 			}
357 
358 			candidateImage = image;
359 		}
360 	}
361 
362 	image_t* otherImage = get_loaded_images().head;
363 	while (otherImage != NULL) {
364 		if (otherImage == rootImage
365 				? !symbolic
366 				: (otherImage->type != B_ADD_ON_IMAGE
367 					&& (otherImage->flags
368 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) {
369 			if (elf_sym* symbol = find_symbol(otherImage, lookupInfo)) {
370 				if (symbol->Bind() != STB_WEAK) {
371 					*_foundInImage = otherImage;
372 					return symbol;
373 				}
374 
375 				if (candidateSymbol == NULL) {
376 					candidateSymbol = symbol;
377 					candidateImage = otherImage;
378 				}
379 			}
380 		}
381 		otherImage = otherImage->next;
382 	}
383 
384 	if (candidateSymbol != NULL)
385 		*_foundInImage = candidateImage;
386 
387 	return candidateSymbol;
388 }
389 
390 
391 elf_sym*
392 find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
393 	const SymbolLookupInfo& lookupInfo, image_t** _foundInImage)
394 {
395 	// Similar to global load order symbol resolution: All loaded images are
396 	// searched for the symbol in the order they have been loaded. We skip
397 	// add-on images and RTLD_LOCAL images though. The root image (i.e. the
398 	// add-on image) is skipped, too, but for the add-on itself we look up
399 	// a symbol that hasn't been found anywhere else in the add-on image.
400 	// The reason for skipping the add-on image is that we must not resolve
401 	// library symbol references to symbol definitions in the add-on, as
402 	// libraries can be shared between different add-ons and we must not
403 	// introduce connections between add-ons.
404 
405 	// For the add-on image itself resolve non-weak symbols defined in the
406 	// add-on to themselves. This makes the symbol resolution order inconsistent
407 	// for those symbols, but avoids clashes of global symbols defined in the
408 	// add-on with symbols defined e.g. in the application. There's really the
409 	// same problem for weak symbols, but we don't have any way to discriminate
410 	// weak symbols that must be resolved globally from those that should be
411 	// resolved within the add-on.
412 	if (rootImage == image) {
413 		if (elf_sym* symbol = lookupInfo.requestingSymbol) {
414 			if (symbol->st_shndx != SHN_UNDEF
415 				&& (symbol->Bind() == STB_GLOBAL)) {
416 				*_foundInImage = image;
417 				return symbol;
418 			}
419 		}
420 	}
421 
422 	image_t* candidateImage = NULL;
423 	elf_sym* candidateSymbol = NULL;
424 
425 	// If the requesting image is linked symbolically, look up the symbol there
426 	// first.
427 	bool symbolic = (image->flags & RFLAG_SYMBOLIC) != 0;
428 	if (symbolic) {
429 		candidateSymbol = find_symbol(image, lookupInfo);
430 		if (candidateSymbol != NULL) {
431 			if (candidateSymbol->Bind() != STB_WEAK) {
432 				*_foundInImage = image;
433 				return candidateSymbol;
434 			}
435 
436 			candidateImage = image;
437 		}
438 	}
439 
440 	image_t* otherImage = get_loaded_images().head;
441 	while (otherImage != NULL) {
442 		if (otherImage != rootImage
443 			&& otherImage->type != B_ADD_ON_IMAGE
444 			&& (otherImage->flags
445 				& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0) {
446 			if (elf_sym* symbol = find_symbol(otherImage, lookupInfo)) {
447 				if (symbol->Bind() != STB_WEAK) {
448 					*_foundInImage = otherImage;
449 					return symbol;
450 				}
451 
452 				if (candidateSymbol == NULL) {
453 					candidateSymbol = symbol;
454 					candidateImage = otherImage;
455 				}
456 			}
457 		}
458 		otherImage = otherImage->next;
459 	}
460 
461 	// If the symbol has not been found and we're trying to resolve a reference
462 	// in the add-on image, we also try to look it up there.
463 	if (!symbolic && candidateSymbol == NULL && image == rootImage) {
464 		candidateSymbol = find_symbol(image, lookupInfo);
465 		candidateImage = image;
466 	}
467 
468 	if (candidateSymbol != NULL)
469 		*_foundInImage = candidateImage;
470 
471 	return candidateSymbol;
472 }
473 
474 
475 int
476 resolve_symbol(image_t* rootImage, image_t* image, elf_sym* sym,
477 	SymbolLookupCache* cache, addr_t* symAddress, image_t** symbolImage)
478 {
479 	uint32 index = sym - image->syms;
480 
481 	// check the cache first
482 	if (cache->IsSymbolValueCached(index)) {
483 		*symAddress = cache->SymbolValueAt(index, symbolImage);
484 		return B_OK;
485 	}
486 
487 	elf_sym* sharedSym;
488 	image_t* sharedImage;
489 	const char* symName = SYMNAME(image, sym);
490 
491 	// get the symbol type
492 	int32 type = B_SYMBOL_TYPE_ANY;
493 	if (sym->Type() == STT_FUNC)
494 		type = B_SYMBOL_TYPE_TEXT;
495 	else if (sym->Type() == STT_OBJECT)
496 		type = B_SYMBOL_TYPE_DATA;
497 
498 	if (sym->Bind() == STB_LOCAL) {
499 		// Local symbols references are always resolved to the given symbol.
500 		sharedImage = image;
501 		sharedSym = sym;
502 	} else {
503 		// get the version info
504 		const elf_version_info* versionInfo = NULL;
505 		if (image->symbol_versions != NULL) {
506 			uint32 versionIndex = VER_NDX(image->symbol_versions[index]);
507 			if (versionIndex >= VER_NDX_INITIAL)
508 				versionInfo = image->versions + versionIndex;
509 		}
510 
511 		// search the symbol
512 		sharedSym = rootImage->find_undefined_symbol(rootImage, image,
513 			SymbolLookupInfo(symName, type, versionInfo, 0, sym), &sharedImage);
514 	}
515 
516 	enum {
517 		SUCCESS,
518 		ERROR_NO_SYMBOL,
519 		ERROR_WRONG_TYPE,
520 		ERROR_NOT_EXPORTED,
521 		ERROR_UNPATCHED
522 	};
523 	uint32 lookupError = ERROR_UNPATCHED;
524 
525 	bool tlsSymbol = sym->Type() == STT_TLS;
526 	void* location = NULL;
527 	if (sharedSym == NULL) {
528 		// symbol not found at all
529 		lookupError = ERROR_NO_SYMBOL;
530 		sharedImage = NULL;
531 	} else if (sym->Type() != STT_NOTYPE
532 		&& sym->Type() != sharedSym->Type()) {
533 		// symbol not of the requested type
534 		lookupError = ERROR_WRONG_TYPE;
535 		sharedImage = NULL;
536 	} else if (sharedSym->Bind() != STB_GLOBAL
537 		&& sharedSym->Bind() != STB_WEAK) {
538 		// symbol not exported
539 		lookupError = ERROR_NOT_EXPORTED;
540 		sharedImage = NULL;
541 	} else {
542 		// symbol is fine, get its location
543 		location = (void*)sharedSym->st_value;
544 		if (!tlsSymbol) {
545 			location
546 				= (void*)((addr_t)location + sharedImage->regions[0].delta);
547 		} else
548 			lookupError = SUCCESS;
549 	}
550 
551 	if (!tlsSymbol) {
552 		patch_undefined_symbol(rootImage, image, symName, &sharedImage,
553 			&location, &type);
554 	}
555 
556 	if (location == NULL && lookupError != SUCCESS) {
557 		switch (lookupError) {
558 			case ERROR_NO_SYMBOL:
559 				FATAL("%s: Could not resolve symbol '%s'\n",
560 					image->path, symName);
561 				break;
562 			case ERROR_WRONG_TYPE:
563 				FATAL("%s: Found symbol '%s' in shared image but wrong "
564 					"type\n", image->path, symName);
565 				break;
566 			case ERROR_NOT_EXPORTED:
567 				FATAL("%s: Found symbol '%s', but not exported\n",
568 					image->path, symName);
569 				break;
570 			case ERROR_UNPATCHED:
571 				FATAL("%s: Found symbol '%s', but was hidden by symbol "
572 					"patchers\n", image->path, symName);
573 				break;
574 		}
575 
576 		if (report_errors())
577 			gErrorMessage.AddString("missing symbol", symName);
578 
579 		return B_MISSING_SYMBOL;
580 	}
581 
582 	cache->SetSymbolValueAt(index, (addr_t)location, sharedImage);
583 
584 	if (symbolImage)
585 		*symbolImage = sharedImage;
586 	*symAddress = (addr_t)location;
587 	return B_OK;
588 }
589