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
40struct 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
89struct 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
187private:
188	typedef BObjectList<Function> FunctionList;
189
190private:
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
219private:
220	LocatableFile*		fSourceFile;
221	FileSourceCode*		fSourceCode;
222	FunctionList		fFunctions;
223
224public:
225	SourceFileEntry*	fNext;
226};
227
228
229// #pragma mark - SourceFileHashDefinition
230
231
232struct 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
261TeamDebugInfo::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
278TeamDebugInfo::~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
309status_t
310TeamDebugInfo::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
377status_t
378TeamDebugInfo::LookupTypeByName(const BString& name,
379	const TypeLookupConstraints& constraints, Type*& _type)
380{
381	return GetType(fTypeCache, name, constraints, _type);
382}
383
384
385bool
386TeamDebugInfo::TypeExistsByName(const BString& name,
387	const TypeLookupConstraints& constraints)
388{
389	return HasType(fTypeCache, name, constraints);
390}
391
392
393status_t
394TeamDebugInfo::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
439bool
440TeamDebugInfo::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
480status_t
481TeamDebugInfo::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			function_source_state state = function->SourceCodeState();
491			if (function->SourceCodeState() == FUNCTION_SOURCE_LOADED) {
492				_code = function->GetSourceCode();
493				_code->AcquireReference();
494				return B_OK;
495			} else if (state == FUNCTION_SOURCE_NOT_LOADED) {
496				// if the function's source state is not loaded, check
497				// if we already know the file anyways. Currently, when
498				// a source code job runs, it does so on behalf of a specific
499				// function, and consequently only sets the loaded source code
500				// on that particular function at that point in time, rather
501				// than all others sharing that same file. Consequently,
502				// set it lazily here.
503				SourceFileEntry* entry = fSourceFiles->Lookup(file);
504				if (entry != NULL) {
505					FileSourceCode* sourceCode = entry->GetSourceCode();
506					if (sourceCode != NULL) {
507						function->SetSourceCode(sourceCode,
508							FUNCTION_SOURCE_LOADED);
509						_code = sourceCode;
510						_code->AcquireReference();
511						return B_OK;
512					}
513				}
514			}
515		}
516	}
517
518	for (int32 i = 0; i < fImages.CountItems(); i++) {
519		ImageDebugInfo* imageInfo = fImages.ItemAt(i);
520		FunctionInstance* instance = imageInfo->FunctionAtAddress(
521			info->Address());
522		if (instance != NULL && instance->SourceCodeState()
523				== FUNCTION_SOURCE_LOADED) {
524			_code = instance->GetSourceCode();
525			_code->AcquireReference();
526			return B_OK;
527		}
528	}
529
530	return B_ENTRY_NOT_FOUND;
531}
532
533
534status_t
535TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo,
536	LocatableFile* imageFile, ImageDebugInfoLoadingState& _state,
537	ImageDebugInfo*& _imageDebugInfo)
538{
539	ImageDebugInfo* imageDebugInfo = new(std::nothrow) ImageDebugInfo(
540		imageInfo);
541	if (imageDebugInfo == NULL)
542		return B_NO_MEMORY;
543	BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo, true);
544
545	for (int32 i = 0; SpecificTeamDebugInfo* specificTeamInfo
546			= fSpecificInfos.ItemAt(i); i++) {
547		SpecificImageDebugInfo* specificImageInfo;
548		status_t error = specificTeamInfo->CreateImageDebugInfo(imageInfo,
549			imageFile, _state, specificImageInfo);
550		if (error == B_OK) {
551			if (!imageDebugInfo->AddSpecificInfo(specificImageInfo)) {
552				delete specificImageInfo;
553				return B_NO_MEMORY;
554			}
555		} else if (_state.UserInputRequired()) {
556			_state.SetSpecificInfoIndex(i);
557			return error;
558		} else if (error == B_NO_MEMORY)
559			return error;
560				// fail only when out of memory
561
562		_state.ClearSpecificDebugInfoLoadingState();
563			// if we made it this far, then we're done with current specific
564			// info, and its corresponding state object, if any, is no longer
565			// needed
566	}
567
568	status_t error = imageDebugInfo->FinishInit(fDebuggerInterface);
569	if (error != B_OK)
570		return error;
571
572	if (fMainFunction == NULL) {
573		FunctionInstance* instance = imageDebugInfo->MainFunction();
574		if (instance != NULL)
575			fMainFunction = instance;
576	}
577
578	_imageDebugInfo = imageDebugInfoReference.Detach();
579	return B_OK;
580}
581
582
583status_t
584TeamDebugInfo::LoadSourceCode(LocatableFile* file, FileSourceCode*& _sourceCode)
585{
586	AutoLocker<BLocker> locker(fLock);
587
588	// If we don't know the source file, there's nothing we can do.
589	SourceFileEntry* entry = fSourceFiles->Lookup(file);
590	if (entry == NULL)
591		return B_ENTRY_NOT_FOUND;
592
593	// the source might already be loaded
594	FileSourceCode* sourceCode = entry->GetSourceCode();
595	if (sourceCode != NULL) {
596		sourceCode->AcquireReference();
597		_sourceCode = sourceCode;
598		return B_OK;
599	}
600
601	// get the source language from some function's image debug info
602	Function* function = entry->FunctionAt(0);
603	if (function == NULL)
604		return B_ENTRY_NOT_FOUND;
605
606	FunctionDebugInfo* functionDebugInfo
607		= function->FirstInstance()->GetFunctionDebugInfo();
608	SourceLanguage* language;
609	status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
610		->GetSourceLanguage(functionDebugInfo, language);
611	if (error != B_OK)
612		return error;
613	BReference<SourceLanguage> languageReference(language, true);
614
615	// no source code yet
616//	locker.Unlock();
617	// TODO: It would be nice to unlock here, but we need to iterate through
618	// the images below. We could clone the list, acquire references, and
619	// unlock. Then we have to compare the list with the then current list when
620	// we're done loading.
621
622	// load the source file
623	SourceFile* sourceFile;
624	error = fFileManager->LoadSourceFile(file, sourceFile);
625	if (error != B_OK)
626		return error;
627
628	// create the source code
629	sourceCode = new(std::nothrow) FileSourceCode(file, sourceFile, language);
630	sourceFile->ReleaseReference();
631	if (sourceCode == NULL)
632		return B_NO_MEMORY;
633	BReference<FileSourceCode> sourceCodeReference(sourceCode, true);
634
635	error = sourceCode->Init();
636	if (error != B_OK)
637		return error;
638
639	// Iterate through all images that know the source file and ask them to add
640	// information.
641	bool anyInfo = false;
642	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++)
643		anyInfo |= imageDebugInfo->AddSourceCodeInfo(file, sourceCode) == B_OK;
644
645	if (!anyInfo)
646		return B_ENTRY_NOT_FOUND;
647
648	entry->SetSourceCode(sourceCode);
649
650	_sourceCode = sourceCodeReference.Detach();
651	return B_OK;
652}
653
654
655void
656TeamDebugInfo::ClearSourceCode(LocatableFile* sourceFile)
657{
658	AutoLocker<BLocker> locker(fLock);
659
660	SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile);
661	if (entry != NULL)
662		entry->SetSourceCode(NULL);
663}
664
665
666status_t
667TeamDebugInfo::DisassembleFunction(FunctionInstance* functionInstance,
668	DisassembledCode*& _sourceCode)
669{
670	// allocate a buffer for the function code
671	static const target_size_t kMaxBufferSize = 64 * 1024;
672	target_size_t bufferSize = std::min(functionInstance->Size(),
673		kMaxBufferSize);
674	void* buffer = malloc(bufferSize);
675	if (buffer == NULL)
676		return B_NO_MEMORY;
677	MemoryDeleter bufferDeleter(buffer);
678
679	// read the function code
680	FunctionDebugInfo* functionDebugInfo
681		= functionInstance->GetFunctionDebugInfo();
682	ssize_t bytesRead = functionDebugInfo->GetSpecificImageDebugInfo()
683		->ReadCode(functionInstance->Address(), buffer, bufferSize);
684	if (bytesRead < 0)
685		return bytesRead;
686
687	return fArchitecture->DisassembleCode(functionDebugInfo, buffer, bytesRead,
688		_sourceCode);
689}
690
691
692status_t
693TeamDebugInfo::AddImageDebugInfo(ImageDebugInfo* imageDebugInfo)
694{
695	AutoLocker<BLocker> locker(fLock);
696		// We have both locks now, so that for read-only access either lock
697		// suffices.
698
699	if (!fImages.AddItem(imageDebugInfo))
700		return B_NO_MEMORY;
701
702	// Match all of the image debug info's functions instances with functions.
703	BObjectList<SourceFileEntry> sourceFileEntries;
704	for (int32 i = 0;
705		FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) {
706		// lookup the function or create it, if it doesn't exist yet
707		Function* function = fFunctions->Lookup(instance);
708		if (function != NULL) {
709// TODO: Also update possible user breakpoints in this function!
710			function->AddInstance(instance);
711			instance->SetFunction(function);
712
713			// The new image debug info might have additional information about
714			// the source file of the function, so remember the source file
715			// entry.
716			if (LocatableFile* sourceFile = function->SourceFile()) {
717				SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile);
718				if (entry != NULL && entry->GetSourceCode() != NULL)
719					sourceFileEntries.AddItem(entry);
720			}
721		} else {
722			function = new(std::nothrow) Function;
723			if (function == NULL) {
724				RemoveImageDebugInfo(imageDebugInfo);
725				return B_NO_MEMORY;
726			}
727			function->AddInstance(instance);
728			instance->SetFunction(function);
729
730			status_t error = _AddFunction(function);
731				// Insert after adding the instance. Otherwise the function
732				// wouldn't be hashable/comparable.
733			if (error != B_OK) {
734				function->RemoveInstance(instance);
735				instance->SetFunction(NULL);
736				RemoveImageDebugInfo(imageDebugInfo);
737				return error;
738			}
739		}
740	}
741
742	// update the source files the image debug info knows about
743	for (int32 i = 0; SourceFileEntry* entry = sourceFileEntries.ItemAt(i);
744			i++) {
745		FileSourceCode* sourceCode = entry->GetSourceCode();
746		sourceCode->Lock();
747		if (imageDebugInfo->AddSourceCodeInfo(entry->SourceFile(),
748				sourceCode) == B_OK) {
749			// TODO: Notify interesting parties! Iterate through all functions
750			// for this source file?
751		}
752		sourceCode->Unlock();
753	}
754
755	return B_OK;
756}
757
758
759void
760TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo* imageDebugInfo)
761{
762	AutoLocker<BLocker> locker(fLock);
763		// We have both locks now, so that for read-only access either lock
764		// suffices.
765
766	// Remove the functions from all of the image debug info's functions
767	// instances.
768	for (int32 i = 0;
769		FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) {
770		if (Function* function = instance->GetFunction()) {
771// TODO: Also update possible user breakpoints in this function!
772			if (function->FirstInstance() == function->LastInstance()) {
773				// function unused -- remove it
774				// Note, that we have to remove it from the hash before removing
775				// the instance, since otherwise the function cannot be compared
776				// anymore.
777				_RemoveFunction(function);
778				function->ReleaseReference();
779					// The instance still has a reference.
780			}
781
782			function->RemoveInstance(instance);
783			instance->SetFunction(NULL);
784				// If this was the last instance, it will remove the last
785				// reference to the function.
786		}
787	}
788
789	// remove cached types from that image
790	fTypeCache->RemoveTypes(imageDebugInfo->GetImageInfo().ImageID());
791
792	fImages.RemoveItem(imageDebugInfo);
793}
794
795
796ImageDebugInfo*
797TeamDebugInfo::ImageDebugInfoByName(const char* name) const
798{
799	for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) {
800		if (imageDebugInfo->GetImageInfo().Name() == name)
801			return imageDebugInfo;
802	}
803
804	return NULL;
805}
806
807
808Function*
809TeamDebugInfo::FunctionAtSourceLocation(LocatableFile* file,
810	const SourceLocation& location) const
811{
812	if (SourceFileEntry* entry = fSourceFiles->Lookup(file))
813		return entry->FunctionAtLocation(location);
814	return NULL;
815}
816
817
818Function*
819TeamDebugInfo::FunctionByID(FunctionID* functionID) const
820{
821	if (SourceFunctionID* sourceFunctionID
822			= dynamic_cast<SourceFunctionID*>(functionID)) {
823		// get the source file
824		LocatableFile* file = fFileManager->GetSourceFile(
825			sourceFunctionID->SourceFilePath());
826		if (file == NULL)
827			return NULL;
828		BReference<LocatableFile> fileReference(file, true);
829
830		if (SourceFileEntry* entry = fSourceFiles->Lookup(file))
831			return entry->FunctionByName(functionID->FunctionName());
832		return NULL;
833	}
834
835	ImageFunctionID* imageFunctionID
836		= dynamic_cast<ImageFunctionID*>(functionID);
837	if (imageFunctionID == NULL)
838		return NULL;
839
840	ImageDebugInfo* imageDebugInfo
841		= ImageDebugInfoByName(imageFunctionID->ImageName());
842	if (imageDebugInfo == NULL)
843		return NULL;
844
845	FunctionInstance* functionInstance = imageDebugInfo->FunctionByName(
846		functionID->FunctionName());
847	return functionInstance != NULL ? functionInstance->GetFunction() : NULL;
848}
849
850
851status_t
852TeamDebugInfo::_AddFunction(Function* function)
853{
854	// If the function refers to a source file, add it to the respective entry.
855	if (LocatableFile* sourceFile = function->SourceFile()) {
856		SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile);
857		if (entry == NULL) {
858			// no entry for the source file yet -- create on
859			entry = new(std::nothrow) SourceFileEntry(sourceFile);
860			if (entry == NULL)
861				return B_NO_MEMORY;
862
863			status_t error = entry->Init();
864			if (error != B_OK) {
865				delete entry;
866				return error;
867			}
868
869			fSourceFiles->Insert(entry);
870		}
871
872		// add the function
873		status_t error = entry->AddFunction(function);
874		if (error != B_OK) {
875			if (entry->IsUnused()) {
876				fSourceFiles->Remove(entry);
877				delete entry;
878			}
879			return error;
880		}
881	}
882
883	fFunctions->Insert(function);
884
885	return B_OK;
886}
887
888
889void
890TeamDebugInfo::_RemoveFunction(Function* function)
891{
892	fFunctions->Remove(function);
893
894	// If the function refers to a source file, remove it from the respective
895	// entry.
896	if (LocatableFile* sourceFile = function->SourceFile()) {
897		if (SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile))
898			entry->RemoveFunction(function);
899	}
900}
901