1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011-2013, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7#include "DwarfUtils.h"
8
9#include <String.h>
10
11#include "CompilationUnit.h"
12#include "Dwarf.h"
13#include "DwarfFile.h"
14
15
16/*static*/ void
17DwarfUtils::GetDIEName(const DebugInfoEntry* entry, BString& _name)
18{
19	// If we don't seem to have a name but an abstract origin, return the
20	// origin's name.
21	const char* name = entry->Name();
22	if (name == NULL) {
23		if (DebugInfoEntry* abstractOrigin = entry->AbstractOrigin()) {
24			entry = abstractOrigin;
25			name = entry->Name();
26		}
27	}
28
29	// If we still don't have a name but a specification, return the
30	// specification's name.
31	if (name == NULL) {
32		if (DebugInfoEntry* specification = entry->Specification()) {
33			entry = specification;
34			name = entry->Name();
35		}
36	}
37
38	_name = name;
39}
40
41
42/*static*/ void
43DwarfUtils::GetDIETypeName(const DebugInfoEntry* entry, BString& _name,
44	const DebugInfoEntry* requestingEntry)
45{
46	const DIEType* type = dynamic_cast<const DIEType*>(entry);
47	if (type == NULL)
48		return;
49
50	const DIEModifiedType* modifiedType = dynamic_cast<const DIEModifiedType*>(
51		type);
52	BString typeName;
53	BString modifier;
54
55	if (modifiedType != NULL) {
56		const DIEType* baseType = type;
57		while ((modifiedType = dynamic_cast<const DIEModifiedType*>(
58			baseType)) != NULL) {
59			switch (modifiedType->Tag()) {
60				case DW_TAG_pointer_type:
61					modifier.Prepend("*");
62					break;
63				case DW_TAG_reference_type:
64					modifier.Prepend("&");
65					break;
66				case DW_TAG_const_type:
67					modifier.Prepend(" const ");
68					break;
69				default:
70					break;
71			}
72
73			baseType = modifiedType->GetType();
74		}
75		type = baseType;
76	}
77
78	// if the parameter has no type associated,
79	// then it's the unspecified type.
80	if (type == NULL)
81		typeName = "void";
82	else
83		GetFullyQualifiedDIEName(type, typeName, requestingEntry);
84
85	if (modifier.Length() > 0) {
86		if (modifier[modifier.Length() - 1] == ' ')
87			modifier.Truncate(modifier.Length() - 1);
88
89		// if the modifier has a leading const, treat it
90		// as the degenerate case and prepend it to the
91		// type name since that's the more typically used
92		// representation in source
93		if (modifier[0] == ' ') {
94			typeName.Prepend("const ");
95			modifier.Remove(0, 7);
96		}
97		typeName += modifier;
98	}
99
100	_name = typeName;
101}
102
103
104/*static*/ void
105DwarfUtils::GetFullDIEName(const DebugInfoEntry* entry, BString& _name)
106{
107	BString generatedName;
108	// If we don't seem to have a name but an abstract origin, return the
109	// origin's name.
110	const char* name = entry->Name();
111	if (name == NULL) {
112		if (DebugInfoEntry* abstractOrigin = entry->AbstractOrigin()) {
113			entry = abstractOrigin;
114			name = entry->Name();
115		}
116	}
117
118	// If we still don't have a name but a specification, return the
119	// specification's name.
120	if (name == NULL) {
121		if (DebugInfoEntry* specification = entry->Specification()) {
122			entry = specification;
123			name = entry->Name();
124		}
125	}
126
127	if (name == NULL) {
128		if (dynamic_cast<const DIEModifiedType*>(entry) != NULL)
129			GetDIETypeName(entry, _name);
130
131		// we found no name for this entry whatsoever, abort.
132		return;
133	}
134
135	generatedName = name;
136
137	const DIESubprogram* subProgram = dynamic_cast<const DIESubprogram*>(
138		entry);
139	if (subProgram != NULL) {
140		generatedName += "(";
141		BString parameters;
142		DebugInfoEntryList::ConstIterator iterator
143			= subProgram->Parameters().GetIterator();
144
145		bool firstParameter = true;
146		while (iterator.HasNext()) {
147			DebugInfoEntry* parameterEntry = iterator.Next();
148			if (dynamic_cast<DIEUnspecifiedParameters*>(parameterEntry)
149				!= NULL) {
150				parameters += ", ...";
151				continue;
152			}
153
154			const DIEFormalParameter* parameter
155				= dynamic_cast<DIEFormalParameter*>(parameterEntry);
156			if (parameter == NULL) {
157				// this shouldn't happen
158				return;
159			}
160
161			if (parameter->IsArtificial())
162				continue;
163
164			BString paramName;
165			BString modifier;
166			DIEType* type = parameter->GetType();
167			GetDIETypeName(type, paramName, entry);
168
169			if (firstParameter)
170				firstParameter = false;
171			else
172				parameters += ", ";
173
174			parameters += paramName;
175		}
176
177		if (parameters.Length() > 0)
178			generatedName += parameters;
179		else
180			generatedName += "void";
181		generatedName += ")";
182	}
183	_name = generatedName;
184}
185
186
187/*static*/ void
188DwarfUtils::GetFullyQualifiedDIEName(const DebugInfoEntry* entry,
189	BString& _name, const DebugInfoEntry* requestingEntry)
190{
191	// If we don't seem to have a name but an abstract origin, return the
192	// origin's name.
193	if (entry->Name() == NULL) {
194		if (DebugInfoEntry* abstractOrigin = entry->AbstractOrigin())
195			entry = abstractOrigin;
196	}
197
198	// If we don't still don't have a name but a specification, get the
199	// specification's name.
200	if (entry->Name() == NULL) {
201		if (DebugInfoEntry* specification = entry->Specification())
202			entry = specification;
203	}
204
205	_name.Truncate(0);
206	BString generatedName;
207
208	// Get the namespace, if any.
209	DebugInfoEntry* parent = entry->Parent();
210	while (parent != NULL) {
211		if (parent == requestingEntry)
212			break;
213		if (parent->IsNamespace()) {
214			BString parentName;
215			GetFullyQualifiedDIEName(parent, parentName);
216			if (parentName.Length() > 0) {
217				parentName += "::";
218				generatedName.Prepend(parentName);
219			}
220			break;
221		}
222
223		parent = parent->Parent();
224	}
225
226	BString name;
227	GetFullDIEName(entry, name);
228	if (name.Length() == 0)
229		return;
230
231	generatedName += name;
232
233	_name = generatedName;
234}
235
236
237/*static*/ bool
238DwarfUtils::GetDeclarationLocation(DwarfFile* dwarfFile,
239	const DebugInfoEntry* entry, const char*& _directory, const char*& _file,
240	int32& _line, int32& _column)
241{
242	uint32 file = 0;
243	uint32 line = 0;
244	uint32 column = 0;
245	bool fileSet = entry->GetDeclarationFile(file);
246	bool lineSet = entry->GetDeclarationLine(line);
247	bool columnSet = entry->GetDeclarationColumn(column);
248
249	// if something is not set yet, try the abstract origin (if any)
250	if (!fileSet || !lineSet || !columnSet) {
251		if (DebugInfoEntry* abstractOrigin = entry->AbstractOrigin()) {
252			entry = abstractOrigin;
253			if (!fileSet)
254				fileSet = entry->GetDeclarationFile(file);
255			if (!lineSet)
256				lineSet = entry->GetDeclarationLine(line);
257			if (!columnSet)
258				columnSet = entry->GetDeclarationColumn(column);
259		}
260	}
261
262	// something is not set yet, try the specification (if any)
263	if (!fileSet || !lineSet || !columnSet) {
264		if (DebugInfoEntry* specification = entry->Specification()) {
265			entry = specification;
266			if (!fileSet)
267				fileSet = entry->GetDeclarationFile(file);
268			if (!lineSet)
269				lineSet = entry->GetDeclarationLine(line);
270			if (!columnSet)
271				columnSet = entry->GetDeclarationColumn(column);
272		}
273	}
274
275	if (file == 0)
276		return false;
277
278	// get the compilation unit
279	CompilationUnit* unit = dwarfFile->CompilationUnitForDIE(entry);
280	if (unit == NULL)
281		return false;
282
283	const char* directoryName;
284	const char* fileName = unit->FileAt(file - 1, &directoryName);
285	if (fileName == NULL)
286		return false;
287
288	_directory = directoryName;
289	_file = fileName;
290	_line = (int32)line - 1;
291	_column = (int32)column - 1;
292	return true;
293}
294