xref: /haiku/src/kits/debugger/dwarf/DwarfUtils.cpp (revision faf79e7f783976326856422ff006b4c6ae9c3031)
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
17 DwarfUtils::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
43 DwarfUtils::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
104 DwarfUtils::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
187 DwarfUtils::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
235 DwarfUtils::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