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