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