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