* 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 <new>
#include <AutoDeleter.h>
#include <AutoLocker.h>
#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
{
const Register* registers = Registers();
RegisterMap* toDwarf = NULL;
status_t result = GetDwarfRegisterMaps(&toDwarf, NULL);
if (result != B_OK)
return result;
BReference<RegisterMap> toDwarfMapReference(toDwarf, true);
for (int32 i = 0; i < CountRegisters(); i++) {
int32 dwarfReg = toDwarf->MapRegisterIndex(i);
if (dwarfReg < 0 || dwarfReg > CountRegisters() - 1)
continue;
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<CpuState> cpuStateReference(cpuState);
StackTrace* stackTrace = NULL;
ObjectDeleter<StackTrace> stackTraceDeleter;
StackFrame* nextFrame = NULL;
if (useExistingTrace)
stackTrace = _stackTrace;
else {
stackTrace = new(std::nothrow) StackTrace;
if (stackTrace == NULL)
return B_NO_MEMORY;
stackTraceDeleter.SetTo(stackTrace);
}
if (stackTrace->CountFrames() > 0) {
nextFrame = stackTrace->FrameAt(stackTrace->CountFrames() - 1);
cpuState = nextFrame->PreviousCpuState();
}
while (cpuState != NULL) {
target_addr_t instructionPointer = cpuState->InstructionPointer();
AutoLocker<Team> teamLocker(team);
Image* image = team->ImageByAddress(instructionPointer);
BReference<Image> imageReference(image);
teamLocker.Unlock();
ImageDebugInfo* imageDebugInfo = NULL;
if (image != NULL)
imageInfoProvider->GetImageDebugInfo(image, imageDebugInfo);
BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo,
true);
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 (nextFrame != NULL
&& nextFrame->ReturnAddress() == cpuState->InstructionPointer()) {
UpdateStackFrameCpuState(nextFrame, image,
functionDebugInfo, cpuState);
}
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 (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;
}