xref: /haiku/src/kits/debugger/arch/Architecture.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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 
27 Architecture::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 
38 Architecture::~Architecture()
39 {
40 }
41 
42 
43 status_t
44 Architecture::Init()
45 {
46 	return B_OK;
47 }
48 
49 
50 status_t
51 Architecture::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 
96 status_t
97 Architecture::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