]>
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 | #include "dwflpp.h" | |
12 | #include "config.h" | |
13 | #include "staptree.h" | |
14 | #include "elaborate.h" | |
15 | #include "tapsets.h" | |
16 | #include "task_finder.h" | |
17 | #include "translate.h" | |
18 | #include "session.h" | |
19 | #include "util.h" | |
20 | #include "buildrun.h" | |
21 | #include "dwarf_wrappers.h" | |
22 | #include "auto_free.h" | |
23 | #include "hash.h" | |
2ed04863 | 24 | #include "rpm_finder.h" |
440f755a JS |
25 | |
26 | #include <cstdlib> | |
27 | #include <algorithm> | |
28 | #include <deque> | |
29 | #include <iostream> | |
30 | #include <map> | |
440f755a JS |
31 | #include <set> |
32 | #include <sstream> | |
33 | #include <stdexcept> | |
34 | #include <vector> | |
35 | #include <cstdarg> | |
36 | #include <cassert> | |
37 | #include <iomanip> | |
38 | #include <cerrno> | |
39 | ||
40 | extern "C" { | |
41 | #include <fcntl.h> | |
42 | #include <elfutils/libdwfl.h> | |
43 | #include <elfutils/libdw.h> | |
44 | #include <dwarf.h> | |
45 | #include <elf.h> | |
46 | #include <obstack.h> | |
47 | #include <regex.h> | |
48 | #include <glob.h> | |
49 | #include <fnmatch.h> | |
50 | #include <stdio.h> | |
51 | #include <sys/types.h> | |
52 | ||
53 | #include "loc2c.h" | |
54 | #define __STDC_FORMAT_MACROS | |
55 | #include <inttypes.h> | |
56 | } | |
57 | ||
58 | ||
59 | using namespace std; | |
60 | using namespace __gnu_cxx; | |
61 | ||
62 | ||
63 | static string TOK_KERNEL("kernel"); | |
64 | ||
65 | ||
ae2552da | 66 | dwflpp::dwflpp(systemtap_session & session, const string& name, bool kernel_p): |
d0b4a5ff JS |
67 | sess(session), module(NULL), module_bias(0), mod_info(NULL), |
68 | module_start(0), module_end(0), cu(NULL), dwfl(NULL), | |
c8ad0687 JS |
69 | module_dwarf(NULL), function(NULL), blacklist_enabled(false), |
70 | pc_cached_scopes(0), num_cached_scopes(0), cached_scopes(NULL) | |
440f755a | 71 | { |
ae2552da FCE |
72 | if (kernel_p) |
73 | setup_kernel(name); | |
440f755a | 74 | else |
0c16d512 JS |
75 | { |
76 | vector<string> modules; | |
77 | modules.push_back(name); | |
78 | setup_user(modules); | |
79 | } | |
80 | } | |
81 | ||
82 | ||
83 | dwflpp::dwflpp(systemtap_session & session, const vector<string>& names): | |
84 | sess(session), module(NULL), module_bias(0), mod_info(NULL), | |
85 | module_start(0), module_end(0), cu(NULL), dwfl(NULL), | |
86 | module_dwarf(NULL), function(NULL), blacklist_enabled(false), | |
87 | pc_cached_scopes(0), num_cached_scopes(0), cached_scopes(NULL) | |
88 | { | |
89 | setup_user(names); | |
440f755a JS |
90 | } |
91 | ||
92 | ||
93 | dwflpp::~dwflpp() | |
94 | { | |
c8ad0687 | 95 | free(cached_scopes); |
440f755a JS |
96 | if (dwfl) |
97 | dwfl_end(dwfl); | |
98 | } | |
99 | ||
100 | ||
440f755a JS |
101 | void |
102 | dwflpp::get_module_dwarf(bool required, bool report) | |
103 | { | |
104 | module_dwarf = dwfl_module_getdwarf(module, &module_bias); | |
105 | mod_info->dwarf_status = (module_dwarf ? info_present : info_absent); | |
106 | if (!module_dwarf && report) | |
107 | { | |
108 | string msg = "cannot find "; | |
109 | if (module_name == "") | |
110 | msg += "kernel"; | |
111 | else | |
112 | msg += string("module ") + module_name; | |
113 | msg += " debuginfo"; | |
114 | ||
115 | int i = dwfl_errno(); | |
116 | if (i) | |
117 | msg += string(": ") + dwfl_errmsg (i); | |
118 | ||
2ed04863 WC |
119 | /* add module_name to list to find rpm */ |
120 | find_debug_rpms(sess, module_name.c_str()); | |
121 | ||
440f755a JS |
122 | if (required) |
123 | throw semantic_error (msg); | |
83ca3872 | 124 | else if (! sess.suppress_warnings) |
440f755a JS |
125 | cerr << "WARNING: " << msg << "\n"; |
126 | } | |
127 | } | |
128 | ||
129 | ||
130 | void | |
131 | dwflpp::focus_on_module(Dwfl_Module * m, module_info * mi) | |
132 | { | |
133 | module = m; | |
134 | mod_info = mi; | |
135 | if (m) | |
136 | { | |
f517ee24 JS |
137 | module_name = dwfl_module_info(module, NULL, &module_start, &module_end, |
138 | NULL, NULL, NULL, NULL) ?: "module"; | |
440f755a JS |
139 | } |
140 | else | |
141 | { | |
142 | assert(mi && mi->name && mi->name == TOK_KERNEL); | |
143 | module_name = mi->name; | |
144 | module_start = 0; | |
145 | module_end = 0; | |
146 | module_bias = mi->bias; | |
147 | } | |
148 | ||
149 | // Reset existing pointers and names | |
150 | ||
151 | module_dwarf = NULL; | |
152 | ||
153 | cu_name.clear(); | |
154 | cu = NULL; | |
155 | ||
156 | function_name.clear(); | |
157 | function = NULL; | |
158 | } | |
159 | ||
160 | ||
161 | void | |
162 | dwflpp::focus_on_cu(Dwarf_Die * c) | |
163 | { | |
164 | assert(c); | |
165 | assert(module); | |
166 | ||
167 | cu = c; | |
f517ee24 | 168 | cu_name = dwarf_diename(c) ?: "CU"; |
440f755a JS |
169 | |
170 | // Reset existing pointers and names | |
171 | function_name.clear(); | |
172 | function = NULL; | |
c8ad0687 JS |
173 | |
174 | free(cached_scopes); | |
175 | cached_scopes = NULL; | |
440f755a JS |
176 | } |
177 | ||
178 | ||
179 | void | |
180 | dwflpp::focus_on_function(Dwarf_Die * f) | |
181 | { | |
182 | assert(f); | |
183 | assert(module); | |
184 | assert(cu); | |
185 | ||
186 | function = f; | |
f517ee24 | 187 | function_name = dwarf_diename(function) ?: "function"; |
440f755a JS |
188 | } |
189 | ||
190 | ||
1f8592d1 MW |
191 | /* Return the Dwarf_Die for the given address in the current module. |
192 | * The address should be in the module address address space (this | |
193 | * function will take care of any dw bias). | |
194 | */ | |
1adf8ef1 JS |
195 | Dwarf_Die * |
196 | dwflpp::query_cu_containing_address(Dwarf_Addr a) | |
440f755a JS |
197 | { |
198 | Dwarf_Addr bias; | |
199 | assert(dwfl); | |
b6fa229b | 200 | assert(module); |
440f755a | 201 | get_module_dwarf(); |
b6fa229b | 202 | |
440f755a | 203 | Dwarf_Die* cudie = dwfl_module_addrdie(module, a, &bias); |
440f755a | 204 | assert(bias == module_bias); |
1adf8ef1 | 205 | return cudie; |
440f755a JS |
206 | } |
207 | ||
208 | ||
440f755a | 209 | bool |
5f4c8c6e | 210 | dwflpp::module_name_matches(const string& pattern) |
440f755a JS |
211 | { |
212 | bool t = (fnmatch(pattern.c_str(), module_name.c_str(), 0) == 0); | |
213 | if (t && sess.verbose>3) | |
214 | clog << "pattern '" << pattern << "' " | |
215 | << "matches " | |
216 | << "module '" << module_name << "'" << "\n"; | |
217 | return t; | |
218 | } | |
219 | ||
220 | ||
221 | bool | |
665e1256 | 222 | dwflpp::name_has_wildcard (const string& pattern) |
440f755a JS |
223 | { |
224 | return (pattern.find('*') != string::npos || | |
225 | pattern.find('?') != string::npos || | |
226 | pattern.find('[') != string::npos); | |
227 | } | |
228 | ||
229 | ||
230 | bool | |
5f4c8c6e | 231 | dwflpp::module_name_final_match(const string& pattern) |
440f755a JS |
232 | { |
233 | // Assume module_name_matches(). Can there be any more matches? | |
234 | // Not unless the pattern is a wildcard, since module names are | |
235 | // presumed unique. | |
236 | return !name_has_wildcard(pattern); | |
237 | } | |
238 | ||
239 | ||
240 | bool | |
5f4c8c6e | 241 | dwflpp::function_name_matches_pattern(const string& name, const string& pattern) |
440f755a JS |
242 | { |
243 | bool t = (fnmatch(pattern.c_str(), name.c_str(), 0) == 0); | |
244 | if (t && sess.verbose>3) | |
245 | clog << "pattern '" << pattern << "' " | |
246 | << "matches " | |
247 | << "function '" << name << "'" << "\n"; | |
248 | return t; | |
249 | } | |
250 | ||
251 | ||
252 | bool | |
5f4c8c6e | 253 | dwflpp::function_name_matches(const string& pattern) |
440f755a JS |
254 | { |
255 | assert(function); | |
256 | return function_name_matches_pattern(function_name, pattern); | |
257 | } | |
258 | ||
259 | ||
260 | bool | |
5f4c8c6e | 261 | dwflpp::function_name_final_match(const string& pattern) |
440f755a JS |
262 | { |
263 | return module_name_final_match (pattern); | |
264 | } | |
265 | ||
266 | ||
ae2552da FCE |
267 | static const char *offline_search_modname = NULL; |
268 | static int offline_search_match_p = 0; | |
269 | ||
270 | static int dwfl_report_offline_predicate (const char* modname, const char* filename) | |
271 | { | |
272 | if (pending_interrupts) | |
273 | return -1; | |
274 | ||
ae2552da FCE |
275 | assert (offline_search_modname); |
276 | ||
fd6fef3d FCE |
277 | // elfutils sends us NULL filenames sometimes if it can't find dwarf |
278 | if (filename == NULL) | |
279 | return 0; | |
280 | ||
665e1256 FCE |
281 | if (dwflpp::name_has_wildcard (offline_search_modname)) { |
282 | int match_p = !fnmatch(offline_search_modname, modname, 0); | |
283 | // In the wildcard case, we don't short-circuit (return -1) upon | |
284 | // offline_search_match_p, analogously to dwflpp::module_name_final_match(). | |
285 | ||
286 | if (match_p) | |
ae2552da | 287 | offline_search_match_p ++; |
665e1256 FCE |
288 | |
289 | return match_p; | |
290 | } else { /* non-wildcard mode */ | |
291 | if (offline_search_match_p) | |
292 | return -1; | |
293 | ||
294 | /* Reject mismatching module names */ | |
295 | if (strcmp(modname, offline_search_modname)) | |
296 | return 0; | |
297 | else | |
298 | { | |
299 | offline_search_match_p ++; | |
300 | return 1; | |
301 | } | |
302 | } | |
ae2552da FCE |
303 | } |
304 | ||
305 | ||
440f755a | 306 | void |
ae2552da | 307 | dwflpp::setup_kernel(const string& name, bool debuginfo_needed) |
440f755a JS |
308 | { |
309 | // XXX: See also translate.cxx:emit_symbol_data | |
310 | ||
311 | if (! sess.module_cache) | |
312 | sess.module_cache = new module_cache (); | |
313 | ||
314 | static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; | |
315 | static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); | |
316 | static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr ); | |
317 | ||
318 | static const Dwfl_Callbacks kernel_callbacks = | |
319 | { | |
320 | dwfl_linux_kernel_find_elf, | |
321 | dwfl_standard_find_debuginfo, | |
322 | dwfl_offline_section_address, | |
323 | (char **) & debuginfo_path | |
324 | }; | |
325 | ||
326 | dwfl = dwfl_begin (&kernel_callbacks); | |
327 | if (!dwfl) | |
328 | throw semantic_error ("cannot open dwfl"); | |
329 | dwfl_report_begin (dwfl); | |
330 | ||
331 | // We have a problem with -r REVISION vs -r BUILDDIR here. If | |
332 | // we're running against a fedora/rhel style kernel-debuginfo | |
333 | // tree, s.kernel_build_tree is not the place where the unstripped | |
334 | // vmlinux will be installed. Rather, it's over yonder at | |
335 | // /usr/lib/debug/lib/modules/$REVISION/. It seems that there is | |
336 | // no way to set the dwfl_callback.debuginfo_path and always | |
337 | // passs the plain kernel_release here. So instead we have to | |
338 | // hard-code this magic here. | |
339 | string elfutils_kernel_path; | |
340 | if (sess.kernel_build_tree == string("/lib/modules/" + sess.kernel_release + "/build")) | |
341 | elfutils_kernel_path = sess.kernel_release; | |
342 | else | |
343 | elfutils_kernel_path = sess.kernel_build_tree; | |
344 | ||
ae2552da FCE |
345 | offline_search_modname = name.c_str(); |
346 | offline_search_match_p = 0; | |
440f755a JS |
347 | int rc = dwfl_linux_kernel_report_offline (dwfl, |
348 | elfutils_kernel_path.c_str(), | |
349 | &dwfl_report_offline_predicate); | |
ae2552da FCE |
350 | offline_search_modname = NULL; |
351 | ||
352 | (void) rc; /* Ignore since the predicate probably returned -1 at some point, | |
353 | And libdwfl interprets that as "whole query failed" rather than | |
354 | "found it already, stop looking". */ | |
440f755a | 355 | |
ae2552da FCE |
356 | /* But we still need to check whether the module was itself found. One could |
357 | do an iterate_modules() search over the resulting dwfl and count hits. Or | |
358 | one could rely on the match_p flag being set just before. */ | |
359 | if (! offline_search_match_p) | |
360 | { | |
361 | if (debuginfo_needed) { | |
362 | // Suggest a likely kernel dir to find debuginfo rpm for | |
363 | string dir = string("/lib/modules/" + sess.kernel_release ); | |
364 | find_debug_rpms(sess, dir.c_str()); | |
365 | } | |
366 | throw semantic_error (string("missing ") + sess.architecture + | |
367 | string(" kernel/module debuginfo under '") + | |
368 | sess.kernel_build_tree + string("'")); | |
209dd533 | 369 | } |
440f755a | 370 | |
440f755a JS |
371 | // NB: the result of an _offline call is the assignment of |
372 | // virtualized addresses to relocatable objects such as | |
373 | // modules. These have to be converted to real addresses at | |
374 | // run time. See the dwarf_derived_probe ctor and its caller. | |
375 | ||
376 | dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); | |
27646582 JS |
377 | |
378 | build_blacklist(); | |
440f755a JS |
379 | } |
380 | ||
381 | ||
382 | void | |
0c16d512 | 383 | dwflpp::setup_user(const vector<string>& modules, bool debuginfo_needed) |
440f755a JS |
384 | { |
385 | if (! sess.module_cache) | |
386 | sess.module_cache = new module_cache (); | |
387 | ||
388 | static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; | |
389 | static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); | |
390 | // NB: kernel_build_tree doesn't enter into this, as it's for | |
391 | // kernel-side modules only. | |
392 | static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); | |
393 | ||
394 | static const Dwfl_Callbacks user_callbacks = | |
395 | { | |
396 | NULL, /* dwfl_linux_kernel_find_elf, */ | |
397 | dwfl_standard_find_debuginfo, | |
398 | dwfl_offline_section_address, | |
399 | (char **) & debuginfo_path | |
400 | }; | |
401 | ||
402 | dwfl = dwfl_begin (&user_callbacks); | |
403 | if (!dwfl) | |
404 | throw semantic_error ("cannot open dwfl"); | |
405 | dwfl_report_begin (dwfl); | |
406 | ||
0c16d512 JS |
407 | vector<string>::const_iterator it; |
408 | for (it = modules.begin(); it != modules.end(); ++it) | |
409 | { | |
410 | // XXX: should support buildid-based naming | |
411 | ||
412 | const string& module_name = *it; | |
413 | Dwfl_Module *mod = dwfl_report_offline (dwfl, | |
414 | module_name.c_str(), | |
415 | module_name.c_str(), | |
416 | -1); | |
0c16d512 JS |
417 | |
418 | if (debuginfo_needed) | |
419 | dwfl_assert (string("missing process ") + | |
420 | module_name + | |
421 | string(" ") + | |
422 | sess.architecture + | |
423 | string(" debuginfo"), | |
424 | mod); | |
425 | } | |
440f755a JS |
426 | |
427 | // NB: the result of an _offline call is the assignment of | |
428 | // virtualized addresses to relocatable objects such as | |
429 | // modules. These have to be converted to real addresses at | |
430 | // run time. See the dwarf_derived_probe ctor and its caller. | |
431 | ||
432 | dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); | |
433 | } | |
434 | ||
435 | ||
436 | void | |
437 | dwflpp::iterate_over_modules(int (* callback)(Dwfl_Module *, void **, | |
438 | const char *, Dwarf_Addr, | |
439 | void *), | |
440 | base_query *data) | |
441 | { | |
0e14e079 JS |
442 | dwfl_getmodules (dwfl, callback, data, 0); |
443 | ||
440f755a JS |
444 | // Don't complain if we exited dwfl_getmodules early. |
445 | // This could be a $target variable error that will be | |
446 | // reported soon anyway. | |
447 | // dwfl_assert("dwfl_getmodules", off == 0); | |
448 | ||
449 | // PR6864 XXX: For dwarfless case (if .../vmlinux is missing), then the | |
450 | // "kernel" module is not reported in the loop above. However, we | |
451 | // may be able to make do with symbol table data. | |
452 | } | |
453 | ||
454 | ||
440f755a JS |
455 | void |
456 | dwflpp::iterate_over_cus (int (*callback)(Dwarf_Die * die, void * arg), | |
457 | void * data) | |
458 | { | |
459 | get_module_dwarf(false); | |
460 | Dwarf *dw = module_dwarf; | |
461 | if (!dw) return; | |
462 | ||
463 | vector<Dwarf_Die>* v = module_cu_cache[dw]; | |
464 | if (v == 0) | |
465 | { | |
466 | v = new vector<Dwarf_Die>; | |
467 | module_cu_cache[dw] = v; | |
468 | ||
469 | Dwarf_Off off = 0; | |
470 | size_t cuhl; | |
471 | Dwarf_Off noff; | |
472 | while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) | |
473 | { | |
474 | if (pending_interrupts) return; | |
475 | Dwarf_Die die_mem; | |
476 | Dwarf_Die *die; | |
477 | die = dwarf_offdie (dw, off + cuhl, &die_mem); | |
478 | v->push_back (*die); /* copy */ | |
479 | off = noff; | |
480 | } | |
481 | } | |
482 | ||
483 | for (unsigned i = 0; i < v->size(); i++) | |
484 | { | |
485 | if (pending_interrupts) return; | |
486 | Dwarf_Die die = v->at(i); | |
487 | int rc = (*callback)(& die, data); | |
488 | if (rc != DWARF_CB_OK) break; | |
489 | } | |
490 | } | |
491 | ||
492 | ||
493 | bool | |
494 | dwflpp::func_is_inline() | |
495 | { | |
496 | assert (function); | |
497 | return dwarf_func_inline (function) != 0; | |
498 | } | |
499 | ||
500 | ||
501 | int | |
502 | dwflpp::cu_inl_function_caching_callback (Dwarf_Die* func, void *arg) | |
503 | { | |
504 | vector<Dwarf_Die>* v = static_cast<vector<Dwarf_Die>*>(arg); | |
505 | v->push_back (* func); | |
506 | return DWARF_CB_OK; | |
507 | } | |
508 | ||
509 | ||
510 | void | |
511 | dwflpp::iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * arg), | |
512 | void * data) | |
513 | { | |
514 | assert (function); | |
515 | assert (func_is_inline ()); | |
516 | ||
517 | string key = module_name + ":" + cu_name + ":" + function_name; | |
518 | vector<Dwarf_Die>* v = cu_inl_function_cache[key]; | |
519 | if (v == 0) | |
520 | { | |
521 | v = new vector<Dwarf_Die>; | |
522 | cu_inl_function_cache[key] = v; | |
523 | dwarf_func_inline_instances (function, cu_inl_function_caching_callback, v); | |
524 | } | |
525 | ||
526 | for (unsigned i=0; i<v->size(); i++) | |
527 | { | |
528 | if (pending_interrupts) return; | |
529 | Dwarf_Die die = v->at(i); | |
530 | int rc = (*callback)(& die, data); | |
531 | if (rc != DWARF_CB_OK) break; | |
532 | } | |
533 | } | |
534 | ||
535 | ||
536 | int | |
537 | dwflpp::global_alias_caching_callback(Dwarf_Die *die, void *arg) | |
538 | { | |
539 | cu_function_cache_t *cache = static_cast<cu_function_cache_t*>(arg); | |
540 | const char *name = dwarf_diename(die); | |
541 | ||
542 | if (!name) | |
543 | return DWARF_CB_OK; | |
544 | ||
545 | string structure_name = name; | |
546 | ||
547 | if (!dwarf_hasattr(die, DW_AT_declaration) && | |
548 | cache->find(structure_name) == cache->end()) | |
549 | (*cache)[structure_name] = *die; | |
550 | ||
551 | return DWARF_CB_OK; | |
552 | } | |
553 | ||
554 | ||
555 | Dwarf_Die * | |
556 | dwflpp::declaration_resolve(const char *name) | |
557 | { | |
558 | if (!name) | |
559 | return NULL; | |
560 | ||
561 | string key = module_name + ":" + cu_name; | |
562 | cu_function_cache_t *v = global_alias_cache[key]; | |
563 | if (v == 0) // need to build the cache, just once per encountered module/cu | |
564 | { | |
565 | v = new cu_function_cache_t; | |
566 | global_alias_cache[key] = v; | |
567 | iterate_over_globals(global_alias_caching_callback, v); | |
568 | if (sess.verbose > 4) | |
569 | clog << "global alias cache " << key << " size " << v->size() << endl; | |
570 | } | |
571 | ||
572 | // XXX: it may be desirable to search other modules' declarations | |
573 | // too, in case a module/shared-library processes a | |
574 | // forward-declared pointer type only, where the actual definition | |
575 | // may only be in vmlinux or the application. | |
576 | ||
577 | // XXX: it is probably desirable to search other CU's declarations | |
578 | // in the same module. | |
579 | ||
580 | if (v->find(name) == v->end()) | |
581 | return NULL; | |
582 | ||
583 | return & ((*v)[name]); | |
584 | } | |
585 | ||
586 | ||
587 | int | |
588 | dwflpp::cu_function_caching_callback (Dwarf_Die* func, void *arg) | |
589 | { | |
590 | cu_function_cache_t* v = static_cast<cu_function_cache_t*>(arg); | |
591 | const char *name = dwarf_diename(func); | |
592 | if (!name) | |
593 | return DWARF_CB_OK; | |
594 | ||
595 | string function_name = name; | |
596 | (*v)[function_name] = * func; | |
597 | return DWARF_CB_OK; | |
598 | } | |
599 | ||
600 | ||
601 | int | |
602 | dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query * q), | |
603 | base_query * q, const string& function, | |
604 | bool has_statement_num) | |
605 | { | |
606 | int rc = DWARF_CB_OK; | |
607 | assert (module); | |
608 | assert (cu); | |
609 | ||
610 | string key = module_name + ":" + cu_name; | |
611 | cu_function_cache_t *v = cu_function_cache[key]; | |
612 | if (v == 0) | |
613 | { | |
614 | v = new cu_function_cache_t; | |
615 | cu_function_cache[key] = v; | |
616 | dwarf_getfuncs (cu, cu_function_caching_callback, v, 0); | |
617 | if (sess.verbose > 4) | |
618 | clog << "function cache " << key << " size " << v->size() << endl; | |
1c6b77e5 | 619 | mod_info->update_symtab(v); |
440f755a JS |
620 | } |
621 | ||
5f4c8c6e JS |
622 | cu_function_cache_t::iterator it = v->find(function); |
623 | if (it != v->end()) | |
440f755a | 624 | { |
1c6b77e5 | 625 | Dwarf_Die& die = it->second; |
440f755a | 626 | if (sess.verbose > 4) |
5f4c8c6e | 627 | clog << "function cache " << key << " hit " << function << endl; |
440f755a JS |
628 | return (*callback)(& die, q); |
629 | } | |
5f4c8c6e | 630 | else if (name_has_wildcard (function)) |
440f755a | 631 | { |
5f4c8c6e | 632 | for (it = v->begin(); it != v->end(); it++) |
440f755a | 633 | { |
1c6b77e5 JS |
634 | if (pending_interrupts) return DWARF_CB_ABORT; |
635 | const string& func_name = it->first; | |
636 | Dwarf_Die& die = it->second; | |
5f4c8c6e | 637 | if (function_name_matches_pattern (func_name, function)) |
440f755a JS |
638 | { |
639 | if (sess.verbose > 4) | |
640 | clog << "function cache " << key << " match " << func_name << " vs " | |
5f4c8c6e | 641 | << function << endl; |
440f755a JS |
642 | |
643 | rc = (*callback)(& die, q); | |
644 | if (rc != DWARF_CB_OK) break; | |
645 | } | |
646 | } | |
647 | } | |
648 | else if (has_statement_num) // searching all for kernel.statement | |
649 | { | |
650 | for (cu_function_cache_t::iterator it = v->begin(); it != v->end(); it++) | |
651 | { | |
652 | Dwarf_Die die = it->second; | |
653 | rc = (*callback)(& die, q); | |
654 | if (rc != DWARF_CB_OK) break; | |
655 | } | |
656 | } | |
657 | else // not a wildcard and no match in this CU | |
658 | { | |
659 | // do nothing | |
660 | } | |
661 | return rc; | |
662 | } | |
663 | ||
664 | ||
665 | /* This basically only goes one level down from the compile unit so it | |
666 | * only picks up top level stuff (i.e. nothing in a lower scope) */ | |
667 | int | |
668 | dwflpp::iterate_over_globals (int (* callback)(Dwarf_Die *, void *), | |
669 | void * data) | |
670 | { | |
671 | int rc = DWARF_CB_OK; | |
672 | Dwarf_Die die; | |
673 | ||
674 | assert (module); | |
675 | assert (cu); | |
676 | assert (dwarf_tag(cu) == DW_TAG_compile_unit); | |
677 | ||
678 | if (dwarf_child(cu, &die) != 0) | |
679 | return rc; | |
680 | ||
681 | do | |
682 | /* We're only currently looking for named types, | |
683 | * although other types of declarations exist */ | |
684 | switch (dwarf_tag(&die)) | |
685 | { | |
686 | case DW_TAG_base_type: | |
687 | case DW_TAG_enumeration_type: | |
688 | case DW_TAG_structure_type: | |
9c119951 | 689 | case DW_TAG_class_type: |
440f755a JS |
690 | case DW_TAG_typedef: |
691 | case DW_TAG_union_type: | |
692 | rc = (*callback)(&die, data); | |
693 | break; | |
694 | } | |
695 | while (rc == DWARF_CB_OK && dwarf_siblingof(&die, &die) == 0); | |
696 | ||
697 | return rc; | |
698 | } | |
699 | ||
700 | ||
701 | // This little test routine represents an unfortunate breakdown in | |
702 | // abstraction between dwflpp (putatively, a layer right on top of | |
703 | // elfutils), and dwarf_query (interpreting a systemtap probe point). | |
704 | // It arises because we sometimes try to fix up slightly-off | |
705 | // .statement() probes (something we find out in fairly low-level). | |
706 | // | |
707 | // An alternative would be to put some more intelligence into query_cu(), | |
708 | // and have it print additional suggestions after finding that | |
709 | // q->dw.iterate_over_srcfile_lines resulted in no new finished_results. | |
710 | ||
711 | bool | |
712 | dwflpp::has_single_line_record (dwarf_query * q, char const * srcfile, int lineno) | |
713 | { | |
714 | if (lineno < 0) | |
715 | return false; | |
716 | ||
717 | Dwarf_Line **srcsp = NULL; | |
718 | size_t nsrcs = 0; | |
719 | ||
720 | dwarf_assert ("dwarf_getsrc_file", | |
721 | dwarf_getsrc_file (module_dwarf, | |
722 | srcfile, lineno, 0, | |
723 | &srcsp, &nsrcs)); | |
724 | ||
725 | if (nsrcs != 1) | |
726 | { | |
727 | if (sess.verbose>4) | |
728 | clog << "alternative line " << lineno << " rejected: nsrcs=" << nsrcs << endl; | |
729 | return false; | |
730 | } | |
731 | ||
732 | // We also try to filter out lines that leave the selected | |
733 | // functions (if any). | |
734 | ||
735 | dwarf_line_t line(srcsp[0]); | |
736 | Dwarf_Addr addr = line.addr(); | |
737 | ||
738 | func_info_map_t *filtered_functions = get_filtered_functions(q); | |
739 | for (func_info_map_t::iterator i = filtered_functions->begin(); | |
740 | i != filtered_functions->end(); ++i) | |
741 | { | |
742 | if (die_has_pc (i->die, addr)) | |
743 | { | |
744 | if (sess.verbose>4) | |
745 | clog << "alternative line " << lineno << " accepted: fn=" << i->name << endl; | |
746 | return true; | |
747 | } | |
748 | } | |
749 | ||
750 | inline_instance_map_t *filtered_inlines = get_filtered_inlines(q); | |
751 | for (inline_instance_map_t::iterator i = filtered_inlines->begin(); | |
752 | i != filtered_inlines->end(); ++i) | |
753 | { | |
754 | if (die_has_pc (i->die, addr)) | |
755 | { | |
756 | if (sess.verbose>4) | |
757 | clog << "alternative line " << lineno << " accepted: ifn=" << i->name << endl; | |
758 | return true; | |
759 | } | |
760 | } | |
761 | ||
762 | if (sess.verbose>4) | |
763 | clog << "alternative line " << lineno << " rejected: leaves selected fns" << endl; | |
764 | return false; | |
765 | } | |
766 | ||
767 | ||
768 | void | |
769 | dwflpp::iterate_over_srcfile_lines (char const * srcfile, | |
770 | int lines[2], | |
771 | bool need_single_match, | |
772 | enum line_t line_type, | |
773 | void (* callback) (const dwarf_line_t& line, | |
774 | void * arg), | |
9b988eff | 775 | const std::string& func_pattern, |
440f755a JS |
776 | void *data) |
777 | { | |
778 | Dwarf_Line **srcsp = NULL; | |
779 | size_t nsrcs = 0; | |
780 | dwarf_query * q = static_cast<dwarf_query *>(data); | |
781 | int lineno = lines[0]; | |
782 | auto_free_ref<Dwarf_Line**> free_srcsp(srcsp); | |
783 | ||
784 | get_module_dwarf(); | |
e679283a WH |
785 | if (!this->function) |
786 | return; | |
440f755a JS |
787 | |
788 | if (line_type == RELATIVE) | |
789 | { | |
790 | Dwarf_Addr addr; | |
791 | Dwarf_Line *line; | |
792 | int line_number; | |
793 | ||
794 | dwarf_assert ("dwarf_entrypc", dwarf_entrypc (this->function, &addr)); | |
795 | line = dwarf_getsrc_die (this->cu, addr); | |
796 | dwarf_assert ("dwarf_getsrc_die", line == NULL); | |
797 | dwarf_assert ("dwarf_lineno", dwarf_lineno (line, &line_number)); | |
798 | lineno += line_number; | |
799 | } | |
800 | else if (line_type == WILDCARD) | |
801 | function_line (&lineno); | |
1123a74a WH |
802 | else if (line_type == RANGE) { /* correct lineno */ |
803 | int start_lineno; | |
804 | ||
9b988eff WH |
805 | if (name_has_wildcard(func_pattern)) /* PR10294: wider range like statement("*@foo.c") */ |
806 | start_lineno = lineno; | |
807 | else | |
808 | function_line (&start_lineno); | |
1123a74a WH |
809 | lineno = lineno < start_lineno ? start_lineno : lineno; |
810 | if (lineno > lines[1]) { /* invalid line range */ | |
811 | stringstream advice; | |
812 | advice << "Invalid line range (" << lines[0] << "-" << lines[1] << ")"; | |
813 | if (start_lineno > lines[1]) | |
814 | advice << ", the end line number " << lines[1] << " < " << start_lineno; | |
815 | throw semantic_error (advice.str()); | |
816 | } | |
817 | } | |
818 | ||
440f755a JS |
819 | |
820 | for (int l = lineno; ; l = l + 1) | |
821 | { | |
822 | set<int> lines_probed; | |
823 | pair<set<int>::iterator,bool> line_probed; | |
1123a74a WH |
824 | int ret = 0; |
825 | ||
826 | ret = dwarf_getsrc_file (module_dwarf, srcfile, l, 0, | |
827 | &srcsp, &nsrcs); | |
828 | if (line_type != WILDCARD && line_type != RANGE) | |
829 | dwarf_assert ("dwarf_getsrc_file", ret); | |
830 | ||
440f755a JS |
831 | if (line_type == WILDCARD || line_type == RANGE) |
832 | { | |
833 | Dwarf_Addr line_addr; | |
1123a74a WH |
834 | |
835 | if (ret != 0) /* tolerate invalid line number */ | |
836 | break; | |
837 | ||
440f755a | 838 | dwarf_lineno (srcsp [0], &lineno); |
1123a74a WH |
839 | /* Maybe lineno will exceed the input end */ |
840 | if (line_type == RANGE && lineno > lines[1]) | |
841 | break; | |
440f755a JS |
842 | line_probed = lines_probed.insert(lineno); |
843 | if (lineno != l || line_probed.second == false || nsrcs > 1) | |
844 | continue; | |
845 | dwarf_lineaddr (srcsp [0], &line_addr); | |
9b988eff | 846 | if (!function_name_matches(func_pattern) && dwarf_haspc (function, line_addr) != 1) |
440f755a JS |
847 | break; |
848 | } | |
849 | ||
850 | // NB: Formerly, we used to filter, because: | |
851 | ||
852 | // dwarf_getsrc_file gets one *near hits* for line numbers, not | |
853 | // exact matches. For example, an existing file but a nonexistent | |
854 | // line number will be rounded up to the next definition in that | |
855 | // file. This may be similar to the GDB breakpoint algorithm, but | |
856 | // we don't want to be so fuzzy in systemtap land. So we filter. | |
857 | ||
858 | // But we now see the error of our ways, and skip this filtering. | |
859 | ||
860 | // XXX: the code also fails to match e.g. inline function | |
861 | // definitions when the srcfile is a header file rather than the | |
862 | // CU name. | |
863 | ||
864 | size_t remaining_nsrcs = nsrcs; | |
865 | ||
866 | if (need_single_match && remaining_nsrcs > 1) | |
867 | { | |
868 | // We wanted a single line record (a unique address for the | |
869 | // line) and we got a bunch of line records. We're going to | |
870 | // skip this probe (throw an exception) but before we throw | |
871 | // we're going to look around a bit to see if there's a low or | |
872 | // high line number nearby which *doesn't* have this problem, | |
873 | // so we can give the user some advice. | |
874 | ||
875 | int lo_try = -1; | |
876 | int hi_try = -1; | |
877 | for (size_t i = 1; i < 6; ++i) | |
878 | { | |
879 | if (lo_try == -1 && has_single_line_record(q, srcfile, lineno - i)) | |
880 | lo_try = lineno - i; | |
881 | ||
882 | if (hi_try == -1 && has_single_line_record(q, srcfile, lineno + i)) | |
883 | hi_try = lineno + i; | |
884 | } | |
885 | ||
886 | stringstream advice; | |
887 | advice << "multiple addresses for " << srcfile << ":" << lineno; | |
888 | if (lo_try > 0 || hi_try > 0) | |
889 | { | |
890 | advice << " (try "; | |
891 | if (lo_try > 0) | |
892 | advice << srcfile << ":" << lo_try; | |
893 | if (lo_try > 0 && hi_try > 0) | |
894 | advice << " or "; | |
895 | if (hi_try > 0) | |
896 | advice << srcfile << ":" << hi_try; | |
897 | advice << ")"; | |
898 | } | |
899 | throw semantic_error (advice.str()); | |
900 | } | |
901 | ||
902 | for (size_t i = 0; i < nsrcs; ++i) | |
903 | { | |
904 | if (pending_interrupts) return; | |
905 | if (srcsp [i]) // skip over mismatched lines | |
906 | callback (dwarf_line_t(srcsp[i]), data); | |
907 | } | |
908 | ||
909 | if (line_type == ABSOLUTE || line_type == RELATIVE) | |
910 | break; | |
911 | else if (line_type == RANGE && l == lines[1]) | |
912 | break; | |
913 | } | |
914 | } | |
915 | ||
916 | ||
917 | void | |
918 | dwflpp::iterate_over_labels (Dwarf_Die *begin_die, | |
919 | const char *sym, | |
920 | const char *symfunction, | |
921 | void *data, | |
922 | void (* callback)(const string &, | |
923 | const char *, | |
924 | int, | |
925 | Dwarf_Die *, | |
926 | Dwarf_Addr, | |
927 | dwarf_query *)) | |
928 | { | |
929 | dwarf_query * q __attribute__ ((unused)) = static_cast<dwarf_query *>(data) ; | |
930 | ||
931 | get_module_dwarf(); | |
932 | ||
933 | Dwarf_Die die; | |
934 | int res = dwarf_child (begin_die, &die); | |
935 | if (res != 0) | |
936 | return; // die without children, bail out. | |
937 | ||
938 | static string function_name = dwarf_diename (begin_die); | |
939 | do | |
940 | { | |
440f755a | 941 | int tag = dwarf_tag(&die); |
de9a66e3 | 942 | const char *name = dwarf_diename (&die); |
440f755a JS |
943 | switch (tag) |
944 | { | |
945 | case DW_TAG_label: | |
30868aad MW |
946 | if (name) |
947 | break; | |
948 | else | |
949 | continue; // Cannot handle unnamed label. | |
440f755a JS |
950 | break; |
951 | case DW_TAG_subprogram: | |
30868aad | 952 | if (!dwarf_hasattr(&die, DW_AT_declaration) && name) |
440f755a JS |
953 | function_name = name; |
954 | else | |
955 | continue; | |
30868aad MW |
956 | case DW_TAG_inlined_subroutine: |
957 | if (name) | |
958 | function_name = name; | |
440f755a JS |
959 | default: |
960 | if (dwarf_haschildren (&die)) | |
961 | iterate_over_labels (&die, sym, symfunction, q, callback); | |
962 | continue; | |
963 | } | |
964 | ||
965 | if (strcmp(function_name.c_str(), symfunction) == 0 | |
966 | || (name_has_wildcard(symfunction) | |
967 | && function_name_matches (symfunction))) | |
968 | { | |
969 | } | |
970 | else | |
971 | continue; | |
972 | if (strcmp(name, sym) == 0 | |
973 | || (name_has_wildcard(sym) | |
974 | && function_name_matches_pattern (name, sym))) | |
975 | { | |
976 | const char *file = dwarf_decl_file (&die); | |
7f17af5c | 977 | |
440f755a | 978 | // Get the line number for this label |
7f17af5c JS |
979 | int dline; |
980 | dwarf_decl_line (&die, &dline); | |
981 | ||
440f755a JS |
982 | Dwarf_Addr stmt_addr; |
983 | if (dwarf_lowpc (&die, &stmt_addr) != 0) | |
30868aad | 984 | continue; // Don't try to be smart. Just drop no addr labels. |
440f755a JS |
985 | |
986 | Dwarf_Die *scopes; | |
987 | int nscopes = 0; | |
988 | nscopes = dwarf_getscopes_die (&die, &scopes); | |
989 | if (nscopes > 1) | |
990 | { | |
991 | callback(function_name.c_str(), file, | |
7f17af5c | 992 | dline, &scopes[1], stmt_addr, q); |
440f755a JS |
993 | add_label_name(q, name); |
994 | } | |
995 | } | |
996 | } | |
997 | while (dwarf_siblingof (&die, &die) == 0); | |
998 | } | |
999 | ||
1000 | ||
1001 | void | |
1002 | dwflpp::collect_srcfiles_matching (string const & pattern, | |
bd25380d | 1003 | set<string> & filtered_srcfiles) |
440f755a JS |
1004 | { |
1005 | assert (module); | |
1006 | assert (cu); | |
1007 | ||
1008 | size_t nfiles; | |
1009 | Dwarf_Files *srcfiles; | |
1010 | ||
1011 | // PR 5049: implicit * in front of given path pattern. | |
1012 | // NB: fnmatch() is used without FNM_PATHNAME. | |
1013 | string prefixed_pattern = string("*/") + pattern; | |
1014 | ||
1015 | dwarf_assert ("dwarf_getsrcfiles", | |
1016 | dwarf_getsrcfiles (cu, &srcfiles, &nfiles)); | |
1017 | { | |
1018 | for (size_t i = 0; i < nfiles; ++i) | |
1019 | { | |
1020 | char const * fname = dwarf_filesrc (srcfiles, i, NULL, NULL); | |
1021 | if (fnmatch (pattern.c_str(), fname, 0) == 0 || | |
1022 | fnmatch (prefixed_pattern.c_str(), fname, 0) == 0) | |
1023 | { | |
1024 | filtered_srcfiles.insert (fname); | |
1025 | if (sess.verbose>2) | |
1026 | clog << "selected source file '" << fname << "'\n"; | |
1027 | } | |
1028 | } | |
1029 | } | |
1030 | } | |
1031 | ||
1032 | ||
1033 | void | |
1034 | dwflpp::resolve_prologue_endings (func_info_map_t & funcs) | |
1035 | { | |
1036 | // This heuristic attempts to pick the first address that has a | |
1037 | // source line distinct from the function declaration's. In a | |
1038 | // perfect world, this would be the first statement *past* the | |
1039 | // prologue. | |
1040 | ||
1041 | assert(module); | |
1042 | assert(cu); | |
1043 | ||
1044 | size_t nlines = 0; | |
1045 | Dwarf_Lines *lines = NULL; | |
1046 | ||
1047 | /* trouble cases: | |
1048 | malloc do_symlink in init/initramfs.c tail-recursive/tiny then no-prologue | |
1049 | sys_get?id in kernel/timer.c no-prologue | |
1050 | sys_exit_group tail-recursive | |
1051 | {do_,}sys_open extra-long-prologue (gcc 3.4) | |
1052 | cpu_to_logical_apicid NULL-decl_file | |
1053 | */ | |
1054 | ||
1055 | // Fetch all srcline records, sorted by address. | |
1056 | dwarf_assert ("dwarf_getsrclines", | |
1057 | dwarf_getsrclines(cu, &lines, &nlines)); | |
1058 | // XXX: free lines[] later, but how? | |
1059 | ||
1060 | for(func_info_map_t::iterator it = funcs.begin(); it != funcs.end(); it++) | |
1061 | { | |
1062 | #if 0 /* someday */ | |
1063 | Dwarf_Addr* bkpts = 0; | |
1064 | int n = dwarf_entry_breakpoints (& it->die, & bkpts); | |
1065 | // ... | |
1066 | free (bkpts); | |
1067 | #endif | |
1068 | ||
1069 | Dwarf_Addr entrypc = it->entrypc; | |
1070 | Dwarf_Addr highpc; // NB: highpc is exclusive: [entrypc,highpc) | |
1071 | dwfl_assert ("dwarf_highpc", dwarf_highpc (& it->die, | |
1072 | & highpc)); | |
1073 | ||
1074 | if (it->decl_file == 0) it->decl_file = ""; | |
1075 | ||
1076 | unsigned entrypc_srcline_idx = 0; | |
1077 | dwarf_line_t entrypc_srcline; | |
1078 | // open-code binary search for exact match | |
1079 | { | |
1080 | unsigned l = 0, h = nlines; | |
1081 | while (l < h) | |
1082 | { | |
1083 | entrypc_srcline_idx = (l + h) / 2; | |
1084 | const dwarf_line_t lr(dwarf_onesrcline(lines, | |
1085 | entrypc_srcline_idx)); | |
1086 | Dwarf_Addr addr = lr.addr(); | |
1087 | if (addr == entrypc) { entrypc_srcline = lr; break; } | |
1088 | else if (l + 1 == h) { break; } // ran off bottom of tree | |
1089 | else if (addr < entrypc) { l = entrypc_srcline_idx; } | |
1090 | else { h = entrypc_srcline_idx; } | |
1091 | } | |
1092 | } | |
1093 | if (!entrypc_srcline) | |
1094 | { | |
1095 | if (sess.verbose > 2) | |
1096 | clog << "missing entrypc dwarf line record for function '" | |
1097 | << it->name << "'\n"; | |
1098 | // This is probably an inlined function. We'll end up using | |
1099 | // its lowpc as a probe address. | |
1100 | continue; | |
1101 | } | |
1102 | ||
1103 | if (sess.verbose>2) | |
1104 | clog << "prologue searching function '" << it->name << "'" | |
1105 | << " 0x" << hex << entrypc << "-0x" << highpc << dec | |
1106 | << "@" << it->decl_file << ":" << it->decl_line | |
1107 | << "\n"; | |
1108 | ||
1109 | // Now we go searching for the first line record that has a | |
1110 | // file/line different from the one in the declaration. | |
1111 | // Normally, this will be the next one. BUT: | |
1112 | // | |
1113 | // We may have to skip a few because some old compilers plop | |
1114 | // in dummy line records for longer prologues. If we go too | |
1115 | // far (addr >= highpc), we take the previous one. Or, it may | |
1116 | // be the first one, if the function had no prologue, and thus | |
1117 | // the entrypc maps to a statement in the body rather than the | |
1118 | // declaration. | |
1119 | ||
1120 | unsigned postprologue_srcline_idx = entrypc_srcline_idx; | |
1121 | bool ranoff_end = false; | |
1122 | while (postprologue_srcline_idx < nlines) | |
1123 | { | |
1124 | dwarf_line_t lr(dwarf_onesrcline(lines, postprologue_srcline_idx)); | |
1125 | Dwarf_Addr postprologue_addr = lr.addr(); | |
1126 | const char* postprologue_file = lr.linesrc(); | |
1127 | int postprologue_lineno = lr.lineno(); | |
1128 | ||
1129 | if (sess.verbose>2) | |
1130 | clog << "checking line record 0x" << hex << postprologue_addr << dec | |
1131 | << "@" << postprologue_file << ":" << postprologue_lineno << "\n"; | |
1132 | ||
1133 | if (postprologue_addr >= highpc) | |
1134 | { | |
1135 | ranoff_end = true; | |
1136 | postprologue_srcline_idx --; | |
1137 | continue; | |
1138 | } | |
1139 | if (ranoff_end || | |
1140 | (strcmp (postprologue_file, it->decl_file) || // We have a winner! | |
1141 | (postprologue_lineno != it->decl_line))) | |
1142 | { | |
1143 | it->prologue_end = postprologue_addr; | |
1144 | ||
1145 | if (sess.verbose>2) | |
1146 | { | |
1147 | clog << "prologue found function '" << it->name << "'"; | |
1148 | // Add a little classification datum | |
1149 | if (postprologue_srcline_idx == entrypc_srcline_idx) clog << " (naked)"; | |
1150 | if (ranoff_end) clog << " (tail-call?)"; | |
1151 | clog << " = 0x" << hex << postprologue_addr << dec << "\n"; | |
1152 | } | |
1153 | ||
1154 | break; | |
1155 | } | |
1156 | ||
1157 | // Let's try the next srcline. | |
1158 | postprologue_srcline_idx ++; | |
1159 | } // loop over srclines | |
1160 | ||
1161 | // if (strlen(it->decl_file) == 0) it->decl_file = NULL; | |
1162 | ||
1163 | } // loop over functions | |
1164 | ||
1165 | // XXX: how to free lines? | |
1166 | } | |
1167 | ||
1168 | ||
1169 | bool | |
1170 | dwflpp::function_entrypc (Dwarf_Addr * addr) | |
1171 | { | |
1172 | assert (function); | |
1173 | return (dwarf_entrypc (function, addr) == 0); | |
440f755a JS |
1174 | } |
1175 | ||
1176 | ||
1177 | bool | |
1178 | dwflpp::die_entrypc (Dwarf_Die * die, Dwarf_Addr * addr) | |
1179 | { | |
1180 | int rc = 0; | |
1181 | string lookup_method; | |
1182 | ||
1183 | * addr = 0; | |
1184 | ||
1185 | lookup_method = "dwarf_entrypc"; | |
1186 | rc = dwarf_entrypc (die, addr); | |
1187 | ||
440f755a JS |
1188 | if (rc) |
1189 | { | |
1190 | lookup_method = "dwarf_ranges"; | |
1191 | ||
1192 | Dwarf_Addr base; | |
1193 | Dwarf_Addr begin; | |
1194 | Dwarf_Addr end; | |
1195 | ptrdiff_t offset = dwarf_ranges (die, 0, &base, &begin, &end); | |
1196 | if (offset < 0) rc = -1; | |
1197 | else if (offset > 0) | |
1198 | { | |
1199 | * addr = begin; | |
1200 | rc = 0; | |
1201 | ||
1202 | // Now we need to check that there are no more ranges | |
1203 | // associated with this function, which could conceivably | |
1204 | // happen if a function is inlined, then pieces of it are | |
1205 | // split amongst different conditional branches. It's not | |
1206 | // obvious which of them to favour. As a heuristic, we | |
1207 | // pick the beginning of the first range, and ignore the | |
1208 | // others (but with a warning). | |
1209 | ||
1210 | unsigned extra = 0; | |
1211 | while ((offset = dwarf_ranges (die, offset, &base, &begin, &end)) > 0) | |
1212 | extra ++; | |
1213 | if (extra) | |
1214 | lookup_method += ", ignored " + lex_cast<string>(extra) + " more"; | |
1215 | } | |
1216 | } | |
1217 | ||
1218 | if (sess.verbose > 2) | |
1219 | clog << "entry-pc lookup (" << lookup_method << ") = 0x" << hex << *addr << dec | |
1220 | << " (rc " << rc << ")" | |
1221 | << endl; | |
1222 | return (rc == 0); | |
1223 | } | |
1224 | ||
1225 | ||
1226 | void | |
1227 | dwflpp::function_die (Dwarf_Die *d) | |
1228 | { | |
1229 | assert (function); | |
1230 | *d = *function; | |
1231 | } | |
1232 | ||
1233 | ||
1234 | void | |
1235 | dwflpp::function_file (char const ** c) | |
1236 | { | |
1237 | assert (function); | |
1238 | assert (c); | |
1239 | *c = dwarf_decl_file (function); | |
1240 | } | |
1241 | ||
1242 | ||
1243 | void | |
1244 | dwflpp::function_line (int *linep) | |
1245 | { | |
1246 | assert (function); | |
1247 | dwarf_decl_line (function, linep); | |
1248 | } | |
1249 | ||
1250 | ||
1251 | bool | |
1252 | dwflpp::die_has_pc (Dwarf_Die & die, Dwarf_Addr pc) | |
1253 | { | |
1254 | int res = dwarf_haspc (&die, pc); | |
1255 | // dwarf_ranges will return -1 if a function die has no DW_AT_ranges | |
1256 | // if (res == -1) | |
1257 | // dwarf_assert ("dwarf_haspc", res); | |
1258 | return res == 1; | |
1259 | } | |
1260 | ||
1261 | ||
1262 | void | |
1263 | dwflpp::loc2c_error (void *, const char *fmt, ...) | |
1264 | { | |
1265 | const char *msg = "?"; | |
1266 | char *tmp = NULL; | |
1267 | int rc; | |
1268 | va_list ap; | |
1269 | va_start (ap, fmt); | |
1270 | rc = vasprintf (& tmp, fmt, ap); | |
1271 | if (rc < 0) | |
1272 | msg = "?"; | |
1273 | else | |
1274 | msg = tmp; | |
1275 | va_end (ap); | |
1276 | throw semantic_error (msg); | |
1277 | } | |
1278 | ||
1279 | ||
1280 | // This function generates code used for addressing computations of | |
1281 | // target variables. | |
1282 | void | |
1283 | dwflpp::emit_address (struct obstack *pool, Dwarf_Addr address) | |
1284 | { | |
1285 | #if 0 | |
1286 | // The easy but incorrect way is to just print a hard-wired | |
1287 | // constant. | |
1288 | obstack_printf (pool, "%#" PRIx64 "UL", address); | |
1289 | #endif | |
1290 | ||
1291 | // Turn this address into a section-relative offset if it should be one. | |
1292 | // We emit a comment approximating the variable+offset expression that | |
1293 | // relocatable module probing code will need to have. | |
1294 | Dwfl_Module *mod = dwfl_addrmodule (dwfl, address); | |
1295 | dwfl_assert ("dwfl_addrmodule", mod); | |
1296 | const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, | |
1297 | NULL, NULL, NULL, NULL); | |
1298 | int n = dwfl_module_relocations (mod); | |
1299 | dwfl_assert ("dwfl_module_relocations", n >= 0); | |
1300 | Dwarf_Addr reloc_address = address; | |
1301 | int i = dwfl_module_relocate_address (mod, &reloc_address); | |
1302 | dwfl_assert ("dwfl_module_relocate_address", i >= 0); | |
1303 | dwfl_assert ("dwfl_module_info", modname); | |
1304 | const char *secname = dwfl_module_relocation_info (mod, i, NULL); | |
1305 | ||
1306 | if (sess.verbose > 2) | |
1307 | { | |
1308 | clog << "emit dwarf addr 0x" << hex << address << dec | |
1309 | << " => module " << modname | |
1310 | << " section " << (secname ?: "null") | |
1311 | << " relocaddr 0x" << hex << reloc_address << dec | |
1312 | << endl; | |
1313 | } | |
1314 | ||
1315 | if (n > 0 && !(n == 1 && secname == NULL)) | |
1316 | { | |
1317 | dwfl_assert ("dwfl_module_relocation_info", secname); | |
1318 | if (n > 1 || secname[0] != '\0') | |
1319 | { | |
1320 | // This gives us the module name, and section name within the | |
1321 | // module, for a kernel module (or other ET_REL module object). | |
1322 | obstack_printf (pool, "({ static unsigned long addr = 0; "); | |
1323 | obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ", | |
1324 | modname, secname, reloc_address); | |
1325 | obstack_printf (pool, "addr; })"); | |
1326 | } | |
1327 | else if (n == 1 && module_name == TOK_KERNEL && secname[0] == '\0') | |
1328 | { | |
1329 | // elfutils' way of telling us that this is a relocatable kernel address, which we | |
1330 | // need to treat the same way here as dwarf_query::add_probe_point does: _stext. | |
1331 | address -= sess.sym_stext; | |
1332 | secname = "_stext"; | |
1333 | obstack_printf (pool, "({ static unsigned long addr = 0; "); | |
1334 | obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ", | |
1335 | modname, secname, address); // PR10000 NB: not reloc_address | |
1336 | obstack_printf (pool, "addr; })"); | |
1337 | } | |
1338 | else | |
1339 | { | |
1340 | throw semantic_error ("cannot relocate user-space dso (?) address"); | |
1341 | #if 0 | |
1342 | // This would happen for a Dwfl_Module that's a user-level DSO. | |
1343 | obstack_printf (pool, " /* %s+%#" PRIx64 " */", | |
1344 | modname, address); | |
1345 | #endif | |
1346 | } | |
1347 | } | |
1348 | else | |
1349 | obstack_printf (pool, "%#" PRIx64 "UL", address); // assume as constant | |
1350 | } | |
1351 | ||
1352 | ||
1353 | void | |
1354 | dwflpp::loc2c_emit_address (void *arg, struct obstack *pool, | |
1355 | Dwarf_Addr address) | |
1356 | { | |
c94efd63 | 1357 | static_cast<dwflpp *>(arg)->emit_address (pool, address); |
440f755a JS |
1358 | } |
1359 | ||
1360 | ||
1361 | void | |
1362 | dwflpp::print_locals(Dwarf_Die *die, ostream &o) | |
1363 | { | |
1364 | // Try to get the first child of die. | |
1365 | Dwarf_Die child; | |
1366 | if (dwarf_child (die, &child) == 0) | |
1367 | { | |
1368 | do | |
1369 | { | |
1370 | const char *name; | |
1371 | // Output each sibling's name (that is a variable or | |
1372 | // parameter) to 'o'. | |
1373 | switch (dwarf_tag (&child)) | |
1374 | { | |
1375 | case DW_TAG_variable: | |
1376 | case DW_TAG_formal_parameter: | |
1377 | name = dwarf_diename (&child); | |
1378 | if (name) | |
1379 | o << " " << name; | |
1380 | break; | |
1381 | default: | |
1382 | break; | |
1383 | } | |
1384 | } | |
1385 | while (dwarf_siblingof (&child, &child) == 0); | |
1386 | } | |
1387 | } | |
1388 | ||
1389 | ||
1390 | Dwarf_Attribute * | |
1391 | dwflpp::find_variable_and_frame_base (Dwarf_Die *scope_die, | |
1392 | Dwarf_Addr pc, | |
1393 | string const & local, | |
1394 | const target_symbol *e, | |
1395 | Dwarf_Die *vardie, | |
1396 | Dwarf_Attribute *fb_attr_mem) | |
1397 | { | |
1398 | Dwarf_Die *scopes; | |
1399 | int nscopes = 0; | |
1400 | Dwarf_Attribute *fb_attr = NULL; | |
1401 | ||
1402 | assert (cu); | |
1403 | ||
c8ad0687 | 1404 | nscopes = dwarf_getscopes_cached (pc, &scopes); |
440f755a JS |
1405 | if (nscopes <= 0) |
1406 | { | |
1407 | throw semantic_error ("unable to find any scopes containing " | |
1408 | + lex_cast_hex<string>(pc) | |
1409 | + ((scope_die == NULL) ? "" | |
1410 | : (string (" in ") | |
1411 | + (dwarf_diename(scope_die) ?: "<unknown>") | |
1412 | + "(" + (dwarf_diename(cu) ?: "<unknown>") | |
1413 | + ")")) | |
1414 | + " while searching for local '" + local + "'", | |
1415 | e->tok); | |
1416 | } | |
1417 | ||
1418 | int declaring_scope = dwarf_getscopevar (scopes, nscopes, | |
1419 | local.c_str(), | |
1420 | 0, NULL, 0, 0, | |
1421 | vardie); | |
1422 | if (declaring_scope < 0) | |
1423 | { | |
1424 | stringstream alternatives; | |
1425 | print_locals (scopes, alternatives); | |
1426 | throw semantic_error ("unable to find local '" + local + "'" | |
1427 | + " near pc " + lex_cast_hex<string>(pc) | |
1428 | + ((scope_die == NULL) ? "" | |
1429 | : (string (" in ") | |
1430 | + (dwarf_diename(scope_die) ?: "<unknown>") | |
1431 | + "(" + (dwarf_diename(cu) ?: "<unknown>") | |
1432 | + ")")) | |
1433 | + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")), | |
1434 | e->tok); | |
1435 | } | |
1436 | ||
7bce6f87 MW |
1437 | /* We start out walking the "lexical scopes" as returned by |
1438 | * as returned by dwarf_getscopes for the address, starting with the | |
1439 | * declaring_scope that the variable was found in. | |
1440 | */ | |
1441 | for (int inner = declaring_scope; | |
1442 | inner < nscopes && fb_attr == NULL; | |
1443 | ++inner) | |
440f755a JS |
1444 | { |
1445 | switch (dwarf_tag (&scopes[inner])) | |
1446 | { | |
1447 | default: | |
1448 | continue; | |
1449 | case DW_TAG_subprogram: | |
1450 | case DW_TAG_entry_point: | |
7bce6f87 MW |
1451 | fb_attr = dwarf_attr_integrate (&scopes[inner], |
1452 | DW_AT_frame_base, | |
1453 | fb_attr_mem); | |
1454 | break; | |
1455 | case DW_TAG_inlined_subroutine: | |
1456 | /* Unless we already are going through the "pyshical die tree", | |
1457 | * we now need to start walking the die tree where this | |
1458 | * subroutine is inlined to find the appropriate frame base. */ | |
1459 | if (declaring_scope != -1) | |
1460 | { | |
1461 | nscopes = dwarf_getscopes_die (&scopes[inner], &scopes); | |
1462 | if (nscopes == -1) | |
1463 | throw semantic_error ("unable to get die scopes for '" + | |
1464 | local + "' in an inlined subroutines", | |
1465 | e->tok); | |
1466 | inner = 0; // zero is current scope, for look will increase. | |
1467 | declaring_scope = -1; | |
1468 | } | |
440f755a JS |
1469 | break; |
1470 | } | |
1471 | } | |
7bce6f87 | 1472 | |
440f755a JS |
1473 | return fb_attr; |
1474 | } | |
1475 | ||
1476 | ||
1477 | struct location * | |
1478 | dwflpp::translate_location(struct obstack *pool, | |
1479 | Dwarf_Attribute *attr, Dwarf_Addr pc, | |
1480 | Dwarf_Attribute *fb_attr, | |
1481 | struct location **tail, | |
1482 | const target_symbol *e) | |
1483 | { | |
619d9aaf MW |
1484 | |
1485 | /* DW_AT_data_member_location, can be either constant offsets | |
1486 | (struct member fields), or full blown location expressions. */ | |
1487 | if (dwarf_whatattr (attr) == DW_AT_data_member_location) | |
1488 | { | |
1489 | unsigned int form = dwarf_whatform (attr); | |
1490 | if (form == DW_FORM_data1 || form == DW_FORM_data2 | |
1491 | || form == DW_FORM_sdata || form == DW_FORM_udata) | |
1492 | { | |
1493 | Dwarf_Sword off; | |
1494 | if (dwarf_formsdata (attr, &off) != 0) | |
1495 | throw semantic_error (string ("dwarf_formsdata failed, ") | |
1496 | + string (dwarf_errmsg (-1)), e->tok); | |
1497 | c_translate_add_offset (pool, 1, NULL, off, tail); | |
1498 | return *tail; | |
1499 | } | |
1500 | } | |
1501 | ||
440f755a JS |
1502 | Dwarf_Op *expr; |
1503 | size_t len; | |
1504 | ||
1505 | /* PR9768: formerly, we added pc+module_bias here. However, that bias value | |
1506 | is not present in the pc value by the time we get it, so adding it would | |
1507 | result in false negatives of variable reachibility. In other instances | |
1508 | further below, the c_translate_FOO functions, the module_bias value used | |
1509 | to be passed in, but instead should now be zero for the same reason. */ | |
1510 | ||
1511 | switch (dwarf_getlocation_addr (attr, pc /*+ module_bias*/, &expr, &len, 1)) | |
1512 | { | |
1513 | case 1: /* Should always happen. */ | |
1514 | if (len > 0) | |
1515 | break; | |
1516 | /* Fall through. */ | |
1517 | ||
1518 | case 0: /* Shouldn't happen. */ | |
1519 | throw semantic_error ("not accessible at this address", e->tok); | |
1520 | ||
1521 | default: /* Shouldn't happen. */ | |
1522 | case -1: | |
619d9aaf | 1523 | throw semantic_error (string ("dwarf_getlocation_addr failed, ") + |
440f755a JS |
1524 | string (dwarf_errmsg (-1)), |
1525 | e->tok); | |
1526 | } | |
1527 | ||
88eaee9f MW |
1528 | // get_cfa_ops works on the dw address space, pc is relative to current |
1529 | // module, so add do need to add module_bias. | |
1530 | Dwarf_Op *cfa_ops = get_cfa_ops (pc + module_bias); | |
440f755a JS |
1531 | return c_translate_location (pool, &loc2c_error, this, |
1532 | &loc2c_emit_address, | |
1533 | 1, 0 /* PR9768 */, | |
00b01a99 | 1534 | pc, expr, len, tail, fb_attr, cfa_ops); |
440f755a JS |
1535 | } |
1536 | ||
1537 | ||
1538 | void | |
1539 | dwflpp::print_members(Dwarf_Die *vardie, ostream &o) | |
1540 | { | |
1541 | const int typetag = dwarf_tag (vardie); | |
1542 | ||
9c119951 JS |
1543 | if (typetag != DW_TAG_structure_type && |
1544 | typetag != DW_TAG_class_type && | |
1545 | typetag != DW_TAG_union_type) | |
440f755a JS |
1546 | { |
1547 | o << " Error: " | |
f1c8f8a5 | 1548 | << dwarf_type_name(vardie) |
9c119951 | 1549 | << " isn't a struct/class/union"; |
440f755a JS |
1550 | return; |
1551 | } | |
1552 | ||
1553 | // Try to get the first child of vardie. | |
1554 | Dwarf_Die die_mem; | |
1555 | Dwarf_Die *die = &die_mem; | |
1556 | switch (dwarf_child (vardie, die)) | |
1557 | { | |
1558 | case 1: // No children. | |
f1c8f8a5 | 1559 | o << dwarf_type_name(vardie) |
440f755a JS |
1560 | << " is empty"; |
1561 | break; | |
1562 | ||
1563 | case -1: // Error. | |
1564 | default: // Shouldn't happen. | |
f1c8f8a5 | 1565 | o << dwarf_type_name(vardie) |
440f755a JS |
1566 | << ": " << dwarf_errmsg (-1); |
1567 | break; | |
1568 | ||
1569 | case 0: // Success. | |
1570 | break; | |
1571 | } | |
1572 | ||
1573 | // Output each sibling's name to 'o'. | |
9c119951 | 1574 | do |
440f755a | 1575 | { |
9c119951 JS |
1576 | int tag = dwarf_tag(die); |
1577 | if (tag != DW_TAG_member && tag != DW_TAG_inheritance) | |
1578 | continue; | |
1579 | ||
23d106b9 | 1580 | const char *member = dwarf_diename (die) ; |
440f755a | 1581 | |
9c119951 | 1582 | if ( tag == DW_TAG_member && member != NULL ) |
440f755a JS |
1583 | o << " " << member; |
1584 | else | |
1585 | { | |
f1c8f8a5 | 1586 | Dwarf_Die temp_die; |
3d1ad340 | 1587 | if (!dwarf_attr_die (die, DW_AT_type, &temp_die)) |
440f755a | 1588 | { |
f1c8f8a5 JS |
1589 | string source = dwarf_decl_file(die) ?: "<unknown source>"; |
1590 | int line = -1; | |
1591 | dwarf_decl_line(die, &line); | |
1592 | clog << "\n Error in obtaining type attribute for anonymous member at " | |
1593 | << source << ":" << line; | |
440f755a JS |
1594 | return; |
1595 | } | |
1596 | ||
1597 | print_members(&temp_die,o); | |
1598 | } | |
1599 | ||
440f755a | 1600 | } |
9c119951 | 1601 | while (dwarf_siblingof (die, die) == 0); |
440f755a JS |
1602 | } |
1603 | ||
1604 | ||
1605 | bool | |
c67847a0 | 1606 | dwflpp::find_struct_member(const target_symbol::component& c, |
440f755a | 1607 | Dwarf_Die *parentdie, |
440f755a JS |
1608 | Dwarf_Die *memberdie, |
1609 | vector<Dwarf_Attribute>& locs) | |
1610 | { | |
1611 | Dwarf_Attribute attr; | |
b57ba9b8 | 1612 | Dwarf_Die die; |
440f755a | 1613 | |
b57ba9b8 | 1614 | switch (dwarf_child (parentdie, &die)) |
440f755a JS |
1615 | { |
1616 | case 0: /* First child found. */ | |
1617 | break; | |
1618 | case 1: /* No children. */ | |
1619 | return false; | |
1620 | case -1: /* Error. */ | |
1621 | default: /* Shouldn't happen */ | |
f1c8f8a5 | 1622 | throw semantic_error (dwarf_type_name(parentdie) + ": " |
440f755a | 1623 | + string (dwarf_errmsg (-1)), |
c67847a0 | 1624 | c.tok); |
440f755a JS |
1625 | } |
1626 | ||
1627 | do | |
1628 | { | |
9c119951 JS |
1629 | int tag = dwarf_tag(&die); |
1630 | if (tag != DW_TAG_member && tag != DW_TAG_inheritance) | |
440f755a JS |
1631 | continue; |
1632 | ||
23d106b9 | 1633 | const char *name = dwarf_diename(&die); |
9c119951 | 1634 | if (name == NULL || tag == DW_TAG_inheritance) |
440f755a | 1635 | { |
9c119951 JS |
1636 | // need to recurse for anonymous structs/unions and |
1637 | // for inherited members | |
440f755a | 1638 | Dwarf_Die subdie; |
3d1ad340 JS |
1639 | if (dwarf_attr_die (&die, DW_AT_type, &subdie) && |
1640 | find_struct_member(c, &subdie, memberdie, locs)) | |
440f755a JS |
1641 | goto success; |
1642 | } | |
c67847a0 | 1643 | else if (name == c.member) |
440f755a JS |
1644 | { |
1645 | *memberdie = die; | |
1646 | goto success; | |
1647 | } | |
1648 | } | |
1649 | while (dwarf_siblingof (&die, &die) == 0); | |
1650 | ||
1651 | return false; | |
1652 | ||
1653 | success: | |
1654 | /* As we unwind the recursion, we need to build the chain of | |
1655 | * locations that got to the final answer. */ | |
1656 | if (dwarf_attr_integrate (&die, DW_AT_data_member_location, &attr)) | |
1657 | locs.insert(locs.begin(), attr); | |
1658 | ||
1659 | /* Union members don't usually have a location, | |
1660 | * but just use the containing union's location. */ | |
1661 | else if (dwarf_tag(parentdie) != DW_TAG_union_type) | |
c67847a0 | 1662 | throw semantic_error ("no location for field '" + c.member |
440f755a | 1663 | + "': " + string(dwarf_errmsg (-1)), |
c67847a0 | 1664 | c.tok); |
440f755a JS |
1665 | |
1666 | return true; | |
1667 | } | |
1668 | ||
1669 | ||
1670 | Dwarf_Die * | |
1671 | dwflpp::translate_components(struct obstack *pool, | |
1672 | struct location **tail, | |
1673 | Dwarf_Addr pc, | |
1674 | const target_symbol *e, | |
1675 | Dwarf_Die *vardie, | |
1676 | Dwarf_Die *die_mem, | |
1677 | Dwarf_Attribute *attr_mem) | |
1678 | { | |
1679 | Dwarf_Die *die = NULL; | |
1680 | ||
1681 | unsigned i = 0; | |
1682 | ||
1683 | if (vardie) | |
1684 | *die_mem = *vardie; | |
1685 | ||
1686 | if (e->components.empty()) | |
1687 | return die_mem; | |
1688 | ||
1689 | while (i < e->components.size()) | |
1690 | { | |
c67847a0 JS |
1691 | const target_symbol::component& c = e->components[i]; |
1692 | ||
440f755a JS |
1693 | /* XXX: This would be desirable, but we don't get the target_symbol token, |
1694 | and printing that gives us the file:line number too early anyway. */ | |
1695 | #if 0 | |
1696 | // Emit a marker to note which field is being access-attempted, to give | |
1697 | // better error messages if deref() fails. | |
1698 | string piece = string(...target_symbol token...) + string ("#") + stringify(components[i].second); | |
1699 | obstack_printf (pool, "c->last_stmt = %s;", lex_cast_qstring(piece).c_str()); | |
1700 | #endif | |
1701 | ||
1702 | die = die ? dwarf_formref_die (attr_mem, die_mem) : die_mem; | |
1703 | const int typetag = dwarf_tag (die); | |
1704 | switch (typetag) | |
1705 | { | |
1706 | case DW_TAG_typedef: | |
1707 | case DW_TAG_const_type: | |
1708 | case DW_TAG_volatile_type: | |
1709 | /* Just iterate on the referent type. */ | |
1710 | break; | |
1711 | ||
9c119951 JS |
1712 | case DW_TAG_reference_type: |
1713 | case DW_TAG_rvalue_reference_type: | |
1714 | c_translate_pointer (pool, 1, 0 /* PR9768*/, die, tail); | |
1715 | break; | |
1716 | ||
440f755a | 1717 | case DW_TAG_pointer_type: |
c4dddae6 JS |
1718 | /* A pointer with no type is a void* -- can't dereference it. */ |
1719 | if (!dwarf_hasattr_integrate (die, DW_AT_type)) | |
1720 | throw semantic_error ("invalid access '" + lex_cast<string>(c) | |
1721 | + "' vs. " + dwarf_type_name(die), | |
1722 | c.tok); | |
1723 | ||
440f755a | 1724 | c_translate_pointer (pool, 1, 0 /* PR9768*/, die, tail); |
6fda2dff JS |
1725 | if (c.type != target_symbol::comp_literal_array_index && |
1726 | c.type != target_symbol::comp_expression_array_index) | |
d52761f8 JS |
1727 | break; |
1728 | /* else fall through as an array access */ | |
440f755a JS |
1729 | |
1730 | case DW_TAG_array_type: | |
c67847a0 | 1731 | if (c.type == target_symbol::comp_literal_array_index) |
440f755a JS |
1732 | { |
1733 | c_translate_array (pool, 1, 0 /* PR9768 */, die, tail, | |
c67847a0 | 1734 | NULL, c.num_index); |
440f755a JS |
1735 | ++i; |
1736 | } | |
6fda2dff JS |
1737 | else if (c.type == target_symbol::comp_expression_array_index) |
1738 | { | |
1739 | string index = "THIS->index" + lex_cast<string>(i); | |
1740 | c_translate_array (pool, 1, 0 /* PR9768 */, die, tail, | |
1741 | index.c_str(), 0); | |
1742 | ++i; | |
1743 | } | |
440f755a | 1744 | else |
c67847a0 JS |
1745 | throw semantic_error ("invalid access '" |
1746 | + lex_cast<string>(c) | |
1747 | + "' for array type", | |
1748 | c.tok); | |
440f755a JS |
1749 | break; |
1750 | ||
1751 | case DW_TAG_structure_type: | |
1752 | case DW_TAG_union_type: | |
9c119951 | 1753 | case DW_TAG_class_type: |
c67847a0 JS |
1754 | if (c.type != target_symbol::comp_struct_member) |
1755 | throw semantic_error ("invalid access '" | |
1756 | + lex_cast<string>(c) | |
f1c8f8a5 | 1757 | + "' for " + dwarf_type_name(die), |
c67847a0 JS |
1758 | c.tok); |
1759 | ||
440f755a JS |
1760 | if (dwarf_hasattr(die, DW_AT_declaration)) |
1761 | { | |
1762 | Dwarf_Die *tmpdie = dwflpp::declaration_resolve(dwarf_diename(die)); | |
1763 | if (tmpdie == NULL) | |
f1c8f8a5 | 1764 | throw semantic_error ("unresolved " + dwarf_type_name(die), |
c67847a0 | 1765 | c.tok); |
440f755a JS |
1766 | *die_mem = *tmpdie; |
1767 | } | |
1768 | ||
1769 | { | |
b57ba9b8 | 1770 | Dwarf_Die parentdie = *die; |
440f755a | 1771 | vector<Dwarf_Attribute> locs; |
b57ba9b8 | 1772 | if (!find_struct_member(c, &parentdie, die, locs)) |
440f755a | 1773 | { |
72c5ecc2 JS |
1774 | /* Add a file:line hint for anonymous types */ |
1775 | string source; | |
1776 | if (!dwarf_hasattr_integrate(&parentdie, DW_AT_name)) | |
1777 | { | |
1778 | int line; | |
1779 | const char *file = dwarf_decl_file(&parentdie); | |
1780 | if (file && dwarf_decl_line(&parentdie, &line) == 0) | |
1781 | source = " (" + string(file) + ":" | |
1782 | + lex_cast<string>(line) + ")"; | |
1783 | } | |
1784 | ||
440f755a JS |
1785 | string alternatives; |
1786 | stringstream members; | |
b57ba9b8 | 1787 | print_members(&parentdie, members); |
440f755a | 1788 | if (members.str().size() != 0) |
72c5ecc2 | 1789 | alternatives = " (alternatives:" + members.str() + ")"; |
440f755a | 1790 | throw semantic_error("unable to find member '" + |
f1c8f8a5 JS |
1791 | c.member + "' for " |
1792 | + dwarf_type_name(&parentdie) | |
72c5ecc2 | 1793 | + source + alternatives, |
c67847a0 | 1794 | c.tok); |
440f755a JS |
1795 | } |
1796 | ||
1797 | for (unsigned j = 0; j < locs.size(); ++j) | |
1798 | translate_location (pool, &locs[j], pc, NULL, tail, e); | |
1799 | } | |
1800 | ||
1801 | ++i; | |
1802 | break; | |
1803 | ||
1804 | case DW_TAG_enumeration_type: | |
440f755a | 1805 | case DW_TAG_base_type: |
c67847a0 JS |
1806 | throw semantic_error ("invalid access '" |
1807 | + lex_cast<string>(c) | |
f1c8f8a5 | 1808 | + "' vs. " + dwarf_type_name(die), |
c67847a0 | 1809 | c.tok); |
440f755a | 1810 | break; |
f1c8f8a5 | 1811 | |
440f755a JS |
1812 | case -1: |
1813 | throw semantic_error ("cannot find type: " + string(dwarf_errmsg (-1)), | |
c67847a0 | 1814 | c.tok); |
440f755a JS |
1815 | break; |
1816 | ||
1817 | default: | |
f1c8f8a5 | 1818 | throw semantic_error (dwarf_type_name(die) + ": unexpected type tag " |
440f755a | 1819 | + lex_cast<string>(dwarf_tag (die)), |
c67847a0 | 1820 | c.tok); |
440f755a JS |
1821 | break; |
1822 | } | |
1823 | ||
1824 | /* Now iterate on the type in DIE's attribute. */ | |
1825 | if (dwarf_attr_integrate (die, DW_AT_type, attr_mem) == NULL) | |
c67847a0 JS |
1826 | throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1)), |
1827 | c.tok); | |
440f755a | 1828 | } |
d52761f8 JS |
1829 | |
1830 | /* For an array index, we need to dereference the final DIE */ | |
6fda2dff JS |
1831 | if (e->components.back().type == target_symbol::comp_literal_array_index || |
1832 | e->components.back().type == target_symbol::comp_expression_array_index) | |
d52761f8 JS |
1833 | die = dwarf_formref_die (attr_mem, die_mem); |
1834 | ||
440f755a JS |
1835 | return die; |
1836 | } | |
1837 | ||
1838 | ||
1839 | Dwarf_Die * | |
1840 | dwflpp::resolve_unqualified_inner_typedie (Dwarf_Die *typedie_mem, | |
1841 | Dwarf_Attribute *attr_mem, | |
1842 | const target_symbol *e) | |
1843 | { | |
1844 | Dwarf_Die *typedie; | |
1845 | int typetag = 0; | |
1846 | while (1) | |
1847 | { | |
1848 | typedie = dwarf_formref_die (attr_mem, typedie_mem); | |
1849 | if (typedie == NULL) | |
1850 | throw semantic_error ("cannot get type: " + string(dwarf_errmsg (-1)), e->tok); | |
1851 | typetag = dwarf_tag (typedie); | |
1852 | if (typetag != DW_TAG_typedef && | |
1853 | typetag != DW_TAG_const_type && | |
1854 | typetag != DW_TAG_volatile_type) | |
1855 | break; | |
1856 | if (dwarf_attr_integrate (typedie, DW_AT_type, attr_mem) == NULL) | |
1857 | throw semantic_error ("cannot get type of pointee: " + string(dwarf_errmsg (-1)), e->tok); | |
1858 | } | |
1859 | return typedie; | |
1860 | } | |
1861 | ||
1862 | ||
1863 | void | |
1864 | dwflpp::translate_final_fetch_or_store (struct obstack *pool, | |
1865 | struct location **tail, | |
1866 | Dwarf_Addr module_bias, | |
1867 | Dwarf_Die *die, | |
1868 | Dwarf_Attribute *attr_mem, | |
1869 | bool lvalue, | |
1870 | const target_symbol *e, | |
1871 | string &, | |
1872 | string &, | |
1873 | exp_type & ty) | |
1874 | { | |
1875 | /* First boil away any qualifiers associated with the type DIE of | |
1876 | the final location to be accessed. */ | |
1877 | ||
1878 | Dwarf_Die typedie_mem; | |
1879 | Dwarf_Die *typedie; | |
1880 | int typetag; | |
440f755a JS |
1881 | |
1882 | typedie = resolve_unqualified_inner_typedie (&typedie_mem, attr_mem, e); | |
1883 | typetag = dwarf_tag (typedie); | |
1884 | ||
03c75a4a JS |
1885 | /* If we're looking for an address, then we can just provide what |
1886 | we computed to this point, without using a fetch/store. */ | |
1887 | if (e->addressof) | |
1888 | { | |
1889 | if (lvalue) | |
1890 | throw semantic_error ("cannot write to member address", e->tok); | |
1891 | ||
1892 | if (dwarf_hasattr_integrate (die, DW_AT_bit_offset)) | |
1893 | throw semantic_error ("cannot take address of bit-field", e->tok); | |
1894 | ||
1895 | c_translate_addressof (pool, 1, 0, 0, die, tail, "THIS->__retvalue"); | |
1896 | ty = pe_long; | |
1897 | return; | |
1898 | } | |
1899 | ||
440f755a JS |
1900 | /* Then switch behavior depending on the type of fetch/store we |
1901 | want, and the type and pointer-ness of the final location. */ | |
1902 | ||
1903 | switch (typetag) | |
1904 | { | |
1905 | default: | |
440f755a JS |
1906 | throw semantic_error ("unsupported type tag " |
1907 | + lex_cast<string>(typetag) | |
9c119951 | 1908 | + " for " + dwarf_type_name(typedie), e->tok); |
440f755a JS |
1909 | break; |
1910 | ||
1911 | case DW_TAG_structure_type: | |
9c119951 | 1912 | case DW_TAG_class_type: |
440f755a | 1913 | case DW_TAG_union_type: |
9c119951 | 1914 | throw semantic_error ("'" + dwarf_type_name(typedie) |
f1c8f8a5 | 1915 | + "' is being accessed instead of a member", e->tok); |
440f755a JS |
1916 | break; |
1917 | ||
1918 | case DW_TAG_enumeration_type: | |
1919 | case DW_TAG_base_type: | |
1920 | ||
1921 | // Reject types we can't handle in systemtap | |
1922 | { | |
440f755a JS |
1923 | Dwarf_Attribute encoding_attr; |
1924 | Dwarf_Word encoding = (Dwarf_Word) -1; | |
1925 | dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, &encoding_attr), | |
1926 | & encoding); | |
1927 | if (encoding < 0) | |
1928 | { | |
1929 | // clog << "bad type1 " << encoding << " diestr" << endl; | |
1930 | throw semantic_error ("unsupported type (mystery encoding " + lex_cast<string>(encoding) + ")" + | |
9c119951 | 1931 | " for " + dwarf_type_name(typedie), e->tok); |
440f755a JS |
1932 | } |
1933 | ||
1934 | if (encoding == DW_ATE_float | |
1935 | || encoding == DW_ATE_complex_float | |
1936 | /* XXX || many others? */) | |
1937 | { | |
1938 | // clog << "bad type " << encoding << " diestr" << endl; | |
1939 | throw semantic_error ("unsupported type (encoding " + lex_cast<string>(encoding) + ")" + | |
9c119951 | 1940 | " for " + dwarf_type_name(typedie), e->tok); |
440f755a JS |
1941 | } |
1942 | } | |
1943 | ||
1944 | ty = pe_long; | |
1945 | if (lvalue) | |
1946 | c_translate_store (pool, 1, 0 /* PR9768 */, die, typedie, tail, | |
1947 | "THIS->value"); | |
1948 | else | |
1949 | c_translate_fetch (pool, 1, 0 /* PR9768 */, die, typedie, tail, | |
1950 | "THIS->__retvalue"); | |
1951 | break; | |
1952 | ||
1953 | case DW_TAG_array_type: | |
1954 | case DW_TAG_pointer_type: | |
9c119951 JS |
1955 | case DW_TAG_reference_type: |
1956 | case DW_TAG_rvalue_reference_type: | |
440f755a JS |
1957 | |
1958 | { | |
1959 | Dwarf_Die pointee_typedie_mem; | |
1960 | Dwarf_Die *pointee_typedie; | |
1961 | Dwarf_Word pointee_encoding; | |
1962 | Dwarf_Word pointee_byte_size = 0; | |
1963 | ||
1964 | pointee_typedie = resolve_unqualified_inner_typedie (&pointee_typedie_mem, attr_mem, e); | |
1965 | ||
1966 | if (dwarf_attr_integrate (pointee_typedie, DW_AT_byte_size, attr_mem)) | |
1967 | dwarf_formudata (attr_mem, &pointee_byte_size); | |
1968 | ||
1969 | dwarf_formudata (dwarf_attr_integrate (pointee_typedie, DW_AT_encoding, attr_mem), | |
1970 | &pointee_encoding); | |
1971 | ||
1972 | if (lvalue) | |
1973 | { | |
1974 | ty = pe_long; | |
1975 | if (typetag == DW_TAG_array_type) | |
1976 | throw semantic_error ("cannot write to array address", e->tok); | |
9c119951 JS |
1977 | if (typetag == DW_TAG_reference_type || |
1978 | typetag == DW_TAG_rvalue_reference_type) | |
1979 | throw semantic_error ("cannot write to reference", e->tok); | |
440f755a JS |
1980 | assert (typetag == DW_TAG_pointer_type); |
1981 | c_translate_pointer_store (pool, 1, 0 /* PR9768 */, typedie, tail, | |
1982 | "THIS->value"); | |
1983 | } | |
1984 | else | |
1985 | { | |
1986 | // We have the pointer: cast it to an integral type via &(*(...)) | |
1987 | ||
1988 | // NB: per bug #1187, at one point char*-like types were | |
1989 | // automagically converted here to systemtap string values. | |
1990 | // For several reasons, this was taken back out, leaving | |
1991 | // pointer-to-string "conversion" (copying) to tapset functions. | |
1992 | ||
1993 | ty = pe_long; | |
1994 | if (typetag == DW_TAG_array_type) | |
1995 | c_translate_array (pool, 1, 0 /* PR9768 */, typedie, tail, NULL, 0); | |
1996 | else | |
1997 | c_translate_pointer (pool, 1, 0 /* PR9768 */, typedie, tail); | |
1998 | c_translate_addressof (pool, 1, 0 /* PR9768 */, NULL, pointee_typedie, tail, | |
1999 | "THIS->__retvalue"); | |
2000 | } | |
2001 | } | |
2002 | break; | |
2003 | } | |
2004 | } | |
2005 | ||
2006 | ||
2007 | string | |
2008 | dwflpp::express_as_string (string prelude, | |
2009 | string postlude, | |
2010 | struct location *head) | |
2011 | { | |
2012 | size_t bufsz = 1024; | |
2013 | char *buf = static_cast<char*>(malloc(bufsz)); | |
2014 | assert(buf); | |
2015 | ||
2016 | FILE *memstream = open_memstream (&buf, &bufsz); | |
2017 | assert(memstream); | |
2018 | ||
2019 | fprintf(memstream, "{\n"); | |
2020 | fprintf(memstream, "%s", prelude.c_str()); | |
2021 | bool deref = c_emit_location (memstream, head, 1); | |
2022 | fprintf(memstream, "%s", postlude.c_str()); | |
2023 | fprintf(memstream, " goto out;\n"); | |
2024 | ||
2025 | // dummy use of deref_fault label, to disable warning if deref() not used | |
2026 | fprintf(memstream, "if (0) goto deref_fault;\n"); | |
2027 | ||
2028 | // XXX: deref flag not reliable; emit fault label unconditionally | |
2029 | (void) deref; | |
2030 | fprintf(memstream, | |
2031 | "deref_fault:\n" | |
2032 | " goto out;\n"); | |
2033 | fprintf(memstream, "}\n"); | |
2034 | ||
2035 | fclose (memstream); | |
2036 | string result(buf); | |
2037 | free (buf); | |
2038 | return result; | |
2039 | } | |
2040 | ||
2041 | ||
2042 | string | |
2043 | dwflpp::literal_stmt_for_local (Dwarf_Die *scope_die, | |
2044 | Dwarf_Addr pc, | |
2045 | string const & local, | |
2046 | const target_symbol *e, | |
2047 | bool lvalue, | |
2048 | exp_type & ty) | |
2049 | { | |
2050 | Dwarf_Die vardie; | |
2051 | Dwarf_Attribute fb_attr_mem, *fb_attr = NULL; | |
2052 | ||
2053 | fb_attr = find_variable_and_frame_base (scope_die, pc, local, e, | |
2054 | &vardie, &fb_attr_mem); | |
2055 | ||
2056 | if (sess.verbose>2) | |
2057 | clog << "finding location for local '" << local | |
2058 | << "' near address 0x" << hex << pc | |
2059 | << ", module bias 0x" << module_bias << dec | |
2060 | << "\n"; | |
2061 | ||
2062 | Dwarf_Attribute attr_mem; | |
2063 | if (dwarf_attr_integrate (&vardie, DW_AT_location, &attr_mem) == NULL) | |
2064 | { | |
2065 | throw semantic_error("failed to retrieve location " | |
2066 | "attribute for local '" + local | |
2067 | + "' (dieoffset: " | |
2068 | + lex_cast_hex<string>(dwarf_dieoffset (&vardie)) | |
2069 | + ")", | |
2070 | e->tok); | |
2071 | } | |
2072 | ||
2073 | #define obstack_chunk_alloc malloc | |
2074 | #define obstack_chunk_free free | |
2075 | ||
2076 | struct obstack pool; | |
2077 | obstack_init (&pool); | |
2078 | struct location *tail = NULL; | |
2079 | ||
2080 | /* Given $foo->bar->baz[NN], translate the location of foo. */ | |
2081 | ||
2082 | struct location *head = translate_location (&pool, | |
2083 | &attr_mem, pc, fb_attr, &tail, | |
2084 | e); | |
2085 | ||
2086 | if (dwarf_attr_integrate (&vardie, DW_AT_type, &attr_mem) == NULL) | |
2087 | throw semantic_error("failed to retrieve type " | |
2088 | "attribute for local '" + local + "'", | |
2089 | e->tok); | |
2090 | ||
2091 | /* Translate the ->bar->baz[NN] parts. */ | |
2092 | ||
2093 | Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); | |
2094 | die = translate_components (&pool, &tail, pc, e, | |
2095 | die, &die_mem, &attr_mem); | |
2096 | ||
2097 | /* Translate the assignment part, either | |
2098 | x = $foo->bar->baz[NN] | |
2099 | or | |
2100 | $foo->bar->baz[NN] = x | |
2101 | */ | |
2102 | ||
2103 | string prelude, postlude; | |
2104 | translate_final_fetch_or_store (&pool, &tail, module_bias, | |
2105 | die, &attr_mem, lvalue, e, | |
2106 | prelude, postlude, ty); | |
2107 | ||
2108 | /* Write the translation to a string. */ | |
2109 | return express_as_string(prelude, postlude, head); | |
2110 | } | |
2111 | ||
2112 | ||
2113 | string | |
2114 | dwflpp::literal_stmt_for_return (Dwarf_Die *scope_die, | |
2115 | Dwarf_Addr pc, | |
2116 | const target_symbol *e, | |
2117 | bool lvalue, | |
2118 | exp_type & ty) | |
2119 | { | |
2120 | if (sess.verbose>2) | |
2121 | clog << "literal_stmt_for_return: finding return value for " | |
2122 | << (dwarf_diename(scope_die) ?: "<unknown>") | |
2123 | << "(" | |
2124 | << (dwarf_diename(cu) ?: "<unknown>") | |
2125 | << ")\n"; | |
2126 | ||
2127 | struct obstack pool; | |
2128 | obstack_init (&pool); | |
2129 | struct location *tail = NULL; | |
2130 | ||
2131 | /* Given $return->bar->baz[NN], translate the location of return. */ | |
2132 | const Dwarf_Op *locops; | |
2133 | int nlocops = dwfl_module_return_value_location (module, scope_die, | |
2134 | &locops); | |
2135 | if (nlocops < 0) | |
2136 | { | |
2137 | throw semantic_error("failed to retrieve return value location" | |
2138 | " for " | |
2139 | + string(dwarf_diename(scope_die) ?: "<unknown>") | |
2140 | + "(" + string(dwarf_diename(cu) ?: "<unknown>") | |
2141 | + ")", | |
2142 | e->tok); | |
2143 | } | |
2144 | // the function has no return value (e.g. "void" in C) | |
2145 | else if (nlocops == 0) | |
2146 | { | |
2147 | throw semantic_error("function " | |
2148 | + string(dwarf_diename(scope_die) ?: "<unknown>") | |
2149 | + "(" + string(dwarf_diename(cu) ?: "<unknown>") | |
2150 | + ") has no return value", | |
2151 | e->tok); | |
2152 | } | |
2153 | ||
2154 | struct location *head = c_translate_location (&pool, &loc2c_error, this, | |
2155 | &loc2c_emit_address, | |
2156 | 1, 0 /* PR9768 */, | |
2157 | pc, locops, nlocops, | |
00b01a99 | 2158 | &tail, NULL, NULL); |
440f755a JS |
2159 | |
2160 | /* Translate the ->bar->baz[NN] parts. */ | |
2161 | ||
2162 | Dwarf_Attribute attr_mem; | |
2163 | if (dwarf_attr_integrate (scope_die, DW_AT_type, &attr_mem) == NULL) | |
2164 | throw semantic_error("failed to retrieve return value type attribute for " | |
2165 | + string(dwarf_diename(scope_die) ?: "<unknown>") | |
2166 | + "(" + string(dwarf_diename(cu) ?: "<unknown>") | |
2167 | + ")", | |
2168 | e->tok); | |
2169 | ||
2170 | Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); | |
2171 | die = translate_components (&pool, &tail, pc, e, | |
2172 | die, &die_mem, &attr_mem); | |
2173 | ||
2174 | /* Translate the assignment part, either | |
2175 | x = $return->bar->baz[NN] | |
2176 | or | |
2177 | $return->bar->baz[NN] = x | |
2178 | */ | |
2179 | ||
2180 | string prelude, postlude; | |
2181 | translate_final_fetch_or_store (&pool, &tail, module_bias, | |
2182 | die, &attr_mem, lvalue, e, | |
2183 | prelude, postlude, ty); | |
2184 | ||
2185 | /* Write the translation to a string. */ | |
2186 | return express_as_string(prelude, postlude, head); | |
2187 | } | |
2188 | ||
2189 | ||
2190 | string | |
2191 | dwflpp::literal_stmt_for_pointer (Dwarf_Die *type_die, | |
2192 | const target_symbol *e, | |
2193 | bool lvalue, | |
2194 | exp_type & ty) | |
2195 | { | |
2196 | if (sess.verbose>2) | |
2197 | clog << "literal_stmt_for_pointer: finding value for " | |
f1c8f8a5 | 2198 | << dwarf_type_name(type_die) |
440f755a JS |
2199 | << "(" |
2200 | << (dwarf_diename(cu) ?: "<unknown>") | |
2201 | << ")\n"; | |
2202 | ||
2203 | struct obstack pool; | |
2204 | obstack_init (&pool); | |
2205 | struct location *head = c_translate_argument (&pool, &loc2c_error, this, | |
2206 | &loc2c_emit_address, | |
2207 | 1, "THIS->pointer"); | |
2208 | struct location *tail = head; | |
2209 | ||
2210 | /* Translate the ->bar->baz[NN] parts. */ | |
2211 | ||
2212 | Dwarf_Attribute attr_mem; | |
2213 | Dwarf_Die die_mem, *die = NULL; | |
2214 | die = translate_components (&pool, &tail, 0, e, | |
2215 | type_die, &die_mem, &attr_mem); | |
2216 | ||
2217 | /* Translate the assignment part, either | |
2218 | x = (THIS->pointer)->bar->baz[NN] | |
2219 | or | |
2220 | (THIS->pointer)->bar->baz[NN] = x | |
2221 | */ | |
2222 | ||
2223 | string prelude, postlude; | |
2224 | translate_final_fetch_or_store (&pool, &tail, module_bias, | |
2225 | die, &attr_mem, lvalue, e, | |
2226 | prelude, postlude, ty); | |
2227 | ||
2228 | /* Write the translation to a string. */ | |
2229 | return express_as_string(prelude, postlude, head); | |
2230 | } | |
2231 | ||
2232 | ||
27646582 JS |
2233 | static bool |
2234 | in_kprobes_function(systemtap_session& sess, Dwarf_Addr addr) | |
2235 | { | |
2236 | if (sess.sym_kprobes_text_start != 0 && sess.sym_kprobes_text_end != 0) | |
2237 | { | |
2238 | // If the probe point address is anywhere in the __kprobes | |
2239 | // address range, we can't use this probe point. | |
2240 | if (addr >= sess.sym_kprobes_text_start && addr < sess.sym_kprobes_text_end) | |
2241 | return true; | |
2242 | } | |
2243 | return false; | |
2244 | } | |
2245 | ||
2246 | ||
2247 | bool | |
2248 | dwflpp::blacklisted_p(const string& funcname, | |
2249 | const string& filename, | |
2250 | int, | |
2251 | const string& module, | |
2252 | const string& section, | |
2253 | Dwarf_Addr addr, | |
2254 | bool has_return) | |
2255 | { | |
2256 | if (!blacklist_enabled) | |
2257 | return false; // no blacklist for userspace | |
2258 | ||
2259 | if (section.substr(0, 6) == string(".init.") || | |
2260 | section.substr(0, 6) == string(".exit.") || | |
2261 | section.substr(0, 9) == string(".devinit.") || | |
2262 | section.substr(0, 9) == string(".devexit.") || | |
2263 | section.substr(0, 9) == string(".cpuinit.") || | |
2264 | section.substr(0, 9) == string(".cpuexit.") || | |
2265 | section.substr(0, 9) == string(".meminit.") || | |
2266 | section.substr(0, 9) == string(".memexit.")) | |
2267 | { | |
2268 | // NB: module .exit. routines could be probed in theory: | |
2269 | // if the exit handler in "struct module" is diverted, | |
2270 | // first inserting the kprobes | |
2271 | // then allowing the exit code to run | |
2272 | // then removing these kprobes | |
2273 | if (sess.verbose>1) | |
2274 | clog << " skipping - init/exit"; | |
2275 | return true; | |
2276 | } | |
2277 | ||
2278 | // Check for function marked '__kprobes'. | |
2279 | if (module == TOK_KERNEL && in_kprobes_function(sess, addr)) | |
2280 | { | |
2281 | if (sess.verbose>1) | |
2282 | clog << " skipping - __kprobes"; | |
2283 | return true; | |
2284 | } | |
2285 | ||
2286 | // Check probe point against blacklist. | |
2287 | int goodfn = regexec (&blacklist_func, funcname.c_str(), 0, NULL, 0); | |
2288 | if (has_return) | |
2289 | goodfn = goodfn && regexec (&blacklist_func_ret, funcname.c_str(), 0, NULL, 0); | |
2290 | int goodfile = regexec (&blacklist_file, filename.c_str(), 0, NULL, 0); | |
2291 | ||
2292 | if (! (goodfn && goodfile)) | |
2293 | { | |
2294 | if (sess.guru_mode) | |
2295 | { | |
2296 | if (sess.verbose>1) | |
2297 | clog << " guru mode enabled - ignoring blacklist"; | |
2298 | } | |
2299 | else | |
2300 | { | |
2301 | if (sess.verbose>1) | |
2302 | clog << " skipping - blacklisted"; | |
2303 | return true; | |
2304 | } | |
2305 | } | |
2306 | ||
2307 | // This probe point is not blacklisted. | |
2308 | return false; | |
2309 | } | |
2310 | ||
2311 | ||
2312 | void | |
2313 | dwflpp::build_blacklist() | |
2314 | { | |
2315 | // We build up the regexps in these strings | |
2316 | ||
2317 | // Add ^ anchors at the front; $ will be added just before regcomp. | |
2318 | ||
2319 | string blfn = "^("; | |
2320 | string blfn_ret = "^("; | |
2321 | string blfile = "^("; | |
2322 | ||
2323 | blfile += "kernel/kprobes.c"; // first alternative, no "|" | |
2324 | blfile += "|arch/.*/kernel/kprobes.c"; | |
2325 | // Older kernels need ... | |
2326 | blfile += "|include/asm/io.h"; | |
2327 | blfile += "|include/asm/bitops.h"; | |
2328 | // While newer ones need ... | |
2329 | blfile += "|arch/.*/include/asm/io.h"; | |
2330 | blfile += "|arch/.*/include/asm/bitops.h"; | |
2331 | blfile += "|drivers/ide/ide-iops.c"; | |
2332 | ||
2333 | // XXX: it would be nice if these blacklisted functions were pulled | |
2334 | // in dynamically, instead of being statically defined here. | |
2335 | // Perhaps it could be populated from script files. A "noprobe | |
2336 | // kernel.function("...")" construct might do the trick. | |
2337 | ||
2338 | // Most of these are marked __kprobes in newer kernels. We list | |
2339 | // them here (anyway) so the translator can block them on older | |
2340 | // kernels that don't have the __kprobes function decorator. This | |
2341 | // also allows detection of problems at translate- rather than | |
2342 | // run-time. | |
2343 | ||
2344 | blfn += "atomic_notifier_call_chain"; // first blfn; no "|" | |
2345 | blfn += "|default_do_nmi"; | |
2346 | blfn += "|__die"; | |
2347 | blfn += "|die_nmi"; | |
2348 | blfn += "|do_debug"; | |
2349 | blfn += "|do_general_protection"; | |
2350 | blfn += "|do_int3"; | |
2351 | blfn += "|do_IRQ"; | |
2352 | blfn += "|do_page_fault"; | |
2353 | blfn += "|do_sparc64_fault"; | |
2354 | blfn += "|do_trap"; | |
2355 | blfn += "|dummy_nmi_callback"; | |
2356 | blfn += "|flush_icache_range"; | |
2357 | blfn += "|ia64_bad_break"; | |
2358 | blfn += "|ia64_do_page_fault"; | |
2359 | blfn += "|ia64_fault"; | |
2360 | blfn += "|io_check_error"; | |
2361 | blfn += "|mem_parity_error"; | |
2362 | blfn += "|nmi_watchdog_tick"; | |
2363 | blfn += "|notifier_call_chain"; | |
2364 | blfn += "|oops_begin"; | |
2365 | blfn += "|oops_end"; | |
2366 | blfn += "|program_check_exception"; | |
2367 | blfn += "|single_step_exception"; | |
2368 | blfn += "|sync_regs"; | |
2369 | blfn += "|unhandled_fault"; | |
2370 | blfn += "|unknown_nmi_error"; | |
2371 | ||
2372 | // Lots of locks | |
2373 | blfn += "|.*raw_.*lock.*"; | |
2374 | blfn += "|.*read_.*lock.*"; | |
2375 | blfn += "|.*write_.*lock.*"; | |
2376 | blfn += "|.*spin_.*lock.*"; | |
2377 | blfn += "|.*rwlock_.*lock.*"; | |
2378 | blfn += "|.*rwsem_.*lock.*"; | |
2379 | blfn += "|.*mutex_.*lock.*"; | |
2380 | blfn += "|raw_.*"; | |
2381 | blfn += "|.*seq_.*lock.*"; | |
2382 | ||
2383 | // atomic functions | |
2384 | blfn += "|atomic_.*"; | |
2385 | blfn += "|atomic64_.*"; | |
2386 | ||
2387 | // few other problematic cases | |
2388 | blfn += "|get_bh"; | |
2389 | blfn += "|put_bh"; | |
2390 | ||
2391 | // Experimental | |
2392 | blfn += "|.*apic.*|.*APIC.*"; | |
2393 | blfn += "|.*softirq.*"; | |
2394 | blfn += "|.*IRQ.*"; | |
2395 | blfn += "|.*_intr.*"; | |
2396 | blfn += "|__delay"; | |
2397 | blfn += "|.*kernel_text.*"; | |
2398 | blfn += "|get_current"; | |
2399 | blfn += "|current_.*"; | |
2400 | blfn += "|.*exception_tables.*"; | |
2401 | blfn += "|.*setup_rt_frame.*"; | |
2402 | ||
2403 | // PR 5759, CONFIG_PREEMPT kernels | |
2404 | blfn += "|.*preempt_count.*"; | |
2405 | blfn += "|preempt_schedule"; | |
2406 | ||
2407 | // These functions don't return, so return probes would never be recovered | |
2408 | blfn_ret += "do_exit"; // no "|" | |
2409 | blfn_ret += "|sys_exit"; | |
2410 | blfn_ret += "|sys_exit_group"; | |
2411 | ||
2412 | // __switch_to changes "current" on x86_64 and i686, so return probes | |
2413 | // would cause kernel panic, and it is marked as "__kprobes" on x86_64 | |
2414 | if (sess.architecture == "x86_64") | |
2415 | blfn += "|__switch_to"; | |
2416 | if (sess.architecture == "i686") | |
2417 | blfn_ret += "|__switch_to"; | |
2418 | ||
2419 | blfn += ")$"; | |
2420 | blfn_ret += ")$"; | |
2421 | blfile += ")$"; | |
2422 | ||
2423 | if (sess.verbose > 2) | |
2424 | { | |
2425 | clog << "blacklist regexps:" << endl; | |
2426 | clog << "blfn: " << blfn << endl; | |
2427 | clog << "blfn_ret: " << blfn_ret << endl; | |
2428 | clog << "blfile: " << blfile << endl; | |
2429 | } | |
2430 | ||
2431 | int rc = regcomp (& blacklist_func, blfn.c_str(), REG_NOSUB|REG_EXTENDED); | |
2432 | if (rc) throw semantic_error ("blacklist_func regcomp failed"); | |
2433 | rc = regcomp (& blacklist_func_ret, blfn_ret.c_str(), REG_NOSUB|REG_EXTENDED); | |
2434 | if (rc) throw semantic_error ("blacklist_func_ret regcomp failed"); | |
2435 | rc = regcomp (& blacklist_file, blfile.c_str(), REG_NOSUB|REG_EXTENDED); | |
2436 | if (rc) throw semantic_error ("blacklist_file regcomp failed"); | |
2437 | ||
2438 | blacklist_enabled = true; | |
2439 | } | |
2440 | ||
2441 | ||
2442 | string | |
2443 | dwflpp::get_blacklist_section(Dwarf_Addr addr) | |
2444 | { | |
2445 | string blacklist_section; | |
2446 | Dwarf_Addr bias; | |
2447 | // We prefer dwfl_module_getdwarf to dwfl_module_getelf here, | |
2448 | // because dwfl_module_getelf can force costly section relocations | |
2449 | // we don't really need, while either will do for this purpose. | |
2450 | Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (module, &bias)) | |
2451 | ?: dwfl_module_getelf (module, &bias)); | |
2452 | ||
2453 | Dwarf_Addr offset = addr - bias; | |
2454 | if (elf) | |
2455 | { | |
2456 | Elf_Scn* scn = 0; | |
2457 | size_t shstrndx; | |
fcc30d6d | 2458 | dwfl_assert ("getshdrstrndx", elf_getshdrstrndx (elf, &shstrndx)); |
27646582 JS |
2459 | while ((scn = elf_nextscn (elf, scn)) != NULL) |
2460 | { | |
2461 | GElf_Shdr shdr_mem; | |
2462 | GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); | |
2463 | if (! shdr) | |
2464 | continue; // XXX error? | |
2465 | ||
2466 | if (!(shdr->sh_flags & SHF_ALLOC)) | |
2467 | continue; | |
2468 | ||
2469 | GElf_Addr start = shdr->sh_addr; | |
2470 | GElf_Addr end = start + shdr->sh_size; | |
2471 | if (! (offset >= start && offset < end)) | |
2472 | continue; | |
2473 | ||
2474 | blacklist_section = elf_strptr (elf, shstrndx, shdr->sh_name); | |
2475 | break; | |
2476 | } | |
2477 | } | |
2478 | return blacklist_section; | |
2479 | } | |
2480 | ||
2481 | ||
2482 | Dwarf_Addr | |
d2309c6c | 2483 | dwflpp::relocate_address(Dwarf_Addr dw_addr, |
27646582 JS |
2484 | string& reloc_section, |
2485 | string& blacklist_section) | |
2486 | { | |
d2309c6c MW |
2487 | // PR10273 |
2488 | // libdw address, so adjust for bias gotten from dwfl_module_getdwarf | |
2489 | Dwarf_Addr reloc_addr = dw_addr + module_bias; | |
27646582 JS |
2490 | if (!module) |
2491 | { | |
2492 | assert(module_name == TOK_KERNEL); | |
2493 | reloc_section = ""; | |
2494 | blacklist_section = ""; | |
2495 | } | |
2496 | else if (dwfl_module_relocations (module) > 0) | |
2497 | { | |
2498 | // This is a relocatable module; libdwfl already knows its | |
2499 | // sections, so we can relativize addr. | |
2500 | int idx = dwfl_module_relocate_address (module, &reloc_addr); | |
2501 | const char* r_s = dwfl_module_relocation_info (module, idx, NULL); | |
2502 | if (r_s) | |
2503 | reloc_section = r_s; | |
2504 | blacklist_section = reloc_section; | |
2505 | ||
2506 | if (reloc_section == "" && dwfl_module_relocations (module) == 1) | |
2507 | { | |
d2309c6c | 2508 | blacklist_section = get_blacklist_section(dw_addr); |
27646582 | 2509 | reloc_section = ".dynamic"; |
27646582 JS |
2510 | } |
2511 | } | |
2512 | else | |
2513 | { | |
d2309c6c | 2514 | blacklist_section = get_blacklist_section(dw_addr); |
27646582 JS |
2515 | reloc_section = ".absolute"; |
2516 | } | |
2517 | return reloc_addr; | |
2518 | } | |
2519 | ||
1f8592d1 MW |
2520 | /* Converts a "global" literal address to the module symbol address |
2521 | * space. If necessary (not for kernel and executables using absolute | |
2522 | * addresses), this adjust the address for the current module symbol | |
2523 | * bias. Literal addresses are provided by the user (or contained on | |
2524 | * the .probes section) based on the "on disk" layout of the module. | |
2525 | */ | |
2526 | Dwarf_Addr | |
2527 | dwflpp::literal_addr_to_sym_addr(Dwarf_Addr lit_addr) | |
2528 | { | |
88eaee9f MW |
2529 | if (sess.verbose > 2) |
2530 | clog << "literal_addr_to_sym_addr 0x" << hex << lit_addr << dec << endl; | |
2531 | ||
1f8592d1 MW |
2532 | // Assume the address came from the symbol list. |
2533 | // If we cannot get the symbol bias fall back on the dw bias. | |
2534 | // The kernel (and other absolute executable modules) is special though. | |
2535 | if (module_name != TOK_KERNEL | |
2536 | && dwfl_module_relocations (module) > 0) | |
2537 | { | |
2538 | Dwarf_Addr symbias = ~0; | |
2539 | if (dwfl_module_getsymtab (module) != -1) | |
2540 | dwfl_module_info (module, NULL, NULL, NULL, NULL, | |
2541 | &symbias, NULL, NULL); | |
88eaee9f MW |
2542 | |
2543 | if (sess.verbose > 3) | |
2544 | clog << "symbias 0x" << hex << symbias << dec | |
2545 | << ", dwbias 0x" << hex << module_bias << dec << endl; | |
2546 | ||
1f8592d1 MW |
2547 | if (symbias == (Dwarf_Addr) ~0) |
2548 | symbias = module_bias; | |
2549 | ||
2550 | lit_addr += symbias; | |
2551 | } | |
2552 | ||
88eaee9f MW |
2553 | if (sess.verbose > 2) |
2554 | clog << "literal_addr_to_sym_addr ret 0x" << hex << lit_addr << dec << endl; | |
2555 | ||
1f8592d1 MW |
2556 | return lit_addr; |
2557 | } | |
27646582 | 2558 | |
c8ad0687 JS |
2559 | int |
2560 | dwflpp::dwarf_getscopes_cached (Dwarf_Addr pc, Dwarf_Die **scopes) | |
2561 | { | |
2562 | if (!cached_scopes || pc != pc_cached_scopes) | |
2563 | { | |
2564 | free(cached_scopes); | |
2565 | cached_scopes = NULL; | |
2566 | pc_cached_scopes = pc; | |
2567 | num_cached_scopes = dwarf_getscopes(cu, pc, &cached_scopes); | |
2568 | } | |
2569 | *scopes = cached_scopes; | |
2570 | return num_cached_scopes; | |
2571 | } | |
2572 | ||
88eaee9f MW |
2573 | /* Returns the call frame address operations for the given program counter |
2574 | * in the libdw address space. | |
2575 | */ | |
00b01a99 MW |
2576 | Dwarf_Op * |
2577 | dwflpp::get_cfa_ops (Dwarf_Addr pc) | |
2578 | { | |
2579 | Dwarf_Op *cfa_ops = NULL; | |
2580 | ||
88eaee9f MW |
2581 | if (sess.verbose > 2) |
2582 | clog << "get_cfa_ops @0x" << hex << pc << dec | |
2583 | << ", module_start @0x" << hex << module_start << dec << endl; | |
2584 | ||
00b01a99 | 2585 | #if _ELFUTILS_PREREQ(0,142) |
6a38401c | 2586 | // Try debug_frame first, then fall back on eh_frame. |
4a8636a3 | 2587 | size_t cfa_nops; |
00b01a99 MW |
2588 | Dwarf_Addr bias; |
2589 | Dwarf_CFI *cfi = dwfl_module_dwarf_cfi (module, &bias); | |
2590 | if (cfi != NULL) | |
2591 | { | |
88eaee9f MW |
2592 | if (sess.verbose > 3) |
2593 | clog << "got dwarf cfi bias: 0x" << hex << bias << dec << endl; | |
00b01a99 | 2594 | Dwarf_Frame *frame = NULL; |
88eaee9f | 2595 | if (dwarf_cfi_addrframe (cfi, pc - bias, &frame) == 0) |
97f529ab | 2596 | dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops); |
88eaee9f MW |
2597 | else if (sess.verbose > 3) |
2598 | clog << "dwarf_cfi_addrframe failed: " << dwarf_errmsg(-1) << endl; | |
00b01a99 | 2599 | } |
88eaee9f MW |
2600 | else if (sess.verbose > 3) |
2601 | clog << "dwfl_module_dwarf_cfi failed: " << dwfl_errmsg(-1) << endl; | |
2602 | ||
00b01a99 MW |
2603 | if (cfa_ops == NULL) |
2604 | { | |
2605 | cfi = dwfl_module_eh_cfi (module, &bias); | |
2606 | if (cfi != NULL) | |
2607 | { | |
88eaee9f MW |
2608 | if (sess.verbose > 3) |
2609 | clog << "got eh cfi bias: 0x" << hex << bias << dec << endl; | |
00b01a99 | 2610 | Dwarf_Frame *frame = NULL; |
88eaee9f | 2611 | if (dwarf_cfi_addrframe (cfi, pc - bias, &frame) == 0) |
97f529ab | 2612 | dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops); |
88eaee9f MW |
2613 | else if (sess.verbose > 3) |
2614 | clog << "dwarf_cfi_addrframe failed: " << dwarf_errmsg(-1) << endl; | |
00b01a99 | 2615 | } |
88eaee9f MW |
2616 | else if (sess.verbose > 3) |
2617 | clog << "dwfl_module_eh_cfi failed: " << dwfl_errmsg(-1) << endl; | |
2618 | ||
00b01a99 | 2619 | } |
00b01a99 MW |
2620 | #endif |
2621 | ||
88eaee9f MW |
2622 | if (sess.verbose > 2) |
2623 | clog << (cfa_ops == NULL ? "not " : " ") << "found cfa" << endl; | |
2624 | ||
00b01a99 MW |
2625 | return cfa_ops; |
2626 | } | |
c8ad0687 | 2627 | |
440f755a | 2628 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |