xref: /haiku/src/kits/debugger/debug_info/TeamDebugInfo.cpp (revision 6c2abee2f5e73c3fc81c33da51ac610f8bf1117a)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2012-2016, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "TeamDebugInfo.h"
9 
10 #include <stdio.h>
11 
12 #include <new>
13 
14 #include <AutoDeleter.h>
15 #include <AutoLocker.h>
16 
17 #include "Architecture.h"
18 #include "DebuggerInterface.h"
19 #include "DebuggerTeamDebugInfo.h"
20 #include "DisassembledCode.h"
21 #include "DwarfTeamDebugInfo.h"
22 #include "FileManager.h"
23 #include "FileSourceCode.h"
24 #include "Function.h"
25 #include "FunctionID.h"
26 #include "ImageDebugInfo.h"
27 #include "ImageDebugInfoLoadingState.h"
28 #include "LocatableFile.h"
29 #include "SourceFile.h"
30 #include "SourceLanguage.h"
31 #include "SpecificImageDebugInfo.h"
32 #include "StringUtils.h"
33 #include "Type.h"
34 #include "TypeLookupConstraints.h"
35 
36 
37 // #pragma mark - FunctionHashDefinition
38 
39 
40 struct TeamDebugInfo::FunctionHashDefinition {
41 	typedef const FunctionInstance*	KeyType;
42 	typedef	Function				ValueType;
43 
44 	size_t HashKey(const FunctionInstance* key) const
45 	{
46 		// Instances without source file only equal themselves.
47 		if (key->SourceFile() == NULL)
48 			return (uint32)(addr_t)key;
49 
50 		uint32 hash = StringUtils::HashValue(key->Name());
51 		hash = hash * 17 + (uint32)(addr_t)key->SourceFile();
52 		SourceLocation location = key->GetSourceLocation();
53 		hash = hash * 17 + location.Line();
54 		hash = hash * 17 + location.Column();
55 
56 		return hash;
57 	}
58 
59 	size_t Hash(const Function* value) const
60 	{
61 		return HashKey(value->FirstInstance());
62 	}
63 
64 	bool Compare(const FunctionInstance* key, const Function* value) const
65 	{
66 		// source file must be the same
67 		if (key->SourceFile() != value->SourceFile())
68 			return false;
69 
70 		// Instances without source file only equal themselves.
71 		if (key->SourceFile() == NULL)
72 			return key == value->FirstInstance();
73 
74 		// Source location and function name must also match.
75 		return key->GetSourceLocation() == value->GetSourceLocation()
76 			&& key->Name() == value->Name();
77 	}
78 
79 	Function*& GetLink(Function* value) const
80 	{
81 		return value->fNext;
82 	}
83 };
84 
85 
86 // #pragma mark - SourceFileEntry
87 
88 
89 struct TeamDebugInfo::SourceFileEntry {
90 	SourceFileEntry(LocatableFile* sourceFile)
91 		:
92 		fSourceFile(sourceFile),
93 		fSourceCode(NULL)
94 	{
95 		fSourceFile->AcquireReference();
96 	}
97 
98 	~SourceFileEntry()
99 	{
100 		SetSourceCode(NULL);
101 		fSourceFile->ReleaseReference();
102 	}
103 
104 	status_t Init()
105 	{
106 		return B_OK;
107 	}
108 
109 	LocatableFile* SourceFile() const
110 	{
111 		return fSourceFile;
112 	}
113 
114 	FileSourceCode* GetSourceCode() const
115 	{
116 		return fSourceCode;
117 	}
118 
119 	void SetSourceCode(FileSourceCode* sourceCode)
120 	{
121 		if (sourceCode == fSourceCode)
122 			return;
123 
124 		if (fSourceCode != NULL)
125 			fSourceCode->ReleaseReference();
126 
127 		fSourceCode = sourceCode;
128 
129 		if (fSourceCode != NULL)
130 			fSourceCode->AcquireReference();
131 	}
132 
133 
134 	bool IsUnused() const
135 	{
136 		return fFunctions.IsEmpty();
137 	}
138 
139 	status_t AddFunction(Function* function)
140 	{
141 		if (!fFunctions.BinaryInsert(function, &_CompareFunctions))
142 			return B_NO_MEMORY;
143 
144 		return B_OK;
145 	}
146 
147 	void RemoveFunction(Function* function)
148 	{
149 		int32 index = fFunctions.BinarySearchIndex(*function,
150 			&_CompareFunctions);
151 		if (index >= 0)
152 			fFunctions.RemoveItemAt(index);
153 	}
154 
155 	Function* FunctionAtLocation(const SourceLocation& location) const
156 	{
157 		int32 index = fFunctions.BinarySearchIndexByKey(location,
158 			&_CompareLocationFunction);
159 		if (index >= 0)
160 			return fFunctions.ItemAt(index);
161 
162 		// No exact match, so we return the previous function which might still
163 		// contain the location.
164 		index = -index - 1;
165 
166 		if (index == 0)
167 			return NULL;
168 
169 		return fFunctions.ItemAt(index - 1);
170 	}
171 
172 	Function* FunctionAt(int32 index) const
173 	{
174 		return fFunctions.ItemAt(index);
175 	}
176 
177 	Function* FunctionByName(const BString& name) const
178 	{
179 		// TODO: That's not exactly optimal.
180 		for (int32 i = 0; Function* function = fFunctions.ItemAt(i); i++) {
181 			if (name == function->Name())
182 				return function;
183 		}
184 		return NULL;
185 	}
186 
187 private:
188 	typedef BObjectList<Function> FunctionList;
189 
190 private:
191 	static int _CompareFunctions(const Function* a, const Function* b)
192 	{
193 		SourceLocation locationA = a->GetSourceLocation();
194 		SourceLocation locationB = b->GetSourceLocation();
195 
196 		if (locationA < locationB)
197 			return -1;
198 
199 		if (locationA != locationB )
200 			return 1;
201 
202 		// if the locations match we still need to compare by name to be
203 		// certain, since differently typed instantiations of template
204 		// functions will have the same source file and location
205 		return a->Name().Compare(b->Name());
206 	}
207 
208 	static int _CompareLocationFunction(const SourceLocation* location,
209 		const Function* function)
210 	{
211 		SourceLocation functionLocation = function->GetSourceLocation();
212 
213 		if (*location < functionLocation)
214 			return -1;
215 
216 		return *location == functionLocation ? 0 : 1;
217 	}
218 
219 private:
220 	LocatableFile*		fSourceFile;
221 	FileSourceCode*		fSourceCode;
222 	FunctionList		fFunctions;
223 
224 public:
225 	SourceFileEntry*	fNext;
226 };
227 
228 
229 // #pragma mark - SourceFileHashDefinition
230 
231 
232 struct TeamDebugInfo::SourceFileHashDefinition {
233 	typedef const LocatableFile*	KeyType;
234 	typedef	SourceFileEntry			ValueType;
235 
236 	size_t HashKey(const LocatableFile* key) const
237 	{
238 		return (size_t)(addr_t)key;
239 	}
240 
241 	size_t Hash(const SourceFileEntry* value) const
242 	{
243 		return HashKey(value->SourceFile());
244 	}
245 
246 	bool Compare(const LocatableFile* key, const SourceFileEntry* value) const
247 	{
248 		return key == value->SourceFile();
249 	}
250 
251 	SourceFileEntry*& GetLink(SourceFileEntry* value) const
252 	{
253 		return value->fNext;
254 	}
255 };
256 
257 
258 // #pragma mark - TeamDebugInfo
259 
260 
261 TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
262 	Architecture* architecture, FileManager* fileManager)
263 	:
264 	fLock("team debug info"),
265 	fDebuggerInterface(debuggerInterface),
266 	fArchitecture(architecture),
267 	fFileManager(fileManager),
268 	fSpecificInfos(10, true),
269 	fFunctions(NULL),
270 	fSourceFiles(NULL),
271 	fTypeCache(NULL),
272 	fMainFunction(NULL)
273 {
274 	fDebuggerInterface->AcquireReference();
275 }
276 
277 
278 TeamDebugInfo::~TeamDebugInfo()
279 {
280 	if (fTypeCache != NULL)
281 		fTypeCache->ReleaseReference();
282 
283 	if (fSourceFiles != NULL) {
284 		SourceFileEntry* entry = fSourceFiles->Clear(true);
285 		while (entry != NULL) {
286 			SourceFileEntry* next = entry->fNext;
287 			delete entry;
288 			entry = next;
289 		}
290 
291 		delete fSourceFiles;
292 	}
293 
294 	if (fFunctions != NULL) {
295 		Function* function = fFunctions->Clear(true);
296 		while (function != NULL) {
297 			Function* next = function->fNext;
298 			function->ReleaseReference();
299 			function = next;
300 		}
301 
302 		delete fFunctions;
303 	}
304 
305 	fDebuggerInterface->ReleaseReference();
306 }
307 
308 
309 status_t
310 TeamDebugInfo::Init()
311 {
312 	// check the lock
313 	status_t error = fLock.InitCheck();
314 	if (error != B_OK)
315 		return error;
316 
317 	// create function hash table
318 	fFunctions = new(std::nothrow) FunctionTable;
319 	if (fFunctions == NULL)
320 		return B_NO_MEMORY;
321 
322 	error = fFunctions->Init();
323 	if (error != B_OK)
324 		return error;
325 
326 	// create source file hash table
327 	fSourceFiles = new(std::nothrow) SourceFileTable;
328 	if (fSourceFiles == NULL)
329 		return B_NO_MEMORY;
330 
331 	error = fSourceFiles->Init();
332 	if (error != B_OK)
333 		return error;
334 
335 	// create a type cache
336 	fTypeCache = new(std::nothrow) GlobalTypeCache;
337 	if (fTypeCache == NULL)
338 		return B_NO_MEMORY;
339 
340 	error = fTypeCache->Init();
341 	if (error != B_OK)
342 		return error;
343 
344 	// Create specific infos for all types of debug info we support, in
345 	// descending order of expressiveness.
346 
347 	// DWARF
348 	DwarfTeamDebugInfo* dwarfInfo = new(std::nothrow) DwarfTeamDebugInfo(
349 		fArchitecture, fDebuggerInterface, fFileManager, this, this,
350 		fTypeCache);
351 	if (dwarfInfo == NULL || !fSpecificInfos.AddItem(dwarfInfo)) {
352 		delete dwarfInfo;
353 		return B_NO_MEMORY;
354 	}
355 
356 	error = dwarfInfo->Init();
357 	if (error != B_OK)
358 		return error;
359 
360 	// debugger based info
361 	DebuggerTeamDebugInfo* debuggerInfo
362 		= new(std::nothrow) DebuggerTeamDebugInfo(fDebuggerInterface,
363 			fArchitecture);
364 	if (debuggerInfo == NULL || !fSpecificInfos.AddItem(debuggerInfo)) {
365 		delete debuggerInfo;
366 		return B_NO_MEMORY;
367 	}
368 
369 	error = debuggerInfo->Init();
370 	if (error != B_OK)
371 		return error;
372 
373 	return B_OK;
374 }
375 
376 
377 status_t
378 TeamDebugInfo::LookupTypeByName(const BString& name,
379 	const TypeLookupConstraints& constraints, Type*& _type)
380 {
381 	return GetType(fTypeCache, name, constraints, _type);
382 }
383 
384 
385 bool
386 TeamDebugInfo::TypeExistsByName(const BString& name,
387 	const TypeLookupConstraints& constraints)
388 {
389 	return HasType(fTypeCache, name, constraints);
390 }
391 
392 
393 status_t
394 TeamDebugInfo::GetType(GlobalTypeCache* cache, const BString& name,
395 	const TypeLookupConstraints& constraints, Type*& _type)
396 {
397 	// maybe the type is already cached
398 	AutoLocker<GlobalTypeCache> cacheLocker(cache);
399 
400 	Type* type = cache->GetType(name, constraints);
401 	if (type != NULL) {
402 		type->AcquireReference();
403 		_type = type;
404 		return B_OK;
405 	}
406 
407 	cacheLocker.Unlock();
408 
409 	// Clone the image list and get references to the images, so we can iterate
410 	// through them without locking.
411 	AutoLocker<BLocker> locker(fLock);
412 
413 	ImageList images;
414 	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) {
415 		if (images.AddItem(imageDebugInfo))
416 			imageDebugInfo->AcquireReference();
417 	}
418 
419 	locker.Unlock();
420 
421 	// get the type
422 	status_t error = B_ENTRY_NOT_FOUND;
423 	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = images.ItemAt(i); i++) {
424 		error = imageDebugInfo->GetType(cache, name, constraints, type);
425 		if (error == B_OK) {
426 			_type = type;
427 			break;
428 		}
429 	}
430 
431 	// release the references
432 	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = images.ItemAt(i); i++)
433 		imageDebugInfo->ReleaseReference();
434 
435 	return error;
436 }
437 
438 
439 bool
440 TeamDebugInfo::HasType(GlobalTypeCache* cache, const BString& name,
441 	const TypeLookupConstraints& constraints)
442 {
443 	// maybe the type is already cached
444 	AutoLocker<GlobalTypeCache> cacheLocker(cache);
445 
446 	Type* type = cache->GetType(name, constraints);
447 	if (type != NULL)
448 		return true;
449 
450 	cacheLocker.Unlock();
451 
452 	// Clone the image list and get references to the images, so we can iterate
453 	// through them without locking.
454 	AutoLocker<BLocker> locker(fLock);
455 
456 	ImageList images;
457 	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) {
458 		if (images.AddItem(imageDebugInfo))
459 			imageDebugInfo->AcquireReference();
460 	}
461 
462 	locker.Unlock();
463 
464 	bool found = false;
465 	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = images.ItemAt(i); i++) {
466 		if (imageDebugInfo->HasType(name, constraints)) {
467 			found = true;
468 			break;
469 		}
470 	}
471 
472 	// release the references
473 	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = images.ItemAt(i); i++)
474 		imageDebugInfo->ReleaseReference();
475 
476 	return found;
477 }
478 
479 
480 status_t
481 TeamDebugInfo::GetActiveSourceCode(FunctionDebugInfo* info, SourceCode*& _code)
482 {
483 	AutoLocker<BLocker> locker(fLock);
484 
485 	LocatableFile* file = info->SourceFile();
486 	if (file != NULL) {
487 		Function* function = FunctionAtSourceLocation(file,
488 			info->SourceStartLocation());
489 		if (function != NULL) {
490 			if (function->SourceCodeState() == FUNCTION_SOURCE_LOADED) {
491 				_code = function->GetSourceCode();
492 				_code->AcquireReference();
493 				return B_OK;
494 			}
495 		}
496 	}
497 
498 	for (int32 i = 0; i < fImages.CountItems(); i++) {
499 		ImageDebugInfo* imageInfo = fImages.ItemAt(i);
500 		FunctionInstance* instance = imageInfo->FunctionAtAddress(
501 			info->Address());
502 		if (instance != NULL && instance->SourceCodeState()
503 				== FUNCTION_SOURCE_LOADED) {
504 			_code = instance->GetSourceCode();
505 			_code->AcquireReference();
506 			return B_OK;
507 		}
508 	}
509 
510 	return B_ENTRY_NOT_FOUND;
511 }
512 
513 
514 status_t
515 TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo,
516 	LocatableFile* imageFile, ImageDebugInfoLoadingState& _state,
517 	ImageDebugInfo*& _imageDebugInfo)
518 {
519 	ImageDebugInfo* imageDebugInfo = new(std::nothrow) ImageDebugInfo(
520 		imageInfo);
521 	if (imageDebugInfo == NULL)
522 		return B_NO_MEMORY;
523 	BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo, true);
524 
525 	for (int32 i = 0; SpecificTeamDebugInfo* specificTeamInfo
526 			= fSpecificInfos.ItemAt(i); i++) {
527 		SpecificImageDebugInfo* specificImageInfo;
528 		status_t error = specificTeamInfo->CreateImageDebugInfo(imageInfo,
529 			imageFile, _state, specificImageInfo);
530 		if (error == B_OK) {
531 			if (!imageDebugInfo->AddSpecificInfo(specificImageInfo)) {
532 				delete specificImageInfo;
533 				return B_NO_MEMORY;
534 			}
535 		} else if (_state.UserInputRequired()) {
536 			_state.SetSpecificInfoIndex(i);
537 			return error;
538 		} else if (error == B_NO_MEMORY)
539 			return error;
540 				// fail only when out of memory
541 
542 		_state.ClearSpecificDebugInfoLoadingState();
543 			// if we made it this far, then we're done with current specific
544 			// info, and its corresponding state object, if any, is no longer
545 			// needed
546 	}
547 
548 	status_t error = imageDebugInfo->FinishInit(fDebuggerInterface);
549 	if (error != B_OK)
550 		return error;
551 
552 	if (fMainFunction == NULL) {
553 		FunctionInstance* instance = imageDebugInfo->MainFunction();
554 		if (instance != NULL)
555 			fMainFunction = instance;
556 	}
557 
558 	_imageDebugInfo = imageDebugInfoReference.Detach();
559 	return B_OK;
560 }
561 
562 
563 status_t
564 TeamDebugInfo::LoadSourceCode(LocatableFile* file, FileSourceCode*& _sourceCode)
565 {
566 	AutoLocker<BLocker> locker(fLock);
567 
568 	// If we don't know the source file, there's nothing we can do.
569 	SourceFileEntry* entry = fSourceFiles->Lookup(file);
570 	if (entry == NULL)
571 		return B_ENTRY_NOT_FOUND;
572 
573 	// the source might already be loaded
574 	FileSourceCode* sourceCode = entry->GetSourceCode();
575 	if (sourceCode != NULL) {
576 		sourceCode->AcquireReference();
577 		_sourceCode = sourceCode;
578 		return B_OK;
579 	}
580 
581 	// get the source language from some function's image debug info
582 	Function* function = entry->FunctionAt(0);
583 	if (function == NULL)
584 		return B_ENTRY_NOT_FOUND;
585 
586 	FunctionDebugInfo* functionDebugInfo
587 		= function->FirstInstance()->GetFunctionDebugInfo();
588 	SourceLanguage* language;
589 	status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
590 		->GetSourceLanguage(functionDebugInfo, language);
591 	if (error != B_OK)
592 		return error;
593 	BReference<SourceLanguage> languageReference(language, true);
594 
595 	// no source code yet
596 //	locker.Unlock();
597 	// TODO: It would be nice to unlock here, but we need to iterate through
598 	// the images below. We could clone the list, acquire references, and
599 	// unlock. Then we have to compare the list with the then current list when
600 	// we're done loading.
601 
602 	// load the source file
603 	SourceFile* sourceFile;
604 	error = fFileManager->LoadSourceFile(file, sourceFile);
605 	if (error != B_OK)
606 		return error;
607 
608 	// create the source code
609 	sourceCode = new(std::nothrow) FileSourceCode(file, sourceFile, language);
610 	sourceFile->ReleaseReference();
611 	if (sourceCode == NULL)
612 		return B_NO_MEMORY;
613 	BReference<FileSourceCode> sourceCodeReference(sourceCode, true);
614 
615 	error = sourceCode->Init();
616 	if (error != B_OK)
617 		return error;
618 
619 	// Iterate through all images that know the source file and ask them to add
620 	// information.
621 	bool anyInfo = false;
622 	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++)
623 		anyInfo |= imageDebugInfo->AddSourceCodeInfo(file, sourceCode) == B_OK;
624 
625 	if (!anyInfo)
626 		return B_ENTRY_NOT_FOUND;
627 
628 	entry->SetSourceCode(sourceCode);
629 
630 	_sourceCode = sourceCodeReference.Detach();
631 	return B_OK;
632 }
633 
634 
635 void
636 TeamDebugInfo::ClearSourceCode(LocatableFile* sourceFile)
637 {
638 	AutoLocker<BLocker> locker(fLock);
639 
640 	SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile);
641 	if (entry != NULL)
642 		entry->SetSourceCode(NULL);
643 }
644 
645 
646 status_t
647 TeamDebugInfo::DisassembleFunction(FunctionInstance* functionInstance,
648 	DisassembledCode*& _sourceCode)
649 {
650 	// allocate a buffer for the function code
651 	static const target_size_t kMaxBufferSize = 64 * 1024;
652 	target_size_t bufferSize = std::min(functionInstance->Size(),
653 		kMaxBufferSize);
654 	void* buffer = malloc(bufferSize);
655 	if (buffer == NULL)
656 		return B_NO_MEMORY;
657 	MemoryDeleter bufferDeleter(buffer);
658 
659 	// read the function code
660 	FunctionDebugInfo* functionDebugInfo
661 		= functionInstance->GetFunctionDebugInfo();
662 	ssize_t bytesRead = functionDebugInfo->GetSpecificImageDebugInfo()
663 		->ReadCode(functionInstance->Address(), buffer, bufferSize);
664 	if (bytesRead < 0)
665 		return bytesRead;
666 
667 	return fArchitecture->DisassembleCode(functionDebugInfo, buffer, bytesRead,
668 		_sourceCode);
669 }
670 
671 
672 status_t
673 TeamDebugInfo::AddImageDebugInfo(ImageDebugInfo* imageDebugInfo)
674 {
675 	AutoLocker<BLocker> locker(fLock);
676 		// We have both locks now, so that for read-only access either lock
677 		// suffices.
678 
679 	if (!fImages.AddItem(imageDebugInfo))
680 		return B_NO_MEMORY;
681 
682 	// Match all of the image debug info's functions instances with functions.
683 	BObjectList<SourceFileEntry> sourceFileEntries;
684 	for (int32 i = 0;
685 		FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) {
686 		// lookup the function or create it, if it doesn't exist yet
687 		Function* function = fFunctions->Lookup(instance);
688 		if (function != NULL) {
689 // TODO: Also update possible user breakpoints in this function!
690 			function->AddInstance(instance);
691 			instance->SetFunction(function);
692 
693 			// The new image debug info might have additional information about
694 			// the source file of the function, so remember the source file
695 			// entry.
696 			if (LocatableFile* sourceFile = function->SourceFile()) {
697 				SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile);
698 				if (entry != NULL && entry->GetSourceCode() != NULL)
699 					sourceFileEntries.AddItem(entry);
700 			}
701 		} else {
702 			function = new(std::nothrow) Function;
703 			if (function == NULL) {
704 				RemoveImageDebugInfo(imageDebugInfo);
705 				return B_NO_MEMORY;
706 			}
707 			function->AddInstance(instance);
708 			instance->SetFunction(function);
709 
710 			status_t error = _AddFunction(function);
711 				// Insert after adding the instance. Otherwise the function
712 				// wouldn't be hashable/comparable.
713 			if (error != B_OK) {
714 				function->RemoveInstance(instance);
715 				instance->SetFunction(NULL);
716 				RemoveImageDebugInfo(imageDebugInfo);
717 				return error;
718 			}
719 		}
720 	}
721 
722 	// update the source files the image debug info knows about
723 	for (int32 i = 0; SourceFileEntry* entry = sourceFileEntries.ItemAt(i);
724 			i++) {
725 		FileSourceCode* sourceCode = entry->GetSourceCode();
726 		sourceCode->Lock();
727 		if (imageDebugInfo->AddSourceCodeInfo(entry->SourceFile(),
728 				sourceCode) == B_OK) {
729 			// TODO: Notify interesting parties! Iterate through all functions
730 			// for this source file?
731 		}
732 		sourceCode->Unlock();
733 	}
734 
735 	return B_OK;
736 }
737 
738 
739 void
740 TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo* imageDebugInfo)
741 {
742 	AutoLocker<BLocker> locker(fLock);
743 		// We have both locks now, so that for read-only access either lock
744 		// suffices.
745 
746 	// Remove the functions from all of the image debug info's functions
747 	// instances.
748 	for (int32 i = 0;
749 		FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) {
750 		if (Function* function = instance->GetFunction()) {
751 // TODO: Also update possible user breakpoints in this function!
752 			if (function->FirstInstance() == function->LastInstance()) {
753 				// function unused -- remove it
754 				// Note, that we have to remove it from the hash before removing
755 				// the instance, since otherwise the function cannot be compared
756 				// anymore.
757 				_RemoveFunction(function);
758 				function->ReleaseReference();
759 					// The instance still has a reference.
760 			}
761 
762 			function->RemoveInstance(instance);
763 			instance->SetFunction(NULL);
764 				// If this was the last instance, it will remove the last
765 				// reference to the function.
766 		}
767 	}
768 
769 	// remove cached types from that image
770 	fTypeCache->RemoveTypes(imageDebugInfo->GetImageInfo().ImageID());
771 
772 	fImages.RemoveItem(imageDebugInfo);
773 }
774 
775 
776 ImageDebugInfo*
777 TeamDebugInfo::ImageDebugInfoByName(const char* name) const
778 {
779 	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) {
780 		if (imageDebugInfo->GetImageInfo().Name() == name)
781 			return imageDebugInfo;
782 	}
783 
784 	return NULL;
785 }
786 
787 
788 Function*
789 TeamDebugInfo::FunctionAtSourceLocation(LocatableFile* file,
790 	const SourceLocation& location) const
791 {
792 	if (SourceFileEntry* entry = fSourceFiles->Lookup(file))
793 		return entry->FunctionAtLocation(location);
794 	return NULL;
795 }
796 
797 
798 Function*
799 TeamDebugInfo::FunctionByID(FunctionID* functionID) const
800 {
801 	if (SourceFunctionID* sourceFunctionID
802 			= dynamic_cast<SourceFunctionID*>(functionID)) {
803 		// get the source file
804 		LocatableFile* file = fFileManager->GetSourceFile(
805 			sourceFunctionID->SourceFilePath());
806 		if (file == NULL)
807 			return NULL;
808 		BReference<LocatableFile> fileReference(file, true);
809 
810 		if (SourceFileEntry* entry = fSourceFiles->Lookup(file))
811 			return entry->FunctionByName(functionID->FunctionName());
812 		return NULL;
813 	}
814 
815 	ImageFunctionID* imageFunctionID
816 		= dynamic_cast<ImageFunctionID*>(functionID);
817 	if (imageFunctionID == NULL)
818 		return NULL;
819 
820 	ImageDebugInfo* imageDebugInfo
821 		= ImageDebugInfoByName(imageFunctionID->ImageName());
822 	if (imageDebugInfo == NULL)
823 		return NULL;
824 
825 	FunctionInstance* functionInstance = imageDebugInfo->FunctionByName(
826 		functionID->FunctionName());
827 	return functionInstance != NULL ? functionInstance->GetFunction() : NULL;
828 }
829 
830 
831 status_t
832 TeamDebugInfo::_AddFunction(Function* function)
833 {
834 	// If the function refers to a source file, add it to the respective entry.
835 	if (LocatableFile* sourceFile = function->SourceFile()) {
836 		SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile);
837 		if (entry == NULL) {
838 			// no entry for the source file yet -- create on
839 			entry = new(std::nothrow) SourceFileEntry(sourceFile);
840 			if (entry == NULL)
841 				return B_NO_MEMORY;
842 
843 			status_t error = entry->Init();
844 			if (error != B_OK) {
845 				delete entry;
846 				return error;
847 			}
848 
849 			fSourceFiles->Insert(entry);
850 		}
851 
852 		// add the function
853 		status_t error = entry->AddFunction(function);
854 		if (error != B_OK) {
855 			if (entry->IsUnused()) {
856 				fSourceFiles->Remove(entry);
857 				delete entry;
858 			}
859 			return error;
860 		}
861 	}
862 
863 	fFunctions->Insert(function);
864 
865 	return B_OK;
866 }
867 
868 
869 void
870 TeamDebugInfo::_RemoveFunction(Function* function)
871 {
872 	fFunctions->Remove(function);
873 
874 	// If the function refers to a source file, remove it from the respective
875 	// entry.
876 	if (LocatableFile* sourceFile = function->SourceFile()) {
877 		if (SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile))
878 			entry->RemoveFunction(function);
879 	}
880 }
881