-
-
Notifications
You must be signed in to change notification settings - Fork 340
/
Architecture.cpp
197 lines (165 loc) · 5.09 KB
/
Architecture.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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,
bool bigEndian)
:
fTeamMemory(teamMemory),
fAddressSize(addressSize),
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<RegisterMap> 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, int32 maxStackDepth, bool useExistingTrace)
{
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, 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;
}
frame = nextFrame;
cpuState = previousCpuState;
if (--maxStackDepth == 0)
break;
}
stackTraceDeleter.Detach();
_stackTrace = stackTrace;
return B_OK;
}