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 43 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 58 size_t Hash(const Function* value) const 59 { 60 return HashKey(value->FirstInstance()); 61 } 62 63 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 78 Function*& GetLink(Function* value) const 79 { 80 return value->fNext; 81 } 82 }; 83 84 85 // #pragma mark - SourceFileEntry 86 87 88 struct TeamDebugInfo::SourceFileEntry { 89 SourceFileEntry(LocatableFile* sourceFile) 90 : 91 fSourceFile(sourceFile), 92 fSourceCode(NULL) 93 { 94 fSourceFile->AcquireReference(); 95 } 96 97 ~SourceFileEntry() 98 { 99 SetSourceCode(NULL); 100 fSourceFile->ReleaseReference(); 101 } 102 103 status_t Init() 104 { 105 return B_OK; 106 } 107 108 LocatableFile* SourceFile() const 109 { 110 return fSourceFile; 111 } 112 113 FileSourceCode* GetSourceCode() const 114 { 115 return fSourceCode; 116 } 117 118 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 133 bool IsUnused() const 134 { 135 return fFunctions.IsEmpty(); 136 } 137 138 status_t AddFunction(Function* function) 139 { 140 if (!fFunctions.BinaryInsert(function, &_CompareFunctions)) 141 return B_NO_MEMORY; 142 143 return B_OK; 144 } 145 146 void RemoveFunction(Function* function) 147 { 148 int32 index = fFunctions.BinarySearchIndex(*function, 149 &_CompareFunctions); 150 if (index >= 0) 151 fFunctions.RemoveItemAt(index); 152 } 153 154 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 171 Function* FunctionAt(int32 index) const 172 { 173 return fFunctions.ItemAt(index); 174 } 175 176 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: 190 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 207 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 235 size_t HashKey(const LocatableFile* key) const 236 { 237 return (size_t)(addr_t)key; 238 } 239 240 size_t Hash(const SourceFileEntry* value) const 241 { 242 return HashKey(value->SourceFile()); 243 } 244 245 bool Compare(const LocatableFile* key, const SourceFileEntry* value) const 246 { 247 return key == value->SourceFile(); 248 } 249 250 SourceFileEntry*& GetLink(SourceFileEntry* value) const 251 { 252 return value->fNext; 253 } 254 }; 255 256 257 // #pragma mark - TeamDebugInfo 258 259 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 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 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 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 385 TeamDebugInfo::TypeExistsByName(const BString& name, 386 const TypeLookupConstraints& constraints) 387 { 388 return HasType(fTypeCache, name, constraints); 389 } 390 391 392 status_t 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 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 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 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 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 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 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 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 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* 796 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* 808 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* 818 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 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 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