status_t Architecture::CreateStackTrace(Team* team, ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState, StackTrace*& _stackTrace, ReturnValueInfoList* returnValueInfos, int32 maxStackDepth, bool useExistingTrace, bool getFullFrameInfo) { BReference<CpuState> cpuStateReference(cpuState); StackTrace* stackTrace = NULL; ObjectDeleter<StackTrace> stackTraceDeleter; StackFrame* nextFrame = 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) { nextFrame = stackTrace->FrameAt(stackTrace->CountFrames() - 1); cpuState = nextFrame->PreviousCpuState(); } while (cpuState != NULL) { // get the instruction pointer target_addr_t instructionPointer = cpuState->InstructionPointer(); // 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 (nextFrame != NULL && nextFrame->ReturnAddress() == cpuState->InstructionPointer()) { UpdateStackFrameCpuState(nextFrame, image, functionDebugInfo, cpuState); } // create the frame using the debug info StackFrame* frame = NULL; CpuState* previousCpuState = NULL; if (function != NULL) { status_t error = functionDebugInfo->GetSpecificImageDebugInfo() ->CreateFrame(image, function, cpuState, getFullFrameInfo, nextFrame == NULL ? returnValueInfos : NULL, frame, previousCpuState); if (error != B_OK && error != B_UNSUPPORTED) break; } // If we have no frame yet, let the architecture create it. if (frame == NULL) { status_t error = CreateStackFrame(image, functionDebugInfo, cpuState, nextFrame == NULL, frame, previousCpuState); if (error != B_OK) break; } cpuStateReference.SetTo(previousCpuState, true); frame->SetImage(image); frame->SetFunction(function); if (!stackTrace->AddFrame(frame)) { delete frame; return B_NO_MEMORY; } nextFrame = frame; cpuState = previousCpuState; if (--maxStackDepth == 0) break; } if (stackTrace->CountFrames() == 0) return B_ERROR; stackTraceDeleter.Detach(); _stackTrace = stackTrace; return B_OK; }