/* * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2016, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #include "Architecture.h" #include #include #include #include "CfaContext.h" #include "CpuState.h" #include "FunctionInstance.h" #include "Image.h" #include "ImageDebugInfo.h" #include "ImageDebugInfoProvider.h" #include "Register.h" #include "RegisterMap.h" #include "SpecificImageDebugInfo.h" #include "StackTrace.h" #include "Team.h" Architecture::Architecture(TeamMemory* teamMemory, uint8 addressSize, size_t debugCpuStateSize, bool bigEndian) : fTeamMemory(teamMemory), fAddressSize(addressSize), fDebugCpuStateSize(debugCpuStateSize), fBigEndian(bigEndian) { } Architecture::~Architecture() { } status_t Architecture::Init() { return B_OK; } status_t Architecture::InitRegisterRules(CfaContext& context) const { // Init the initial register rules. The DWARF 3 specs on the // matter: "The default rule for all columns before // interpretation of the initial instructions is the undefined // rule. However, an ABI authoring body or a compilation system // authoring body may specify an alternate default value for any // or all columns." // GCC's assumes the "same value" rule for all callee preserved // registers. We set them respectively. // the stack pointer is initialized to // CFA offset 0 by default. const Register* registers = Registers(); RegisterMap* toDwarf = NULL; status_t result = GetDwarfRegisterMaps(&toDwarf, NULL); if (result != B_OK) return result; BReference toDwarfMapReference(toDwarf, true); for (int32 i = 0; i < CountRegisters(); i++) { int32 dwarfReg = toDwarf->MapRegisterIndex(i); if (dwarfReg < 0 || dwarfReg > CountRegisters() - 1) continue; // TODO: on CPUs that have a return address register // a default rule should be set up to use that to // extract the instruction pointer switch (registers[i].Type()) { case REGISTER_TYPE_STACK_POINTER: { context.RegisterRule(dwarfReg)->SetToValueOffset(0); break; } default: { context.RegisterRule(dwarfReg)->SetToSameValue(); break; } } } return result; } status_t Architecture::CreateStackTrace(Team* team, ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState, StackTrace*& _stackTrace, ReturnValueInfoList* returnValueInfos, int32 maxStackDepth, bool useExistingTrace, bool getFullFrameInfo) { BReference cpuStateReference(cpuState); StackTrace* stackTrace = NULL; ObjectDeleter 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 teamLocker(team); Image* image = team->ImageByAddress(instructionPointer); BReference imageReference(image); teamLocker.Unlock(); // get the image debug info ImageDebugInfo* imageDebugInfo = NULL; if (image != NULL) imageInfoProvider->GetImageDebugInfo(image, imageDebugInfo); BReference 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 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; }