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