libroot_debug: Merge guarded heap into libroot_debug.
[haiku.git] / src / system / runtime_loader / elf_symbol_lookup.cpp
blob593336e1ce32b74c78c79ee7d3c334e0a5b8f119
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.
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 */
11 #include "elf_symbol_lookup.h"
13 #include <dlfcn.h>
14 #include <stdio.h>
15 #include <string.h>
17 #include "add_ons.h"
18 #include "errors.h"
19 #include "images.h"
20 #include "runtime_loader_private.h"
23 /*! Checks whether \a name matches the name of \a image.
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.
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.
33 static bool
34 equals_image_name(image_t* image, const char* name)
36 if (name == NULL)
37 return false;
39 const char* lastSlash = strrchr(name, '/');
40 return strcmp(image->name, lastSlash != NULL ? lastSlash + 1 : name) == 0;
44 // #pragma mark -
47 uint32
48 elf_hash(const char* _name)
50 const uint8* name = (const uint8*)_name;
52 uint32 hash = 0;
53 uint32 temp;
55 while (*name) {
56 hash = (hash << 4) + *name++;
57 if ((temp = hash & 0xf0000000)) {
58 hash ^= temp >> 24;
60 hash &= ~temp;
62 return hash;
66 void
67 patch_defined_symbol(image_t* image, const char* name, void** symbol,
68 int32* type)
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;
80 void
81 patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
82 image_t** foundInImage, void** symbol, int32* type)
84 if (*foundInImage != NULL)
85 patch_defined_symbol(*foundInImage, name, symbol, type);
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;
96 elf_sym*
97 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo)
99 if (image->dynamic_ptr == 0)
100 return NULL;
102 elf_sym* versionedSymbol = NULL;
103 uint32 versionedSymbolCount = 0;
105 uint32 bucket = lookupInfo.hash % HASHTABSIZE(image);
107 for (uint32 i = HASHBUCKETS(image)[bucket]; i != STN_UNDEF;
108 i = HASHCHAINS(image)[i]) {
109 elf_sym* symbol = &image->syms[i];
111 if (symbol->st_shndx != SHN_UNDEF
112 && ((symbol->Bind() == STB_GLOBAL)
113 || (symbol->Bind() == STB_WEAK))
114 && !strcmp(SYMNAME(image, symbol), lookupInfo.name)) {
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;
124 // check the version
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;
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;
143 // This is some other image. We accept the symbol.
144 return symbol;
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];
152 // skip local versions
153 if (versionIndex == VER_NDX_LOCAL)
154 continue;
156 if (lookupInfo.version != NULL) {
157 // a specific version is requested
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;
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;
178 } else {
179 // No specific version requested, but the image has version
180 // information. This can happen in either of these cases:
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().
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.
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.
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;
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;
213 return versionedSymbolCount == 1 ? versionedSymbol : NULL;
217 status_t
218 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo,
219 void **_location)
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;
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);
230 if (_location != NULL)
231 *_location = location;
233 return B_OK;
237 status_t
238 find_symbol_breadth_first(image_t* image, const SymbolLookupInfo& lookupInfo,
239 image_t** _foundInImage, void** _location)
241 image_t* queue[count_loaded_images()];
242 uint32 count = 0;
243 uint32 index = 0;
244 queue[count++] = image;
245 image->flags |= RFLAG_VISITED;
247 elf_sym* candidateSymbol = NULL;
248 image_t* candidateImage = NULL;
250 while (index < count) {
251 // pop next image
252 image = queue[index++];
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;
261 if (!isWeak)
262 break;
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;
276 // clear visited flags
277 for (uint32 i = 0; i < count; i++)
278 queue[i]->flags &= ~RFLAG_VISITED;
280 if (candidateSymbol == NULL)
281 return B_ENTRY_NOT_FOUND;
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);
290 if (_foundInImage != NULL)
291 *_foundInImage = candidateImage;
293 return B_OK;
297 elf_sym*
298 find_undefined_symbol_beos(image_t* rootImage, image_t* image,
299 const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
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;
315 // lookup in image
316 elf_sym* symbol = find_symbol(image, lookupInfo);
317 if (symbol != NULL) {
318 *foundInImage = image;
319 return symbol;
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;
333 return NULL;
337 elf_sym*
338 find_undefined_symbol_global(image_t* rootImage, image_t* image,
339 const SymbolLookupInfo& lookupInfo, image_t** _foundInImage)
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;
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;
358 candidateImage = image;
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;
375 if (candidateSymbol == NULL) {
376 candidateSymbol = symbol;
377 candidateImage = otherImage;
381 otherImage = otherImage->next;
384 if (candidateSymbol != NULL)
385 *_foundInImage = candidateImage;
387 return candidateSymbol;
391 elf_sym*
392 find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
393 const SymbolLookupInfo& lookupInfo, image_t** _foundInImage)
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.
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;
422 image_t* candidateImage = NULL;
423 elf_sym* candidateSymbol = NULL;
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;
436 candidateImage = image;
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;
452 if (candidateSymbol == NULL) {
453 candidateSymbol = symbol;
454 candidateImage = otherImage;
458 otherImage = otherImage->next;
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;
468 if (candidateSymbol != NULL)
469 *_foundInImage = candidateImage;
471 return candidateSymbol;
476 resolve_symbol(image_t* rootImage, image_t* image, elf_sym* sym,
477 SymbolLookupCache* cache, addr_t* symAddress, image_t** symbolImage)
479 uint32 index = sym - image->syms;
481 // check the cache first
482 if (cache->IsSymbolValueCached(index)) {
483 *symAddress = cache->SymbolValueAt(index, symbolImage);
484 return B_OK;
487 elf_sym* sharedSym;
488 image_t* sharedImage;
489 const char* symName = SYMNAME(image, sym);
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;
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;
511 // search the symbol
512 sharedSym = rootImage->find_undefined_symbol(rootImage, image,
513 SymbolLookupInfo(symName, type, versionInfo, 0, sym), &sharedImage);
516 enum {
517 SUCCESS,
518 ERROR_NO_SYMBOL,
519 ERROR_WRONG_TYPE,
520 ERROR_NOT_EXPORTED,
521 ERROR_UNPATCHED
523 uint32 lookupError = ERROR_UNPATCHED;
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;
551 if (!tlsSymbol) {
552 patch_undefined_symbol(rootImage, image, symName, &sharedImage,
553 &location, &type);
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;
576 if (report_errors())
577 gErrorMessage.AddString("missing symbol", symName);
579 return B_MISSING_SYMBOL;
582 cache->SetSymbolValueAt(index, (addr_t)location, sharedImage);
584 if (symbolImage)
585 *symbolImage = sharedImage;
586 *symAddress = (addr_t)location;
587 return B_OK;