1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2016, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7#include "Architecture.h"
8
9#include <new>
10
11#include <AutoDeleter.h>
12#include <AutoLocker.h>
13
14#include "CfaContext.h"
15#include "CpuState.h"
16#include "FunctionInstance.h"
17#include "Image.h"
18#include "ImageDebugInfo.h"
19#include "ImageDebugInfoProvider.h"
20#include "Register.h"
21#include "RegisterMap.h"
22#include "SpecificImageDebugInfo.h"
23#include "StackTrace.h"
24#include "Team.h"
25
26
27Architecture::Architecture(TeamMemory* teamMemory, uint8 addressSize,
28	size_t debugCpuStateSize, bool bigEndian)
29	:
30	fTeamMemory(teamMemory),
31	fAddressSize(addressSize),
32	fDebugCpuStateSize(debugCpuStateSize),
33	fBigEndian(bigEndian)
34{
35}
36
37
38Architecture::~Architecture()
39{
40}
41
42
43status_t
44Architecture::Init()
45{
46	return B_OK;
47}
48
49
50status_t
51Architecture::InitRegisterRules(CfaContext& context) const
52{
53	// Init the initial register rules. The DWARF 3 specs on the
54	// matter: "The default rule for all columns before
55	// interpretation of the initial instructions is the undefined
56	// rule. However, an ABI authoring body or a compilation system
57	// authoring body may specify an alternate default value for any
58	// or all columns."
59	// GCC's assumes the "same value" rule for all callee preserved
60	// registers. We set them respectively.
61	// the stack pointer is initialized to
62	// CFA offset 0 by default.
63	const Register* registers = Registers();
64	RegisterMap* toDwarf = NULL;
65	status_t result = GetDwarfRegisterMaps(&toDwarf, NULL);
66	if (result != B_OK)
67		return result;
68
69	BReference<RegisterMap> toDwarfMapReference(toDwarf, true);
70	for (int32 i = 0; i < CountRegisters(); i++) {
71		int32 dwarfReg = toDwarf->MapRegisterIndex(i);
72		if (dwarfReg < 0 || dwarfReg > CountRegisters() - 1)
73			continue;
74
75		// TODO: on CPUs that have a return address register
76		// a default rule should be set up to use that to
77		// extract the instruction pointer
78		switch (registers[i].Type()) {
79			case REGISTER_TYPE_STACK_POINTER:
80			{
81				context.RegisterRule(dwarfReg)->SetToValueOffset(0);
82				break;
83			}
84			default:
85			{
86				context.RegisterRule(dwarfReg)->SetToSameValue();
87				break;
88			}
89		}
90	}
91
92	return result;
93}
94
95
96status_t
97Architecture::CreateStackTrace(Team* team,
98	ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState,
99	StackTrace*& _stackTrace, ReturnValueInfoList* returnValueInfos,
100	int32 maxStackDepth, bool useExistingTrace, bool getFullFrameInfo)
101{
102	BReference<CpuState> cpuStateReference(cpuState);
103
104	StackTrace* stackTrace = NULL;
105	ObjectDeleter<StackTrace> stackTraceDeleter;
106	StackFrame* nextFrame = NULL;
107
108	if (useExistingTrace)
109		stackTrace = _stackTrace;
110	else {
111		// create the object
112		stackTrace = new(std::nothrow) StackTrace;
113		if (stackTrace == NULL)
114			return B_NO_MEMORY;
115		stackTraceDeleter.SetTo(stackTrace);
116	}
117
118	// if we're passed an already existing partial stack trace,
119	// attempt to continue building it from where it left off.
120	if (stackTrace->CountFrames() > 0) {
121		nextFrame = stackTrace->FrameAt(stackTrace->CountFrames() - 1);
122		cpuState = nextFrame->PreviousCpuState();
123	}
124
125	while (cpuState != NULL) {
126		// get the instruction pointer
127		target_addr_t instructionPointer = cpuState->InstructionPointer();
128
129		// get the image for the instruction pointer
130		AutoLocker<Team> teamLocker(team);
131		Image* image = team->ImageByAddress(instructionPointer);
132		BReference<Image> imageReference(image);
133		teamLocker.Unlock();
134
135		// get the image debug info
136		ImageDebugInfo* imageDebugInfo = NULL;
137		if (image != NULL)
138			imageInfoProvider->GetImageDebugInfo(image, imageDebugInfo);
139		BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo,
140			true);
141
142		// get the function
143		teamLocker.Lock();
144		FunctionInstance* function = NULL;
145		FunctionDebugInfo* functionDebugInfo = NULL;
146		if (imageDebugInfo != NULL) {
147			function = imageDebugInfo->FunctionAtAddress(instructionPointer);
148			if (function != NULL)
149				functionDebugInfo = function->GetFunctionDebugInfo();
150		}
151		BReference<FunctionInstance> functionReference(function);
152		teamLocker.Unlock();
153
154		// If the CPU state's instruction pointer is actually the return address
155		// of the next frame, we let the architecture fix that.
156		if (nextFrame != NULL
157			&& nextFrame->ReturnAddress() == cpuState->InstructionPointer()) {
158			UpdateStackFrameCpuState(nextFrame, image,
159				functionDebugInfo, cpuState);
160		}
161
162		// create the frame using the debug info
163		StackFrame* frame = NULL;
164		CpuState* previousCpuState = NULL;
165		if (function != NULL) {
166			status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
167				->CreateFrame(image, function, cpuState, getFullFrameInfo,
168					nextFrame == NULL
169						? returnValueInfos : NULL, frame,
170					previousCpuState);
171			if (error != B_OK && error != B_UNSUPPORTED)
172				break;
173		}
174
175		// If we have no frame yet, let the architecture create it.
176		if (frame == NULL) {
177			status_t error = CreateStackFrame(image, functionDebugInfo,
178				cpuState, nextFrame == NULL, frame, previousCpuState);
179			if (error != B_OK)
180				break;
181		}
182
183		cpuStateReference.SetTo(previousCpuState, true);
184
185		frame->SetImage(image);
186		frame->SetFunction(function);
187
188		if (!stackTrace->AddFrame(frame)) {
189			delete frame;
190			return B_NO_MEMORY;
191		}
192
193		nextFrame = frame;
194		cpuState = previousCpuState;
195		if (--maxStackDepth == 0)
196			break;
197	}
198
199	if (stackTrace->CountFrames() == 0)
200		return B_ERROR;
201
202	stackTraceDeleter.Detach();
203	_stackTrace = stackTrace;
204	return B_OK;
205}
206