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.
8 #include "TeamDebugInfo.h"
14 #include <AutoDeleter.h>
15 #include <AutoLocker.h>
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"
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"
34 #include "TypeLookupConstraints.h"
37 // #pragma mark - FunctionHashDefinition
40 struct TeamDebugInfo::FunctionHashDefinition
{
41 typedef const FunctionInstance
* KeyType
;
42 typedef Function ValueType
;
44 size_t HashKey(const FunctionInstance
* key
) const
46 // Instances without source file only equal themselves.
47 if (key
->SourceFile() == NULL
)
48 return (uint32
)(addr_t
)key
;
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();
59 size_t Hash(const Function
* value
) const
61 return HashKey(value
->FirstInstance());
64 bool Compare(const FunctionInstance
* key
, const Function
* value
) const
66 // source file must be the same
67 if (key
->SourceFile() != value
->SourceFile())
70 // Instances without source file only equal themselves.
71 if (key
->SourceFile() == NULL
)
72 return key
== value
->FirstInstance();
74 // Source location and function name must also match.
75 return key
->GetSourceLocation() == value
->GetSourceLocation()
76 && key
->Name() == value
->Name();
79 Function
*& GetLink(Function
* value
) const
86 // #pragma mark - SourceFileEntry
89 struct TeamDebugInfo::SourceFileEntry
{
90 SourceFileEntry(LocatableFile
* sourceFile
)
92 fSourceFile(sourceFile
),
95 fSourceFile
->AcquireReference();
101 fSourceFile
->ReleaseReference();
109 LocatableFile
* SourceFile() const
114 FileSourceCode
* GetSourceCode() const
119 void SetSourceCode(FileSourceCode
* sourceCode
)
121 if (sourceCode
== fSourceCode
)
124 if (fSourceCode
!= NULL
)
125 fSourceCode
->ReleaseReference();
127 fSourceCode
= sourceCode
;
129 if (fSourceCode
!= NULL
)
130 fSourceCode
->AcquireReference();
134 bool IsUnused() const
136 return fFunctions
.IsEmpty();
139 status_t
AddFunction(Function
* function
)
141 if (!fFunctions
.BinaryInsert(function
, &_CompareFunctions
))
147 void RemoveFunction(Function
* function
)
149 int32 index
= fFunctions
.BinarySearchIndex(*function
,
152 fFunctions
.RemoveItemAt(index
);
155 Function
* FunctionAtLocation(const SourceLocation
& location
) const
157 int32 index
= fFunctions
.BinarySearchIndexByKey(location
,
158 &_CompareLocationFunction
);
160 return fFunctions
.ItemAt(index
);
162 // No exact match, so we return the previous function which might still
163 // contain the location.
169 return fFunctions
.ItemAt(index
- 1);
172 Function
* FunctionAt(int32 index
) const
174 return fFunctions
.ItemAt(index
);
177 Function
* FunctionByName(const BString
& name
) const
179 // TODO: That's not exactly optimal.
180 for (int32 i
= 0; Function
* function
= fFunctions
.ItemAt(i
); i
++) {
181 if (name
== function
->Name())
188 typedef BObjectList
<Function
> FunctionList
;
191 static int _CompareFunctions(const Function
* a
, const Function
* b
)
193 SourceLocation locationA
= a
->GetSourceLocation();
194 SourceLocation locationB
= b
->GetSourceLocation();
196 if (locationA
< locationB
)
199 if (locationA
!= locationB
)
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());
208 static int _CompareLocationFunction(const SourceLocation
* location
,
209 const Function
* function
)
211 SourceLocation functionLocation
= function
->GetSourceLocation();
213 if (*location
< functionLocation
)
216 return *location
== functionLocation
? 0 : 1;
220 LocatableFile
* fSourceFile
;
221 FileSourceCode
* fSourceCode
;
222 FunctionList fFunctions
;
225 SourceFileEntry
* fNext
;
229 // #pragma mark - SourceFileHashDefinition
232 struct TeamDebugInfo::SourceFileHashDefinition
{
233 typedef const LocatableFile
* KeyType
;
234 typedef SourceFileEntry ValueType
;
236 size_t HashKey(const LocatableFile
* key
) const
238 return (size_t)(addr_t
)key
;
241 size_t Hash(const SourceFileEntry
* value
) const
243 return HashKey(value
->SourceFile());
246 bool Compare(const LocatableFile
* key
, const SourceFileEntry
* value
) const
248 return key
== value
->SourceFile();
251 SourceFileEntry
*& GetLink(SourceFileEntry
* value
) const
258 // #pragma mark - TeamDebugInfo
261 TeamDebugInfo::TeamDebugInfo(DebuggerInterface
* debuggerInterface
,
262 Architecture
* architecture
, FileManager
* fileManager
)
264 fLock("team debug info"),
265 fDebuggerInterface(debuggerInterface
),
266 fArchitecture(architecture
),
267 fFileManager(fileManager
),
268 fSpecificInfos(10, true),
274 fDebuggerInterface
->AcquireReference();
278 TeamDebugInfo::~TeamDebugInfo()
280 if (fTypeCache
!= NULL
)
281 fTypeCache
->ReleaseReference();
283 if (fSourceFiles
!= NULL
) {
284 SourceFileEntry
* entry
= fSourceFiles
->Clear(true);
285 while (entry
!= NULL
) {
286 SourceFileEntry
* next
= entry
->fNext
;
294 if (fFunctions
!= NULL
) {
295 Function
* function
= fFunctions
->Clear(true);
296 while (function
!= NULL
) {
297 Function
* next
= function
->fNext
;
298 function
->ReleaseReference();
305 fDebuggerInterface
->ReleaseReference();
310 TeamDebugInfo::Init()
313 status_t error
= fLock
.InitCheck();
317 // create function hash table
318 fFunctions
= new(std::nothrow
) FunctionTable
;
319 if (fFunctions
== NULL
)
322 error
= fFunctions
->Init();
326 // create source file hash table
327 fSourceFiles
= new(std::nothrow
) SourceFileTable
;
328 if (fSourceFiles
== NULL
)
331 error
= fSourceFiles
->Init();
335 // create a type cache
336 fTypeCache
= new(std::nothrow
) GlobalTypeCache
;
337 if (fTypeCache
== NULL
)
340 error
= fTypeCache
->Init();
344 // Create specific infos for all types of debug info we support, in
345 // descending order of expressiveness.
348 DwarfTeamDebugInfo
* dwarfInfo
= new(std::nothrow
) DwarfTeamDebugInfo(
349 fArchitecture
, fDebuggerInterface
, fFileManager
, this, this,
351 if (dwarfInfo
== NULL
|| !fSpecificInfos
.AddItem(dwarfInfo
)) {
356 error
= dwarfInfo
->Init();
360 // debugger based info
361 DebuggerTeamDebugInfo
* debuggerInfo
362 = new(std::nothrow
) DebuggerTeamDebugInfo(fDebuggerInterface
,
364 if (debuggerInfo
== NULL
|| !fSpecificInfos
.AddItem(debuggerInfo
)) {
369 error
= debuggerInfo
->Init();
378 TeamDebugInfo::LookupTypeByName(const BString
& name
,
379 const TypeLookupConstraints
& constraints
, Type
*& _type
)
381 return GetType(fTypeCache
, name
, constraints
, _type
);
386 TeamDebugInfo::TypeExistsByName(const BString
& name
,
387 const TypeLookupConstraints
& constraints
)
389 return HasType(fTypeCache
, name
, constraints
);
394 TeamDebugInfo::GetType(GlobalTypeCache
* cache
, const BString
& name
,
395 const TypeLookupConstraints
& constraints
, Type
*& _type
)
397 // maybe the type is already cached
398 AutoLocker
<GlobalTypeCache
> cacheLocker(cache
);
400 Type
* type
= cache
->GetType(name
, constraints
);
402 type
->AcquireReference();
407 cacheLocker
.Unlock();
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
);
414 for (int32 i
= 0; ImageDebugInfo
* imageDebugInfo
= fImages
.ItemAt(i
); i
++) {
415 if (images
.AddItem(imageDebugInfo
))
416 imageDebugInfo
->AcquireReference();
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
);
431 // release the references
432 for (int32 i
= 0; ImageDebugInfo
* imageDebugInfo
= images
.ItemAt(i
); i
++)
433 imageDebugInfo
->ReleaseReference();
440 TeamDebugInfo::HasType(GlobalTypeCache
* cache
, const BString
& name
,
441 const TypeLookupConstraints
& constraints
)
443 // maybe the type is already cached
444 AutoLocker
<GlobalTypeCache
> cacheLocker(cache
);
446 Type
* type
= cache
->GetType(name
, constraints
);
450 cacheLocker
.Unlock();
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
);
457 for (int32 i
= 0; ImageDebugInfo
* imageDebugInfo
= fImages
.ItemAt(i
); i
++) {
458 if (images
.AddItem(imageDebugInfo
))
459 imageDebugInfo
->AcquireReference();
465 for (int32 i
= 0; ImageDebugInfo
* imageDebugInfo
= images
.ItemAt(i
); i
++) {
466 if (imageDebugInfo
->HasType(name
, constraints
)) {
472 // release the references
473 for (int32 i
= 0; ImageDebugInfo
* imageDebugInfo
= images
.ItemAt(i
); i
++)
474 imageDebugInfo
->ReleaseReference();
481 TeamDebugInfo::GetActiveSourceCode(FunctionDebugInfo
* info
, SourceCode
*& _code
)
483 AutoLocker
<BLocker
> locker(fLock
);
485 LocatableFile
* file
= info
->SourceFile();
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();
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
);
505 FileSourceCode
* sourceCode
= entry
->GetSourceCode();
506 if (sourceCode
!= NULL
) {
507 function
->SetSourceCode(sourceCode
,
508 FUNCTION_SOURCE_LOADED
);
510 _code
->AcquireReference();
518 for (int32 i
= 0; i
< fImages
.CountItems(); i
++) {
519 ImageDebugInfo
* imageInfo
= fImages
.ItemAt(i
);
520 FunctionInstance
* instance
= imageInfo
->FunctionAtAddress(
522 if (instance
!= NULL
&& instance
->SourceCodeState()
523 == FUNCTION_SOURCE_LOADED
) {
524 _code
= instance
->GetSourceCode();
525 _code
->AcquireReference();
530 return B_ENTRY_NOT_FOUND
;
535 TeamDebugInfo::LoadImageDebugInfo(const ImageInfo
& imageInfo
,
536 LocatableFile
* imageFile
, ImageDebugInfoLoadingState
& _state
,
537 ImageDebugInfo
*& _imageDebugInfo
)
539 ImageDebugInfo
* imageDebugInfo
= new(std::nothrow
) ImageDebugInfo(
541 if (imageDebugInfo
== NULL
)
543 BReference
<ImageDebugInfo
> imageDebugInfoReference(imageDebugInfo
, true);
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
);
551 if (!imageDebugInfo
->AddSpecificInfo(specificImageInfo
)) {
552 delete specificImageInfo
;
555 } else if (_state
.UserInputRequired()) {
556 _state
.SetSpecificInfoIndex(i
);
558 } else if (error
== B_NO_MEMORY
)
560 // fail only when out of memory
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
568 status_t error
= imageDebugInfo
->FinishInit(fDebuggerInterface
);
572 if (fMainFunction
== NULL
) {
573 FunctionInstance
* instance
= imageDebugInfo
->MainFunction();
574 if (instance
!= NULL
)
575 fMainFunction
= instance
;
578 _imageDebugInfo
= imageDebugInfoReference
.Detach();
584 TeamDebugInfo::LoadSourceCode(LocatableFile
* file
, FileSourceCode
*& _sourceCode
)
586 AutoLocker
<BLocker
> locker(fLock
);
588 // If we don't know the source file, there's nothing we can do.
589 SourceFileEntry
* entry
= fSourceFiles
->Lookup(file
);
591 return B_ENTRY_NOT_FOUND
;
593 // the source might already be loaded
594 FileSourceCode
* sourceCode
= entry
->GetSourceCode();
595 if (sourceCode
!= NULL
) {
596 sourceCode
->AcquireReference();
597 _sourceCode
= sourceCode
;
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
;
606 FunctionDebugInfo
* functionDebugInfo
607 = function
->FirstInstance()->GetFunctionDebugInfo();
608 SourceLanguage
* language
;
609 status_t error
= functionDebugInfo
->GetSpecificImageDebugInfo()
610 ->GetSourceLanguage(functionDebugInfo
, language
);
613 BReference
<SourceLanguage
> languageReference(language
, true);
615 // no source code yet
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.
622 // load the source file
623 SourceFile
* sourceFile
;
624 error
= fFileManager
->LoadSourceFile(file
, sourceFile
);
628 // create the source code
629 sourceCode
= new(std::nothrow
) FileSourceCode(file
, sourceFile
, language
);
630 sourceFile
->ReleaseReference();
631 if (sourceCode
== NULL
)
633 BReference
<FileSourceCode
> sourceCodeReference(sourceCode
, true);
635 error
= sourceCode
->Init();
639 // Iterate through all images that know the source file and ask them to add
641 bool anyInfo
= false;
642 for (int32 i
= 0; ImageDebugInfo
* imageDebugInfo
= fImages
.ItemAt(i
); i
++)
643 anyInfo
|= imageDebugInfo
->AddSourceCodeInfo(file
, sourceCode
) == B_OK
;
646 return B_ENTRY_NOT_FOUND
;
648 entry
->SetSourceCode(sourceCode
);
650 _sourceCode
= sourceCodeReference
.Detach();
656 TeamDebugInfo::ClearSourceCode(LocatableFile
* sourceFile
)
658 AutoLocker
<BLocker
> locker(fLock
);
660 SourceFileEntry
* entry
= fSourceFiles
->Lookup(sourceFile
);
662 entry
->SetSourceCode(NULL
);
667 TeamDebugInfo::DisassembleFunction(FunctionInstance
* functionInstance
,
668 DisassembledCode
*& _sourceCode
)
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(),
674 void* buffer
= malloc(bufferSize
);
677 MemoryDeleter
bufferDeleter(buffer
);
679 // read the function code
680 FunctionDebugInfo
* functionDebugInfo
681 = functionInstance
->GetFunctionDebugInfo();
682 ssize_t bytesRead
= functionDebugInfo
->GetSpecificImageDebugInfo()
683 ->ReadCode(functionInstance
->Address(), buffer
, bufferSize
);
687 return fArchitecture
->DisassembleCode(functionDebugInfo
, buffer
, bytesRead
,
693 TeamDebugInfo::AddImageDebugInfo(ImageDebugInfo
* imageDebugInfo
)
695 AutoLocker
<BLocker
> locker(fLock
);
696 // We have both locks now, so that for read-only access either lock
699 if (!fImages
.AddItem(imageDebugInfo
))
702 // Match all of the image debug info's functions instances with functions.
703 BObjectList
<SourceFileEntry
> sourceFileEntries
;
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
);
713 // The new image debug info might have additional information about
714 // the source file of the function, so remember the source file
716 if (LocatableFile
* sourceFile
= function
->SourceFile()) {
717 SourceFileEntry
* entry
= fSourceFiles
->Lookup(sourceFile
);
718 if (entry
!= NULL
&& entry
->GetSourceCode() != NULL
)
719 sourceFileEntries
.AddItem(entry
);
722 function
= new(std::nothrow
) Function
;
723 if (function
== NULL
) {
724 RemoveImageDebugInfo(imageDebugInfo
);
727 function
->AddInstance(instance
);
728 instance
->SetFunction(function
);
730 status_t error
= _AddFunction(function
);
731 // Insert after adding the instance. Otherwise the function
732 // wouldn't be hashable/comparable.
734 function
->RemoveInstance(instance
);
735 instance
->SetFunction(NULL
);
736 RemoveImageDebugInfo(imageDebugInfo
);
742 // update the source files the image debug info knows about
743 for (int32 i
= 0; SourceFileEntry
* entry
= sourceFileEntries
.ItemAt(i
);
745 FileSourceCode
* sourceCode
= entry
->GetSourceCode();
747 if (imageDebugInfo
->AddSourceCodeInfo(entry
->SourceFile(),
748 sourceCode
) == B_OK
) {
749 // TODO: Notify interesting parties! Iterate through all functions
750 // for this source file?
752 sourceCode
->Unlock();
760 TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo
* imageDebugInfo
)
762 AutoLocker
<BLocker
> locker(fLock
);
763 // We have both locks now, so that for read-only access either lock
766 // Remove the functions from all of the image debug info's functions
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
777 _RemoveFunction(function
);
778 function
->ReleaseReference();
779 // The instance still has a reference.
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.
789 // remove cached types from that image
790 fTypeCache
->RemoveTypes(imageDebugInfo
->GetImageInfo().ImageID());
792 fImages
.RemoveItem(imageDebugInfo
);
797 TeamDebugInfo::ImageDebugInfoByName(const char* name
) const
799 for (int32 i
= 0; ImageDebugInfo
* imageDebugInfo
= fImages
.ItemAt(i
); i
++) {
800 if (imageDebugInfo
->GetImageInfo().Name() == name
)
801 return imageDebugInfo
;
809 TeamDebugInfo::FunctionAtSourceLocation(LocatableFile
* file
,
810 const SourceLocation
& location
) const
812 if (SourceFileEntry
* entry
= fSourceFiles
->Lookup(file
))
813 return entry
->FunctionAtLocation(location
);
819 TeamDebugInfo::FunctionByID(FunctionID
* functionID
) const
821 if (SourceFunctionID
* sourceFunctionID
822 = dynamic_cast<SourceFunctionID
*>(functionID
)) {
823 // get the source file
824 LocatableFile
* file
= fFileManager
->GetSourceFile(
825 sourceFunctionID
->SourceFilePath());
828 BReference
<LocatableFile
> fileReference(file
, true);
830 if (SourceFileEntry
* entry
= fSourceFiles
->Lookup(file
))
831 return entry
->FunctionByName(functionID
->FunctionName());
835 ImageFunctionID
* imageFunctionID
836 = dynamic_cast<ImageFunctionID
*>(functionID
);
837 if (imageFunctionID
== NULL
)
840 ImageDebugInfo
* imageDebugInfo
841 = ImageDebugInfoByName(imageFunctionID
->ImageName());
842 if (imageDebugInfo
== NULL
)
845 FunctionInstance
* functionInstance
= imageDebugInfo
->FunctionByName(
846 functionID
->FunctionName());
847 return functionInstance
!= NULL
? functionInstance
->GetFunction() : NULL
;
852 TeamDebugInfo::_AddFunction(Function
* function
)
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
);
858 // no entry for the source file yet -- create on
859 entry
= new(std::nothrow
) SourceFileEntry(sourceFile
);
863 status_t error
= entry
->Init();
869 fSourceFiles
->Insert(entry
);
873 status_t error
= entry
->AddFunction(function
);
875 if (entry
->IsUnused()) {
876 fSourceFiles
->Remove(entry
);
883 fFunctions
->Insert(function
);
890 TeamDebugInfo::_RemoveFunction(Function
* function
)
892 fFunctions
->Remove(function
);
894 // If the function refers to a source file, remove it from the respective
896 if (LocatableFile
* sourceFile
= function
->SourceFile()) {
897 if (SourceFileEntry
* entry
= fSourceFiles
->Lookup(sourceFile
))
898 entry
->RemoveFunction(function
);