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 if (function->SourceCodeState() == FUNCTION_SOURCE_LOADED) { 491 _code = function->GetSourceCode(); 492 _code->AcquireReference(); 493 return B_OK; 494 } 495 } 496 } 497 498 for (int32 i = 0; i < fImages.CountItems(); i++) { 499 ImageDebugInfo* imageInfo = fImages.ItemAt(i); 500 FunctionInstance* instance = imageInfo->FunctionAtAddress( 501 info->Address()); 502 if (instance != NULL && instance->SourceCodeState() 503 == FUNCTION_SOURCE_LOADED) { 504 _code = instance->GetSourceCode(); 505 _code->AcquireReference(); 506 return B_OK; 507 } 508 } 509 510 return B_ENTRY_NOT_FOUND; 511 } 512 513 514 status_t 515 TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo, 516 LocatableFile* imageFile, ImageDebugInfoLoadingState& _state, 517 ImageDebugInfo*& _imageDebugInfo) 518 { 519 ImageDebugInfo* imageDebugInfo = new(std::nothrow) ImageDebugInfo( 520 imageInfo); 521 if (imageDebugInfo == NULL) 522 return B_NO_MEMORY; 523 BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo, true); 524 525 for (int32 i = 0; SpecificTeamDebugInfo* specificTeamInfo 526 = fSpecificInfos.ItemAt(i); i++) { 527 SpecificImageDebugInfo* specificImageInfo; 528 status_t error = specificTeamInfo->CreateImageDebugInfo(imageInfo, 529 imageFile, _state, specificImageInfo); 530 if (error == B_OK) { 531 if (!imageDebugInfo->AddSpecificInfo(specificImageInfo)) { 532 delete specificImageInfo; 533 return B_NO_MEMORY; 534 } 535 } else if (_state.UserInputRequired()) { 536 _state.SetSpecificInfoIndex(i); 537 return error; 538 } else if (error == B_NO_MEMORY) 539 return error; 540 // fail only when out of memory 541 542 _state.ClearSpecificDebugInfoLoadingState(); 543 // if we made it this far, then we're done with current specific 544 // info, and its corresponding state object, if any, is no longer 545 // needed 546 } 547 548 status_t error = imageDebugInfo->FinishInit(fDebuggerInterface); 549 if (error != B_OK) 550 return error; 551 552 if (fMainFunction == NULL) { 553 FunctionInstance* instance = imageDebugInfo->MainFunction(); 554 if (instance != NULL) 555 fMainFunction = instance; 556 } 557 558 _imageDebugInfo = imageDebugInfoReference.Detach(); 559 return B_OK; 560 } 561 562 563 status_t 564 TeamDebugInfo::LoadSourceCode(LocatableFile* file, FileSourceCode*& _sourceCode) 565 { 566 AutoLocker<BLocker> locker(fLock); 567 568 // If we don't know the source file, there's nothing we can do. 569 SourceFileEntry* entry = fSourceFiles->Lookup(file); 570 if (entry == NULL) 571 return B_ENTRY_NOT_FOUND; 572 573 // the source might already be loaded 574 FileSourceCode* sourceCode = entry->GetSourceCode(); 575 if (sourceCode != NULL) { 576 sourceCode->AcquireReference(); 577 _sourceCode = sourceCode; 578 return B_OK; 579 } 580 581 // get the source language from some function's image debug info 582 Function* function = entry->FunctionAt(0); 583 if (function == NULL) 584 return B_ENTRY_NOT_FOUND; 585 586 FunctionDebugInfo* functionDebugInfo 587 = function->FirstInstance()->GetFunctionDebugInfo(); 588 SourceLanguage* language; 589 status_t error = functionDebugInfo->GetSpecificImageDebugInfo() 590 ->GetSourceLanguage(functionDebugInfo, language); 591 if (error != B_OK) 592 return error; 593 BReference<SourceLanguage> languageReference(language, true); 594 595 // no source code yet 596 // locker.Unlock(); 597 // TODO: It would be nice to unlock here, but we need to iterate through 598 // the images below. We could clone the list, acquire references, and 599 // unlock. Then we have to compare the list with the then current list when 600 // we're done loading. 601 602 // load the source file 603 SourceFile* sourceFile; 604 error = fFileManager->LoadSourceFile(file, sourceFile); 605 if (error != B_OK) 606 return error; 607 608 // create the source code 609 sourceCode = new(std::nothrow) FileSourceCode(file, sourceFile, language); 610 sourceFile->ReleaseReference(); 611 if (sourceCode == NULL) 612 return B_NO_MEMORY; 613 BReference<FileSourceCode> sourceCodeReference(sourceCode, true); 614 615 error = sourceCode->Init(); 616 if (error != B_OK) 617 return error; 618 619 // Iterate through all images that know the source file and ask them to add 620 // information. 621 bool anyInfo = false; 622 for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) 623 anyInfo |= imageDebugInfo->AddSourceCodeInfo(file, sourceCode) == B_OK; 624 625 if (!anyInfo) 626 return B_ENTRY_NOT_FOUND; 627 628 entry->SetSourceCode(sourceCode); 629 630 _sourceCode = sourceCodeReference.Detach(); 631 return B_OK; 632 } 633 634 635 void 636 TeamDebugInfo::ClearSourceCode(LocatableFile* sourceFile) 637 { 638 AutoLocker<BLocker> locker(fLock); 639 640 SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile); 641 if (entry != NULL) 642 entry->SetSourceCode(NULL); 643 } 644 645 646 status_t 647 TeamDebugInfo::DisassembleFunction(FunctionInstance* functionInstance, 648 DisassembledCode*& _sourceCode) 649 { 650 // allocate a buffer for the function code 651 static const target_size_t kMaxBufferSize = 64 * 1024; 652 target_size_t bufferSize = std::min(functionInstance->Size(), 653 kMaxBufferSize); 654 void* buffer = malloc(bufferSize); 655 if (buffer == NULL) 656 return B_NO_MEMORY; 657 MemoryDeleter bufferDeleter(buffer); 658 659 // read the function code 660 FunctionDebugInfo* functionDebugInfo 661 = functionInstance->GetFunctionDebugInfo(); 662 ssize_t bytesRead = functionDebugInfo->GetSpecificImageDebugInfo() 663 ->ReadCode(functionInstance->Address(), buffer, bufferSize); 664 if (bytesRead < 0) 665 return bytesRead; 666 667 return fArchitecture->DisassembleCode(functionDebugInfo, buffer, bytesRead, 668 _sourceCode); 669 } 670 671 672 status_t 673 TeamDebugInfo::AddImageDebugInfo(ImageDebugInfo* imageDebugInfo) 674 { 675 AutoLocker<BLocker> locker(fLock); 676 // We have both locks now, so that for read-only access either lock 677 // suffices. 678 679 if (!fImages.AddItem(imageDebugInfo)) 680 return B_NO_MEMORY; 681 682 // Match all of the image debug info's functions instances with functions. 683 BObjectList<SourceFileEntry> sourceFileEntries; 684 for (int32 i = 0; 685 FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) { 686 // lookup the function or create it, if it doesn't exist yet 687 Function* function = fFunctions->Lookup(instance); 688 if (function != NULL) { 689 // TODO: Also update possible user breakpoints in this function! 690 function->AddInstance(instance); 691 instance->SetFunction(function); 692 693 // The new image debug info might have additional information about 694 // the source file of the function, so remember the source file 695 // entry. 696 if (LocatableFile* sourceFile = function->SourceFile()) { 697 SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile); 698 if (entry != NULL && entry->GetSourceCode() != NULL) 699 sourceFileEntries.AddItem(entry); 700 } 701 } else { 702 function = new(std::nothrow) Function; 703 if (function == NULL) { 704 RemoveImageDebugInfo(imageDebugInfo); 705 return B_NO_MEMORY; 706 } 707 function->AddInstance(instance); 708 instance->SetFunction(function); 709 710 status_t error = _AddFunction(function); 711 // Insert after adding the instance. Otherwise the function 712 // wouldn't be hashable/comparable. 713 if (error != B_OK) { 714 function->RemoveInstance(instance); 715 instance->SetFunction(NULL); 716 RemoveImageDebugInfo(imageDebugInfo); 717 return error; 718 } 719 } 720 } 721 722 // update the source files the image debug info knows about 723 for (int32 i = 0; SourceFileEntry* entry = sourceFileEntries.ItemAt(i); 724 i++) { 725 FileSourceCode* sourceCode = entry->GetSourceCode(); 726 sourceCode->Lock(); 727 if (imageDebugInfo->AddSourceCodeInfo(entry->SourceFile(), 728 sourceCode) == B_OK) { 729 // TODO: Notify interesting parties! Iterate through all functions 730 // for this source file? 731 } 732 sourceCode->Unlock(); 733 } 734 735 return B_OK; 736 } 737 738 739 void 740 TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo* imageDebugInfo) 741 { 742 AutoLocker<BLocker> locker(fLock); 743 // We have both locks now, so that for read-only access either lock 744 // suffices. 745 746 // Remove the functions from all of the image debug info's functions 747 // instances. 748 for (int32 i = 0; 749 FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) { 750 if (Function* function = instance->GetFunction()) { 751 // TODO: Also update possible user breakpoints in this function! 752 if (function->FirstInstance() == function->LastInstance()) { 753 // function unused -- remove it 754 // Note, that we have to remove it from the hash before removing 755 // the instance, since otherwise the function cannot be compared 756 // anymore. 757 _RemoveFunction(function); 758 function->ReleaseReference(); 759 // The instance still has a reference. 760 } 761 762 function->RemoveInstance(instance); 763 instance->SetFunction(NULL); 764 // If this was the last instance, it will remove the last 765 // reference to the function. 766 } 767 } 768 769 // remove cached types from that image 770 fTypeCache->RemoveTypes(imageDebugInfo->GetImageInfo().ImageID()); 771 772 fImages.RemoveItem(imageDebugInfo); 773 } 774 775 776 ImageDebugInfo* 777 TeamDebugInfo::ImageDebugInfoByName(const char* name) const 778 { 779 for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) { 780 if (imageDebugInfo->GetImageInfo().Name() == name) 781 return imageDebugInfo; 782 } 783 784 return NULL; 785 } 786 787 788 Function* 789 TeamDebugInfo::FunctionAtSourceLocation(LocatableFile* file, 790 const SourceLocation& location) const 791 { 792 if (SourceFileEntry* entry = fSourceFiles->Lookup(file)) 793 return entry->FunctionAtLocation(location); 794 return NULL; 795 } 796 797 798 Function* 799 TeamDebugInfo::FunctionByID(FunctionID* functionID) const 800 { 801 if (SourceFunctionID* sourceFunctionID 802 = dynamic_cast<SourceFunctionID*>(functionID)) { 803 // get the source file 804 LocatableFile* file = fFileManager->GetSourceFile( 805 sourceFunctionID->SourceFilePath()); 806 if (file == NULL) 807 return NULL; 808 BReference<LocatableFile> fileReference(file, true); 809 810 if (SourceFileEntry* entry = fSourceFiles->Lookup(file)) 811 return entry->FunctionByName(functionID->FunctionName()); 812 return NULL; 813 } 814 815 ImageFunctionID* imageFunctionID 816 = dynamic_cast<ImageFunctionID*>(functionID); 817 if (imageFunctionID == NULL) 818 return NULL; 819 820 ImageDebugInfo* imageDebugInfo 821 = ImageDebugInfoByName(imageFunctionID->ImageName()); 822 if (imageDebugInfo == NULL) 823 return NULL; 824 825 FunctionInstance* functionInstance = imageDebugInfo->FunctionByName( 826 functionID->FunctionName()); 827 return functionInstance != NULL ? functionInstance->GetFunction() : NULL; 828 } 829 830 831 status_t 832 TeamDebugInfo::_AddFunction(Function* function) 833 { 834 // If the function refers to a source file, add it to the respective entry. 835 if (LocatableFile* sourceFile = function->SourceFile()) { 836 SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile); 837 if (entry == NULL) { 838 // no entry for the source file yet -- create on 839 entry = new(std::nothrow) SourceFileEntry(sourceFile); 840 if (entry == NULL) 841 return B_NO_MEMORY; 842 843 status_t error = entry->Init(); 844 if (error != B_OK) { 845 delete entry; 846 return error; 847 } 848 849 fSourceFiles->Insert(entry); 850 } 851 852 // add the function 853 status_t error = entry->AddFunction(function); 854 if (error != B_OK) { 855 if (entry->IsUnused()) { 856 fSourceFiles->Remove(entry); 857 delete entry; 858 } 859 return error; 860 } 861 } 862 863 fFunctions->Insert(function); 864 865 return B_OK; 866 } 867 868 869 void 870 TeamDebugInfo::_RemoveFunction(Function* function) 871 { 872 fFunctions->Remove(function); 873 874 // If the function refers to a source file, remove it from the respective 875 // entry. 876 if (LocatableFile* sourceFile = function->SourceFile()) { 877 if (SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile)) 878 entry->RemoveFunction(function); 879 } 880 } 881