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