xref: /haiku/src/kits/debugger/debug_info/TeamDebugInfo.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 			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 
534 status_t
535 TeamDebugInfo::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 
583 status_t
584 TeamDebugInfo::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 
655 void
656 TeamDebugInfo::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 
666 status_t
667 TeamDebugInfo::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 
692 status_t
693 TeamDebugInfo::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 
759 void
760 TeamDebugInfo::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 
796 ImageDebugInfo*
797 TeamDebugInfo::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 
808 Function*
809 TeamDebugInfo::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 
818 Function*
819 TeamDebugInfo::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 
851 status_t
852 TeamDebugInfo::_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 
889 void
890 TeamDebugInfo::_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