bool ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event) { CpuState* cpuState = event->GetCpuState(); target_addr_t instructionPointer = cpuState->InstructionPointer(); TRACE_EVENTS("ThreadHandler::HandleBreakpointHit(): ip: %" B_PRIx64 "\n", instructionPointer); // check whether this is a temporary breakpoint we're waiting for if (fBreakpointAddress != 0 && instructionPointer == fBreakpointAddress && fStepMode != STEP_NONE) { if (fStepMode != STEP_UNTIL && _HandleBreakpointHitStep(cpuState)) return true; } else { // Might be a user breakpoint, but could as well be a temporary // breakpoint of another thread. AutoLocker<Team> locker(fThread->GetTeam()); Breakpoint* breakpoint = fThread->GetTeam()->BreakpointAtAddress( cpuState->InstructionPointer()); bool continueThread = false; if (breakpoint == NULL) { // spurious breakpoint -- might be a temporary breakpoint, that has // already been uninstalled continueThread = true; } else if (!breakpoint->HasEnabledUserBreakpoint()) { // breakpoint of another thread or one that has been disabled in // the meantime continueThread = true; } if (continueThread) { if (fSingleStepping) { // We might have hit a just-installed software breakpoint and // thus haven't stepped at all. Just try again. if (fPreviousInstructionPointer == instructionPointer) { fDebuggerInterface->SingleStepThread(ThreadID()); return true; } // That shouldn't happen. Try something reasonable anyway. if (fStepMode != STEP_NONE) { if (_HandleSingleStepStep(cpuState)) return true; } } return false; } } return _HandleThreadStopped(cpuState, THREAD_STOPPED_BREAKPOINT); }
status_t DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, ::Thread* thread) { AutoLocker< ::Team> locker; if (thread->State() != THREAD_STATE_STOPPED) return B_OK; StackTrace* trace = NULL; for (;;) { trace = thread->GetStackTrace(); if (trace != NULL) break; locker.Unlock(); status_t result = acquire_sem(fTeamDataSem); if (result != B_OK) return result; locker.Lock(); } _output << "\t\tFrame\t\tIP\t\t\tFunction Name\n"; _output << "\t\t-----------------------------------------------\n"; BString data; for (int32 i = 0; StackFrame* frame = trace->FrameAt(i); i++) { char functionName[512]; data.SetToFormat("\t\t%#08" B_PRIx64 "\t%#08" B_PRIx64 "\t%s\n", frame->FrameAddress(), frame->InstructionPointer(), UiUtils::FunctionNameForFrame(frame, functionName, sizeof(functionName))); _output << data; } _output << "\n\t\tRegisters:\n"; CpuState* state = thread->GetCpuState(); BVariant value; const Register* reg = NULL; for (int32 i = 0; i < fArchitecture->CountRegisters(); i++) { reg = fArchitecture->Registers() + i; state->GetRegisterValue(reg, value); char buffer[64]; data.SetToFormat("\t\t\t%5s:\t%s\n", reg->Name(), UiUtils::VariantToString(value, buffer, sizeof(buffer))); _output << data; } return B_OK; }
bool ThreadHandler::_HandleSetAddress(CpuState* state, target_addr_t address) { CpuState* newState = NULL; if (state->Clone(newState) != B_OK) return false; BReference<CpuState> stateReference(newState, true); newState->SetInstructionPointer(address); if (fDebuggerInterface->SetCpuState(fThread->ID(), newState) != B_OK) return false; AutoLocker<Team> locker(fThread->GetTeam()); fThread->SetStackTrace(NULL); fThread->SetCpuState(newState); return true; }
status_t DwarfImageDebugInfo::CreateFrame(Image* image, FunctionInstance* functionInstance, CpuState* cpuState, bool getFullFrameInfo, ReturnValueInfoList* returnValueInfos, StackFrame*& _frame, CpuState*& _previousCpuState) { DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>( functionInstance->GetFunctionDebugInfo()); FunctionID* functionID = functionInstance->GetFunctionID(); BReference<FunctionID> functionIDReference; if (functionID != NULL) functionIDReference.SetTo(functionID, true); DIESubprogram* entry = function != NULL ? function->SubprogramEntry() : NULL; TRACE_CFI("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p, " "function: %s\n", entry, functionID->FunctionName().String()); int32 registerCount = fArchitecture->CountRegisters(); const Register* registers = fArchitecture->Registers(); // get the DWARF <-> architecture register maps RegisterMap* toDwarfMap; RegisterMap* fromDwarfMap; status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap, &fromDwarfMap); if (error != B_OK) return error; BReference<RegisterMap> toDwarfMapReference(toDwarfMap, true); BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true); // create a clean CPU state for the previous frame CpuState* previousCpuState; error = fArchitecture->CreateCpuState(previousCpuState); if (error != B_OK) return error; BReference<CpuState> previousCpuStateReference(previousCpuState, true); // create the target interfaces UnwindTargetInterface* inputInterface = new(std::nothrow) UnwindTargetInterface(registers, registerCount, fromDwarfMap, toDwarfMap, cpuState, fArchitecture, fDebuggerInterface); if (inputInterface == NULL) return B_NO_MEMORY; BReference<UnwindTargetInterface> inputInterfaceReference(inputInterface, true); UnwindTargetInterface* outputInterface = new(std::nothrow) UnwindTargetInterface(registers, registerCount, fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture, fDebuggerInterface); if (outputInterface == NULL) return B_NO_MEMORY; BReference<UnwindTargetInterface> outputInterfaceReference(outputInterface, true); // do the unwinding target_addr_t instructionPointer = cpuState->InstructionPointer() - fRelocationDelta; target_addr_t framePointer; CompilationUnit* unit = function != NULL ? function->GetCompilationUnit() : NULL; error = fFile->UnwindCallFrame(unit, fArchitecture->AddressSize(), entry, instructionPointer, inputInterface, outputInterface, framePointer); if (error != B_OK) { TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error)); return B_UNSUPPORTED; } TRACE_CFI_ONLY( TRACE_CFI("unwound registers:\n"); for (int32 i = 0; i < registerCount; i++) { const Register* reg = registers + i; BVariant value; if (previousCpuState->GetRegisterValue(reg, value)) { TRACE_CFI(" %3s: %#" B_PRIx64 "\n", reg->Name(), value.ToUInt64()); } else TRACE_CFI(" %3s: undefined\n", reg->Name()); } )
status_t LocalDebuggerInterface::_CreateDebugEvent(int32 messageCode, const debug_debugger_message_data& message, bool& _ignore, DebugEvent*& _event) { DebugEvent* event = NULL; switch (messageCode) { case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: event = new(std::nothrow) ThreadDebuggedEvent(message.origin.team, message.origin.thread); break; case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: event = new(std::nothrow) DebuggerCallEvent(message.origin.team, message.origin.thread, (target_addr_t)message.debugger_call.message); break; case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: { CpuState* state = NULL; status_t error = fArchitecture->CreateCpuState( &message.breakpoint_hit.cpu_state, sizeof(debug_cpu_state), state); if (error != B_OK) return error; event = new(std::nothrow) BreakpointHitEvent(message.origin.team, message.origin.thread, state); state->ReleaseReference(); break; } case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: { CpuState* state = NULL; status_t error = fArchitecture->CreateCpuState( &message.watchpoint_hit.cpu_state, sizeof(debug_cpu_state), state); if (error != B_OK) return error; event = new(std::nothrow) WatchpointHitEvent(message.origin.team, message.origin.thread, state); state->ReleaseReference(); break; } case B_DEBUGGER_MESSAGE_SINGLE_STEP: { CpuState* state = NULL; status_t error = fArchitecture->CreateCpuState( &message.single_step.cpu_state, sizeof(debug_cpu_state), state); if (error != B_OK) return error; event = new(std::nothrow) SingleStepEvent(message.origin.team, message.origin.thread, state); state->ReleaseReference(); break; } case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: event = new(std::nothrow) ExceptionOccurredEvent( message.origin.team, message.origin.thread, message.exception_occurred.exception); break; case B_DEBUGGER_MESSAGE_TEAM_DELETED: if (message.origin.team != fTeamID) { _ignore = true; return B_OK; } event = new(std::nothrow) TeamDeletedEvent(message.origin.team, message.origin.thread); break; case B_DEBUGGER_MESSAGE_TEAM_EXEC: if (message.origin.team != fTeamID) { _ignore = true; return B_OK; } event = new(std::nothrow) TeamExecEvent(message.origin.team, message.origin.thread); break; case B_DEBUGGER_MESSAGE_THREAD_CREATED: event = new(std::nothrow) ThreadCreatedEvent(message.origin.team, message.origin.thread, message.thread_created.new_thread); break; case B_DEBUGGER_MESSAGE_THREAD_DELETED: event = new(std::nothrow) ThreadDeletedEvent(message.origin.team, message.origin.thread); break; case B_DEBUGGER_MESSAGE_IMAGE_CREATED: { const image_info& info = message.image_created.info; event = new(std::nothrow) ImageCreatedEvent(message.origin.team, message.origin.thread, ImageInfo(fTeamID, info.id, info.name, info.type, (addr_t)info.text, info.text_size, (addr_t)info.data, info.data_size)); break; } case B_DEBUGGER_MESSAGE_IMAGE_DELETED: { const image_info& info = message.image_deleted.info; event = new(std::nothrow) ImageDeletedEvent(message.origin.team, message.origin.thread, ImageInfo(fTeamID, info.id, info.name, info.type, (addr_t)info.text, info.text_size, (addr_t)info.data, info.data_size)); break; } case B_DEBUGGER_MESSAGE_POST_SYSCALL: { event = new(std::nothrow) PostSyscallEvent(message.origin.team, message.origin.thread, SyscallInfo(message.post_syscall.start_time, message.post_syscall.end_time, message.post_syscall.return_value, message.post_syscall.syscall, message.post_syscall.args)); break; } case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: { event = new(std::nothrow) SignalReceivedEvent(message.origin.team, message.origin.thread, SignalInfo(message.signal_received.signal, message.signal_received.handler, message.signal_received.deadly)); break; } default: printf("DebuggerInterface for team %" B_PRId32 ": unknown message " "from kernel: %" B_PRId32 "\n", fTeamID, messageCode); // fall through... case B_DEBUGGER_MESSAGE_TEAM_CREATED: case B_DEBUGGER_MESSAGE_PRE_SYSCALL: case B_DEBUGGER_MESSAGE_PROFILER_UPDATE: case B_DEBUGGER_MESSAGE_HANDED_OVER: _ignore = true; return B_OK; } if (event == NULL) return B_NO_MEMORY; if (message.origin.thread >= 0 && message.origin.nub_port >= 0) event->SetThreadStopped(true); _ignore = false; _event = event; return B_OK; }
status_t DwarfImageDebugInfo::CreateFrame(Image* image, FunctionInstance* functionInstance, CpuState* cpuState, StackFrame*& _previousFrame, CpuState*& _previousCpuState) { DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>( functionInstance->GetFunctionDebugInfo()); if (function == NULL) return B_BAD_VALUE; TRACE_CFI("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p\n", function->SubprogramEntry()); int32 registerCount = fArchitecture->CountRegisters(); const Register* registers = fArchitecture->Registers(); // get the DWARF <-> architecture register maps RegisterMap* toDwarfMap; RegisterMap* fromDwarfMap; status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap, &fromDwarfMap); if (error != B_OK) return error; Reference<RegisterMap> toDwarfMapReference(toDwarfMap, true); Reference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true); // create a clean CPU state for the previous frame CpuState* previousCpuState; error = fArchitecture->CreateCpuState(previousCpuState); if (error != B_OK) return error; Reference<CpuState> previousCpuStateReference(previousCpuState, true); // create the target interfaces UnwindTargetInterface* inputInterface = new(std::nothrow) UnwindTargetInterface(registers, registerCount, fromDwarfMap, toDwarfMap, cpuState, fArchitecture, fTeamMemory); if (inputInterface == NULL) return B_NO_MEMORY; Reference<UnwindTargetInterface> inputInterfaceReference(inputInterface, true); UnwindTargetInterface* outputInterface = new(std::nothrow) UnwindTargetInterface(registers, registerCount, fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture, fTeamMemory); if (outputInterface == NULL) return B_NO_MEMORY; Reference<UnwindTargetInterface> outputInterfaceReference(outputInterface, true); // do the unwinding target_addr_t instructionPointer = cpuState->InstructionPointer() - fRelocationDelta; target_addr_t framePointer; CompilationUnit* unit = function->GetCompilationUnit(); error = fFile->UnwindCallFrame(unit, function->SubprogramEntry(), instructionPointer, inputInterface, outputInterface, framePointer); if (error != B_OK) { TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error)); return B_UNSUPPORTED; } TRACE_CFI_ONLY( TRACE_CFI("unwound registers:\n"); for (int32 i = 0; i < registerCount; i++) { const Register* reg = registers + i; BVariant value; if (previousCpuState->GetRegisterValue(reg, value)) TRACE_CFI(" %3s: %#lx\n", reg->Name(), value.ToUInt32()); else TRACE_CFI(" %3s: undefined\n", reg->Name()); } )
status_t DebugReportGenerator::_DumpDebuggedThreadInfo(BFile& _output, ::Thread* thread) { AutoLocker< ::Team> locker; if (thread->State() != THREAD_STATE_STOPPED) return B_OK; status_t error; StackTrace* trace = NULL; for (;;) { trace = thread->GetStackTrace(); if (trace != NULL) break; locker.Unlock(); fTraceWaitingThread = thread; do { error = acquire_sem(fTeamDataSem); } while (error == B_INTERRUPTED); if (error != B_OK) break; locker.Lock(); } BString data("\t\tFrame\t\tIP\t\t\tFunction Name\n"); WRITE_AND_CHECK(_output, data); data = "\t\t-----------------------------------------------\n"; WRITE_AND_CHECK(_output, data); for (int32 i = 0; StackFrame* frame = trace->FrameAt(i); i++) { char functionName[512]; BString sourcePath; target_addr_t ip = frame->InstructionPointer(); FunctionInstance* functionInstance; Statement* statement; if (fTeam->GetStatementAtAddress(ip, functionInstance, statement) == B_OK) { BReference<Statement> statementReference(statement, true); int32 line = statement->StartSourceLocation().Line(); LocatableFile* sourceFile = functionInstance->GetFunction() ->SourceFile(); if (sourceFile != NULL) { sourceFile->GetPath(sourcePath); sourcePath.SetToFormat("(%s:%" B_PRId32 ")", sourcePath.String(), line); } } data.SetToFormat("\t\t%#08" B_PRIx64 "\t%#08" B_PRIx64 "\t%s %s\n", frame->FrameAddress(), ip, UiUtils::FunctionNameForFrame( frame, functionName, sizeof(functionName)), sourcePath.String()); WRITE_AND_CHECK(_output, data); // only dump the topmost frame if (i == 0) { locker.Unlock(); error = _DumpFunctionDisassembly(_output, frame->InstructionPointer()); if (error != B_OK) return error; error = _DumpStackFrameMemory(_output, thread->GetCpuState(), frame->FrameAddress(), thread->GetTeam()->GetArchitecture() ->StackGrowthDirection()); if (error != B_OK) return error; locker.Lock(); } if (frame->CountParameters() == 0 && frame->CountLocalVariables() == 0) continue; data = "\t\t\tVariables:\n"; WRITE_AND_CHECK(_output, data); error = fNodeManager->SetStackFrame(thread, frame); if (error != B_OK) continue; ValueNodeContainer* container = fNodeManager->GetContainer(); AutoLocker<ValueNodeContainer> containerLocker(container); for (int32 i = 0; i < container->CountChildren(); i++) { data.Truncate(0L); ValueNodeChild* child = container->ChildAt(i); containerLocker.Unlock(); _ResolveValueIfNeeded(child->Node(), frame, 1); containerLocker.Lock(); UiUtils::PrintValueNodeGraph(data, child, 3, 1); WRITE_AND_CHECK(_output, data); } data = "\n"; WRITE_AND_CHECK(_output, data); } data = "\n\t\tRegisters:\n"; WRITE_AND_CHECK(_output, data); CpuState* state = thread->GetCpuState(); BVariant value; const Register* reg = NULL; for (int32 i = 0; i < fArchitecture->CountRegisters(); i++) { reg = fArchitecture->Registers() + i; state->GetRegisterValue(reg, value); if (reg->Format() == REGISTER_FORMAT_SIMD) { data.SetToFormat("\t\t\t%5s:\t%s\n", reg->Name(), UiUtils::FormatSIMDValue(value, reg->BitSize(), SIMD_RENDER_FORMAT_INT16, data).String()); } else { char buffer[64]; data.SetToFormat("\t\t\t%5s:\t%s\n", reg->Name(), UiUtils::VariantToString(value, buffer, sizeof(buffer))); } WRITE_AND_CHECK(_output, data); } return B_OK; }