]>
Commit | Line | Data |
---|---|---|
440f755a JS |
1 | // C++ interface to dwfl |
2 | // Copyright (C) 2005-2009 Red Hat Inc. | |
3 | // Copyright (C) 2005-2007 Intel Corporation. | |
4 | // Copyright (C) 2008 James.Bottomley@HansenPartnership.com | |
5 | // | |
6 | // This file is part of systemtap, and is free software. You can | |
7 | // redistribute it and/or modify it under the terms of the GNU General | |
8 | // Public License (GPL); either version 2, or (at your option) any | |
9 | // later version. | |
10 | ||
11 | #ifndef DWFLPP_H | |
12 | #define DWFLPP_H | |
13 | ||
14 | #include "config.h" | |
15 | #include "dwarf_wrappers.h" | |
16 | #include "elaborate.h" | |
17 | #include "session.h" | |
64deb085 | 18 | #include "unordered.h" |
68983551 | 19 | #include "setupdwfl.h" |
440f755a JS |
20 | |
21 | #include <cstring> | |
22 | #include <iostream> | |
23 | #include <map> | |
24 | #include <set> | |
25 | #include <string> | |
26 | #include <vector> | |
27 | ||
440f755a JS |
28 | extern "C" { |
29 | #include <elfutils/libdwfl.h> | |
27646582 | 30 | #include <regex.h> |
440f755a JS |
31 | } |
32 | ||
6a38401c JS |
33 | #if !_ELFUTILS_PREREQ(0,142) |
34 | // Always use newer name, old name is deprecated in 0.142. | |
35 | #define elf_getshdrstrndx elf_getshstrndx | |
36 | #endif | |
37 | ||
440f755a JS |
38 | |
39 | struct func_info; | |
40 | struct inline_instance_info; | |
41 | struct symbol_table; | |
42 | struct base_query; | |
43 | struct dwarf_query; | |
44 | ||
45 | enum line_t { ABSOLUTE, RELATIVE, RANGE, WILDCARD }; | |
46 | enum info_status { info_unknown, info_present, info_absent }; | |
47 | ||
be53d313 | 48 | // module -> cu die[] |
64deb085 | 49 | typedef unordered_map<Dwarf*, std::vector<Dwarf_Die>*> module_cu_cache_t; |
be53d313 | 50 | |
b7478964 JS |
51 | // typename -> die |
52 | typedef unordered_map<std::string, Dwarf_Die> cu_type_cache_t; | |
53 | ||
54 | // cu die -> (typename -> die) | |
55 | typedef unordered_map<void*, cu_type_cache_t*> mod_cu_type_cache_t; | |
56 | ||
54558065 | 57 | // function -> die |
b7478964 JS |
58 | typedef unordered_multimap<std::string, Dwarf_Die> cu_function_cache_t; |
59 | typedef std::pair<cu_function_cache_t::iterator, | |
60 | cu_function_cache_t::iterator> | |
61 | cu_function_cache_range_t; | |
54558065 JS |
62 | |
63 | // cu die -> (function -> die) | |
64deb085 | 64 | typedef unordered_map<void*, cu_function_cache_t*> mod_cu_function_cache_t; |
440f755a | 65 | |
4df79aaf JS |
66 | // module -> (function -> die) |
67 | typedef unordered_map<Dwarf*, cu_function_cache_t*> mod_function_cache_t; | |
68 | ||
d089f5b2 | 69 | // inline function die -> instance die[] |
64deb085 | 70 | typedef unordered_map<void*, std::vector<Dwarf_Die>*> cu_inl_function_cache_t; |
d089f5b2 | 71 | |
9aa8ffce JS |
72 | // die -> parent die |
73 | typedef unordered_map<void*, Dwarf_Die> cu_die_parent_cache_t; | |
74 | ||
75 | // cu die -> (die -> parent die) | |
76 | typedef unordered_map<void*, cu_die_parent_cache_t*> mod_cu_die_parent_cache_t; | |
77 | ||
440f755a JS |
78 | typedef std::vector<func_info> func_info_map_t; |
79 | typedef std::vector<inline_instance_info> inline_instance_map_t; | |
80 | ||
81 | ||
82 | /* XXX FIXME functions that dwflpp needs from tapsets.cxx */ | |
440f755a JS |
83 | func_info_map_t *get_filtered_functions(dwarf_query *q); |
84 | inline_instance_map_t *get_filtered_inlines(dwarf_query *q); | |
440f755a JS |
85 | |
86 | ||
87 | struct | |
88 | module_info | |
89 | { | |
90 | Dwfl_Module* mod; | |
91 | const char* name; | |
92 | std::string elf_path; | |
93 | Dwarf_Addr addr; | |
94 | Dwarf_Addr bias; | |
95 | symbol_table *sym_table; | |
96 | info_status dwarf_status; // module has dwarf info? | |
97 | info_status symtab_status; // symbol table cached? | |
98 | ||
99 | void get_symtab(dwarf_query *q); | |
1c6b77e5 | 100 | void update_symtab(cu_function_cache_t *funcs); |
440f755a JS |
101 | |
102 | module_info(const char *name) : | |
103 | mod(NULL), | |
104 | name(name), | |
105 | addr(0), | |
106 | bias(0), | |
107 | sym_table(NULL), | |
108 | dwarf_status(info_unknown), | |
109 | symtab_status(info_unknown) | |
110 | {} | |
111 | ||
112 | ~module_info(); | |
113 | }; | |
114 | ||
115 | ||
116 | struct | |
117 | module_cache | |
118 | { | |
119 | std::map<std::string, module_info*> cache; | |
120 | bool paths_collected; | |
121 | bool dwarf_collected; | |
122 | ||
123 | module_cache() : paths_collected(false), dwarf_collected(false) {} | |
124 | }; | |
125 | ||
126 | ||
127 | struct func_info | |
128 | { | |
129 | func_info() | |
130 | : decl_file(NULL), decl_line(-1), addr(0), prologue_end(0), weak(false) | |
131 | { | |
132 | std::memset(&die, 0, sizeof(die)); | |
133 | } | |
134 | std::string name; | |
135 | char const * decl_file; | |
136 | int decl_line; | |
137 | Dwarf_Die die; | |
138 | Dwarf_Addr addr; | |
139 | Dwarf_Addr entrypc; | |
140 | Dwarf_Addr prologue_end; | |
141 | bool weak; | |
440f755a JS |
142 | }; |
143 | ||
144 | ||
145 | struct inline_instance_info | |
146 | { | |
147 | inline_instance_info() | |
148 | : decl_file(NULL), decl_line(-1) | |
149 | { | |
150 | std::memset(&die, 0, sizeof(die)); | |
151 | } | |
7fdd3e2c | 152 | bool operator<(const inline_instance_info& other) const; |
440f755a JS |
153 | std::string name; |
154 | char const * decl_file; | |
155 | int decl_line; | |
156 | Dwarf_Addr entrypc; | |
157 | Dwarf_Die die; | |
158 | }; | |
159 | ||
160 | ||
161 | struct dwflpp | |
162 | { | |
163 | systemtap_session & sess; | |
440f755a JS |
164 | |
165 | // These are "current" values we focus on. | |
166 | Dwfl_Module * module; | |
440f755a JS |
167 | Dwarf_Addr module_bias; |
168 | module_info * mod_info; | |
169 | ||
170 | // These describe the current module's PC address range | |
171 | Dwarf_Addr module_start; | |
172 | Dwarf_Addr module_end; | |
173 | ||
174 | Dwarf_Die * cu; | |
440f755a JS |
175 | |
176 | std::string module_name; | |
440f755a JS |
177 | std::string function_name; |
178 | ||
ae2552da | 179 | dwflpp(systemtap_session & session, const std::string& user_module, bool kernel_p); |
59c11f91 | 180 | dwflpp(systemtap_session & session, const std::vector<std::string>& user_modules, bool kernel_p); |
440f755a JS |
181 | ~dwflpp(); |
182 | ||
440f755a JS |
183 | void get_module_dwarf(bool required = false, bool report = true); |
184 | ||
185 | void focus_on_module(Dwfl_Module * m, module_info * mi); | |
186 | void focus_on_cu(Dwarf_Die * c); | |
187 | void focus_on_function(Dwarf_Die * f); | |
440f755a | 188 | |
54417494 JS |
189 | std::string cu_name(void); |
190 | ||
1adf8ef1 | 191 | Dwarf_Die *query_cu_containing_address(Dwarf_Addr a); |
440f755a | 192 | |
5f4c8c6e | 193 | bool module_name_matches(const std::string& pattern); |
665e1256 | 194 | static bool name_has_wildcard(const std::string& pattern); |
5f4c8c6e | 195 | bool module_name_final_match(const std::string& pattern); |
440f755a | 196 | |
5f4c8c6e JS |
197 | bool function_name_matches_pattern(const std::string& name, const std::string& pattern); |
198 | bool function_name_matches(const std::string& pattern); | |
7d6d0afc | 199 | bool function_scope_matches(const std::vector<std::string> scopes); |
440f755a | 200 | |
440f755a JS |
201 | void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, |
202 | const char *, Dwarf_Addr, | |
203 | void *), | |
204 | base_query *data); | |
440f755a | 205 | |
440f755a JS |
206 | void iterate_over_cus (int (*callback)(Dwarf_Die * die, void * arg), |
207 | void * data); | |
208 | ||
209 | bool func_is_inline(); | |
210 | ||
440f755a JS |
211 | void iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * arg), |
212 | void * data); | |
213 | ||
9aa8ffce | 214 | std::vector<Dwarf_Die> getscopes_die(Dwarf_Die* die); |
729455a7 JS |
215 | std::vector<Dwarf_Die> getscopes(Dwarf_Die* die); |
216 | std::vector<Dwarf_Die> getscopes(Dwarf_Addr pc); | |
9aa8ffce | 217 | |
440f755a | 218 | Dwarf_Die *declaration_resolve(const char *name); |
063906a9 | 219 | Dwarf_Die *declaration_resolve_other_cus(const char *name); |
440f755a | 220 | |
440f755a | 221 | int iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query * q), |
5898b6e1 | 222 | base_query * q, const std::string& function); |
440f755a | 223 | |
4df79aaf JS |
224 | int iterate_single_function (int (* callback)(Dwarf_Die * func, base_query * q), |
225 | base_query * q, const std::string& function); | |
226 | ||
440f755a JS |
227 | void iterate_over_srcfile_lines (char const * srcfile, |
228 | int lines[2], | |
229 | bool need_single_match, | |
230 | enum line_t line_type, | |
231 | void (* callback) (const dwarf_line_t& line, | |
232 | void * arg), | |
9b988eff | 233 | const std::string& func_pattern, |
440f755a JS |
234 | void *data); |
235 | ||
236 | void iterate_over_labels (Dwarf_Die *begin_die, | |
8096dd7d | 237 | const std::string& sym, |
f09d0d1e | 238 | const std::string& function, |
8096dd7d | 239 | dwarf_query *q, |
440f755a | 240 | void (* callback)(const std::string &, |
8096dd7d | 241 | const char *, |
440f755a JS |
242 | const char *, |
243 | int, | |
244 | Dwarf_Die *, | |
245 | Dwarf_Addr, | |
f09d0d1e | 246 | dwarf_query *)); |
440f755a JS |
247 | |
248 | void collect_srcfiles_matching (std::string const & pattern, | |
bd25380d | 249 | std::set<std::string> & filtered_srcfiles); |
440f755a JS |
250 | |
251 | void resolve_prologue_endings (func_info_map_t & funcs); | |
252 | ||
253 | bool function_entrypc (Dwarf_Addr * addr); | |
254 | bool die_entrypc (Dwarf_Die * die, Dwarf_Addr * addr); | |
255 | ||
256 | void function_die (Dwarf_Die *d); | |
257 | void function_file (char const ** c); | |
258 | void function_line (int *linep); | |
259 | ||
260 | bool die_has_pc (Dwarf_Die & die, Dwarf_Addr pc); | |
261 | ||
729455a7 | 262 | std::string literal_stmt_for_local (std::vector<Dwarf_Die>& scopes, |
d0b4a5ff JS |
263 | Dwarf_Addr pc, |
264 | std::string const & local, | |
265 | const target_symbol *e, | |
266 | bool lvalue, | |
267 | exp_type & ty); | |
5f36109e JS |
268 | Dwarf_Die* type_die_for_local (std::vector<Dwarf_Die>& scopes, |
269 | Dwarf_Addr pc, | |
270 | std::string const & local, | |
271 | const target_symbol *e, | |
272 | Dwarf_Die *die_mem); | |
d0b4a5ff JS |
273 | |
274 | std::string literal_stmt_for_return (Dwarf_Die *scope_die, | |
275 | Dwarf_Addr pc, | |
276 | const target_symbol *e, | |
277 | bool lvalue, | |
278 | exp_type & ty); | |
5f36109e JS |
279 | Dwarf_Die* type_die_for_return (Dwarf_Die *scope_die, |
280 | Dwarf_Addr pc, | |
281 | const target_symbol *e, | |
282 | Dwarf_Die *die_mem); | |
d0b4a5ff JS |
283 | |
284 | std::string literal_stmt_for_pointer (Dwarf_Die *type_die, | |
285 | const target_symbol *e, | |
286 | bool lvalue, | |
287 | exp_type & ty); | |
5f36109e JS |
288 | Dwarf_Die* type_die_for_pointer (Dwarf_Die *type_die, |
289 | const target_symbol *e, | |
290 | Dwarf_Die *die_mem); | |
d0b4a5ff | 291 | |
27646582 JS |
292 | bool blacklisted_p(const std::string& funcname, |
293 | const std::string& filename, | |
294 | int line, | |
295 | const std::string& module, | |
27646582 JS |
296 | Dwarf_Addr addr, |
297 | bool has_return); | |
298 | ||
789448a3 | 299 | Dwarf_Addr relocate_address(Dwarf_Addr addr, std::string& reloc_section); |
27646582 | 300 | |
5f36109e JS |
301 | void resolve_unqualified_inner_typedie (Dwarf_Die *typedie, |
302 | Dwarf_Die *innerdie, | |
303 | const target_symbol *e); | |
304 | ||
27646582 | 305 | |
d0b4a5ff | 306 | private: |
68983551 | 307 | DwflPtr dwfl_ptr; |
d0b4a5ff JS |
308 | |
309 | // These are "current" values we focus on. | |
310 | Dwarf * module_dwarf; | |
311 | Dwarf_Die * function; | |
312 | ||
ae2552da | 313 | void setup_kernel(const std::string& module_name, bool debuginfo_needed = true); |
59c11f91 | 314 | void setup_kernel(const std::vector<std::string>& modules, bool debuginfo_needed = true); |
0c16d512 | 315 | void setup_user(const std::vector<std::string>& modules, bool debuginfo_needed = true); |
d0b4a5ff | 316 | |
d0b4a5ff | 317 | module_cu_cache_t module_cu_cache; |
4df79aaf JS |
318 | mod_cu_function_cache_t cu_function_cache; |
319 | mod_function_cache_t mod_function_cache; | |
d0b4a5ff | 320 | |
8d7a7bd9 | 321 | std::set<void*> cu_inl_function_cache_done; // CUs that are already cached |
d0b4a5ff | 322 | cu_inl_function_cache_t cu_inl_function_cache; |
8d7a7bd9 | 323 | void cache_inline_instances (Dwarf_Die* die); |
d0b4a5ff | 324 | |
9aa8ffce JS |
325 | mod_cu_die_parent_cache_t cu_die_parent_cache; |
326 | void cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die); | |
729455a7 | 327 | cu_die_parent_cache_t *get_die_parents(); |
9aa8ffce | 328 | |
7d6d0afc JS |
329 | Dwarf_Die* get_parent_scope(Dwarf_Die* die); |
330 | ||
d0b4a5ff JS |
331 | /* The global alias cache is used to resolve any DIE found in a |
332 | * module that is stubbed out with DW_AT_declaration with a defining | |
333 | * DIE found in a different module. The current assumption is that | |
334 | * this only applies to structures and unions, which have a global | |
335 | * namespace (it deliberately only traverses program scope), so this | |
336 | * cache is indexed by name. If other declaration lookups were | |
337 | * added to it, it would have to be indexed by name and tag | |
338 | */ | |
b7478964 | 339 | mod_cu_type_cache_t global_alias_cache; |
d0b4a5ff | 340 | static int global_alias_caching_callback(Dwarf_Die *die, void *arg); |
063906a9 MW |
341 | static int global_alias_caching_callback_cus(Dwarf_Die *die, void *arg); |
342 | static int iterate_over_globals (Dwarf_Die *, | |
343 | int (* callback)(Dwarf_Die *, void *), | |
344 | void * data); | |
d0b4a5ff | 345 | |
4df79aaf | 346 | static int mod_function_caching_callback (Dwarf_Die* func, void *arg); |
d0b4a5ff JS |
347 | static int cu_function_caching_callback (Dwarf_Die* func, void *arg); |
348 | ||
349 | bool has_single_line_record (dwarf_query * q, char const * srcfile, int lineno); | |
350 | ||
440f755a JS |
351 | static void loc2c_error (void *, const char *fmt, ...); |
352 | ||
353 | // This function generates code used for addressing computations of | |
354 | // target variables. | |
355 | void emit_address (struct obstack *pool, Dwarf_Addr address); | |
440f755a JS |
356 | static void loc2c_emit_address (void *arg, struct obstack *pool, |
357 | Dwarf_Addr address); | |
358 | ||
729455a7 | 359 | void print_locals(std::vector<Dwarf_Die>& scopes, std::ostream &o); |
d0b4a5ff | 360 | void print_members(Dwarf_Die *vardie, std::ostream &o); |
440f755a | 361 | |
729455a7 | 362 | Dwarf_Attribute *find_variable_and_frame_base (std::vector<Dwarf_Die>& scopes, |
440f755a JS |
363 | Dwarf_Addr pc, |
364 | std::string const & local, | |
365 | const target_symbol *e, | |
366 | Dwarf_Die *vardie, | |
367 | Dwarf_Attribute *fb_attr_mem); | |
368 | ||
440f755a JS |
369 | struct location *translate_location(struct obstack *pool, |
370 | Dwarf_Attribute *attr, | |
371 | Dwarf_Addr pc, | |
372 | Dwarf_Attribute *fb_attr, | |
373 | struct location **tail, | |
374 | const target_symbol *e); | |
375 | ||
c67847a0 | 376 | bool find_struct_member(const target_symbol::component& c, |
440f755a | 377 | Dwarf_Die *parentdie, |
440f755a JS |
378 | Dwarf_Die *memberdie, |
379 | std::vector<Dwarf_Attribute>& locs); | |
380 | ||
6ce303b8 JS |
381 | void translate_components(struct obstack *pool, |
382 | struct location **tail, | |
383 | Dwarf_Addr pc, | |
384 | const target_symbol *e, | |
385 | Dwarf_Die *vardie, | |
f3b5366d JS |
386 | Dwarf_Die *typedie, |
387 | unsigned first=0); | |
6ce303b8 | 388 | |
440f755a JS |
389 | void translate_final_fetch_or_store (struct obstack *pool, |
390 | struct location **tail, | |
391 | Dwarf_Addr module_bias, | |
6ce303b8 JS |
392 | Dwarf_Die *vardie, |
393 | Dwarf_Die *typedie, | |
440f755a JS |
394 | bool lvalue, |
395 | const target_symbol *e, | |
396 | std::string &, | |
397 | std::string &, | |
398 | exp_type & ty); | |
399 | ||
400 | std::string express_as_string (std::string prelude, | |
401 | std::string postlude, | |
402 | struct location *head); | |
27646582 JS |
403 | |
404 | regex_t blacklist_func; // function/statement probes | |
405 | regex_t blacklist_func_ret; // only for .return probes | |
406 | regex_t blacklist_file; // file name | |
178ac3f6 | 407 | regex_t blacklist_section; // init/exit sections |
27646582 JS |
408 | bool blacklist_enabled; |
409 | void build_blacklist(); | |
410 | std::string get_blacklist_section(Dwarf_Addr addr); | |
c8ad0687 | 411 | |
00b01a99 MW |
412 | // Returns the call frame address operations for the given program counter. |
413 | Dwarf_Op *get_cfa_ops (Dwarf_Addr pc); | |
414 | ||
228af5c4 | 415 | Dwarf_Addr vardie_from_symtable(Dwarf_Die *vardie, Dwarf_Addr *addr); |
440f755a JS |
416 | }; |
417 | ||
418 | #endif // DWFLPP_H | |
419 | ||
420 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |