1/*
2 * Copyright 2012, Rene Gollent, rene@gollent.com.
3 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "DwarfStackFrameDebugInfo.h"
9
10#include <new>
11
12#include "Architecture.h"
13#include "CompilationUnit.h"
14#include "CpuState.h"
15#include "DebugInfoEntries.h"
16#include "Dwarf.h"
17#include "DwarfFile.h"
18#include "DwarfTargetInterface.h"
19#include "DwarfTypeFactory.h"
20#include "DwarfUtils.h"
21#include "DwarfTypes.h"
22#include "FunctionID.h"
23#include "FunctionParameterID.h"
24#include "GlobalTypeLookup.h"
25#include "LocalVariableID.h"
26#include "Register.h"
27#include "RegisterMap.h"
28#include "ReturnValueID.h"
29#include "StringUtils.h"
30#include "Tracing.h"
31#include "ValueLocation.h"
32#include "Variable.h"
33
34
35// #pragma mark - DwarfFunctionParameterID
36
37
38struct DwarfStackFrameDebugInfo::DwarfFunctionParameterID
39	: public FunctionParameterID {
40
41	DwarfFunctionParameterID(FunctionID* functionID, const BString& name)
42		:
43		fFunctionID(functionID),
44		fName(name)
45	{
46		fFunctionID->AcquireReference();
47	}
48
49	virtual ~DwarfFunctionParameterID()
50	{
51		fFunctionID->ReleaseReference();
52	}
53
54	virtual bool operator==(const ObjectID& other) const
55	{
56		const DwarfFunctionParameterID* parameterID
57			= dynamic_cast<const DwarfFunctionParameterID*>(&other);
58		return parameterID != NULL && *fFunctionID == *parameterID->fFunctionID
59			&& fName == parameterID->fName;
60	}
61
62protected:
63	virtual uint32 ComputeHashValue() const
64	{
65		uint32 hash = fFunctionID->HashValue();
66		return hash * 19 + StringUtils::HashValue(fName);
67	}
68
69private:
70	FunctionID*		fFunctionID;
71	const BString	fName;
72};
73
74
75// #pragma mark - DwarfLocalVariableID
76
77
78struct DwarfStackFrameDebugInfo::DwarfLocalVariableID : public LocalVariableID {
79
80	DwarfLocalVariableID(FunctionID* functionID, const BString& name,
81		int32 line, int32 column)
82		:
83		fFunctionID(functionID),
84		fName(name),
85		fLine(line),
86		fColumn(column)
87	{
88		fFunctionID->AcquireReference();
89	}
90
91	virtual ~DwarfLocalVariableID()
92	{
93		fFunctionID->ReleaseReference();
94	}
95
96	virtual bool operator==(const ObjectID& other) const
97	{
98		const DwarfLocalVariableID* otherID
99			= dynamic_cast<const DwarfLocalVariableID*>(&other);
100		return otherID != NULL && *fFunctionID == *otherID->fFunctionID
101			&& fName == otherID->fName && fLine == otherID->fLine
102			&& fColumn == otherID->fColumn;
103	}
104
105protected:
106	virtual uint32 ComputeHashValue() const
107	{
108		uint32 hash = fFunctionID->HashValue();
109		hash = hash * 19 + StringUtils::HashValue(fName);
110		hash = hash * 19 + fLine;
111		hash = hash * 19 + fColumn;
112		return hash;
113	}
114
115private:
116	FunctionID*		fFunctionID;
117	const BString	fName;
118	int32			fLine;
119	int32			fColumn;
120};
121
122
123// #pragma mark - DwarfReturnValueID
124
125
126struct DwarfStackFrameDebugInfo::DwarfReturnValueID
127	: public ReturnValueID {
128
129	DwarfReturnValueID(FunctionID* functionID)
130		:
131		fFunctionID(functionID),
132		fName("(returned)")
133	{
134		fFunctionID->AcquireReference();
135	}
136
137	virtual ~DwarfReturnValueID()
138	{
139		fFunctionID->ReleaseReference();
140	}
141
142	virtual bool operator==(const ObjectID& other) const
143	{
144		const DwarfReturnValueID* returnValueID
145			= dynamic_cast<const DwarfReturnValueID*>(&other);
146		return returnValueID != NULL
147			&& *fFunctionID == *returnValueID->fFunctionID
148			&& fName == returnValueID->fName;
149	}
150
151protected:
152	virtual uint32 ComputeHashValue() const
153	{
154		uint32 hash = fFunctionID->HashValue();
155		return hash * 25 + StringUtils::HashValue(fName);
156	}
157
158private:
159	FunctionID*		fFunctionID;
160	const BString	fName;
161};
162
163
164// #pragma mark - DwarfStackFrameDebugInfo
165
166
167DwarfStackFrameDebugInfo::DwarfStackFrameDebugInfo(Architecture* architecture,
168	image_id imageID, DwarfFile* file, CompilationUnit* compilationUnit,
169	DIESubprogram* subprogramEntry, GlobalTypeLookup* typeLookup,
170	GlobalTypeCache* typeCache, target_addr_t instructionPointer,
171	target_addr_t framePointer, target_addr_t relocationDelta,
172	DwarfTargetInterface* targetInterface, RegisterMap* fromDwarfRegisterMap)
173	:
174	StackFrameDebugInfo(),
175	fTypeContext(new(std::nothrow) DwarfTypeContext(architecture, imageID, file,
176		compilationUnit, subprogramEntry, instructionPointer, framePointer,
177		relocationDelta, targetInterface, fromDwarfRegisterMap)),
178	fTypeLookup(typeLookup),
179	fTypeCache(typeCache)
180{
181	fTypeCache->AcquireReference();
182}
183
184
185DwarfStackFrameDebugInfo::~DwarfStackFrameDebugInfo()
186{
187	fTypeCache->ReleaseReference();
188
189	if (fTypeContext != NULL)
190		fTypeContext->ReleaseReference();
191
192	delete fTypeFactory;
193}
194
195
196status_t
197DwarfStackFrameDebugInfo::Init()
198{
199	if (fTypeContext == NULL)
200		return B_NO_MEMORY;
201
202	// create a type context without dependency to the stack frame
203	DwarfTypeContext* typeContext = new(std::nothrow) DwarfTypeContext(
204		fTypeContext->GetArchitecture(), fTypeContext->ImageID(),
205		fTypeContext->File(), fTypeContext->GetCompilationUnit(), NULL, 0, 0,
206		fTypeContext->RelocationDelta(), fTypeContext->TargetInterface(),
207		fTypeContext->FromDwarfRegisterMap());
208	if (typeContext == NULL)
209		return B_NO_MEMORY;
210	BReference<DwarfTypeContext> typeContextReference(typeContext, true);
211
212	// create the type factory
213	fTypeFactory = new(std::nothrow) DwarfTypeFactory(typeContext, fTypeLookup,
214		fTypeCache);
215	if (fTypeFactory == NULL)
216		return B_NO_MEMORY;
217
218	return B_OK;
219}
220
221
222status_t
223DwarfStackFrameDebugInfo::CreateParameter(FunctionID* functionID,
224	DIEFormalParameter* parameterEntry, Variable*& _parameter)
225{
226	// get the name
227	BString name;
228	DwarfUtils::GetDIEName(parameterEntry, name);
229
230	TRACE_LOCALS("DwarfStackFrameDebugInfo::CreateParameter(DIE: %p): name: "
231		"\"%s\"\n", parameterEntry, name.String());
232
233	// create the ID
234	DwarfFunctionParameterID* id = new(std::nothrow) DwarfFunctionParameterID(
235		functionID, name);
236	if (id == NULL)
237		return B_NO_MEMORY;
238	BReference<DwarfFunctionParameterID> idReference(id, true);
239
240	// create the variable
241	return _CreateVariable(id, name, _GetDIEType(parameterEntry),
242		parameterEntry->GetLocationDescription(), _parameter);
243}
244
245
246status_t
247DwarfStackFrameDebugInfo::CreateLocalVariable(FunctionID* functionID,
248	DIEVariable* variableEntry, Variable*& _variable)
249{
250	// get the name
251	BString name;
252	DwarfUtils::GetDIEName(variableEntry, name);
253
254	TRACE_LOCALS("DwarfStackFrameDebugInfo::CreateLocalVariable(DIE: %p): "
255		"name: \"%s\"\n", variableEntry, name.String());
256
257	// get the declaration location
258	int32 line = -1;
259	int32 column = -1;
260	const char* file;
261	const char* directory;
262	DwarfUtils::GetDeclarationLocation(fTypeContext->File(), variableEntry,
263		directory, file, line, column);
264		// TODO: If the declaration location is unavailable, we should probably
265		// add a component to the ID to make it unique nonetheless (the name
266		// might not suffice).
267
268	// create the ID
269	DwarfLocalVariableID* id = new(std::nothrow) DwarfLocalVariableID(
270		functionID, name, line, column);
271	if (id == NULL)
272		return B_NO_MEMORY;
273	BReference<DwarfLocalVariableID> idReference(id, true);
274
275	// create the variable
276	return _CreateVariable(id, name, _GetDIEType(variableEntry),
277		variableEntry->GetLocationDescription(), _variable);
278}
279
280
281status_t
282DwarfStackFrameDebugInfo::CreateReturnValue(FunctionID* functionID,
283	DIEType* returnType, ValueLocation* location, CpuState* state,
284	Variable*& _variable)
285{
286	if (returnType == NULL)
287		return B_BAD_VALUE;
288
289	// create the type
290	DwarfType* type;
291	status_t error = fTypeFactory->CreateType(returnType, type);
292	if (error != B_OK)
293		return error;
294	BReference<DwarfType> typeReference(type, true);
295
296	DwarfReturnValueID* id = new(std::nothrow) DwarfReturnValueID(
297		functionID);
298	if (id == NULL)
299		return B_NO_MEMORY;
300
301	BString name;
302	name.SetToFormat("%s returned", functionID->FunctionName().String());
303
304	Variable* variable = new(std::nothrow) Variable(id, name,
305		type, location, state);
306	if (variable == NULL)
307		return B_NO_MEMORY;
308
309	_variable = variable;
310
311	return B_OK;
312}
313
314
315status_t
316DwarfStackFrameDebugInfo::_CreateVariable(ObjectID* id, const BString& name,
317	DIEType* typeEntry, LocationDescription* locationDescription,
318	Variable*& _variable)
319{
320	if (typeEntry == NULL)
321		return B_BAD_VALUE;
322
323	// create the type
324	DwarfType* type;
325	status_t error = fTypeFactory->CreateType(typeEntry, type);
326	if (error != B_OK)
327		return error;
328	BReference<DwarfType> typeReference(type, true);
329
330	// get the location, if possible
331	ValueLocation* location = new(std::nothrow) ValueLocation(
332		fTypeContext->GetArchitecture()->IsBigEndian());
333	if (location == NULL)
334		return B_NO_MEMORY;
335	BReference<ValueLocation> locationReference(location, true);
336
337	if (locationDescription->IsValid()) {
338		status_t error = type->ResolveLocation(fTypeContext,
339			locationDescription, 0, false, *location);
340		if (error != B_OK)
341			return error;
342
343		TRACE_LOCALS_ONLY(location->Dump());
344	}
345
346	// create the variable
347	Variable* variable = new(std::nothrow) Variable(id, name, type, location);
348	if (variable == NULL)
349		return B_NO_MEMORY;
350
351	_variable = variable;
352	return B_OK;
353}
354
355
356template<typename EntryType>
357/*static*/ DIEType*
358DwarfStackFrameDebugInfo::_GetDIEType(EntryType* entry)
359{
360	if (DIEType* typeEntry = entry->GetType())
361		return typeEntry;
362
363	if (EntryType* abstractOrigin = dynamic_cast<EntryType*>(
364			entry->AbstractOrigin())) {
365		entry = abstractOrigin;
366		if (DIEType* typeEntry = entry->GetType())
367			return typeEntry;
368	}
369
370	if (EntryType* specification = dynamic_cast<EntryType*>(
371			entry->Specification())) {
372		entry = specification;
373		if (DIEType* typeEntry = entry->GetType())
374			return typeEntry;
375	}
376
377	return NULL;
378}
379