]>
Commit | Line | Data |
---|---|---|
86bf665e | 1 | // -*- C++ -*- |
ef36f781 | 2 | // Copyright (C) 2008-2014 Red Hat Inc. |
86bf665e TM |
3 | // |
4 | // This file is part of systemtap, and is free software. You can | |
5 | // redistribute it and/or modify it under the terms of the GNU General | |
6 | // Public License (GPL); either version 2, or (at your option) any | |
7 | // later version. | |
8 | ||
9 | #include "dwarf_wrappers.h" | |
10 | #include "staptree.h" | |
58a834b1 | 11 | #include "util.h" |
86bf665e TM |
12 | |
13 | #include <cstring> | |
f1c8f8a5 | 14 | #include <sstream> |
86bf665e TM |
15 | #include <string> |
16 | #include <elfutils/libdwfl.h> | |
440f755a | 17 | #include <dwarf.h> |
86bf665e | 18 | |
f1c8f8a5 | 19 | using namespace std; |
86bf665e | 20 | |
e1c3b13a JL |
21 | void dwfl_assert(const string& desc, int rc, |
22 | const string& file, int line) | |
86bf665e TM |
23 | { |
24 | if (rc == 0) | |
25 | return; | |
58a834b1 | 26 | string msg = _F("libdwfl failure (%s): ", desc.c_str()); |
86bf665e | 27 | if (rc < 0) |
316ac905 | 28 | msg += (dwfl_errmsg (rc) ?: "?"); |
86bf665e TM |
29 | else |
30 | msg += std::strerror (rc); | |
e1c3b13a | 31 | throw semantic_error (file+":"+lex_cast(line), msg); |
86bf665e TM |
32 | } |
33 | ||
e1c3b13a JL |
34 | void dwarf_assert(const string& desc, int rc, |
35 | const string& file, int line) | |
86bf665e TM |
36 | { |
37 | if (rc == 0) | |
38 | return; | |
58a834b1 | 39 | string msg = _F("libdw failure (%s): ", desc.c_str()); |
86bf665e TM |
40 | if (rc < 0) |
41 | msg += dwarf_errmsg (rc); | |
42 | else | |
43 | msg += std::strerror (rc); | |
e1c3b13a | 44 | throw semantic_error (file+":"+lex_cast(line), msg); |
86bf665e | 45 | } |
ba53ea9f | 46 | |
440f755a | 47 | |
7f17af5c JS |
48 | #if !_ELFUTILS_PREREQ(0, 143) |
49 | // Elfutils prior to 0.143 didn't use attr_integrate when looking up the | |
50 | // decl_file or decl_line, so the attributes would sometimes be missed. For | |
51 | // those old versions, we define custom implementations to do the integration. | |
52 | ||
53 | const char * | |
54 | dwarf_decl_file_integrate (Dwarf_Die *die) | |
55 | { | |
56 | Dwarf_Attribute attr_mem; | |
57 | Dwarf_Sword idx = 0; | |
58 | if (dwarf_formsdata (dwarf_attr_integrate (die, DW_AT_decl_file, &attr_mem), | |
59 | &idx) != 0 | |
60 | || idx == 0) | |
61 | return NULL; | |
62 | ||
63 | Dwarf_Die cudie; | |
64 | Dwarf_Files *files = NULL; | |
65 | if (dwarf_getsrcfiles (dwarf_diecu (die, &cudie, NULL, NULL), | |
66 | &files, NULL) != 0) | |
67 | return NULL; | |
68 | ||
69 | return dwarf_filesrc(files, idx, NULL, NULL); | |
70 | } | |
71 | ||
72 | int | |
73 | dwarf_decl_line_integrate (Dwarf_Die *die, int *linep) | |
74 | { | |
75 | Dwarf_Attribute attr_mem; | |
76 | Dwarf_Sword line; | |
77 | ||
78 | int res = dwarf_formsdata (dwarf_attr_integrate | |
79 | (die, DW_AT_decl_line, &attr_mem), | |
80 | &line); | |
81 | if (res == 0) | |
82 | *linep = line; | |
83 | ||
84 | return res; | |
85 | } | |
86 | ||
87 | #endif // !_ELFUTILS_PREREQ(0, 143) | |
88 | ||
89 | ||
f1c8f8a5 | 90 | static bool |
b6e49c97 | 91 | dwarf_type_name(Dwarf_Die *type_die, ostream& o, Dwarf_Die& subroutine) |
f1c8f8a5 JS |
92 | { |
93 | // if we've gotten down to a basic type, then we're done | |
94 | bool done = true; | |
95 | switch (dwarf_tag(type_die)) | |
96 | { | |
97 | case DW_TAG_enumeration_type: | |
98 | o << "enum "; | |
99 | break; | |
100 | case DW_TAG_structure_type: | |
101 | o << "struct "; | |
102 | break; | |
103 | case DW_TAG_union_type: | |
104 | o << "union "; | |
105 | break; | |
9c119951 JS |
106 | case DW_TAG_class_type: |
107 | o << "class "; | |
108 | break; | |
f1c8f8a5 JS |
109 | case DW_TAG_typedef: |
110 | case DW_TAG_base_type: | |
111 | break; | |
9c119951 JS |
112 | |
113 | // modifier types that require recursion first | |
114 | case DW_TAG_reference_type: | |
115 | case DW_TAG_rvalue_reference_type: | |
116 | case DW_TAG_pointer_type: | |
117 | case DW_TAG_array_type: | |
118 | case DW_TAG_const_type: | |
119 | case DW_TAG_volatile_type: | |
c69af88f | 120 | case DW_TAG_restrict_type: |
f1c8f8a5 JS |
121 | done = false; |
122 | break; | |
9c119951 | 123 | |
b6e49c97 JS |
124 | case DW_TAG_subroutine_type: |
125 | // Subroutine types (function pointers) are a weird case. The modifiers | |
126 | // we've recursed so far need to go in the middle, with the return type | |
127 | // on the left and parameter types on the right. We'll back out now to | |
128 | // get those modifiers, getting the return and parameters separately. | |
129 | subroutine = *type_die; | |
130 | return true; | |
131 | ||
9c119951 JS |
132 | // unknown tag |
133 | default: | |
134 | return false; | |
f1c8f8a5 JS |
135 | } |
136 | if (done) | |
137 | { | |
138 | // this follows gdb precedent that anonymous structs/unions | |
139 | // are displayed as "struct {...}" and "union {...}". | |
140 | o << (dwarf_diename(type_die) ?: "{...}"); | |
141 | return true; | |
142 | } | |
143 | ||
144 | // otherwise, this die is a type modifier. | |
145 | ||
146 | // recurse into the referent type | |
9c119951 JS |
147 | Dwarf_Die subtype_die_mem, *subtype_die; |
148 | subtype_die = dwarf_attr_die(type_die, DW_AT_type, &subtype_die_mem); | |
149 | ||
150 | // NB: va_list is a builtin type that shows up in the debuginfo as a | |
151 | // "struct __va_list_tag*", but it has to be called only va_list. | |
152 | if (subtype_die != NULL && | |
153 | dwarf_tag(type_die) == DW_TAG_pointer_type && | |
154 | dwarf_tag(subtype_die) == DW_TAG_structure_type && | |
155 | strcmp(dwarf_diename(subtype_die) ?: "", "__va_list_tag") == 0) | |
156 | { | |
157 | o << "va_list"; | |
158 | return true; | |
159 | } | |
160 | ||
f1c8f8a5 | 161 | // if it can't be named, just call it "void" |
9c119951 | 162 | if (subtype_die == NULL || |
b6e49c97 | 163 | !dwarf_type_name(subtype_die, o, subroutine)) |
9c119951 | 164 | o << "void"; |
f1c8f8a5 JS |
165 | |
166 | switch (dwarf_tag(type_die)) | |
167 | { | |
9c119951 JS |
168 | case DW_TAG_reference_type: |
169 | o << "&"; | |
170 | break; | |
171 | case DW_TAG_rvalue_reference_type: | |
172 | o << "&&"; | |
173 | break; | |
f1c8f8a5 JS |
174 | case DW_TAG_pointer_type: |
175 | o << "*"; | |
176 | break; | |
177 | case DW_TAG_array_type: | |
178 | o << "[]"; | |
179 | break; | |
180 | case DW_TAG_const_type: | |
9c119951 JS |
181 | // NB: the debuginfo may sometimes have an extra const tag |
182 | // on reference types, which is redundant to us. | |
183 | if (subtype_die == NULL || | |
184 | (dwarf_tag(subtype_die) != DW_TAG_reference_type && | |
185 | dwarf_tag(subtype_die) != DW_TAG_rvalue_reference_type)) | |
186 | o << " const"; | |
f1c8f8a5 JS |
187 | break; |
188 | case DW_TAG_volatile_type: | |
189 | o << " volatile"; | |
190 | break; | |
c69af88f MW |
191 | case DW_TAG_restrict_type: |
192 | o << " restrict"; | |
193 | break; | |
f1c8f8a5 JS |
194 | default: |
195 | return false; | |
196 | } | |
197 | ||
f1c8f8a5 JS |
198 | return true; |
199 | } | |
200 | ||
201 | ||
b6e49c97 JS |
202 | static bool |
203 | dwarf_subroutine_name(Dwarf_Die *subroutine, ostream& o, const string& modifier) | |
204 | { | |
205 | // First add the return value. | |
206 | Dwarf_Die ret_type; | |
207 | string ret_string; | |
208 | if (dwarf_attr_die (subroutine, DW_AT_type, &ret_type) == NULL) | |
209 | o << "void"; | |
210 | else if (dwarf_type_name (&ret_type, ret_string)) | |
211 | o << ret_string; | |
212 | else | |
213 | return false; | |
214 | ||
215 | // Now the subroutine modifiers. | |
216 | o << " (" << modifier << ")"; | |
217 | ||
218 | // Then write each parameter. | |
219 | o << " ("; | |
220 | bool first = true; | |
221 | Dwarf_Die child; | |
222 | if (dwarf_child (subroutine, &child) == 0) | |
223 | do | |
224 | { | |
225 | auto tag = dwarf_tag (&child); | |
226 | if (tag == DW_TAG_unspecified_parameters | |
227 | || tag == DW_TAG_formal_parameter) | |
228 | { | |
229 | if (first) | |
230 | first = false; | |
231 | else | |
232 | o << ", "; | |
233 | ||
234 | if (tag == DW_TAG_unspecified_parameters) | |
235 | o << "..."; | |
236 | else if (tag == DW_TAG_formal_parameter) | |
237 | { | |
238 | Dwarf_Die param_type; | |
239 | string param_string; | |
240 | if (dwarf_attr_die (&child, DW_AT_type, ¶m_type) == NULL) | |
241 | o << "void"; | |
242 | else if (dwarf_type_name (¶m_type, param_string)) | |
243 | o << param_string; | |
244 | else | |
245 | return false; | |
246 | } | |
247 | } | |
248 | } | |
249 | while (dwarf_siblingof (&child, &child) == 0); | |
250 | if (first) | |
251 | o << "void"; | |
252 | o << ")"; | |
253 | ||
254 | return true; | |
255 | } | |
256 | ||
257 | ||
258 | bool | |
259 | dwarf_type_decl(Dwarf_Die *type_die, const string& var_name, string& decl) | |
260 | { | |
261 | ostringstream o; | |
262 | Dwarf_Die subroutine = { 0, 0, 0, 0 }; | |
263 | if (!dwarf_type_name (type_die, o, subroutine)) | |
264 | return false; | |
265 | ||
266 | if (!var_name.empty()) | |
267 | o << " " << var_name; | |
268 | ||
269 | if (subroutine.addr != 0) | |
270 | { | |
271 | ostringstream subo; | |
272 | if (!dwarf_subroutine_name (&subroutine, subo, o.str())) | |
273 | return false; | |
274 | decl = subo.str(); | |
275 | } | |
276 | else | |
277 | decl = o.str(); | |
278 | ||
279 | return true; | |
280 | } | |
281 | ||
282 | ||
f1c8f8a5 JS |
283 | bool |
284 | dwarf_type_name(Dwarf_Die *type_die, string& type_name) | |
285 | { | |
b6e49c97 | 286 | return dwarf_type_decl(type_die, "", type_name); |
f1c8f8a5 JS |
287 | } |
288 | ||
289 | ||
290 | string | |
291 | dwarf_type_name(Dwarf_Die *type_die) | |
292 | { | |
b6e49c97 JS |
293 | string o; |
294 | return dwarf_type_name (type_die, o) ? o : "<unknown>"; | |
f1c8f8a5 JS |
295 | } |
296 | ||
297 | ||
73267b89 | 298 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |