xref: /haiku/src/kits/debug/SymbolLookup.cpp (revision 0562493379cd52eb7103531f895f10bb8e77c085)
1 /*
2  * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "SymbolLookup.h"
7 
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <unistd.h>
14 
15 #include <new>
16 
17 #include <runtime_loader.h>
18 #include <syscalls.h>
19 
20 
21 #undef TRACE
22 //#define TRACE_DEBUG_SYMBOL_LOOKUP
23 #ifdef TRACE_DEBUG_SYMBOL_LOOKUP
24 #	define TRACE(x) printf x
25 #else
26 #	define TRACE(x) ;
27 #endif
28 
29 
30 using std::nothrow;
31 using namespace BPrivate;
32 
33 
34 // PrepareAddress
35 const void *
36 Area::PrepareAddress(const void *address)
37 {
38 	TRACE(("Area::PrepareAddress(%p): area: %ld\n", address, fRemoteID));
39 
40 	// clone the area, if not done already
41 	if (fLocalID < 0) {
42 		fLocalID = clone_area("cloned area", &fLocalAddress, B_ANY_ADDRESS,
43 			B_READ_AREA, fRemoteID);
44 		if (fLocalID < 0) {
45 			TRACE(("Area::PrepareAddress(): Failed to clone area %ld: %s\n",
46 				fRemoteID, strerror(fLocalID)));
47 			throw Exception(fLocalID);
48 		}
49 	}
50 
51 	// translate the address
52 	const void *result = (const void*)((addr_t)address - (addr_t)fRemoteAddress
53 		+ (addr_t)fLocalAddress);
54 
55 	TRACE(("Area::PrepareAddress(%p) done: %p\n", address, result));
56 
57 	return result;
58 }
59 
60 
61 // #pragma mark -
62 
63 // constructor
64 RemoteMemoryAccessor::RemoteMemoryAccessor(team_id team)
65 	: fTeam(team),
66 	  fAreas()
67 {
68 }
69 
70 // destructor
71 RemoteMemoryAccessor::~RemoteMemoryAccessor()
72 {
73 	// delete the areas
74 	while (Area *area = fAreas.Head()) {
75 		fAreas.Remove(area);
76 		delete area;
77 	}
78 }
79 
80 // Init
81 status_t
82 RemoteMemoryAccessor::Init()
83 {
84 	// If the team is the kernel team, we don't try to clone the areas. Only
85 	// SymbolLookup's image file functionality will be available.
86 	if (fTeam == B_SYSTEM_TEAM)
87 		return B_OK;
88 
89 	// get a list of the team's areas
90 	area_info areaInfo;
91 	int32 cookie = 0;
92 	status_t error;
93 	while ((error = get_next_area_info(fTeam, &cookie, &areaInfo)) == B_OK) {
94 		TRACE(("area %ld: address: %p, size: %ld, name: %s\n", areaInfo.area,
95 			areaInfo.address, areaInfo.size, areaInfo.name));
96 
97 		Area *area = new(nothrow) Area(areaInfo.area, areaInfo.address,
98 			areaInfo.size);
99 		if (!area)
100 			return B_NO_MEMORY;
101 
102 		fAreas.Add(area);
103 	}
104 
105 	if (fAreas.IsEmpty())
106 		return error;
107 
108 	return B_OK;
109 }
110 
111 // PrepareAddress
112 const void *
113 RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress,
114 	int32 size) const
115 {
116 	TRACE(("RemoteMemoryAccessor::PrepareAddress(%p, %ld)\n", remoteAddress,
117 		size));
118 
119 	if (!remoteAddress) {
120 		TRACE(("RemoteMemoryAccessor::PrepareAddress(): Got null address!\n"));
121 		throw Exception(B_BAD_VALUE);
122 	}
123 
124 	return _FindArea(remoteAddress, size).PrepareAddress(remoteAddress);
125 }
126 
127 
128 const void *
129 RemoteMemoryAccessor::PrepareAddressNoThrow(const void *remoteAddress,
130 	int32 size) const
131 {
132 	if (remoteAddress == NULL)
133 		return NULL;
134 
135 	Area* area = _FindAreaNoThrow(remoteAddress, size);
136 	if (area == NULL)
137 		return NULL;
138 
139 	return area->PrepareAddress(remoteAddress);
140 }
141 
142 
143 // AreaForLocalAddress
144 Area*
145 RemoteMemoryAccessor::AreaForLocalAddress(const void* address) const
146 {
147 	if (address == NULL)
148 		return NULL;
149 
150 	for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) {
151 		Area* area = it.Next();
152 		if (area->ContainsLocalAddress(address))
153 			return area;
154 	}
155 
156 	return NULL;
157 }
158 
159 
160 // _FindArea
161 Area &
162 RemoteMemoryAccessor::_FindArea(const void *address, int32 size) const
163 {
164 	TRACE(("RemoteMemoryAccessor::_FindArea(%p, %ld)\n", address, size));
165 
166 	for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) {
167 		Area *area = it.Next();
168 		if (area->ContainsAddress(address, size))
169 			return *area;
170 	}
171 
172 	TRACE(("RemoteMemoryAccessor::_FindArea(): No area found for address %p\n",
173 		address));
174 	throw Exception(B_ENTRY_NOT_FOUND);
175 }
176 
177 
178 // _FindAreaNoThrow
179 Area*
180 RemoteMemoryAccessor::_FindAreaNoThrow(const void *address, int32 size) const
181 {
182 	for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) {
183 		Area *area = it.Next();
184 		if (area->ContainsAddress(address, size))
185 			return area;
186 	}
187 
188 	return NULL;
189 }
190 
191 
192 // #pragma mark -
193 
194 
195 ImageFile::ImageFile(const image_info& info)
196 	:
197 	fInfo(info),
198 	fFD(-1),
199 	fFileSize(0),
200 	fMappedFile((uint8*)MAP_FAILED),
201 	fLoadDelta(0),
202 	fSymbolTable(NULL),
203 	fStringTable(NULL),
204 	fSymbolCount(0),
205 	fStringTableSize(0)
206 {
207 }
208 
209 
210 ImageFile::~ImageFile()
211 {
212 	if (fMappedFile != MAP_FAILED) {
213 		munmap(fMappedFile, fFileSize);
214 	} else {
215 		delete[] fSymbolTable;
216 		delete[] fStringTable;
217 	}
218 
219 	if (fFD >= 0)
220 		close(fFD);
221 }
222 
223 
224 status_t
225 ImageFile::Load()
226 {
227 	// open and stat() the file
228 	fFD = open(fInfo.name, O_RDONLY);
229 	if (fFD < 0)
230 		return errno;
231 
232 	struct stat st;
233 	if (fstat(fFD, &st) < 0)
234 		return errno;
235 
236 	fFileSize = st.st_size;
237 	if (fFileSize < sizeof(Elf32_Ehdr))
238 		return B_NOT_AN_EXECUTABLE;
239 
240 	// map it
241 	fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_PRIVATE, fFD, 0);
242 	if (fMappedFile == MAP_FAILED)
243 		return errno;
244 
245 	// examine the elf header
246 	Elf32_Ehdr* elfHeader = (Elf32_Ehdr*)fMappedFile;
247 	if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0)
248 		return B_NOT_AN_EXECUTABLE;
249 
250 	if (elfHeader->e_ident[4] != ELFCLASS32)
251 		return B_NOT_AN_EXECUTABLE;
252 
253 	// verify the location of the program headers
254 	int32 programHeaderCount = elfHeader->e_phnum;
255 	if (elfHeader->e_phoff < sizeof(Elf32_Ehdr)
256 		|| elfHeader->e_phentsize < sizeof(Elf32_Phdr)
257 		|| elfHeader->e_phoff + programHeaderCount * elfHeader->e_phentsize
258 			> fFileSize) {
259 		return B_NOT_AN_EXECUTABLE;
260 	}
261 
262 	Elf32_Phdr* programHeaders
263 		= (Elf32_Phdr*)(fMappedFile + elfHeader->e_phoff);
264 
265 	// verify the location of the section headers
266 	int32 sectionCount = elfHeader->e_shnum;
267 	if (elfHeader->e_shoff < sizeof(Elf32_Ehdr)
268 		|| elfHeader->e_shentsize < sizeof(Elf32_Shdr)
269 		|| elfHeader->e_shoff + sectionCount * elfHeader->e_shentsize
270 			> fFileSize) {
271 		return B_NOT_AN_EXECUTABLE;
272 	}
273 
274 	Elf32_Shdr* sectionHeaders
275 		= (Elf32_Shdr*)(fMappedFile + elfHeader->e_shoff);
276 
277 	// find the first segment -- we need its relative offset
278 	for (int32 i = 0; i < programHeaderCount; i++) {
279 		Elf32_Phdr* header = (Elf32_Phdr*)
280 			((uint8*)programHeaders + i * elfHeader->e_phentsize);
281 		if (header->p_type == PT_LOAD) {
282 			fLoadDelta = (addr_t)fInfo.text - header->p_vaddr;
283 			break;
284 		}
285 	}
286 
287 	// find the symbol table
288 	for (int32 i = 0; i < elfHeader->e_shnum; i++) {
289 		Elf32_Shdr* sectionHeader = (Elf32_Shdr*)
290 			((uint8*)sectionHeaders + i * elfHeader->e_shentsize);
291 
292 		if (sectionHeader->sh_type == SHT_SYMTAB) {
293 			Elf32_Shdr& stringHeader = *(Elf32_Shdr*)
294 				((uint8*)sectionHeaders
295 					+ sectionHeader->sh_link * elfHeader->e_shentsize);
296 
297 			if (stringHeader.sh_type != SHT_STRTAB)
298 				return B_BAD_DATA;
299 
300 			if (sectionHeader->sh_offset + sectionHeader->sh_size > fFileSize
301 				|| stringHeader.sh_offset + stringHeader.sh_size > fFileSize) {
302 				return B_BAD_DATA;
303 			}
304 
305 			fSymbolTable = (Elf32_Sym*)(fMappedFile + sectionHeader->sh_offset);
306 			fStringTable = (char*)(fMappedFile + stringHeader.sh_offset);
307 			fSymbolCount = sectionHeader->sh_size / sizeof(Elf32_Sym);
308 			fStringTableSize = stringHeader.sh_size;
309 
310 			return B_OK;
311 		}
312 	}
313 
314 	return B_BAD_DATA;
315 }
316 
317 
318 status_t
319 ImageFile::LoadKernel()
320 {
321 	// get the table sizes
322 	fSymbolCount = 0;
323 	fStringTableSize = 0;
324 	status_t error = _kern_read_kernel_image_symbols(fInfo.id,
325 		NULL, &fSymbolCount, NULL, &fStringTableSize, NULL);
326 	if (error != B_OK)
327 		return error;
328 
329 	// allocate the tables
330 	fSymbolTable = new(std::nothrow) Elf32_Sym[fSymbolCount];
331 	fStringTable = new(std::nothrow) char[fStringTableSize];
332 	if (fSymbolTable == NULL || fStringTable == NULL)
333 		return B_NO_MEMORY;
334 
335 	// get the info
336 	return _kern_read_kernel_image_symbols(fInfo.id,
337 		fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize,
338 		&fLoadDelta);
339 }
340 
341 
342 const Elf32_Sym*
343 ImageFile::LookupSymbol(addr_t address, addr_t* _baseAddress,
344 	const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const
345 {
346 	const Elf32_Sym* symbolFound = NULL;
347 	const char* symbolName = NULL;
348 	bool exactMatch = false;
349 	addr_t deltaFound = ~(addr_t)0;
350 
351 	for (int32 i = 0; i < fSymbolCount; i++) {
352 		const Elf32_Sym* symbol = &fSymbolTable[i];
353 
354 		if (symbol->st_value == 0
355 			|| symbol->st_size >= (size_t)fInfo.text_size + fInfo.data_size) {
356 			continue;
357 		}
358 
359 		addr_t symbolAddress = symbol->st_value + fLoadDelta;
360 		if (symbolAddress > address)
361 			continue;
362 
363 		addr_t symbolDelta = address - symbolAddress;
364 		if (symbolDelta >= 0 && symbolDelta < symbol->st_size)
365 			exactMatch = true;
366 
367 		if (exactMatch || symbolDelta < deltaFound) {
368 			deltaFound = symbolDelta;
369 			symbolFound = symbol;
370 			symbolName = fStringTable + symbol->st_name;
371 
372 			if (exactMatch)
373 				break;
374 		}
375 	}
376 
377 	if (symbolFound != NULL) {
378 		if (_baseAddress != NULL)
379 			*_baseAddress = symbolFound->st_value + fLoadDelta;
380 		if (_symbolName != NULL)
381 			*_symbolName = symbolName;
382 		if (_exactMatch != NULL)
383 			*_exactMatch = exactMatch;
384 		if (_symbolNameLen != NULL)
385 			*_symbolNameLen = _SymbolNameLen(symbolName);
386 	}
387 
388 	return symbolFound;
389 }
390 
391 
392 status_t
393 ImageFile::NextSymbol(int32& iterator, const char** _symbolName,
394 	size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
395 	int32* _symbolType) const
396 {
397 	while (true) {
398 		if (++iterator >= fSymbolCount)
399 			return B_ENTRY_NOT_FOUND;
400 
401 		const Elf32_Sym* symbol = &fSymbolTable[iterator];
402 
403 		if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
404 				&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
405 			|| symbol->st_value == 0) {
406 			continue;
407 		}
408 
409 		*_symbolName = fStringTable + symbol->st_name;
410 		*_symbolNameLen = _SymbolNameLen(*_symbolName);
411 		*_symbolAddress = symbol->st_value + fLoadDelta;
412 		*_symbolSize = symbol->st_size;
413 		*_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
414 			? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
415 
416 		return B_OK;
417 	}
418 }
419 
420 
421 size_t
422 ImageFile::_SymbolNameLen(const char* symbolName) const
423 {
424 	if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable
425 		|| (addr_t)symbolName >= (addr_t)fStringTable + fStringTableSize) {
426 		return 0;
427 	}
428 
429 	return strnlen(symbolName,
430 		(addr_t)fStringTable + fStringTableSize - (addr_t)symbolName);
431 }
432 
433 
434 // #pragma mark -
435 
436 
437 // constructor
438 SymbolLookup::SymbolLookup(team_id team)
439 	:
440 	RemoteMemoryAccessor(team),
441 	fDebugArea(NULL),
442 	fImageFiles()
443 {
444 }
445 
446 
447 // destructor
448 SymbolLookup::~SymbolLookup()
449 {
450 	while (ImageFile* imageFile = fImageFiles.RemoveHead())
451 		delete imageFile;
452 }
453 
454 
455 // Init
456 status_t
457 SymbolLookup::Init()
458 {
459 	TRACE(("SymbolLookup::Init()\n"));
460 
461 	status_t error = RemoteMemoryAccessor::Init();
462 	if (error != B_OK)
463 		return error;
464 
465 	if (fTeam != B_SYSTEM_TEAM) {
466 		TRACE(("SymbolLookup::Init(): searching debug area...\n"));
467 
468 		// find the runtime loader debug area
469 		runtime_loader_debug_area *remoteDebugArea = NULL;
470 		int32 cookie = 0;
471 		area_info areaInfo;
472 		while (get_next_area_info(fTeam, &cookie, &areaInfo) == B_OK) {
473 			if (strcmp(areaInfo.name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0) {
474 				remoteDebugArea = (runtime_loader_debug_area*)areaInfo.address;
475 				break;
476 			}
477 		}
478 
479 		if (remoteDebugArea) {
480 			TRACE(("SymbolLookup::Init(): found debug area, translating "
481 				"address...\n"));
482 		} else {
483 			TRACE(("SymbolLookup::Init(): Couldn't find debug area!\n"));
484 		}
485 
486 		// translate the address
487 		try {
488 			if (remoteDebugArea != NULL) {
489 				fDebugArea = &Read(*remoteDebugArea);
490 
491 				TRACE(("SymbolLookup::Init(): translated debug area is at: %p, "
492 					"loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images));
493 			}
494 		} catch (Exception exception) {
495 			// we can live without the debug area
496 		}
497 	}
498 
499 	// create a list of the team's images
500 	image_info imageInfo;
501 	int32 cookie = 0;
502 	while (get_next_image_info(fTeam, &cookie, &imageInfo) == B_OK) {
503 		ImageFile* imageFile = new(std::nothrow) ImageFile(imageInfo);
504 		if (imageFile == NULL)
505 			break;
506 
507 		error = fTeam == B_SYSTEM_TEAM
508 			? imageFile->LoadKernel() : imageFile->Load();
509 		if (error != B_OK) {
510 			delete imageFile;
511 			continue;
512 		}
513 
514 		fImageFiles.Add(imageFile);
515 	}
516 
517 	return B_OK;
518 }
519 
520 
521 // LookupSymbolAddress
522 status_t
523 SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
524 	const char **_symbolName, size_t *_symbolNameLen, const char **_imageName,
525 	bool *_exactMatch) const
526 {
527 	TRACE(("SymbolLookup::LookupSymbolAddress(%p)\n", (void*)address));
528 
529 	// Try the loaded image file first -- it also contains static symbols.
530 	ImageFile* imageFile = _FindImageFileAtAddress(address);
531 	if (imageFile != NULL) {
532 		if (_imageName != NULL)
533 			*_imageName = imageFile->Info().name;
534 		const Elf32_Sym* symbol = imageFile->LookupSymbol(address, _baseAddress,
535 			_symbolName, _symbolNameLen, _exactMatch);
536 		if (symbol != NULL)
537 			return B_OK;
538 	}
539 
540 	// get the image for the address
541 	const image_t *image = _FindImageAtAddress(address);
542 	if (!image)
543 		return B_ENTRY_NOT_FOUND;
544 
545 	TRACE(("SymbolLookup::LookupSymbolAddress(): found image: ID: %ld, text: "
546 		"address: %p, size: %ld\n",
547 		image->id, (void*)image->regions[0].vmstart, image->regions[0].size));
548 
549 	// search the image for the symbol
550 	const struct Elf32_Sym *symbolFound = NULL;
551 	addr_t deltaFound = INT_MAX;
552 	bool exactMatch = false;
553 	const char *symbolName = NULL;
554 
555 	int32 symbolCount = Read(image->symhash[1]);
556 	const elf_region_t *textRegion = image->regions;				// local
557 
558 	for (int32 i = 0; i < symbolCount; i++) {
559 		const struct Elf32_Sym *symbol = &Read(image->syms[i]);
560 
561 		// The symbol table contains not only symbols referring to functions
562 		// and data symbols within the shared object, but also referenced
563 		// symbols of other shared objects, as well as section and file
564 		// references. We ignore everything but function and data symbols
565 		// that have an st_value != 0 (0 seems to be an indication for a
566 		// symbol defined elsewhere -- couldn't verify that in the specs
567 		// though).
568 		if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
569 				&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
570 			|| symbol->st_value == 0
571 			|| symbol->st_value + symbol->st_size + textRegion->delta
572 				> textRegion->vmstart + textRegion->size) {
573 			continue;
574 		}
575 
576 		// skip symbols starting after the given address
577 		addr_t symbolAddress = symbol->st_value + textRegion->delta;
578 
579 		if (symbolAddress > address)
580 			continue;
581 		addr_t symbolDelta = address - symbolAddress;
582 
583 		if (!symbolFound || symbolDelta < deltaFound) {
584 			symbolName = (const char*)PrepareAddressNoThrow(SYMNAME(image,
585 				symbol), 1);
586 			if (symbolName == NULL)
587 				continue;
588 
589 			deltaFound = symbolDelta;
590 			symbolFound = symbol;
591 
592 			if (symbolDelta >= 0 && symbolDelta < symbol->st_size) {
593 				// exact match
594 				exactMatch = true;
595 				break;
596 			}
597 		}
598 	}
599 
600 	TRACE(("SymbolLookup::LookupSymbolAddress(): done: symbol: %p, image name: "
601 		"%s, exact match: %d\n", symbolFound, image->name, exactMatch));
602 
603 	if (_baseAddress) {
604 		if (symbolFound)
605 			*_baseAddress = symbolFound->st_value + textRegion->delta;
606 		else
607 			*_baseAddress = textRegion->vmstart;
608 	}
609 
610 	if (_imageName)
611 		*_imageName = image->name;
612 
613 	if (_symbolName)
614 		*_symbolName = symbolName;	// remote address
615 
616 	if (_exactMatch)
617 		*_exactMatch = exactMatch;
618 
619 	if (_symbolNameLen != NULL)
620 		*_symbolNameLen = _SymbolNameLen(symbolName);
621 
622 	return B_OK;
623 }
624 
625 
626 // InitSymbolIterator
627 status_t
628 SymbolLookup::InitSymbolIterator(image_id imageID,
629 	SymbolIterator& iterator) const
630 {
631 	TRACE(("SymbolLookup::InitSymbolIterator(): image ID: %ld\n", imageID));
632 
633 	// find the image file
634 	iterator.imageFile = _FindImageFileByID(imageID);
635 
636 	// If that didn't work, find the image.
637 	if (iterator.imageFile == NULL) {
638 		const image_t* image = _FindImageByID(imageID);
639 		if (image == NULL) {
640 			TRACE(("SymbolLookup::InitSymbolIterator() done: image not "
641 				"found\n"));
642 			return B_ENTRY_NOT_FOUND;
643 		}
644 
645 		iterator.image = image;
646 		iterator.symbolCount = Read(image->symhash[1]);
647 		iterator.textDelta = image->regions->delta;
648 	}
649 
650 	iterator.currentIndex = -1;
651 
652 	return B_OK;
653 }
654 
655 
656 // InitSymbolIterator
657 status_t
658 SymbolLookup::InitSymbolIteratorByAddress(addr_t address,
659 	SymbolIterator& iterator) const
660 {
661 	TRACE(("SymbolLookup::InitSymbolIteratorByAddress(): base address: %#lx\n",
662 		address));
663 
664 	// find the image file
665 	iterator.imageFile = _FindImageFileAtAddress(address);
666 
667 	// If that didn't work, find the image.
668 	if (iterator.imageFile == NULL) {
669 		const image_t *image = _FindImageAtAddress(address);
670 		if (image == NULL) {
671 			TRACE(("SymbolLookup::InitSymbolIteratorByAddress() done: image "
672 				"not found\n"));
673 			return B_ENTRY_NOT_FOUND;
674 		}
675 
676 		iterator.image = image;
677 		iterator.symbolCount = Read(image->symhash[1]);
678 		iterator.textDelta = image->regions->delta;
679 	}
680 
681 	iterator.currentIndex = -1;
682 
683 	return B_OK;
684 }
685 
686 
687 // NextSymbol
688 status_t
689 SymbolLookup::NextSymbol(SymbolIterator& iterator, const char** _symbolName,
690 	size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
691 	int32* _symbolType) const
692 {
693 	// If we have an image file, get the next symbol from it.
694 	const ImageFile* imageFile = iterator.imageFile;
695 	if (imageFile != NULL) {
696 		return imageFile->NextSymbol(iterator.currentIndex, _symbolName,
697 			_symbolNameLen, _symbolAddress, _symbolSize, _symbolType);
698 	}
699 
700 	// Otherwise we've to fall be to iterating through the image.
701 	const image_t* image = iterator.image;
702 
703 	while (true) {
704 		if (++iterator.currentIndex >= iterator.symbolCount)
705 			return B_ENTRY_NOT_FOUND;
706 
707 		const struct Elf32_Sym* symbol = &Read(image->syms[
708 			iterator.currentIndex]);
709 		if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
710 				&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
711 			|| symbol->st_value == 0) {
712 			continue;
713 		}
714 
715 		*_symbolName = (const char*)PrepareAddressNoThrow(SYMNAME(image,
716 			symbol), 1);
717 		*_symbolNameLen = _SymbolNameLen(*_symbolName);
718 		*_symbolAddress = symbol->st_value + iterator.textDelta;
719 		*_symbolSize = symbol->st_size;
720 		*_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
721 			? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
722 
723 		return B_OK;
724 	}
725 }
726 
727 
728 // _FindImageAtAddress
729 const image_t *
730 SymbolLookup::_FindImageAtAddress(addr_t address) const
731 {
732 	TRACE(("SymbolLookup::_FindImageAtAddress(%p)\n", (void*)address));
733 
734 	if (fDebugArea == NULL)
735 		return NULL;
736 
737 	// iterate through the images
738 	for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head));
739 		 image;
740 		 image = &Read(*image->next)) {
741 		if (image->regions[0].vmstart <= address
742 			&& address < image->regions[0].vmstart + image->regions[0].size) {
743 			return image;
744 		}
745 	}
746 
747 	return NULL;
748 }
749 
750 
751 // _FindImageByID
752 const image_t*
753 SymbolLookup::_FindImageByID(image_id id) const
754 {
755 	if (fDebugArea == NULL)
756 		return NULL;
757 
758 	// iterate through the images
759 	for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head));
760 		 image;
761 		 image = &Read(*image->next)) {
762 		if (image->id == id)
763 			return image;
764 	}
765 
766 	return NULL;
767 }
768 
769 
770 // _FindImageFileAtAddress
771 ImageFile*
772 SymbolLookup::_FindImageFileAtAddress(addr_t address) const
773 {
774 	DoublyLinkedList<ImageFile>::ConstIterator it = fImageFiles.GetIterator();
775 	while (ImageFile* imageFile = it.Next()) {
776 		const image_info& info = imageFile->Info();
777 		if (address >= (addr_t)info.text
778 			&& address < (addr_t)info.text + info.text_size) {
779 			return imageFile;
780 		}
781 	}
782 
783 	return NULL;
784 }
785 
786 
787 // _FindImageFileByID
788 ImageFile*
789 SymbolLookup::_FindImageFileByID(image_id id) const
790 {
791 	DoublyLinkedList<ImageFile>::ConstIterator it = fImageFiles.GetIterator();
792 	while (ImageFile* imageFile = it.Next()) {
793 		if (imageFile->Info().id == id)
794 			return imageFile;
795 	}
796 
797 	return NULL;
798 }
799 
800 
801 // _SymbolNameLen
802 size_t
803 SymbolLookup::_SymbolNameLen(const char* address) const
804 {
805 	Area* area = AreaForLocalAddress(address);
806 	if (area == NULL)
807 		return 0;
808 
809 	return strnlen(address, (addr_t)area->LocalAddress() + area->Size()
810 		- (addr_t)address);
811 }
812