xref: /haiku/src/kits/debugger/arch/Architecture.cpp (revision fce4895d1884da5ae6fb299d23c735c598e690b1)
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 
26 Architecture::Architecture(TeamMemory* teamMemory, uint8 addressSize,
27 	bool bigEndian)
28 	:
29 	fTeamMemory(teamMemory),
30 	fAddressSize(addressSize),
31 	fBigEndian(bigEndian)
32 {
33 }
34 
35 
36 Architecture::~Architecture()
37 {
38 }
39 
40 
41 status_t
42 Architecture::Init()
43 {
44 	return B_OK;
45 }
46 
47 
48 status_t
49 Architecture::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 
94 status_t
95 Architecture::CreateStackTrace(Team* team,
96 	ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState,
97 	StackTrace*& _stackTrace, ReturnValueInfoList* returnValueInfos,
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
167 						? returnValueInfos : NULL, frame,
168 					previousCpuState);
169 			if (error != B_OK && error != B_UNSUPPORTED)
170 				break;
171 		}
172 
173 		// If we have no frame yet, let the architecture create it.
174 		if (frame == NULL) {
175 			status_t error = CreateStackFrame(image, functionDebugInfo,
176 				cpuState, nextFrame == NULL, frame, 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