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