1/* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include "Team.h" 8 9#include <stdio.h> 10 11#include <new> 12 13#include <AutoLocker.h> 14 15#include "Breakpoint.h" 16#include "DisassembledCode.h" 17#include "FileSourceCode.h" 18#include "Function.h" 19#include "ImageDebugInfo.h" 20#include "SourceCode.h" 21#include "SpecificImageDebugInfo.h" 22#include "Statement.h" 23#include "TeamDebugInfo.h" 24#include "Tracing.h" 25#include "Watchpoint.h" 26 27 28// #pragma mark - BreakpointByAddressPredicate 29 30 31struct Team::BreakpointByAddressPredicate 32 : UnaryPredicate<Breakpoint> { 33 BreakpointByAddressPredicate(target_addr_t address) 34 : 35 fAddress(address) 36 { 37 } 38 39 virtual int operator()(const Breakpoint* breakpoint) const 40 { 41 return -Breakpoint::CompareAddressBreakpoint(&fAddress, breakpoint); 42 } 43 44private: 45 target_addr_t fAddress; 46}; 47 48 49// #pragma mark - WatchpointByAddressPredicate 50 51 52struct Team::WatchpointByAddressPredicate 53 : UnaryPredicate<Watchpoint> { 54 WatchpointByAddressPredicate(target_addr_t address) 55 : 56 fAddress(address) 57 { 58 } 59 60 virtual int operator()(const Watchpoint* watchpoint) const 61 { 62 return -Watchpoint::CompareAddressWatchpoint(&fAddress, watchpoint); 63 } 64 65private: 66 target_addr_t fAddress; 67}; 68 69 70// #pragma mark - Team 71 72 73Team::Team(team_id teamID, TeamMemory* teamMemory, Architecture* architecture, 74 TeamDebugInfo* debugInfo, TeamTypeInformation* typeInformation) 75 : 76 fLock("team lock"), 77 fID(teamID), 78 fTeamMemory(teamMemory), 79 fTypeInformation(typeInformation), 80 fArchitecture(architecture), 81 fDebugInfo(debugInfo) 82{ 83 fDebugInfo->AcquireReference(); 84} 85 86 87Team::~Team() 88{ 89 while (UserBreakpoint* userBreakpoint = fUserBreakpoints.RemoveHead()) 90 userBreakpoint->ReleaseReference(); 91 92 for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++) 93 breakpoint->ReleaseReference(); 94 95 for (int32 i = 0; Watchpoint* watchpoint = fWatchpoints.ItemAt(i); i++) 96 watchpoint->ReleaseReference(); 97 98 while (Image* image = fImages.RemoveHead()) 99 image->ReleaseReference(); 100 101 while (Thread* thread = fThreads.RemoveHead()) 102 thread->ReleaseReference(); 103 104 fDebugInfo->ReleaseReference(); 105} 106 107 108status_t 109Team::Init() 110{ 111 return fLock.InitCheck(); 112} 113 114 115void 116Team::SetName(const BString& name) 117{ 118 fName = name; 119} 120 121 122void 123Team::AddThread(Thread* thread) 124{ 125 fThreads.Add(thread); 126 _NotifyThreadAdded(thread); 127} 128 129 130 131status_t 132Team::AddThread(const ThreadInfo& threadInfo, Thread** _thread) 133{ 134 Thread* thread = new(std::nothrow) Thread(this, threadInfo.ThreadID()); 135 if (thread == NULL) 136 return B_NO_MEMORY; 137 138 status_t error = thread->Init(); 139 if (error != B_OK) { 140 delete thread; 141 return error; 142 } 143 144 thread->SetName(threadInfo.Name()); 145 AddThread(thread); 146 147 if (_thread != NULL) 148 *_thread = thread; 149 150 return B_OK; 151} 152 153 154void 155Team::RemoveThread(Thread* thread) 156{ 157 fThreads.Remove(thread); 158 _NotifyThreadRemoved(thread); 159} 160 161 162bool 163Team::RemoveThread(thread_id threadID) 164{ 165 Thread* thread = ThreadByID(threadID); 166 if (thread == NULL) 167 return false; 168 169 RemoveThread(thread); 170 thread->ReleaseReference(); 171 return true; 172} 173 174 175Thread* 176Team::ThreadByID(thread_id threadID) const 177{ 178 for (ThreadList::ConstIterator it = fThreads.GetIterator(); 179 Thread* thread = it.Next();) { 180 if (thread->ID() == threadID) 181 return thread; 182 } 183 184 return NULL; 185} 186 187 188const ThreadList& 189Team::Threads() const 190{ 191 return fThreads; 192} 193 194 195status_t 196Team::AddImage(const ImageInfo& imageInfo, LocatableFile* imageFile, 197 Image** _image) 198{ 199 Image* image = new(std::nothrow) Image(this, imageInfo, imageFile); 200 if (image == NULL) 201 return B_NO_MEMORY; 202 203 status_t error = image->Init(); 204 if (error != B_OK) { 205 delete image; 206 return error; 207 } 208 209 if (image->Type() == B_APP_IMAGE) 210 SetName(image->Name()); 211 212 fImages.Add(image); 213 _NotifyImageAdded(image); 214 215 if (_image != NULL) 216 *_image = image; 217 218 return B_OK; 219} 220 221 222void 223Team::RemoveImage(Image* image) 224{ 225 fImages.Remove(image); 226 _NotifyImageRemoved(image); 227} 228 229 230bool 231Team::RemoveImage(image_id imageID) 232{ 233 Image* image = ImageByID(imageID); 234 if (image == NULL) 235 return false; 236 237 RemoveImage(image); 238 image->ReleaseReference(); 239 return true; 240} 241 242 243Image* 244Team::ImageByID(image_id imageID) const 245{ 246 for (ImageList::ConstIterator it = fImages.GetIterator(); 247 Image* image = it.Next();) { 248 if (image->ID() == imageID) 249 return image; 250 } 251 252 return NULL; 253} 254 255 256Image* 257Team::ImageByAddress(target_addr_t address) const 258{ 259 for (ImageList::ConstIterator it = fImages.GetIterator(); 260 Image* image = it.Next();) { 261 if (image->ContainsAddress(address)) 262 return image; 263 } 264 265 return NULL; 266} 267 268 269const ImageList& 270Team::Images() const 271{ 272 return fImages; 273} 274 275 276bool 277Team::AddBreakpoint(Breakpoint* breakpoint) 278{ 279 if (fBreakpoints.BinaryInsert(breakpoint, &Breakpoint::CompareBreakpoints)) 280 return true; 281 282 breakpoint->ReleaseReference(); 283 return false; 284} 285 286 287void 288Team::RemoveBreakpoint(Breakpoint* breakpoint) 289{ 290 int32 index = fBreakpoints.BinarySearchIndex(*breakpoint, 291 &Breakpoint::CompareBreakpoints); 292 if (index < 0) 293 return; 294 295 fBreakpoints.RemoveItemAt(index); 296 breakpoint->ReleaseReference(); 297} 298 299 300int32 301Team::CountBreakpoints() const 302{ 303 return fBreakpoints.CountItems(); 304} 305 306 307Breakpoint* 308Team::BreakpointAt(int32 index) const 309{ 310 return fBreakpoints.ItemAt(index); 311} 312 313 314Breakpoint* 315Team::BreakpointAtAddress(target_addr_t address) const 316{ 317 return fBreakpoints.BinarySearchByKey(address, 318 &Breakpoint::CompareAddressBreakpoint); 319} 320 321 322void 323Team::GetBreakpointsInAddressRange(TargetAddressRange range, 324 BObjectList<UserBreakpoint>& breakpoints) const 325{ 326 int32 index = fBreakpoints.FindBinaryInsertionIndex( 327 BreakpointByAddressPredicate(range.Start())); 328 for (; Breakpoint* breakpoint = fBreakpoints.ItemAt(index); index++) { 329 if (breakpoint->Address() > range.End()) 330 break; 331 332 for (UserBreakpointInstanceList::ConstIterator it 333 = breakpoint->UserBreakpoints().GetIterator(); 334 UserBreakpointInstance* instance = it.Next();) { 335 breakpoints.AddItem(instance->GetUserBreakpoint()); 336 } 337 } 338 339 // TODO: Avoid duplicates! 340} 341 342 343void 344Team::GetBreakpointsForSourceCode(SourceCode* sourceCode, 345 BObjectList<UserBreakpoint>& breakpoints) const 346{ 347 if (DisassembledCode* disassembledCode 348 = dynamic_cast<DisassembledCode*>(sourceCode)) { 349 GetBreakpointsInAddressRange(disassembledCode->StatementAddressRange(), 350 breakpoints); 351 return; 352 } 353 354 LocatableFile* sourceFile = sourceCode->GetSourceFile(); 355 if (sourceFile == NULL) 356 return; 357 358 // TODO: This can probably be optimized. Maybe by registering the user 359 // breakpoints with the team and sorting them by source code. 360 for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++) { 361 UserBreakpointInstance* userBreakpointInstance 362 = breakpoint->FirstUserBreakpoint(); 363 if (userBreakpointInstance == NULL) 364 continue; 365 366 UserBreakpoint* userBreakpoint 367 = userBreakpointInstance->GetUserBreakpoint(); 368 if (userBreakpoint->Location().SourceFile() == sourceFile) 369 breakpoints.AddItem(userBreakpoint); 370 } 371} 372 373 374void 375Team::AddUserBreakpoint(UserBreakpoint* userBreakpoint) 376{ 377 fUserBreakpoints.Add(userBreakpoint); 378 userBreakpoint->AcquireReference(); 379} 380 381 382void 383Team::RemoveUserBreakpoint(UserBreakpoint* userBreakpoint) 384{ 385 fUserBreakpoints.Remove(userBreakpoint); 386 userBreakpoint->ReleaseReference(); 387} 388 389 390bool 391Team::AddWatchpoint(Watchpoint* watchpoint) 392{ 393 if (fWatchpoints.BinaryInsert(watchpoint, &Watchpoint::CompareWatchpoints)) 394 return true; 395 396 watchpoint->ReleaseReference(); 397 return false; 398} 399 400 401void 402Team::RemoveWatchpoint(Watchpoint* watchpoint) 403{ 404 int32 index = fWatchpoints.BinarySearchIndex(*watchpoint, 405 &Watchpoint::CompareWatchpoints); 406 if (index < 0) 407 return; 408 409 fWatchpoints.RemoveItemAt(index); 410 watchpoint->ReleaseReference(); 411} 412 413 414int32 415Team::CountWatchpoints() const 416{ 417 return fWatchpoints.CountItems(); 418} 419 420 421Watchpoint* 422Team::WatchpointAt(int32 index) const 423{ 424 return fWatchpoints.ItemAt(index); 425} 426 427 428Watchpoint* 429Team::WatchpointAtAddress(target_addr_t address) const 430{ 431 return fWatchpoints.BinarySearchByKey(address, 432 &Watchpoint::CompareAddressWatchpoint); 433} 434 435 436void 437Team::GetWatchpointsInAddressRange(TargetAddressRange range, 438 BObjectList<Watchpoint>& watchpoints) const 439{ 440 int32 index = fWatchpoints.FindBinaryInsertionIndex( 441 WatchpointByAddressPredicate(range.Start())); 442 for (; Watchpoint* watchpoint = fWatchpoints.ItemAt(index); index++) { 443 if (watchpoint->Address() > range.End()) 444 break; 445 446 watchpoints.AddItem(watchpoint); 447 } 448} 449 450 451status_t 452Team::GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function, 453 Statement*& _statement) 454{ 455 TRACE_CODE("Team::GetStatementAtAddress(%#" B_PRIx64 ")\n", address); 456 457 // get the image at the address 458 Image* image = ImageByAddress(address); 459 if (image == NULL) { 460 TRACE_CODE(" -> no image\n"); 461 return B_ENTRY_NOT_FOUND; 462 } 463 464 ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); 465 if (imageDebugInfo == NULL) { 466 TRACE_CODE(" -> no image debug info\n"); 467 return B_ENTRY_NOT_FOUND; 468 } 469 470 // get the function 471 FunctionInstance* functionInstance 472 = imageDebugInfo->FunctionAtAddress(address); 473 if (functionInstance == NULL) { 474 TRACE_CODE(" -> no function instance\n"); 475 return B_ENTRY_NOT_FOUND; 476 } 477 478 // If the function instance has disassembled code attached, we can get the 479 // statement directly. 480 if (DisassembledCode* code = functionInstance->GetSourceCode()) { 481 Statement* statement = code->StatementAtAddress(address); 482 if (statement == NULL) 483 return B_ENTRY_NOT_FOUND; 484 485 statement->AcquireReference(); 486 _statement = statement; 487 _function = functionInstance; 488 return B_OK; 489 } 490 491 // get the statement from the image debug info 492 FunctionDebugInfo* functionDebugInfo 493 = functionInstance->GetFunctionDebugInfo(); 494 status_t error = functionDebugInfo->GetSpecificImageDebugInfo() 495 ->GetStatement(functionDebugInfo, address, _statement); 496 if (error != B_OK) { 497 TRACE_CODE(" -> no statement from the specific image debug info\n"); 498 return error; 499 } 500 501 _function = functionInstance; 502 return B_OK; 503} 504 505 506status_t 507Team::GetStatementAtSourceLocation(SourceCode* sourceCode, 508 const SourceLocation& location, Statement*& _statement) 509{ 510 TRACE_CODE("Team::GetStatementAtSourceLocation(%p, (%" B_PRId32 ", %" 511 B_PRId32 "))\n", sourceCode, location.Line(), location.Column()); 512 513 // If we're lucky the source code can provide us with a statement. 514 if (DisassembledCode* code = dynamic_cast<DisassembledCode*>(sourceCode)) { 515 Statement* statement = code->StatementAtLocation(location); 516 if (statement == NULL) 517 return B_ENTRY_NOT_FOUND; 518 519 statement->AcquireReference(); 520 _statement = statement; 521 return B_OK; 522 } 523 524 // Go the long and stony way over the source file and the team debug info. 525 // get the source file for the source code 526 LocatableFile* sourceFile = sourceCode->GetSourceFile(); 527 if (sourceFile == NULL) 528 return B_ENTRY_NOT_FOUND; 529 530 // get the function at the source location 531 Function* function = fDebugInfo->FunctionAtSourceLocation(sourceFile, 532 location); 533 if (function == NULL) 534 return B_ENTRY_NOT_FOUND; 535 536 // Get some function instance and ask its image debug info to provide us 537 // with a statement. 538 FunctionInstance* functionInstance = function->FirstInstance(); 539 if (functionInstance == NULL) 540 return B_ENTRY_NOT_FOUND; 541 542 FunctionDebugInfo* functionDebugInfo 543 = functionInstance->GetFunctionDebugInfo(); 544 return functionDebugInfo->GetSpecificImageDebugInfo() 545 ->GetStatementAtSourceLocation(functionDebugInfo, location, _statement); 546} 547 548 549Function* 550Team::FunctionByID(FunctionID* functionID) const 551{ 552 return fDebugInfo->FunctionByID(functionID); 553} 554 555 556void 557Team::AddListener(Listener* listener) 558{ 559 AutoLocker<Team> locker(this); 560 fListeners.Add(listener); 561} 562 563 564void 565Team::RemoveListener(Listener* listener) 566{ 567 AutoLocker<Team> locker(this); 568 fListeners.Remove(listener); 569} 570 571 572void 573Team::NotifyThreadStateChanged(Thread* thread) 574{ 575 for (ListenerList::Iterator it = fListeners.GetIterator(); 576 Listener* listener = it.Next();) { 577 listener->ThreadStateChanged( 578 ThreadEvent(TEAM_EVENT_THREAD_STATE_CHANGED, thread)); 579 } 580} 581 582 583void 584Team::NotifyThreadCpuStateChanged(Thread* thread) 585{ 586 for (ListenerList::Iterator it = fListeners.GetIterator(); 587 Listener* listener = it.Next();) { 588 listener->ThreadCpuStateChanged( 589 ThreadEvent(TEAM_EVENT_THREAD_CPU_STATE_CHANGED, thread)); 590 } 591} 592 593 594void 595Team::NotifyThreadStackTraceChanged(Thread* thread) 596{ 597 for (ListenerList::Iterator it = fListeners.GetIterator(); 598 Listener* listener = it.Next();) { 599 listener->ThreadStackTraceChanged( 600 ThreadEvent(TEAM_EVENT_THREAD_STACK_TRACE_CHANGED, thread)); 601 } 602} 603 604 605void 606Team::NotifyImageDebugInfoChanged(Image* image) 607{ 608 for (ListenerList::Iterator it = fListeners.GetIterator(); 609 Listener* listener = it.Next();) { 610 listener->ImageDebugInfoChanged( 611 ImageEvent(TEAM_EVENT_IMAGE_DEBUG_INFO_CHANGED, image)); 612 } 613} 614 615 616void 617Team::NotifyUserBreakpointChanged(UserBreakpoint* breakpoint) 618{ 619 for (ListenerList::Iterator it = fListeners.GetIterator(); 620 Listener* listener = it.Next();) { 621 listener->UserBreakpointChanged(UserBreakpointEvent( 622 TEAM_EVENT_USER_BREAKPOINT_CHANGED, this, breakpoint)); 623 } 624} 625 626 627void 628Team::NotifyWatchpointChanged(Watchpoint* watchpoint) 629{ 630 for (ListenerList::Iterator it = fListeners.GetIterator(); 631 Listener* listener = it.Next();) { 632 listener->WatchpointChanged(WatchpointEvent( 633 TEAM_EVENT_WATCHPOINT_CHANGED, this, watchpoint)); 634 } 635} 636 637 638void 639Team::NotifyDebugReportChanged(const char* reportPath) 640{ 641 for (ListenerList::Iterator it = fListeners.GetIterator(); 642 Listener* listener = it.Next();) { 643 listener->DebugReportChanged(DebugReportEvent( 644 TEAM_EVENT_DEBUG_REPORT_CHANGED, this, reportPath)); 645 } 646} 647 648 649void 650Team::_NotifyThreadAdded(Thread* thread) 651{ 652 for (ListenerList::Iterator it = fListeners.GetIterator(); 653 Listener* listener = it.Next();) { 654 listener->ThreadAdded(ThreadEvent(TEAM_EVENT_THREAD_ADDED, thread)); 655 } 656} 657 658 659void 660Team::_NotifyThreadRemoved(Thread* thread) 661{ 662 for (ListenerList::Iterator it = fListeners.GetIterator(); 663 Listener* listener = it.Next();) { 664 listener->ThreadRemoved(ThreadEvent(TEAM_EVENT_THREAD_REMOVED, thread)); 665 } 666} 667 668 669void 670Team::_NotifyImageAdded(Image* image) 671{ 672 for (ListenerList::Iterator it = fListeners.GetIterator(); 673 Listener* listener = it.Next();) { 674 listener->ImageAdded(ImageEvent(TEAM_EVENT_IMAGE_ADDED, image)); 675 } 676} 677 678 679void 680Team::_NotifyImageRemoved(Image* image) 681{ 682 for (ListenerList::Iterator it = fListeners.GetIterator(); 683 Listener* listener = it.Next();) { 684 listener->ImageRemoved(ImageEvent(TEAM_EVENT_IMAGE_REMOVED, image)); 685 } 686} 687 688 689// #pragma mark - Event 690 691 692Team::Event::Event(uint32 type, Team* team) 693 : 694 fEventType(type), 695 fTeam(team) 696{ 697} 698 699 700// #pragma mark - ThreadEvent 701 702 703Team::ThreadEvent::ThreadEvent(uint32 type, Thread* thread) 704 : 705 Event(type, thread->GetTeam()), 706 fThread(thread) 707{ 708} 709 710 711// #pragma mark - ImageEvent 712 713 714Team::ImageEvent::ImageEvent(uint32 type, Image* image) 715 : 716 Event(type, image->GetTeam()), 717 fImage(image) 718{ 719} 720 721 722// #pragma mark - BreakpointEvent 723 724 725Team::BreakpointEvent::BreakpointEvent(uint32 type, Team* team, 726 Breakpoint* breakpoint) 727 : 728 Event(type, team), 729 fBreakpoint(breakpoint) 730{ 731} 732 733 734// #pragma mark - DebugReportEvent 735 736 737Team::DebugReportEvent::DebugReportEvent(uint32 type, Team* team, 738 const char* reportPath) 739 : 740 Event(type, team), 741 fReportPath(reportPath) 742{ 743} 744 745 746// #pragma mark - WatchpointEvent 747 748 749Team::WatchpointEvent::WatchpointEvent(uint32 type, Team* team, 750 Watchpoint* watchpoint) 751 : 752 Event(type, team), 753 fWatchpoint(watchpoint) 754{ 755} 756 757 758// #pragma mark - UserBreakpointEvent 759 760 761Team::UserBreakpointEvent::UserBreakpointEvent(uint32 type, Team* team, 762 UserBreakpoint* breakpoint) 763 : 764 Event(type, team), 765 fBreakpoint(breakpoint) 766{ 767} 768 769 770// #pragma mark - Listener 771 772 773Team::Listener::~Listener() 774{ 775} 776 777 778void 779Team::Listener::ThreadAdded(const Team::ThreadEvent& event) 780{ 781} 782 783 784void 785Team::Listener::ThreadRemoved(const Team::ThreadEvent& event) 786{ 787} 788 789 790void 791Team::Listener::ImageAdded(const Team::ImageEvent& event) 792{ 793} 794 795 796void 797Team::Listener::ImageRemoved(const Team::ImageEvent& event) 798{ 799} 800 801 802void 803Team::Listener::ThreadStateChanged(const Team::ThreadEvent& event) 804{ 805} 806 807 808void 809Team::Listener::ThreadCpuStateChanged(const Team::ThreadEvent& event) 810{ 811} 812 813 814void 815Team::Listener::ThreadStackTraceChanged(const Team::ThreadEvent& event) 816{ 817} 818 819 820void 821Team::Listener::ImageDebugInfoChanged(const Team::ImageEvent& event) 822{ 823} 824 825 826void 827Team::Listener::BreakpointAdded(const Team::BreakpointEvent& event) 828{ 829} 830 831 832void 833Team::Listener::BreakpointRemoved(const Team::BreakpointEvent& event) 834{ 835} 836 837 838void 839Team::Listener::UserBreakpointChanged(const Team::UserBreakpointEvent& event) 840{ 841} 842 843 844void 845Team::Listener::WatchpointAdded(const Team::WatchpointEvent& event) 846{ 847} 848 849 850void 851Team::Listener::WatchpointRemoved(const Team::WatchpointEvent& event) 852{ 853} 854 855 856void 857Team::Listener::WatchpointChanged(const Team::WatchpointEvent& event) 858{ 859} 860 861 862void 863Team::Listener::DebugReportChanged(const Team::DebugReportEvent& event) 864{ 865} 866