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