Function* TeamDebugInfo::FunctionByID(FunctionID* functionID) const { if (SourceFunctionID* sourceFunctionID = dynamic_cast<SourceFunctionID*>(functionID)) { // get the source file LocatableFile* file = fFileManager->GetSourceFile( sourceFunctionID->SourceFilePath()); if (file == NULL) return NULL; BReference<LocatableFile> fileReference(file, true); if (SourceFileEntry* entry = fSourceFiles->Lookup(file)) return entry->FunctionByName(functionID->FunctionName()); return NULL; } ImageFunctionID* imageFunctionID = dynamic_cast<ImageFunctionID*>(functionID); if (imageFunctionID == NULL) return NULL; ImageDebugInfo* imageDebugInfo = ImageDebugInfoByName(imageFunctionID->ImageName()); if (imageDebugInfo == NULL) return NULL; FunctionInstance* functionInstance = imageDebugInfo->FunctionByName( functionID->FunctionName()); return functionInstance != NULL ? functionInstance->GetFunction() : NULL; }
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; }
status_t DebugReportGenerator::_DumpFunctionDisassembly(BFile& _output, target_addr_t instructionPointer) { AutoLocker< ::Team> teamLocker(fTeam); BString data; FunctionInstance* instance = NULL; Statement* statement = NULL; status_t error = fTeam->GetStatementAtAddress(instructionPointer, instance, statement); if (error != B_OK) { data.SetToFormat("Unable to retrieve disassembly for IP %#" B_PRIx64 ": %s\n", instructionPointer, strerror(error)); WRITE_AND_CHECK(_output, data); return B_OK; } DisassembledCode* code = instance->GetSourceCode(); Function* function = instance->GetFunction(); if (code == NULL) { switch (function->SourceCodeState()) { case FUNCTION_SOURCE_NOT_LOADED: case FUNCTION_SOURCE_LOADED: // FUNCTION_SOURCE_LOADED is included since, if we entered // here, it implies that the high level source for the // function has been loaded, but the disassembly has not. function->AddListener(this); fSourceWaitingFunction = function; fListener->FunctionSourceCodeRequested(instance, true); // fall through case FUNCTION_SOURCE_LOADING: { teamLocker.Unlock(); do { error = acquire_sem(fTeamDataSem); } while (error == B_INTERRUPTED); if (error != B_OK) return error; teamLocker.Lock(); break; } default: return B_OK; } if (instance->SourceCodeState() == FUNCTION_SOURCE_UNAVAILABLE) return B_OK; error = fTeam->GetStatementAtAddress(instructionPointer, instance, statement); code = instance->GetSourceCode(); } SourceLocation location = statement->StartSourceLocation(); data = "\t\t\tDisassembly:\n"; WRITE_AND_CHECK(_output, data); for (int32 i = 0; i <= location.Line(); i++) { data = "\t\t\t\t"; data << code->LineAt(i); if (i == location.Line()) data << " <--"; data << "\n"; WRITE_AND_CHECK(_output, data); } data = "\n"; WRITE_AND_CHECK(_output, data); return B_OK; }
void TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled) { TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#llx, %d)\n", address, enabled); // check whether there already is a breakpoint AutoLocker< ::Team> locker(fTeam); Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address); UserBreakpoint* userBreakpoint = NULL; if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL) userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint(); BReference<UserBreakpoint> userBreakpointReference(userBreakpoint); if (userBreakpoint == NULL) { TRACE_CONTROL(" no breakpoint yet\n"); // get the function at the address Image* image = fTeam->ImageByAddress(address); TRACE_CONTROL(" image: %p\n", image); if (image == NULL) return; ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); TRACE_CONTROL(" image debug info: %p\n", imageDebugInfo); if (imageDebugInfo == NULL) return; // TODO: Handle this case by loading the debug info, if possible! FunctionInstance* functionInstance = imageDebugInfo->FunctionAtAddress(address); TRACE_CONTROL(" function instance: %p\n", functionInstance); if (functionInstance == NULL) return; Function* function = functionInstance->GetFunction(); TRACE_CONTROL(" function: %p\n", function); // get the source location for the address FunctionDebugInfo* functionDebugInfo = functionInstance->GetFunctionDebugInfo(); SourceLocation sourceLocation; Statement* breakpointStatement = NULL; if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement( functionDebugInfo, address, breakpointStatement) != B_OK) { return; } sourceLocation = breakpointStatement->StartSourceLocation(); breakpointStatement->ReleaseReference(); target_addr_t relativeAddress = address - functionInstance->Address(); TRACE_CONTROL(" relative address: %#llx, source location: " "(%ld, %ld)\n", relativeAddress, sourceLocation.Line(), sourceLocation.Column()); // get function id FunctionID* functionID = functionInstance->GetFunctionID(); if (functionID == NULL) return; BReference<FunctionID> functionIDReference(functionID, true); // create the user breakpoint userBreakpoint = new(std::nothrow) UserBreakpoint( UserBreakpointLocation(functionID, function->SourceFile(), sourceLocation, relativeAddress)); if (userBreakpoint == NULL) return; userBreakpointReference.SetTo(userBreakpoint, true); TRACE_CONTROL(" created user breakpoint: %p\n", userBreakpoint); // iterate through all function instances and create // UserBreakpointInstances for (FunctionInstanceList::ConstIterator it = function->Instances().GetIterator(); FunctionInstance* instance = it.Next();) { TRACE_CONTROL(" function instance %p: range: %#llx - %#llx\n", instance, instance->Address(), instance->Address() + instance->Size()); // get the breakpoint address for the instance target_addr_t instanceAddress = 0; if (instance == functionInstance) { instanceAddress = address; } else if (functionInstance->SourceFile() != NULL) { // We have a source file, so get the address for the source // location. Statement* statement = NULL; functionDebugInfo = instance->GetFunctionDebugInfo(); functionDebugInfo->GetSpecificImageDebugInfo() ->GetStatementAtSourceLocation(functionDebugInfo, sourceLocation, statement); if (statement != NULL) { instanceAddress = statement->CoveringAddressRange().Start(); // TODO: What about BreakpointAllowed()? statement->ReleaseReference(); } } TRACE_CONTROL(" breakpoint address using source info: %llx\n", instanceAddress); if (instanceAddress == 0) { // No source file (or we failed getting the statement), so try // to use the same relative address. if (relativeAddress > instance->Size()) continue; instanceAddress = instance->Address() + relativeAddress; } TRACE_CONTROL(" final breakpoint address: %llx\n", instanceAddress); UserBreakpointInstance* breakpointInstance = new(std::nothrow) UserBreakpointInstance(userBreakpoint, instanceAddress); if (breakpointInstance == NULL || !userBreakpoint->AddInstance(breakpointInstance)) { delete breakpointInstance; return; } TRACE_CONTROL(" breakpoint instance: %p\n", breakpointInstance); } } locker.Unlock(); _HandleSetUserBreakpoint(userBreakpoint, enabled); }