Statement* ThreadHandler::_GetStatementAtInstructionPointer(StackFrame* frame) { AutoLocker<Team> locker(fThread->GetTeam()); FunctionInstance* functionInstance = frame->Function(); if (functionInstance == NULL) return NULL; FunctionDebugInfo* function = functionInstance->GetFunctionDebugInfo(); // If there's source code attached to the function, we can just get the // statement. // SourceCode* sourceCode = function->GetSourceCode(); // if (sourceCode != NULL) { // Statement* statement = sourceCode->StatementAtAddress( // frame->InstructionPointer()); // if (statement != NULL) // statement->AcquireReference(); // return statement; // } locker.Unlock(); // We need to get the statement from the debug info of the function. Statement* statement; if (function->GetSpecificImageDebugInfo()->GetStatement(function, frame->InstructionPointer(), statement) != B_OK) { return NULL; } return statement; }
status_t Team::GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function, Statement*& _statement) { TRACE_CODE("Team::GetStatementAtAddress(%#" B_PRIx64 ")\n", address); // get the image at the address Image* image = ImageByAddress(address); if (image == NULL) { TRACE_CODE(" -> no image\n"); return B_ENTRY_NOT_FOUND; } ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); if (imageDebugInfo == NULL) { TRACE_CODE(" -> no image debug info\n"); return B_ENTRY_NOT_FOUND; } // get the function FunctionInstance* functionInstance = imageDebugInfo->FunctionAtAddress(address); if (functionInstance == NULL) { TRACE_CODE(" -> no function instance\n"); return B_ENTRY_NOT_FOUND; } // If the function instance has disassembled code attached, we can get the // statement directly. if (DisassembledCode* code = functionInstance->GetSourceCode()) { Statement* statement = code->StatementAtAddress(address); if (statement == NULL) return B_ENTRY_NOT_FOUND; statement->AcquireReference(); _statement = statement; _function = functionInstance; return B_OK; } // get the statement from the image debug info FunctionDebugInfo* functionDebugInfo = functionInstance->GetFunctionDebugInfo(); status_t error = functionDebugInfo->GetSpecificImageDebugInfo() ->GetStatement(functionDebugInfo, address, _statement); if (error != B_OK) { TRACE_CODE(" -> no statement from the specific image debug info\n"); return error; } _function = functionInstance; return B_OK; }
status_t Team::GetStatementAtSourceLocation(SourceCode* sourceCode, const SourceLocation& location, Statement*& _statement) { TRACE_CODE("Team::GetStatementAtSourceLocation(%p, (%" B_PRId32 ", %" B_PRId32 "))\n", sourceCode, location.Line(), location.Column()); // If we're lucky the source code can provide us with a statement. if (DisassembledCode* code = dynamic_cast<DisassembledCode*>(sourceCode)) { Statement* statement = code->StatementAtLocation(location); if (statement == NULL) return B_ENTRY_NOT_FOUND; statement->AcquireReference(); _statement = statement; return B_OK; } // Go the long and stony way over the source file and the team debug info. // get the source file for the source code LocatableFile* sourceFile = sourceCode->GetSourceFile(); if (sourceFile == NULL) return B_ENTRY_NOT_FOUND; // get the function at the source location Function* function = fDebugInfo->FunctionAtSourceLocation(sourceFile, location); if (function == NULL) return B_ENTRY_NOT_FOUND; // Get some function instance and ask its image debug info to provide us // with a statement. FunctionInstance* functionInstance = function->FirstInstance(); if (functionInstance == NULL) return B_ENTRY_NOT_FOUND; FunctionDebugInfo* functionDebugInfo = functionInstance->GetFunctionDebugInfo(); return functionDebugInfo->GetSpecificImageDebugInfo() ->GetStatementAtSourceLocation(functionDebugInfo, location, _statement); }
status_t TeamDebugInfo::DisassembleFunction(FunctionInstance* functionInstance, DisassembledCode*& _sourceCode) { // allocate a buffer for the function code static const target_size_t kMaxBufferSize = 64 * 1024; target_size_t bufferSize = std::min(functionInstance->Size(), kMaxBufferSize); void* buffer = malloc(bufferSize); if (buffer == NULL) return B_NO_MEMORY; MemoryDeleter bufferDeleter(buffer); // read the function code FunctionDebugInfo* functionDebugInfo = functionInstance->GetFunctionDebugInfo(); ssize_t bytesRead = functionDebugInfo->GetSpecificImageDebugInfo() ->ReadCode(functionInstance->Address(), buffer, bufferSize); if (bytesRead < 0) return bytesRead; return fArchitecture->DisassembleCode(functionDebugInfo, buffer, bytesRead, _sourceCode); }
status_t TeamDebugInfo::LoadSourceCode(LocatableFile* file, FileSourceCode*& _sourceCode) { AutoLocker<BLocker> locker(fLock); // If we don't know the source file, there's nothing we can do. SourceFileEntry* entry = fSourceFiles->Lookup(file); if (entry == NULL) return B_ENTRY_NOT_FOUND; // the source might already be loaded FileSourceCode* sourceCode = entry->GetSourceCode(); if (sourceCode != NULL) { sourceCode->AcquireReference(); _sourceCode = sourceCode; return B_OK; } // get the source language from some function's image debug info Function* function = entry->FunctionAt(0); if (function == NULL) return B_ENTRY_NOT_FOUND; FunctionDebugInfo* functionDebugInfo = function->FirstInstance()->GetFunctionDebugInfo(); SourceLanguage* language; status_t error = functionDebugInfo->GetSpecificImageDebugInfo() ->GetSourceLanguage(functionDebugInfo, language); if (error != B_OK) return error; BReference<SourceLanguage> languageReference(language, true); // no source code yet // locker.Unlock(); // TODO: It would be nice to unlock here, but we need to iterate through // the images below. We could clone the list, acquire references, and // unlock. Then we have to compare the list with the then current list when // we're done loading. // load the source file SourceFile* sourceFile; error = fFileManager->LoadSourceFile(file, sourceFile); if (error != B_OK) return error; // create the source code sourceCode = new(std::nothrow) FileSourceCode(file, sourceFile, language); sourceFile->ReleaseReference(); if (sourceCode == NULL) return B_NO_MEMORY; BReference<FileSourceCode> sourceCodeReference(sourceCode, true); error = sourceCode->Init(); if (error != B_OK) return error; // Iterate through all images that know the source file and ask them to add // information. bool anyInfo = false; for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) anyInfo |= imageDebugInfo->AddSourceCodeInfo(file, sourceCode) == B_OK; if (!anyInfo) return B_ENTRY_NOT_FOUND; entry->SetSourceCode(sourceCode); _sourceCode = sourceCodeReference.Detach(); return B_OK; }
status_t Architecture::CreateStackTrace(Team* team, ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState, StackTrace*& _stackTrace, int32 maxStackDepth, bool useExistingTrace) { BReference<CpuState> cpuStateReference(cpuState); StackTrace* stackTrace = NULL; ObjectDeleter<StackTrace> stackTraceDeleter; StackFrame* frame = NULL; if (useExistingTrace) stackTrace = _stackTrace; else { // create the object stackTrace = new(std::nothrow) StackTrace; if (stackTrace == NULL) return B_NO_MEMORY; stackTraceDeleter.SetTo(stackTrace); } // if we're passed an already existing partial stack trace, // attempt to continue building it from where it left off. if (stackTrace->CountFrames() > 0) { frame = stackTrace->FrameAt(stackTrace->CountFrames() - 1); cpuState = frame->GetCpuState(); } while (cpuState != NULL) { // get the instruction pointer target_addr_t instructionPointer = cpuState->InstructionPointer(); if (instructionPointer == 0) break; // get the image for the instruction pointer AutoLocker<Team> teamLocker(team); Image* image = team->ImageByAddress(instructionPointer); BReference<Image> imageReference(image); teamLocker.Unlock(); // get the image debug info ImageDebugInfo* imageDebugInfo = NULL; if (image != NULL) imageInfoProvider->GetImageDebugInfo(image, imageDebugInfo); BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo, true); // get the function teamLocker.Lock(); FunctionInstance* function = NULL; FunctionDebugInfo* functionDebugInfo = NULL; if (imageDebugInfo != NULL) { function = imageDebugInfo->FunctionAtAddress(instructionPointer); if (function != NULL) functionDebugInfo = function->GetFunctionDebugInfo(); } BReference<FunctionInstance> functionReference(function); teamLocker.Unlock(); // If the CPU state's instruction pointer is actually the return address // of the next frame, we let the architecture fix that. if (frame != NULL && frame->ReturnAddress() == cpuState->InstructionPointer()) { UpdateStackFrameCpuState(frame, image, functionDebugInfo, cpuState); } // create the frame using the debug info StackFrame* previousFrame = NULL; CpuState* previousCpuState = NULL; if (function != NULL) { status_t error = functionDebugInfo->GetSpecificImageDebugInfo() ->CreateFrame(image, function, cpuState, previousFrame, previousCpuState); if (error != B_OK && error != B_UNSUPPORTED) break; } // If we have no frame yet, let the architecture create it. if (previousFrame == NULL) { status_t error = CreateStackFrame(image, functionDebugInfo, cpuState, frame == NULL, previousFrame, previousCpuState); if (error != B_OK) break; } cpuStateReference.SetTo(previousCpuState, true); previousFrame->SetImage(image); previousFrame->SetFunction(function); if (!stackTrace->AddFrame(previousFrame)) { delete previousFrame; return B_NO_MEMORY; } frame = previousFrame; cpuState = previousCpuState; if (--maxStackDepth == 0) break; } stackTraceDeleter.Detach(); _stackTrace = stackTrace; return B_OK; }
void BreakpointManager::_UpdateImageBreakpoints(Image* image, bool removeOnly) { AutoLocker<BLocker> installLocker(fLock); AutoLocker<Team> teamLocker(fTeam); // remove obsolete user breakpoint instances BObjectList<Breakpoint> breakpointsToUpdate; for (UserBreakpointList::ConstIterator it = fTeam->UserBreakpoints().GetIterator(); UserBreakpoint* userBreakpoint = it.Next();) { int32 instanceCount = userBreakpoint->CountInstances(); for (int32 i = instanceCount - 1; i >= 0; i--) { UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); Breakpoint* breakpoint = instance->GetBreakpoint(); if (breakpoint == NULL || breakpoint->GetImage() != image) continue; userBreakpoint->RemoveInstanceAt(i); breakpoint->RemoveUserBreakpoint(instance); if (!breakpointsToUpdate.AddItem(breakpoint)) { _UpdateBreakpointInstallation(breakpoint); if (breakpoint->IsUnused()) fTeam->RemoveBreakpoint(breakpoint); } delete instance; } } // update breakpoints teamLocker.Unlock(); for (int32 i = 0; Breakpoint* breakpoint = breakpointsToUpdate.ItemAt(i); i++) { _UpdateBreakpointInstallation(breakpoint); } teamLocker.Lock(); for (int32 i = 0; Breakpoint* breakpoint = breakpointsToUpdate.ItemAt(i); i++) { if (breakpoint->IsUnused()) fTeam->RemoveBreakpoint(breakpoint); } // add breakpoint instances for function instances in the image (if we have // an image debug info) BObjectList<UserBreakpointInstance> newInstances; ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); if (imageDebugInfo == NULL) return; for (UserBreakpointList::ConstIterator it = fTeam->UserBreakpoints().GetIterator(); UserBreakpoint* userBreakpoint = it.Next();) { // get the function Function* function = fTeam->FunctionByID( userBreakpoint->Location().GetFunctionID()); if (function == NULL) continue; const SourceLocation& sourceLocation = userBreakpoint->Location().GetSourceLocation(); target_addr_t relativeAddress = userBreakpoint->Location().RelativeAddress(); // iterate through the function instances for (FunctionInstanceList::ConstIterator it = function->Instances().GetIterator(); FunctionInstance* functionInstance = it.Next();) { if (functionInstance->GetImageDebugInfo() != imageDebugInfo) continue; // get the breakpoint address for the instance target_addr_t instanceAddress = 0; if (functionInstance->SourceFile() != NULL) { // We have a source file, so get the address for the source // location. Statement* statement = NULL; FunctionDebugInfo* functionDebugInfo = functionInstance->GetFunctionDebugInfo(); functionDebugInfo->GetSpecificImageDebugInfo() ->GetStatementAtSourceLocation(functionDebugInfo, sourceLocation, statement); if (statement != NULL) { instanceAddress = statement->CoveringAddressRange().Start(); // TODO: What about BreakpointAllowed()? statement->ReleaseReference(); // TODO: Make sure we do hit the function in question! } } if (instanceAddress == 0) { // No source file (or we failed getting the statement), so try // to use the same relative address. if (relativeAddress > functionInstance->Size()) continue; instanceAddress = functionInstance->Address() + relativeAddress; // TODO: Make sure it does at least hit an instruction! } // create the user breakpoint instance UserBreakpointInstance* instance = new(std::nothrow) UserBreakpointInstance(userBreakpoint, instanceAddress); if (instance == NULL || !newInstances.AddItem(instance)) { delete instance; continue; } if (!userBreakpoint->AddInstance(instance)) { newInstances.RemoveItemAt(newInstances.CountItems() - 1); delete instance; } // get/create the breakpoint for the address target_addr_t address = instance->Address(); Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address); if (breakpoint == NULL) { breakpoint = new(std::nothrow) Breakpoint(image, address); if (breakpoint == NULL || !fTeam->AddBreakpoint(breakpoint)) { delete breakpoint; break; } } breakpoint->AddUserBreakpoint(instance); instance->SetBreakpoint(breakpoint); } } // install the breakpoints for the new user breakpoint instances teamLocker.Unlock(); for (int32 i = 0; UserBreakpointInstance* instance = newInstances.ItemAt(i); i++) { Breakpoint* breakpoint = instance->GetBreakpoint(); if (breakpoint == NULL || _UpdateBreakpointInstallation(breakpoint) != B_OK) { // something went wrong -- remove the instance teamLocker.Lock(); instance->GetUserBreakpoint()->RemoveInstance(instance); if (breakpoint != NULL) { breakpoint->AddUserBreakpoint(instance); if (breakpoint->IsUnused()) fTeam->RemoveBreakpoint(breakpoint); } teamLocker.Unlock(); } } }
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); }