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