1 /* 2 * Copyright 2012-2016, Rene Gollent, rene@gollent.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "DebugReportGenerator.h" 8 9 #include <cpu_type.h> 10 11 #include <AutoLocker.h> 12 #include <Entry.h> 13 #include <File.h> 14 #include <Path.h> 15 #include <StringForSize.h> 16 17 #include "Architecture.h" 18 #include "AreaInfo.h" 19 #include "AutoDeleter.h" 20 #include "CpuState.h" 21 #include "DebuggerInterface.h" 22 #include "DisassembledCode.h" 23 #include "FunctionInstance.h" 24 #include "Image.h" 25 #include "ImageDebugInfo.h" 26 #include "MessageCodes.h" 27 #include "Register.h" 28 #include "SemaphoreInfo.h" 29 #include "StackFrame.h" 30 #include "StackTrace.h" 31 #include "Statement.h" 32 #include "StringUtils.h" 33 #include "SystemInfo.h" 34 #include "Team.h" 35 #include "TeamDebugInfo.h" 36 #include "Thread.h" 37 #include "Type.h" 38 #include "UiUtils.h" 39 #include "UserInterface.h" 40 #include "Value.h" 41 #include "ValueLoader.h" 42 #include "ValueLocation.h" 43 #include "ValueNode.h" 44 #include "ValueNodeManager.h" 45 46 47 #define WRITE_AND_CHECK(output, data) \ 48 { \ 49 ssize_t error = output.Write(data.String(), data.Length()); \ 50 if (error < 0) \ 51 return error; \ 52 } 53 54 55 DebugReportGenerator::DebugReportGenerator(::Team* team, 56 UserInterfaceListener* listener, DebuggerInterface* interface) 57 : 58 BLooper("DebugReportGenerator"), 59 fTeam(team), 60 fArchitecture(team->GetArchitecture()), 61 fDebuggerInterface(interface), 62 fTeamDataSem(-1), 63 fNodeManager(NULL), 64 fListener(listener), 65 fWaitingNode(NULL), 66 fCurrentBlock(NULL), 67 fBlockRetrievalStatus(B_OK), 68 fTraceWaitingThread(NULL), 69 fSourceWaitingFunction(NULL) 70 { 71 fTeam->AddListener(this); 72 fArchitecture->AcquireReference(); 73 } 74 75 76 DebugReportGenerator::~DebugReportGenerator() 77 { 78 fTeam->RemoveListener(this); 79 fArchitecture->ReleaseReference(); 80 if (fNodeManager != NULL) { 81 fNodeManager->RemoveListener(this); 82 fNodeManager->ReleaseReference(); 83 } 84 85 if (fCurrentBlock != NULL) 86 fCurrentBlock->ReleaseReference(); 87 88 if (fTeamDataSem >= 0) 89 delete_sem(fTeamDataSem); 90 } 91 92 93 status_t 94 DebugReportGenerator::Init() 95 { 96 fTeamDataSem = create_sem(0, "debug_controller_data_wait"); 97 if (fTeamDataSem < B_OK) 98 return fTeamDataSem; 99 100 fNodeManager = new(std::nothrow) ValueNodeManager(); 101 if (fNodeManager == NULL) 102 return B_NO_MEMORY; 103 104 fNodeManager->AddListener(this); 105 106 Run(); 107 108 return B_OK; 109 } 110 111 112 DebugReportGenerator* 113 DebugReportGenerator::Create(::Team* team, UserInterfaceListener* listener, 114 DebuggerInterface* interface) 115 { 116 DebugReportGenerator* self = new DebugReportGenerator(team, listener, 117 interface); 118 119 try { 120 self->Init(); 121 } catch (...) { 122 delete self; 123 throw; 124 } 125 126 return self; 127 } 128 129 130 status_t 131 DebugReportGenerator::_GenerateReport(const char* outputPath) 132 { 133 BFile file(outputPath, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 134 status_t result = file.InitCheck(); 135 if (result != B_OK) 136 return result; 137 138 result = _GenerateReportHeader(file); 139 if (result != B_OK) 140 return result; 141 142 result = _DumpRunningThreads(file); 143 if (result != B_OK) 144 return result; 145 146 result = _DumpLoadedImages(file); 147 if (result != B_OK) 148 return result; 149 150 result = _DumpAreas(file); 151 if (result != B_OK) 152 return result; 153 154 result = _DumpSemaphores(file); 155 if (result != B_OK) 156 return result; 157 158 AutoLocker< ::Team> teamLocker(fTeam); 159 fTeam->NotifyDebugReportChanged(outputPath, B_OK); 160 161 return B_OK; 162 } 163 164 165 void 166 DebugReportGenerator::MessageReceived(BMessage* message) 167 { 168 switch (message->what) { 169 case MSG_GENERATE_DEBUG_REPORT: 170 { 171 entry_ref ref; 172 if (message->FindRef("target", &ref) == B_OK) { 173 BPath path(&ref); 174 status_t error = _GenerateReport(path.Path()); 175 if (error != B_OK) 176 fTeam->NotifyDebugReportChanged(path.Path(), error); 177 } 178 break; 179 } 180 181 default: 182 BLooper::MessageReceived(message); 183 break; 184 } 185 } 186 187 188 void 189 DebugReportGenerator::ThreadStackTraceChanged(const ::Team::ThreadEvent& event) 190 { 191 if (fTraceWaitingThread == event.GetThread()) { 192 fTraceWaitingThread = NULL; 193 release_sem(fTeamDataSem); 194 } 195 } 196 197 198 void 199 DebugReportGenerator::MemoryBlockRetrieved(TeamMemoryBlock* block) 200 { 201 _HandleMemoryBlockRetrieved(block, B_OK); 202 } 203 204 205 void 206 DebugReportGenerator::MemoryBlockRetrievalFailed(TeamMemoryBlock* block, 207 status_t result) 208 { 209 _HandleMemoryBlockRetrieved(block, result); 210 } 211 212 213 void 214 DebugReportGenerator::ValueNodeValueChanged(ValueNode* node) 215 { 216 if (node == fWaitingNode) { 217 fWaitingNode = NULL; 218 release_sem(fTeamDataSem); 219 } 220 } 221 222 223 void 224 DebugReportGenerator::FunctionSourceCodeChanged(Function* function) 225 { 226 AutoLocker< ::Team> teamLocker(fTeam); 227 if (function == fSourceWaitingFunction) { 228 function_source_state state = function->SourceCodeState(); 229 230 switch (state) { 231 case FUNCTION_SOURCE_LOADED: 232 case FUNCTION_SOURCE_SUPPRESSED: 233 case FUNCTION_SOURCE_UNAVAILABLE: 234 { 235 fSourceWaitingFunction->RemoveListener(this); 236 fSourceWaitingFunction = NULL; 237 release_sem(fTeamDataSem); 238 // fall through 239 } 240 default: 241 break; 242 } 243 } 244 } 245 246 status_t 247 DebugReportGenerator::_GenerateReportHeader(BFile& _output) 248 { 249 AutoLocker< ::Team> locker(fTeam); 250 251 BString data; 252 data.SetToFormat("Debug information for team %s (%" B_PRId32 "):\n", 253 fTeam->Name(), fTeam->ID()); 254 WRITE_AND_CHECK(_output, data); 255 256 cpu_platform platform = B_CPU_UNKNOWN; 257 cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN; 258 uint32 cpuModel = 0; 259 uint32 topologyNodeCount = 0; 260 cpu_topology_node_info* topology = NULL; 261 get_cpu_topology_info(NULL, &topologyNodeCount); 262 if (topologyNodeCount != 0) { 263 topology = new(std::nothrow) cpu_topology_node_info[topologyNodeCount]; 264 if (topology == NULL) 265 return B_NO_MEMORY; 266 267 BPrivate::ArrayDeleter<cpu_topology_node_info> deleter(topology); 268 get_cpu_topology_info(topology, &topologyNodeCount); 269 270 for (uint32 i = 0; i < topologyNodeCount; i++) { 271 switch (topology[i].type) { 272 case B_TOPOLOGY_ROOT: 273 platform = topology[i].data.root.platform; 274 break; 275 276 case B_TOPOLOGY_PACKAGE: 277 cpuVendor = topology[i].data.package.vendor; 278 break; 279 280 case B_TOPOLOGY_CORE: 281 cpuModel = topology[i].data.core.model; 282 break; 283 284 default: 285 break; 286 } 287 } 288 } 289 290 SystemInfo sysInfo; 291 if (fDebuggerInterface->GetSystemInfo(sysInfo) == B_OK) { 292 const system_info &info = sysInfo.GetSystemInfo(); 293 const char* vendor = get_cpu_vendor_string(cpuVendor); 294 const char* model = get_cpu_model_string(platform, cpuVendor, cpuModel); 295 296 data.SetToFormat("CPU(s): %" B_PRId32 "x %s %s\n", 297 info.cpu_count, vendor != NULL ? vendor : "unknown", 298 model != NULL ? model : "unknown"); 299 WRITE_AND_CHECK(_output, data); 300 301 char maxSize[32]; 302 char usedSize[32]; 303 304 data.SetToFormat("Memory: %s total, %s used\n", 305 BPrivate::string_for_size((int64)info.max_pages * B_PAGE_SIZE, 306 maxSize, sizeof(maxSize)), 307 BPrivate::string_for_size((int64)info.used_pages * B_PAGE_SIZE, 308 usedSize, sizeof(usedSize))); 309 WRITE_AND_CHECK(_output, data); 310 311 const utsname& name = sysInfo.GetSystemName(); 312 data.SetToFormat("Haiku revision: %s (%s)\n", name.version, 313 name.machine); 314 WRITE_AND_CHECK(_output, data); 315 } 316 317 return B_OK; 318 } 319 320 321 status_t 322 DebugReportGenerator::_DumpLoadedImages(BFile& _output) 323 { 324 AutoLocker< ::Team> locker(fTeam); 325 326 BString data("\nLoaded Images:\n"); 327 WRITE_AND_CHECK(_output, data); 328 BObjectList<Image> images; 329 for (ImageList::ConstIterator it = fTeam->Images().GetIterator(); 330 Image* image = it.Next();) { 331 images.AddItem(image); 332 } 333 334 images.SortItems(&_CompareImages); 335 336 Image* image = NULL; 337 data.SetToFormat("\tID\t\tText Base\tText End\tData Base\tData" 338 " End\tType\tName\n\t"); 339 WRITE_AND_CHECK(_output, data); 340 data.Truncate(0L); 341 data.Append('-', 80); 342 data.Append("\n"); 343 WRITE_AND_CHECK(_output, data); 344 for (int32 i = 0; (image = images.ItemAt(i)) != NULL; i++) { 345 const ImageInfo& info = image->Info(); 346 char buffer[32]; 347 try { 348 target_addr_t textBase = info.TextBase(); 349 target_addr_t dataBase = info.DataBase(); 350 351 data.SetToFormat("\t%" B_PRId32 "\t0x%08" B_PRIx64 "\t" 352 "0x%08" B_PRIx64 "\t0x%08" B_PRIx64 "\t0x%08" B_PRIx64 "\t" 353 "%-7s\t%s\n", info.ImageID(), textBase, textBase + info.TextSize(), 354 dataBase, dataBase + info.DataSize(), 355 UiUtils::ImageTypeToString(info.Type(), buffer, 356 sizeof(buffer)), info.Name().String()); 357 358 WRITE_AND_CHECK(_output, data); 359 } catch (...) { 360 return B_NO_MEMORY; 361 } 362 } 363 364 return B_OK; 365 } 366 367 368 status_t 369 DebugReportGenerator::_DumpAreas(BFile& _output) 370 { 371 BObjectList<AreaInfo> areas(20, true); 372 status_t result = fDebuggerInterface->GetAreaInfos(areas); 373 if (result != B_OK) 374 return result; 375 376 areas.SortItems(&_CompareAreas); 377 378 BString data("\nAreas:\n"); 379 WRITE_AND_CHECK(_output, data); 380 data.SetToFormat("\tID\t\tBase\t\tEnd\t\t\tSize (KiB)\tProtection\tLocking\t\t\tName\n\t"); 381 WRITE_AND_CHECK(_output, data); 382 data.Truncate(0L); 383 data.Append('-', 80); 384 data.Append("\n"); 385 WRITE_AND_CHECK(_output, data); 386 AreaInfo* info; 387 BString protectionBuffer; 388 char lockingBuffer[32]; 389 for (int32 i = 0; (info = areas.ItemAt(i)) != NULL; i++) { 390 try { 391 data.SetToFormat("\t%" B_PRId32 "\t0x%08" B_PRIx64 "\t" 392 "0x%08" B_PRIx64 "\t%10" B_PRId64 "\t%-11s\t%-14s\t%s\n", 393 info->AreaID(), info->BaseAddress(), info->BaseAddress() 394 + info->Size(), info->Size() / 1024, 395 UiUtils::AreaProtectionFlagsToString(info->Protection(), 396 protectionBuffer).String(), 397 UiUtils::AreaLockingFlagsToString(info->Lock(), lockingBuffer, 398 sizeof(lockingBuffer)), info->Name().String()); 399 400 WRITE_AND_CHECK(_output, data); 401 } catch (...) { 402 return B_NO_MEMORY; 403 } 404 } 405 406 data = "\nProtection Flags: r - read, w - write, x - execute, " 407 "s - stack, o - overcommit, c - cloneable, S - shared, k - kernel\n"; 408 WRITE_AND_CHECK(_output, data); 409 410 return B_OK; 411 } 412 413 414 status_t 415 DebugReportGenerator::_DumpSemaphores(BFile& _output) 416 { 417 BObjectList<SemaphoreInfo> semaphores(20, true); 418 status_t error = fDebuggerInterface->GetSemaphoreInfos(semaphores); 419 if (error != B_OK) 420 return error; 421 422 semaphores.SortItems(&_CompareSemaphores); 423 424 BString data = "\nSemaphores:\n"; 425 WRITE_AND_CHECK(_output, data); 426 data.SetToFormat("\tID\t\tCount\tLast Holder\tName\n\t"); 427 WRITE_AND_CHECK(_output, data); 428 data.Truncate(0L); 429 data.Append('-', 60); 430 data.Append("\n"); 431 WRITE_AND_CHECK(_output, data); 432 SemaphoreInfo* info; 433 for (int32 i = 0; (info = semaphores.ItemAt(i)) != NULL; i++) { 434 try { 435 data.SetToFormat("\t%" B_PRId32 "\t%5" B_PRId32 "\t%11" B_PRId32 436 "\t%s\n", info->SemID(), info->Count(), 437 info->LatestHolder(), info->Name().String()); 438 439 WRITE_AND_CHECK(_output, data); 440 } catch (...) { 441 return B_NO_MEMORY; 442 } 443 } 444 445 return B_OK; 446 } 447 448 449 status_t 450 DebugReportGenerator::_DumpRunningThreads(BFile& _output) 451 { 452 AutoLocker< ::Team> locker(fTeam); 453 454 BString data("\nActive Threads:\n"); 455 WRITE_AND_CHECK(_output, data); 456 BObjectList< ::Thread> threads; 457 ::Thread* thread; 458 for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator(); 459 (thread = it.Next());) { 460 threads.AddItem(thread); 461 thread->AcquireReference(); 462 } 463 464 status_t error = B_OK; 465 threads.SortItems(&_CompareThreads); 466 for (int32 i = 0; (thread = threads.ItemAt(i)) != NULL; i++) { 467 try { 468 data.SetToFormat("\tthread %" B_PRId32 ": %s %s\n", thread->ID(), 469 thread->Name(), thread->IsMainThread() 470 ? "(main)" : ""); 471 WRITE_AND_CHECK(_output, data); 472 473 if (thread->State() == THREAD_STATE_STOPPED) { 474 data.SetToFormat("\t\tstate: %s", 475 UiUtils::ThreadStateToString(thread->State(), 476 thread->StoppedReason())); 477 const BString& stoppedInfo = thread->StoppedReasonInfo(); 478 if (stoppedInfo.Length() != 0) 479 data << " (" << stoppedInfo << ")"; 480 data << "\n\n"; 481 WRITE_AND_CHECK(_output, data); 482 483 // we need to release our lock on the team here 484 // since we might need to block and wait 485 // on the stack trace. 486 locker.Unlock(); 487 error = _DumpDebuggedThreadInfo(_output, thread); 488 locker.Lock(); 489 if (error != B_OK) 490 break; 491 } 492 } catch (...) { 493 error = B_NO_MEMORY; 494 } 495 } 496 497 for (int32 i = 0; (thread = threads.ItemAt(i)) != NULL; i++) 498 thread->ReleaseReference(); 499 500 return error; 501 } 502 503 504 status_t 505 DebugReportGenerator::_DumpDebuggedThreadInfo(BFile& _output, 506 ::Thread* thread) 507 { 508 AutoLocker< ::Team> locker; 509 if (thread->State() != THREAD_STATE_STOPPED) 510 return B_OK; 511 512 status_t error; 513 StackTrace* trace = NULL; 514 for (;;) { 515 trace = thread->GetStackTrace(); 516 if (trace != NULL) 517 break; 518 519 locker.Unlock(); 520 fTraceWaitingThread = thread; 521 do { 522 error = acquire_sem(fTeamDataSem); 523 } while (error == B_INTERRUPTED); 524 525 if (error != B_OK) 526 return error; 527 528 locker.Lock(); 529 } 530 531 BString data("\t\tFrame\t\tIP\t\t\tFunction Name\n"); 532 WRITE_AND_CHECK(_output, data); 533 data = "\t\t-----------------------------------------------\n"; 534 WRITE_AND_CHECK(_output, data); 535 for (int32 i = 0; StackFrame* frame = trace->FrameAt(i); i++) { 536 char functionName[512]; 537 BString sourcePath; 538 539 target_addr_t ip = frame->InstructionPointer(); 540 Image* image = fTeam->ImageByAddress(ip); 541 FunctionInstance* functionInstance = NULL; 542 if (image != NULL && image->ImageDebugInfoState() 543 == IMAGE_DEBUG_INFO_LOADED) { 544 ImageDebugInfo* info = image->GetImageDebugInfo(); 545 functionInstance = info->FunctionAtAddress(ip); 546 } 547 548 if (functionInstance != NULL) { 549 Function* function = functionInstance->GetFunction(); 550 if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED 551 && functionInstance->SourceCodeState() 552 == FUNCTION_SOURCE_NOT_LOADED) { 553 fSourceWaitingFunction = function; 554 fSourceWaitingFunction->AddListener(this); 555 fListener->FunctionSourceCodeRequested(functionInstance); 556 557 locker.Unlock(); 558 559 do { 560 error = acquire_sem(fTeamDataSem); 561 } while (error == B_INTERRUPTED); 562 563 if (error != B_OK) 564 return error; 565 566 locker.Lock(); 567 } 568 } 569 570 Statement* statement; 571 if (fTeam->GetStatementAtAddress(ip, 572 functionInstance, statement) == B_OK) { 573 BReference<Statement> statementReference(statement, true); 574 575 int32 line = statement->StartSourceLocation().Line(); 576 LocatableFile* sourceFile = functionInstance->GetFunction() 577 ->SourceFile(); 578 if (sourceFile != NULL) { 579 sourceFile->GetPath(sourcePath); 580 sourcePath.SetToFormat("(%s:%" B_PRId32 ")", 581 sourcePath.String(), line); 582 } 583 } 584 585 586 data.SetToFormat("\t\t%#08" B_PRIx64 "\t%#08" B_PRIx64 "\t%s %s\n", 587 frame->FrameAddress(), ip, UiUtils::FunctionNameForFrame( 588 frame, functionName, sizeof(functionName)), 589 sourcePath.String()); 590 591 WRITE_AND_CHECK(_output, data); 592 593 // only dump the topmost frame 594 if (i == 0) { 595 locker.Unlock(); 596 error = _DumpFunctionDisassembly(_output, 597 frame->InstructionPointer()); 598 if (error != B_OK) 599 return error; 600 error = _DumpStackFrameMemory(_output, thread->GetCpuState(), 601 frame->FrameAddress(), thread->GetTeam()->GetArchitecture() 602 ->StackGrowthDirection()); 603 if (error != B_OK) 604 return error; 605 locker.Lock(); 606 } 607 608 if (frame->CountParameters() == 0 && frame->CountLocalVariables() == 0) 609 continue; 610 611 data = "\t\t\tVariables:\n"; 612 WRITE_AND_CHECK(_output, data); 613 error = fNodeManager->SetStackFrame(thread, frame); 614 if (error != B_OK) 615 continue; 616 617 ValueNodeContainer* container = fNodeManager->GetContainer(); 618 AutoLocker<ValueNodeContainer> containerLocker(container); 619 for (int32 i = 0; i < container->CountChildren(); i++) { 620 data.Truncate(0L); 621 ValueNodeChild* child = container->ChildAt(i); 622 containerLocker.Unlock(); 623 _ResolveValueIfNeeded(child->Node(), frame, 1); 624 containerLocker.Lock(); 625 UiUtils::PrintValueNodeGraph(data, child, 3, 1); 626 WRITE_AND_CHECK(_output, data); 627 } 628 data = "\n"; 629 WRITE_AND_CHECK(_output, data); 630 } 631 632 data = "\n\t\tRegisters:\n"; 633 WRITE_AND_CHECK(_output, data); 634 635 CpuState* state = thread->GetCpuState(); 636 BVariant value; 637 const Register* reg = NULL; 638 for (int32 i = 0; i < fArchitecture->CountRegisters(); i++) { 639 reg = fArchitecture->Registers() + i; 640 state->GetRegisterValue(reg, value); 641 642 if (reg->Format() == REGISTER_FORMAT_SIMD) { 643 data.SetToFormat("\t\t\t%5s:\t%s\n", reg->Name(), 644 UiUtils::FormatSIMDValue(value, reg->BitSize(), 645 SIMD_RENDER_FORMAT_INT16, data).String()); 646 } else { 647 char buffer[64]; 648 data.SetToFormat("\t\t\t%5s:\t%s\n", reg->Name(), 649 UiUtils::VariantToString(value, buffer, sizeof(buffer))); 650 } 651 652 WRITE_AND_CHECK(_output, data); 653 } 654 655 return B_OK; 656 } 657 658 659 status_t 660 DebugReportGenerator::_DumpFunctionDisassembly(BFile& _output, 661 target_addr_t instructionPointer) 662 { 663 AutoLocker< ::Team> teamLocker(fTeam); 664 BString data; 665 FunctionInstance* instance = NULL; 666 Image* image = fTeam->ImageByAddress(instructionPointer); 667 if (image == NULL) { 668 data.SetToFormat("\t\t\tUnable to retrieve disassembly for IP %#" 669 B_PRIx64 ": address not contained in any valid image.\n", 670 instructionPointer); 671 WRITE_AND_CHECK(_output, data); 672 return B_OK; 673 } 674 675 ImageDebugInfo* info = image->GetImageDebugInfo(); 676 if (info == NULL) { 677 data.SetToFormat("\t\t\tUnable to retrieve disassembly for IP %#" 678 B_PRIx64 ": no debug info available for image '%s'.\n", 679 instructionPointer, image->Name().String()); 680 WRITE_AND_CHECK(_output, data); 681 return B_OK; 682 } 683 684 instance = info->FunctionAtAddress(instructionPointer); 685 if (instance == NULL) { 686 data.SetToFormat("\t\t\tUnable to retrieve disassembly for IP %#" 687 B_PRIx64 ": address does not point to a function.\n", 688 instructionPointer); 689 WRITE_AND_CHECK(_output, data); 690 return B_OK; 691 } 692 693 Statement* statement = NULL; 694 DisassembledCode* code = instance->GetSourceCode(); 695 BReference<DisassembledCode> codeReference; 696 if (code == NULL) { 697 status_t error = fTeam->DebugInfo()->DisassembleFunction(instance, 698 code); 699 if (error != B_OK) { 700 data.SetToFormat("\t\t\tUnable to retrieve disassembly for IP %#" 701 B_PRIx64 ": %s.\n", instructionPointer, strerror(error)); 702 WRITE_AND_CHECK(_output, data); 703 return B_OK; 704 } 705 706 codeReference.SetTo(code, true); 707 } else 708 codeReference.SetTo(code); 709 710 statement = code->StatementAtAddress(instructionPointer); 711 if (statement == NULL) { 712 data.SetToFormat("\t\t\tUnable to retrieve disassembly for IP %#" 713 B_PRIx64 ": address does not map to a valid instruction.\n", 714 instructionPointer); 715 WRITE_AND_CHECK(_output, data); 716 return B_OK; 717 } 718 719 SourceLocation location = statement->StartSourceLocation(); 720 721 data = "\t\t\tDisassembly:\n"; 722 WRITE_AND_CHECK(_output, data); 723 for (int32 i = 0; i <= location.Line(); i++) { 724 data = "\t\t\t\t"; 725 data << code->LineAt(i); 726 if (i == location.Line()) 727 data << " <--"; 728 data << "\n"; 729 WRITE_AND_CHECK(_output, data); 730 } 731 data = "\n"; 732 WRITE_AND_CHECK(_output, data); 733 734 return B_OK; 735 } 736 737 738 status_t 739 DebugReportGenerator::_DumpStackFrameMemory(BFile& _output, 740 CpuState* state, target_addr_t framePointer, uint8 stackDirection) 741 { 742 target_addr_t startAddress; 743 target_addr_t endAddress; 744 if (stackDirection == STACK_GROWTH_DIRECTION_POSITIVE) { 745 startAddress = framePointer; 746 endAddress = state->StackPointer(); 747 } else { 748 startAddress = state->StackPointer(); 749 endAddress = framePointer; 750 } 751 752 if (endAddress <= startAddress) 753 return B_OK; 754 755 if (fCurrentBlock == NULL || !fCurrentBlock->Contains(startAddress)) { 756 status_t error; 757 fListener->InspectRequested(startAddress, this); 758 do { 759 error = acquire_sem(fTeamDataSem); 760 } while (error == B_INTERRUPTED); 761 762 if (error != B_OK) 763 return error; 764 } 765 766 BString data("\t\t\tFrame memory:\n"); 767 WRITE_AND_CHECK(_output, data); 768 if (fBlockRetrievalStatus == B_OK) { 769 data.Truncate(0L); 770 UiUtils::DumpMemory(data, 4, fCurrentBlock, startAddress, 1, 16, 771 endAddress - startAddress); 772 WRITE_AND_CHECK(_output, data); 773 } else { 774 data.SetToFormat("\t\t\t\tUnavailable (%s)\n", strerror( 775 fBlockRetrievalStatus)); 776 WRITE_AND_CHECK(_output, data); 777 } 778 779 return B_OK; 780 } 781 782 783 status_t 784 DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame, 785 int32 maxDepth) 786 { 787 status_t result = B_OK; 788 if (node->LocationAndValueResolutionState() == VALUE_NODE_UNRESOLVED) { 789 fWaitingNode = node; 790 fListener->ValueNodeValueRequested(frame->GetCpuState(), 791 fNodeManager->GetContainer(), node); 792 do { 793 result = acquire_sem(fTeamDataSem); 794 } while (result == B_INTERRUPTED); 795 } 796 797 if (node->LocationAndValueResolutionState() == B_OK && maxDepth > 0) { 798 AutoLocker<ValueNodeContainer> containerLocker( 799 fNodeManager->GetContainer()); 800 for (int32 i = 0; i < node->CountChildren(); i++) { 801 ValueNodeChild* child = node->ChildAt(i); 802 containerLocker.Unlock(); 803 result = fNodeManager->AddChildNodes(child); 804 if (result != B_OK) 805 continue; 806 807 // since in the case of a pointer to a compound we hide 808 // the intervening compound, don't consider the hidden node 809 // a level for the purposes of depth traversal 810 if (node->GetType()->ResolveRawType(false)->Kind() == TYPE_ADDRESS 811 && child->GetType()->ResolveRawType(false)->Kind() 812 == TYPE_COMPOUND) { 813 _ResolveValueIfNeeded(child->Node(), frame, maxDepth); 814 } else 815 _ResolveValueIfNeeded(child->Node(), frame, maxDepth - 1); 816 containerLocker.Lock(); 817 } 818 } 819 820 return result; 821 } 822 823 824 void 825 DebugReportGenerator::_HandleMemoryBlockRetrieved(TeamMemoryBlock* block, 826 status_t result) 827 { 828 if (fCurrentBlock != NULL) { 829 fCurrentBlock->ReleaseReference(); 830 fCurrentBlock = NULL; 831 } 832 833 fBlockRetrievalStatus = result; 834 835 fCurrentBlock = block; 836 release_sem(fTeamDataSem); 837 } 838 839 840 841 /*static*/ int 842 DebugReportGenerator::_CompareAreas(const AreaInfo* a, const AreaInfo* b) 843 { 844 if (a->BaseAddress() < b->BaseAddress()) 845 return -1; 846 847 return 1; 848 } 849 850 851 /*static*/ int 852 DebugReportGenerator::_CompareImages(const Image* a, const Image* b) 853 { 854 if (a->Info().TextBase() < b->Info().TextBase()) 855 return -1; 856 857 return 1; 858 } 859 860 861 /*static*/ int 862 DebugReportGenerator::_CompareSemaphores(const SemaphoreInfo* a, 863 const SemaphoreInfo* b) 864 { 865 if (a->SemID() < b->SemID()) 866 return -1; 867 868 return 1; 869 } 870 871 872 /*static*/ int 873 DebugReportGenerator::_CompareThreads(const ::Thread* a, 874 const ::Thread* b) 875 { 876 // sort stopped threads last, otherwise sort by thread ID 877 if (a->State() == b->State()) 878 return a->ID() < b->ID() ? -1 : 1; 879 880 if (a->State() == THREAD_STATE_STOPPED && b->State() 881 != THREAD_STATE_STOPPED) { 882 return 1; 883 } 884 885 return -1; 886 } 887