]>
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: | |
689 | case DW_TAG_typedef: | |
690 | case DW_TAG_union_type: | |
691 | rc = (*callback)(&die, data); | |
692 | break; | |
693 | } | |
694 | while (rc == DWARF_CB_OK && dwarf_siblingof(&die, &die) == 0); | |
695 | ||
696 | return rc; | |
697 | } | |
698 | ||
699 | ||
700 | // This little test routine represents an unfortunate breakdown in | |
701 | // abstraction between dwflpp (putatively, a layer right on top of | |
702 | // elfutils), and dwarf_query (interpreting a systemtap probe point). | |
703 | // It arises because we sometimes try to fix up slightly-off | |
704 | // .statement() probes (something we find out in fairly low-level). | |
705 | // | |
706 | // An alternative would be to put some more intelligence into query_cu(), | |
707 | // and have it print additional suggestions after finding that | |
708 | // q->dw.iterate_over_srcfile_lines resulted in no new finished_results. | |
709 | ||
710 | bool | |
711 | dwflpp::has_single_line_record (dwarf_query * q, char const * srcfile, int lineno) | |
712 | { | |
713 | if (lineno < 0) | |
714 | return false; | |
715 | ||
716 | Dwarf_Line **srcsp = NULL; | |
717 | size_t nsrcs = 0; | |
718 | ||
719 | dwarf_assert ("dwarf_getsrc_file", | |
720 | dwarf_getsrc_file (module_dwarf, | |
721 | srcfile, lineno, 0, | |
722 | &srcsp, &nsrcs)); | |
723 | ||
724 | if (nsrcs != 1) | |
725 | { | |
726 | if (sess.verbose>4) | |
727 | clog << "alternative line " << lineno << " rejected: nsrcs=" << nsrcs << endl; | |
728 | return false; | |
729 | } | |
730 | ||
731 | // We also try to filter out lines that leave the selected | |
732 | // functions (if any). | |
733 | ||
734 | dwarf_line_t line(srcsp[0]); | |
735 | Dwarf_Addr addr = line.addr(); | |
736 | ||
737 | func_info_map_t *filtered_functions = get_filtered_functions(q); | |
738 | for (func_info_map_t::iterator i = filtered_functions->begin(); | |
739 | i != filtered_functions->end(); ++i) | |
740 | { | |
741 | if (die_has_pc (i->die, addr)) | |
742 | { | |
743 | if (sess.verbose>4) | |
744 | clog << "alternative line " << lineno << " accepted: fn=" << i->name << endl; | |
745 | return true; | |
746 | } | |
747 | } | |
748 | ||
749 | inline_instance_map_t *filtered_inlines = get_filtered_inlines(q); | |
750 | for (inline_instance_map_t::iterator i = filtered_inlines->begin(); | |
751 | i != filtered_inlines->end(); ++i) | |
752 | { | |
753 | if (die_has_pc (i->die, addr)) | |
754 | { | |
755 | if (sess.verbose>4) | |
756 | clog << "alternative line " << lineno << " accepted: ifn=" << i->name << endl; | |
757 | return true; | |
758 | } | |
759 | } | |
760 | ||
761 | if (sess.verbose>4) | |
762 | clog << "alternative line " << lineno << " rejected: leaves selected fns" << endl; | |
763 | return false; | |
764 | } | |
765 | ||
766 | ||
767 | void | |
768 | dwflpp::iterate_over_srcfile_lines (char const * srcfile, | |
769 | int lines[2], | |
770 | bool need_single_match, | |
771 | enum line_t line_type, | |
772 | void (* callback) (const dwarf_line_t& line, | |
773 | void * arg), | |
9b988eff | 774 | const std::string& func_pattern, |
440f755a JS |
775 | void *data) |
776 | { | |
777 | Dwarf_Line **srcsp = NULL; | |
778 | size_t nsrcs = 0; | |
779 | dwarf_query * q = static_cast<dwarf_query *>(data); | |
780 | int lineno = lines[0]; | |
781 | auto_free_ref<Dwarf_Line**> free_srcsp(srcsp); | |
782 | ||
783 | get_module_dwarf(); | |
e679283a WH |
784 | if (!this->function) |
785 | return; | |
440f755a JS |
786 | |
787 | if (line_type == RELATIVE) | |
788 | { | |
789 | Dwarf_Addr addr; | |
790 | Dwarf_Line *line; | |
791 | int line_number; | |
792 | ||
793 | dwarf_assert ("dwarf_entrypc", dwarf_entrypc (this->function, &addr)); | |
794 | line = dwarf_getsrc_die (this->cu, addr); | |
795 | dwarf_assert ("dwarf_getsrc_die", line == NULL); | |
796 | dwarf_assert ("dwarf_lineno", dwarf_lineno (line, &line_number)); | |
797 | lineno += line_number; | |
798 | } | |
799 | else if (line_type == WILDCARD) | |
800 | function_line (&lineno); | |
1123a74a WH |
801 | else if (line_type == RANGE) { /* correct lineno */ |
802 | int start_lineno; | |
803 | ||
9b988eff WH |
804 | if (name_has_wildcard(func_pattern)) /* PR10294: wider range like statement("*@foo.c") */ |
805 | start_lineno = lineno; | |
806 | else | |
807 | function_line (&start_lineno); | |
1123a74a WH |
808 | lineno = lineno < start_lineno ? start_lineno : lineno; |
809 | if (lineno > lines[1]) { /* invalid line range */ | |
810 | stringstream advice; | |
811 | advice << "Invalid line range (" << lines[0] << "-" << lines[1] << ")"; | |
812 | if (start_lineno > lines[1]) | |
813 | advice << ", the end line number " << lines[1] << " < " << start_lineno; | |
814 | throw semantic_error (advice.str()); | |
815 | } | |
816 | } | |
817 | ||
440f755a JS |
818 | |
819 | for (int l = lineno; ; l = l + 1) | |
820 | { | |
821 | set<int> lines_probed; | |
822 | pair<set<int>::iterator,bool> line_probed; | |
1123a74a WH |
823 | int ret = 0; |
824 | ||
825 | ret = dwarf_getsrc_file (module_dwarf, srcfile, l, 0, | |
826 | &srcsp, &nsrcs); | |
827 | if (line_type != WILDCARD && line_type != RANGE) | |
828 | dwarf_assert ("dwarf_getsrc_file", ret); | |
829 | ||
440f755a JS |
830 | if (line_type == WILDCARD || line_type == RANGE) |
831 | { | |
832 | Dwarf_Addr line_addr; | |
1123a74a WH |
833 | |
834 | if (ret != 0) /* tolerate invalid line number */ | |
835 | break; | |
836 | ||
440f755a | 837 | dwarf_lineno (srcsp [0], &lineno); |
1123a74a WH |
838 | /* Maybe lineno will exceed the input end */ |
839 | if (line_type == RANGE && lineno > lines[1]) | |
840 | break; | |
440f755a JS |
841 | line_probed = lines_probed.insert(lineno); |
842 | if (lineno != l || line_probed.second == false || nsrcs > 1) | |
843 | continue; | |
844 | dwarf_lineaddr (srcsp [0], &line_addr); | |
9b988eff | 845 | if (!function_name_matches(func_pattern) && dwarf_haspc (function, line_addr) != 1) |
440f755a JS |
846 | break; |
847 | } | |
848 | ||
849 | // NB: Formerly, we used to filter, because: | |
850 | ||
851 | // dwarf_getsrc_file gets one *near hits* for line numbers, not | |
852 | // exact matches. For example, an existing file but a nonexistent | |
853 | // line number will be rounded up to the next definition in that | |
854 | // file. This may be similar to the GDB breakpoint algorithm, but | |
855 | // we don't want to be so fuzzy in systemtap land. So we filter. | |
856 | ||
857 | // But we now see the error of our ways, and skip this filtering. | |
858 | ||
859 | // XXX: the code also fails to match e.g. inline function | |
860 | // definitions when the srcfile is a header file rather than the | |
861 | // CU name. | |
862 | ||
863 | size_t remaining_nsrcs = nsrcs; | |
864 | ||
865 | if (need_single_match && remaining_nsrcs > 1) | |
866 | { | |
867 | // We wanted a single line record (a unique address for the | |
868 | // line) and we got a bunch of line records. We're going to | |
869 | // skip this probe (throw an exception) but before we throw | |
870 | // we're going to look around a bit to see if there's a low or | |
871 | // high line number nearby which *doesn't* have this problem, | |
872 | // so we can give the user some advice. | |
873 | ||
874 | int lo_try = -1; | |
875 | int hi_try = -1; | |
876 | for (size_t i = 1; i < 6; ++i) | |
877 | { | |
878 | if (lo_try == -1 && has_single_line_record(q, srcfile, lineno - i)) | |
879 | lo_try = lineno - i; | |
880 | ||
881 | if (hi_try == -1 && has_single_line_record(q, srcfile, lineno + i)) | |
882 | hi_try = lineno + i; | |
883 | } | |
884 | ||
885 | stringstream advice; | |
886 | advice << "multiple addresses for " << srcfile << ":" << lineno; | |
887 | if (lo_try > 0 || hi_try > 0) | |
888 | { | |
889 | advice << " (try "; | |
890 | if (lo_try > 0) | |
891 | advice << srcfile << ":" << lo_try; | |
892 | if (lo_try > 0 && hi_try > 0) | |
893 | advice << " or "; | |
894 | if (hi_try > 0) | |
895 | advice << srcfile << ":" << hi_try; | |
896 | advice << ")"; | |
897 | } | |
898 | throw semantic_error (advice.str()); | |
899 | } | |
900 | ||
901 | for (size_t i = 0; i < nsrcs; ++i) | |
902 | { | |
903 | if (pending_interrupts) return; | |
904 | if (srcsp [i]) // skip over mismatched lines | |
905 | callback (dwarf_line_t(srcsp[i]), data); | |
906 | } | |
907 | ||
908 | if (line_type == ABSOLUTE || line_type == RELATIVE) | |
909 | break; | |
910 | else if (line_type == RANGE && l == lines[1]) | |
911 | break; | |
912 | } | |
913 | } | |
914 | ||
915 | ||
916 | void | |
917 | dwflpp::iterate_over_labels (Dwarf_Die *begin_die, | |
918 | const char *sym, | |
919 | const char *symfunction, | |
920 | void *data, | |
921 | void (* callback)(const string &, | |
922 | const char *, | |
923 | int, | |
924 | Dwarf_Die *, | |
925 | Dwarf_Addr, | |
926 | dwarf_query *)) | |
927 | { | |
928 | dwarf_query * q __attribute__ ((unused)) = static_cast<dwarf_query *>(data) ; | |
929 | ||
930 | get_module_dwarf(); | |
931 | ||
932 | Dwarf_Die die; | |
933 | int res = dwarf_child (begin_die, &die); | |
934 | if (res != 0) | |
935 | return; // die without children, bail out. | |
936 | ||
937 | static string function_name = dwarf_diename (begin_die); | |
938 | do | |
939 | { | |
940 | Dwarf_Attribute attr_mem; | |
941 | Dwarf_Attribute *attr = dwarf_attr (&die, DW_AT_name, &attr_mem); | |
942 | int tag = dwarf_tag(&die); | |
943 | const char *name = dwarf_formstring (attr); | |
944 | if (name == 0) | |
945 | continue; | |
946 | switch (tag) | |
947 | { | |
948 | case DW_TAG_label: | |
949 | break; | |
950 | case DW_TAG_subprogram: | |
951 | if (!dwarf_hasattr(&die, DW_AT_declaration)) | |
952 | function_name = name; | |
953 | else | |
954 | continue; | |
955 | default: | |
956 | if (dwarf_haschildren (&die)) | |
957 | iterate_over_labels (&die, sym, symfunction, q, callback); | |
958 | continue; | |
959 | } | |
960 | ||
961 | if (strcmp(function_name.c_str(), symfunction) == 0 | |
962 | || (name_has_wildcard(symfunction) | |
963 | && function_name_matches (symfunction))) | |
964 | { | |
965 | } | |
966 | else | |
967 | continue; | |
968 | if (strcmp(name, sym) == 0 | |
969 | || (name_has_wildcard(sym) | |
970 | && function_name_matches_pattern (name, sym))) | |
971 | { | |
972 | const char *file = dwarf_decl_file (&die); | |
7f17af5c | 973 | |
440f755a | 974 | // Get the line number for this label |
7f17af5c JS |
975 | int dline; |
976 | dwarf_decl_line (&die, &dline); | |
977 | ||
440f755a JS |
978 | Dwarf_Addr stmt_addr; |
979 | if (dwarf_lowpc (&die, &stmt_addr) != 0) | |
980 | { | |
981 | // There is no lowpc so figure out the address | |
982 | // Get the real die for this cu | |
983 | Dwarf_Die cudie; | |
984 | dwarf_diecu (cu, &cudie, NULL, NULL); | |
985 | size_t nlines = 0; | |
986 | // Get the line for this label | |
987 | Dwarf_Line **aline; | |
7f17af5c | 988 | dwarf_getsrc_file (module_dwarf, file, dline, 0, &aline, &nlines); |
440f755a JS |
989 | // Get the address |
990 | for (size_t i = 0; i < nlines; i++) | |
991 | { | |
992 | dwarf_lineaddr (*aline, &stmt_addr); | |
993 | if ((dwarf_haspc (&die, stmt_addr))) | |
994 | break; | |
995 | } | |
996 | } | |
997 | ||
998 | Dwarf_Die *scopes; | |
999 | int nscopes = 0; | |
1000 | nscopes = dwarf_getscopes_die (&die, &scopes); | |
1001 | if (nscopes > 1) | |
1002 | { | |
1003 | callback(function_name.c_str(), file, | |
7f17af5c | 1004 | dline, &scopes[1], stmt_addr, q); |
440f755a JS |
1005 | add_label_name(q, name); |
1006 | } | |
1007 | } | |
1008 | } | |
1009 | while (dwarf_siblingof (&die, &die) == 0); | |
1010 | } | |
1011 | ||
1012 | ||
1013 | void | |
1014 | dwflpp::collect_srcfiles_matching (string const & pattern, | |
1015 | set<char const *> & filtered_srcfiles) | |
1016 | { | |
1017 | assert (module); | |
1018 | assert (cu); | |
1019 | ||
1020 | size_t nfiles; | |
1021 | Dwarf_Files *srcfiles; | |
1022 | ||
1023 | // PR 5049: implicit * in front of given path pattern. | |
1024 | // NB: fnmatch() is used without FNM_PATHNAME. | |
1025 | string prefixed_pattern = string("*/") + pattern; | |
1026 | ||
1027 | dwarf_assert ("dwarf_getsrcfiles", | |
1028 | dwarf_getsrcfiles (cu, &srcfiles, &nfiles)); | |
1029 | { | |
1030 | for (size_t i = 0; i < nfiles; ++i) | |
1031 | { | |
1032 | char const * fname = dwarf_filesrc (srcfiles, i, NULL, NULL); | |
1033 | if (fnmatch (pattern.c_str(), fname, 0) == 0 || | |
1034 | fnmatch (prefixed_pattern.c_str(), fname, 0) == 0) | |
1035 | { | |
1036 | filtered_srcfiles.insert (fname); | |
1037 | if (sess.verbose>2) | |
1038 | clog << "selected source file '" << fname << "'\n"; | |
1039 | } | |
1040 | } | |
1041 | } | |
1042 | } | |
1043 | ||
1044 | ||
1045 | void | |
1046 | dwflpp::resolve_prologue_endings (func_info_map_t & funcs) | |
1047 | { | |
1048 | // This heuristic attempts to pick the first address that has a | |
1049 | // source line distinct from the function declaration's. In a | |
1050 | // perfect world, this would be the first statement *past* the | |
1051 | // prologue. | |
1052 | ||
1053 | assert(module); | |
1054 | assert(cu); | |
1055 | ||
1056 | size_t nlines = 0; | |
1057 | Dwarf_Lines *lines = NULL; | |
1058 | ||
1059 | /* trouble cases: | |
1060 | malloc do_symlink in init/initramfs.c tail-recursive/tiny then no-prologue | |
1061 | sys_get?id in kernel/timer.c no-prologue | |
1062 | sys_exit_group tail-recursive | |
1063 | {do_,}sys_open extra-long-prologue (gcc 3.4) | |
1064 | cpu_to_logical_apicid NULL-decl_file | |
1065 | */ | |
1066 | ||
1067 | // Fetch all srcline records, sorted by address. | |
1068 | dwarf_assert ("dwarf_getsrclines", | |
1069 | dwarf_getsrclines(cu, &lines, &nlines)); | |
1070 | // XXX: free lines[] later, but how? | |
1071 | ||
1072 | for(func_info_map_t::iterator it = funcs.begin(); it != funcs.end(); it++) | |
1073 | { | |
1074 | #if 0 /* someday */ | |
1075 | Dwarf_Addr* bkpts = 0; | |
1076 | int n = dwarf_entry_breakpoints (& it->die, & bkpts); | |
1077 | // ... | |
1078 | free (bkpts); | |
1079 | #endif | |
1080 | ||
1081 | Dwarf_Addr entrypc = it->entrypc; | |
1082 | Dwarf_Addr highpc; // NB: highpc is exclusive: [entrypc,highpc) | |
1083 | dwfl_assert ("dwarf_highpc", dwarf_highpc (& it->die, | |
1084 | & highpc)); | |
1085 | ||
1086 | if (it->decl_file == 0) it->decl_file = ""; | |
1087 | ||
1088 | unsigned entrypc_srcline_idx = 0; | |
1089 | dwarf_line_t entrypc_srcline; | |
1090 | // open-code binary search for exact match | |
1091 | { | |
1092 | unsigned l = 0, h = nlines; | |
1093 | while (l < h) | |
1094 | { | |
1095 | entrypc_srcline_idx = (l + h) / 2; | |
1096 | const dwarf_line_t lr(dwarf_onesrcline(lines, | |
1097 | entrypc_srcline_idx)); | |
1098 | Dwarf_Addr addr = lr.addr(); | |
1099 | if (addr == entrypc) { entrypc_srcline = lr; break; } | |
1100 | else if (l + 1 == h) { break; } // ran off bottom of tree | |
1101 | else if (addr < entrypc) { l = entrypc_srcline_idx; } | |
1102 | else { h = entrypc_srcline_idx; } | |
1103 | } | |
1104 | } | |
1105 | if (!entrypc_srcline) | |
1106 | { | |
1107 | if (sess.verbose > 2) | |
1108 | clog << "missing entrypc dwarf line record for function '" | |
1109 | << it->name << "'\n"; | |
1110 | // This is probably an inlined function. We'll end up using | |
1111 | // its lowpc as a probe address. | |
1112 | continue; | |
1113 | } | |
1114 | ||
1115 | if (sess.verbose>2) | |
1116 | clog << "prologue searching function '" << it->name << "'" | |
1117 | << " 0x" << hex << entrypc << "-0x" << highpc << dec | |
1118 | << "@" << it->decl_file << ":" << it->decl_line | |
1119 | << "\n"; | |
1120 | ||
1121 | // Now we go searching for the first line record that has a | |
1122 | // file/line different from the one in the declaration. | |
1123 | // Normally, this will be the next one. BUT: | |
1124 | // | |
1125 | // We may have to skip a few because some old compilers plop | |
1126 | // in dummy line records for longer prologues. If we go too | |
1127 | // far (addr >= highpc), we take the previous one. Or, it may | |
1128 | // be the first one, if the function had no prologue, and thus | |
1129 | // the entrypc maps to a statement in the body rather than the | |
1130 | // declaration. | |
1131 | ||
1132 | unsigned postprologue_srcline_idx = entrypc_srcline_idx; | |
1133 | bool ranoff_end = false; | |
1134 | while (postprologue_srcline_idx < nlines) | |
1135 | { | |
1136 | dwarf_line_t lr(dwarf_onesrcline(lines, postprologue_srcline_idx)); | |
1137 | Dwarf_Addr postprologue_addr = lr.addr(); | |
1138 | const char* postprologue_file = lr.linesrc(); | |
1139 | int postprologue_lineno = lr.lineno(); | |
1140 | ||
1141 | if (sess.verbose>2) | |
1142 | clog << "checking line record 0x" << hex << postprologue_addr << dec | |
1143 | << "@" << postprologue_file << ":" << postprologue_lineno << "\n"; | |
1144 | ||
1145 | if (postprologue_addr >= highpc) | |
1146 | { | |
1147 | ranoff_end = true; | |
1148 | postprologue_srcline_idx --; | |
1149 | continue; | |
1150 | } | |
1151 | if (ranoff_end || | |
1152 | (strcmp (postprologue_file, it->decl_file) || // We have a winner! | |
1153 | (postprologue_lineno != it->decl_line))) | |
1154 | { | |
1155 | it->prologue_end = postprologue_addr; | |
1156 | ||
1157 | if (sess.verbose>2) | |
1158 | { | |
1159 | clog << "prologue found function '" << it->name << "'"; | |
1160 | // Add a little classification datum | |
1161 | if (postprologue_srcline_idx == entrypc_srcline_idx) clog << " (naked)"; | |
1162 | if (ranoff_end) clog << " (tail-call?)"; | |
1163 | clog << " = 0x" << hex << postprologue_addr << dec << "\n"; | |
1164 | } | |
1165 | ||
1166 | break; | |
1167 | } | |
1168 | ||
1169 | // Let's try the next srcline. | |
1170 | postprologue_srcline_idx ++; | |
1171 | } // loop over srclines | |
1172 | ||
1173 | // if (strlen(it->decl_file) == 0) it->decl_file = NULL; | |
1174 | ||
1175 | } // loop over functions | |
1176 | ||
1177 | // XXX: how to free lines? | |
1178 | } | |
1179 | ||
1180 | ||
1181 | bool | |
1182 | dwflpp::function_entrypc (Dwarf_Addr * addr) | |
1183 | { | |
1184 | assert (function); | |
1185 | return (dwarf_entrypc (function, addr) == 0); | |
440f755a JS |
1186 | } |
1187 | ||
1188 | ||
1189 | bool | |
1190 | dwflpp::die_entrypc (Dwarf_Die * die, Dwarf_Addr * addr) | |
1191 | { | |
1192 | int rc = 0; | |
1193 | string lookup_method; | |
1194 | ||
1195 | * addr = 0; | |
1196 | ||
1197 | lookup_method = "dwarf_entrypc"; | |
1198 | rc = dwarf_entrypc (die, addr); | |
1199 | ||
440f755a JS |
1200 | if (rc) |
1201 | { | |
1202 | lookup_method = "dwarf_ranges"; | |
1203 | ||
1204 | Dwarf_Addr base; | |
1205 | Dwarf_Addr begin; | |
1206 | Dwarf_Addr end; | |
1207 | ptrdiff_t offset = dwarf_ranges (die, 0, &base, &begin, &end); | |
1208 | if (offset < 0) rc = -1; | |
1209 | else if (offset > 0) | |
1210 | { | |
1211 | * addr = begin; | |
1212 | rc = 0; | |
1213 | ||
1214 | // Now we need to check that there are no more ranges | |
1215 | // associated with this function, which could conceivably | |
1216 | // happen if a function is inlined, then pieces of it are | |
1217 | // split amongst different conditional branches. It's not | |
1218 | // obvious which of them to favour. As a heuristic, we | |
1219 | // pick the beginning of the first range, and ignore the | |
1220 | // others (but with a warning). | |
1221 | ||
1222 | unsigned extra = 0; | |
1223 | while ((offset = dwarf_ranges (die, offset, &base, &begin, &end)) > 0) | |
1224 | extra ++; | |
1225 | if (extra) | |
1226 | lookup_method += ", ignored " + lex_cast<string>(extra) + " more"; | |
1227 | } | |
1228 | } | |
1229 | ||
1230 | if (sess.verbose > 2) | |
1231 | clog << "entry-pc lookup (" << lookup_method << ") = 0x" << hex << *addr << dec | |
1232 | << " (rc " << rc << ")" | |
1233 | << endl; | |
1234 | return (rc == 0); | |
1235 | } | |
1236 | ||
1237 | ||
1238 | void | |
1239 | dwflpp::function_die (Dwarf_Die *d) | |
1240 | { | |
1241 | assert (function); | |
1242 | *d = *function; | |
1243 | } | |
1244 | ||
1245 | ||
1246 | void | |
1247 | dwflpp::function_file (char const ** c) | |
1248 | { | |
1249 | assert (function); | |
1250 | assert (c); | |
1251 | *c = dwarf_decl_file (function); | |
1252 | } | |
1253 | ||
1254 | ||
1255 | void | |
1256 | dwflpp::function_line (int *linep) | |
1257 | { | |
1258 | assert (function); | |
1259 | dwarf_decl_line (function, linep); | |
1260 | } | |
1261 | ||
1262 | ||
1263 | bool | |
1264 | dwflpp::die_has_pc (Dwarf_Die & die, Dwarf_Addr pc) | |
1265 | { | |
1266 | int res = dwarf_haspc (&die, pc); | |
1267 | // dwarf_ranges will return -1 if a function die has no DW_AT_ranges | |
1268 | // if (res == -1) | |
1269 | // dwarf_assert ("dwarf_haspc", res); | |
1270 | return res == 1; | |
1271 | } | |
1272 | ||
1273 | ||
1274 | void | |
1275 | dwflpp::loc2c_error (void *, const char *fmt, ...) | |
1276 | { | |
1277 | const char *msg = "?"; | |
1278 | char *tmp = NULL; | |
1279 | int rc; | |
1280 | va_list ap; | |
1281 | va_start (ap, fmt); | |
1282 | rc = vasprintf (& tmp, fmt, ap); | |
1283 | if (rc < 0) | |
1284 | msg = "?"; | |
1285 | else | |
1286 | msg = tmp; | |
1287 | va_end (ap); | |
1288 | throw semantic_error (msg); | |
1289 | } | |
1290 | ||
1291 | ||
1292 | // This function generates code used for addressing computations of | |
1293 | // target variables. | |
1294 | void | |
1295 | dwflpp::emit_address (struct obstack *pool, Dwarf_Addr address) | |
1296 | { | |
1297 | #if 0 | |
1298 | // The easy but incorrect way is to just print a hard-wired | |
1299 | // constant. | |
1300 | obstack_printf (pool, "%#" PRIx64 "UL", address); | |
1301 | #endif | |
1302 | ||
1303 | // Turn this address into a section-relative offset if it should be one. | |
1304 | // We emit a comment approximating the variable+offset expression that | |
1305 | // relocatable module probing code will need to have. | |
1306 | Dwfl_Module *mod = dwfl_addrmodule (dwfl, address); | |
1307 | dwfl_assert ("dwfl_addrmodule", mod); | |
1308 | const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, | |
1309 | NULL, NULL, NULL, NULL); | |
1310 | int n = dwfl_module_relocations (mod); | |
1311 | dwfl_assert ("dwfl_module_relocations", n >= 0); | |
1312 | Dwarf_Addr reloc_address = address; | |
1313 | int i = dwfl_module_relocate_address (mod, &reloc_address); | |
1314 | dwfl_assert ("dwfl_module_relocate_address", i >= 0); | |
1315 | dwfl_assert ("dwfl_module_info", modname); | |
1316 | const char *secname = dwfl_module_relocation_info (mod, i, NULL); | |
1317 | ||
1318 | if (sess.verbose > 2) | |
1319 | { | |
1320 | clog << "emit dwarf addr 0x" << hex << address << dec | |
1321 | << " => module " << modname | |
1322 | << " section " << (secname ?: "null") | |
1323 | << " relocaddr 0x" << hex << reloc_address << dec | |
1324 | << endl; | |
1325 | } | |
1326 | ||
1327 | if (n > 0 && !(n == 1 && secname == NULL)) | |
1328 | { | |
1329 | dwfl_assert ("dwfl_module_relocation_info", secname); | |
1330 | if (n > 1 || secname[0] != '\0') | |
1331 | { | |
1332 | // This gives us the module name, and section name within the | |
1333 | // module, for a kernel module (or other ET_REL module object). | |
1334 | obstack_printf (pool, "({ static unsigned long addr = 0; "); | |
1335 | obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ", | |
1336 | modname, secname, reloc_address); | |
1337 | obstack_printf (pool, "addr; })"); | |
1338 | } | |
1339 | else if (n == 1 && module_name == TOK_KERNEL && secname[0] == '\0') | |
1340 | { | |
1341 | // elfutils' way of telling us that this is a relocatable kernel address, which we | |
1342 | // need to treat the same way here as dwarf_query::add_probe_point does: _stext. | |
1343 | address -= sess.sym_stext; | |
1344 | secname = "_stext"; | |
1345 | obstack_printf (pool, "({ static unsigned long addr = 0; "); | |
1346 | obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ", | |
1347 | modname, secname, address); // PR10000 NB: not reloc_address | |
1348 | obstack_printf (pool, "addr; })"); | |
1349 | } | |
1350 | else | |
1351 | { | |
1352 | throw semantic_error ("cannot relocate user-space dso (?) address"); | |
1353 | #if 0 | |
1354 | // This would happen for a Dwfl_Module that's a user-level DSO. | |
1355 | obstack_printf (pool, " /* %s+%#" PRIx64 " */", | |
1356 | modname, address); | |
1357 | #endif | |
1358 | } | |
1359 | } | |
1360 | else | |
1361 | obstack_printf (pool, "%#" PRIx64 "UL", address); // assume as constant | |
1362 | } | |
1363 | ||
1364 | ||
1365 | void | |
1366 | dwflpp::loc2c_emit_address (void *arg, struct obstack *pool, | |
1367 | Dwarf_Addr address) | |
1368 | { | |
c94efd63 | 1369 | static_cast<dwflpp *>(arg)->emit_address (pool, address); |
440f755a JS |
1370 | } |
1371 | ||
1372 | ||
1373 | void | |
1374 | dwflpp::print_locals(Dwarf_Die *die, ostream &o) | |
1375 | { | |
1376 | // Try to get the first child of die. | |
1377 | Dwarf_Die child; | |
1378 | if (dwarf_child (die, &child) == 0) | |
1379 | { | |
1380 | do | |
1381 | { | |
1382 | const char *name; | |
1383 | // Output each sibling's name (that is a variable or | |
1384 | // parameter) to 'o'. | |
1385 | switch (dwarf_tag (&child)) | |
1386 | { | |
1387 | case DW_TAG_variable: | |
1388 | case DW_TAG_formal_parameter: | |
1389 | name = dwarf_diename (&child); | |
1390 | if (name) | |
1391 | o << " " << name; | |
1392 | break; | |
1393 | default: | |
1394 | break; | |
1395 | } | |
1396 | } | |
1397 | while (dwarf_siblingof (&child, &child) == 0); | |
1398 | } | |
1399 | } | |
1400 | ||
1401 | ||
1402 | Dwarf_Attribute * | |
1403 | dwflpp::find_variable_and_frame_base (Dwarf_Die *scope_die, | |
1404 | Dwarf_Addr pc, | |
1405 | string const & local, | |
1406 | const target_symbol *e, | |
1407 | Dwarf_Die *vardie, | |
1408 | Dwarf_Attribute *fb_attr_mem) | |
1409 | { | |
1410 | Dwarf_Die *scopes; | |
1411 | int nscopes = 0; | |
1412 | Dwarf_Attribute *fb_attr = NULL; | |
1413 | ||
1414 | assert (cu); | |
1415 | ||
c8ad0687 | 1416 | nscopes = dwarf_getscopes_cached (pc, &scopes); |
440f755a JS |
1417 | if (nscopes <= 0) |
1418 | { | |
1419 | throw semantic_error ("unable to find any scopes containing " | |
1420 | + lex_cast_hex<string>(pc) | |
1421 | + ((scope_die == NULL) ? "" | |
1422 | : (string (" in ") | |
1423 | + (dwarf_diename(scope_die) ?: "<unknown>") | |
1424 | + "(" + (dwarf_diename(cu) ?: "<unknown>") | |
1425 | + ")")) | |
1426 | + " while searching for local '" + local + "'", | |
1427 | e->tok); | |
1428 | } | |
1429 | ||
1430 | int declaring_scope = dwarf_getscopevar (scopes, nscopes, | |
1431 | local.c_str(), | |
1432 | 0, NULL, 0, 0, | |
1433 | vardie); | |
1434 | if (declaring_scope < 0) | |
1435 | { | |
1436 | stringstream alternatives; | |
1437 | print_locals (scopes, alternatives); | |
1438 | throw semantic_error ("unable to find local '" + local + "'" | |
1439 | + " near pc " + lex_cast_hex<string>(pc) | |
1440 | + ((scope_die == NULL) ? "" | |
1441 | : (string (" in ") | |
1442 | + (dwarf_diename(scope_die) ?: "<unknown>") | |
1443 | + "(" + (dwarf_diename(cu) ?: "<unknown>") | |
1444 | + ")")) | |
1445 | + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")), | |
1446 | e->tok); | |
1447 | } | |
1448 | ||
7bce6f87 MW |
1449 | /* We start out walking the "lexical scopes" as returned by |
1450 | * as returned by dwarf_getscopes for the address, starting with the | |
1451 | * declaring_scope that the variable was found in. | |
1452 | */ | |
1453 | for (int inner = declaring_scope; | |
1454 | inner < nscopes && fb_attr == NULL; | |
1455 | ++inner) | |
440f755a JS |
1456 | { |
1457 | switch (dwarf_tag (&scopes[inner])) | |
1458 | { | |
1459 | default: | |
1460 | continue; | |
1461 | case DW_TAG_subprogram: | |
1462 | case DW_TAG_entry_point: | |
7bce6f87 MW |
1463 | fb_attr = dwarf_attr_integrate (&scopes[inner], |
1464 | DW_AT_frame_base, | |
1465 | fb_attr_mem); | |
1466 | break; | |
1467 | case DW_TAG_inlined_subroutine: | |
1468 | /* Unless we already are going through the "pyshical die tree", | |
1469 | * we now need to start walking the die tree where this | |
1470 | * subroutine is inlined to find the appropriate frame base. */ | |
1471 | if (declaring_scope != -1) | |
1472 | { | |
1473 | nscopes = dwarf_getscopes_die (&scopes[inner], &scopes); | |
1474 | if (nscopes == -1) | |
1475 | throw semantic_error ("unable to get die scopes for '" + | |
1476 | local + "' in an inlined subroutines", | |
1477 | e->tok); | |
1478 | inner = 0; // zero is current scope, for look will increase. | |
1479 | declaring_scope = -1; | |
1480 | } | |
440f755a JS |
1481 | break; |
1482 | } | |
1483 | } | |
7bce6f87 | 1484 | |
440f755a JS |
1485 | return fb_attr; |
1486 | } | |
1487 | ||
1488 | ||
1489 | struct location * | |
1490 | dwflpp::translate_location(struct obstack *pool, | |
1491 | Dwarf_Attribute *attr, Dwarf_Addr pc, | |
1492 | Dwarf_Attribute *fb_attr, | |
1493 | struct location **tail, | |
1494 | const target_symbol *e) | |
1495 | { | |
619d9aaf MW |
1496 | |
1497 | /* DW_AT_data_member_location, can be either constant offsets | |
1498 | (struct member fields), or full blown location expressions. */ | |
1499 | if (dwarf_whatattr (attr) == DW_AT_data_member_location) | |
1500 | { | |
1501 | unsigned int form = dwarf_whatform (attr); | |
1502 | if (form == DW_FORM_data1 || form == DW_FORM_data2 | |
1503 | || form == DW_FORM_sdata || form == DW_FORM_udata) | |
1504 | { | |
1505 | Dwarf_Sword off; | |
1506 | if (dwarf_formsdata (attr, &off) != 0) | |
1507 | throw semantic_error (string ("dwarf_formsdata failed, ") | |
1508 | + string (dwarf_errmsg (-1)), e->tok); | |
1509 | c_translate_add_offset (pool, 1, NULL, off, tail); | |
1510 | return *tail; | |
1511 | } | |
1512 | } | |
1513 | ||
440f755a JS |
1514 | Dwarf_Op *expr; |
1515 | size_t len; | |
1516 | ||
1517 | /* PR9768: formerly, we added pc+module_bias here. However, that bias value | |
1518 | is not present in the pc value by the time we get it, so adding it would | |
1519 | result in false negatives of variable reachibility. In other instances | |
1520 | further below, the c_translate_FOO functions, the module_bias value used | |
1521 | to be passed in, but instead should now be zero for the same reason. */ | |
1522 | ||
1523 | switch (dwarf_getlocation_addr (attr, pc /*+ module_bias*/, &expr, &len, 1)) | |
1524 | { | |
1525 | case 1: /* Should always happen. */ | |
1526 | if (len > 0) | |
1527 | break; | |
1528 | /* Fall through. */ | |
1529 | ||
1530 | case 0: /* Shouldn't happen. */ | |
1531 | throw semantic_error ("not accessible at this address", e->tok); | |
1532 | ||
1533 | default: /* Shouldn't happen. */ | |
1534 | case -1: | |
619d9aaf | 1535 | throw semantic_error (string ("dwarf_getlocation_addr failed, ") + |
440f755a JS |
1536 | string (dwarf_errmsg (-1)), |
1537 | e->tok); | |
1538 | } | |
1539 | ||
88eaee9f MW |
1540 | // get_cfa_ops works on the dw address space, pc is relative to current |
1541 | // module, so add do need to add module_bias. | |
1542 | Dwarf_Op *cfa_ops = get_cfa_ops (pc + module_bias); | |
440f755a JS |
1543 | return c_translate_location (pool, &loc2c_error, this, |
1544 | &loc2c_emit_address, | |
1545 | 1, 0 /* PR9768 */, | |
00b01a99 | 1546 | pc, expr, len, tail, fb_attr, cfa_ops); |
440f755a JS |
1547 | } |
1548 | ||
1549 | ||
1550 | void | |
1551 | dwflpp::print_members(Dwarf_Die *vardie, ostream &o) | |
1552 | { | |
1553 | const int typetag = dwarf_tag (vardie); | |
1554 | ||
1555 | if (typetag != DW_TAG_structure_type && typetag != DW_TAG_union_type) | |
1556 | { | |
1557 | o << " Error: " | |
23d106b9 | 1558 | << (dwarf_diename (vardie) ?: "<anonymous>") |
440f755a JS |
1559 | << " isn't a struct/union"; |
1560 | return; | |
1561 | } | |
1562 | ||
1563 | // Try to get the first child of vardie. | |
1564 | Dwarf_Die die_mem; | |
1565 | Dwarf_Die *die = &die_mem; | |
1566 | switch (dwarf_child (vardie, die)) | |
1567 | { | |
1568 | case 1: // No children. | |
1569 | o << ((typetag == DW_TAG_union_type) ? " union " : " struct ") | |
23d106b9 | 1570 | << (dwarf_diename (die) ?: "<anonymous>") |
440f755a JS |
1571 | << " is empty"; |
1572 | break; | |
1573 | ||
1574 | case -1: // Error. | |
1575 | default: // Shouldn't happen. | |
1576 | o << ((typetag == DW_TAG_union_type) ? " union " : " struct ") | |
23d106b9 | 1577 | << (dwarf_diename (die) ?: "<anonymous>") |
440f755a JS |
1578 | << ": " << dwarf_errmsg (-1); |
1579 | break; | |
1580 | ||
1581 | case 0: // Success. | |
1582 | break; | |
1583 | } | |
1584 | ||
1585 | // Output each sibling's name to 'o'. | |
1586 | while (dwarf_tag (die) == DW_TAG_member) | |
1587 | { | |
23d106b9 | 1588 | const char *member = dwarf_diename (die) ; |
440f755a JS |
1589 | |
1590 | if ( member != NULL ) | |
1591 | o << " " << member; | |
1592 | else | |
1593 | { | |
1594 | Dwarf_Die temp_die = *die; | |
1595 | Dwarf_Attribute temp_attr ; | |
1596 | ||
1597 | if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr)) | |
1598 | { | |
1599 | clog << "\n Error in obtaining type attribute for " | |
1600 | << (dwarf_diename(&temp_die)?:"<anonymous>"); | |
1601 | return; | |
1602 | } | |
1603 | ||
1604 | if (!dwarf_formref_die (&temp_attr, &temp_die)) | |
1605 | { | |
1606 | clog << "\n Error in decoding type attribute for " | |
1607 | << (dwarf_diename(&temp_die)?:"<anonymous>"); | |
1608 | return; | |
1609 | } | |
1610 | ||
1611 | print_members(&temp_die,o); | |
1612 | } | |
1613 | ||
1614 | if (dwarf_siblingof (die, &die_mem) != 0) | |
1615 | break; | |
1616 | } | |
1617 | } | |
1618 | ||
1619 | ||
1620 | bool | |
c67847a0 | 1621 | dwflpp::find_struct_member(const target_symbol::component& c, |
440f755a | 1622 | Dwarf_Die *parentdie, |
440f755a JS |
1623 | Dwarf_Die *memberdie, |
1624 | vector<Dwarf_Attribute>& locs) | |
1625 | { | |
1626 | Dwarf_Attribute attr; | |
b57ba9b8 | 1627 | Dwarf_Die die; |
440f755a | 1628 | |
b57ba9b8 | 1629 | switch (dwarf_child (parentdie, &die)) |
440f755a JS |
1630 | { |
1631 | case 0: /* First child found. */ | |
1632 | break; | |
1633 | case 1: /* No children. */ | |
1634 | return false; | |
1635 | case -1: /* Error. */ | |
1636 | default: /* Shouldn't happen */ | |
b57ba9b8 JS |
1637 | throw semantic_error (string (dwarf_tag(parentdie) == DW_TAG_union_type ? "union" : "struct") |
1638 | + string (dwarf_diename (parentdie) ?: "<anonymous>") | |
440f755a | 1639 | + string (dwarf_errmsg (-1)), |
c67847a0 | 1640 | c.tok); |
440f755a JS |
1641 | } |
1642 | ||
1643 | do | |
1644 | { | |
1645 | if (dwarf_tag(&die) != DW_TAG_member) | |
1646 | continue; | |
1647 | ||
23d106b9 | 1648 | const char *name = dwarf_diename(&die); |
440f755a JS |
1649 | if (name == NULL) |
1650 | { | |
1651 | // need to recurse for anonymous structs/unions | |
1652 | Dwarf_Die subdie; | |
1653 | ||
1654 | if (!dwarf_attr_integrate (&die, DW_AT_type, &attr) || | |
1655 | !dwarf_formref_die (&attr, &subdie)) | |
1656 | continue; | |
1657 | ||
c67847a0 | 1658 | if (find_struct_member(c, &subdie, memberdie, locs)) |
440f755a JS |
1659 | goto success; |
1660 | } | |
c67847a0 | 1661 | else if (name == c.member) |
440f755a JS |
1662 | { |
1663 | *memberdie = die; | |
1664 | goto success; | |
1665 | } | |
1666 | } | |
1667 | while (dwarf_siblingof (&die, &die) == 0); | |
1668 | ||
1669 | return false; | |
1670 | ||
1671 | success: | |
1672 | /* As we unwind the recursion, we need to build the chain of | |
1673 | * locations that got to the final answer. */ | |
1674 | if (dwarf_attr_integrate (&die, DW_AT_data_member_location, &attr)) | |
1675 | locs.insert(locs.begin(), attr); | |
1676 | ||
1677 | /* Union members don't usually have a location, | |
1678 | * but just use the containing union's location. */ | |
1679 | else if (dwarf_tag(parentdie) != DW_TAG_union_type) | |
c67847a0 | 1680 | throw semantic_error ("no location for field '" + c.member |
440f755a | 1681 | + "': " + string(dwarf_errmsg (-1)), |
c67847a0 | 1682 | c.tok); |
440f755a JS |
1683 | |
1684 | return true; | |
1685 | } | |
1686 | ||
1687 | ||
1688 | Dwarf_Die * | |
1689 | dwflpp::translate_components(struct obstack *pool, | |
1690 | struct location **tail, | |
1691 | Dwarf_Addr pc, | |
1692 | const target_symbol *e, | |
1693 | Dwarf_Die *vardie, | |
1694 | Dwarf_Die *die_mem, | |
1695 | Dwarf_Attribute *attr_mem) | |
1696 | { | |
1697 | Dwarf_Die *die = NULL; | |
1698 | ||
1699 | unsigned i = 0; | |
1700 | ||
1701 | if (vardie) | |
1702 | *die_mem = *vardie; | |
1703 | ||
1704 | if (e->components.empty()) | |
1705 | return die_mem; | |
1706 | ||
1707 | while (i < e->components.size()) | |
1708 | { | |
c67847a0 JS |
1709 | const target_symbol::component& c = e->components[i]; |
1710 | ||
440f755a JS |
1711 | /* XXX: This would be desirable, but we don't get the target_symbol token, |
1712 | and printing that gives us the file:line number too early anyway. */ | |
1713 | #if 0 | |
1714 | // Emit a marker to note which field is being access-attempted, to give | |
1715 | // better error messages if deref() fails. | |
1716 | string piece = string(...target_symbol token...) + string ("#") + stringify(components[i].second); | |
1717 | obstack_printf (pool, "c->last_stmt = %s;", lex_cast_qstring(piece).c_str()); | |
1718 | #endif | |
1719 | ||
1720 | die = die ? dwarf_formref_die (attr_mem, die_mem) : die_mem; | |
1721 | const int typetag = dwarf_tag (die); | |
1722 | switch (typetag) | |
1723 | { | |
1724 | case DW_TAG_typedef: | |
1725 | case DW_TAG_const_type: | |
1726 | case DW_TAG_volatile_type: | |
1727 | /* Just iterate on the referent type. */ | |
1728 | break; | |
1729 | ||
1730 | case DW_TAG_pointer_type: | |
440f755a | 1731 | c_translate_pointer (pool, 1, 0 /* PR9768*/, die, tail); |
6fda2dff JS |
1732 | if (c.type != target_symbol::comp_literal_array_index && |
1733 | c.type != target_symbol::comp_expression_array_index) | |
d52761f8 JS |
1734 | break; |
1735 | /* else fall through as an array access */ | |
440f755a JS |
1736 | |
1737 | case DW_TAG_array_type: | |
c67847a0 | 1738 | if (c.type == target_symbol::comp_literal_array_index) |
440f755a JS |
1739 | { |
1740 | c_translate_array (pool, 1, 0 /* PR9768 */, die, tail, | |
c67847a0 | 1741 | NULL, c.num_index); |
440f755a JS |
1742 | ++i; |
1743 | } | |
6fda2dff JS |
1744 | else if (c.type == target_symbol::comp_expression_array_index) |
1745 | { | |
1746 | string index = "THIS->index" + lex_cast<string>(i); | |
1747 | c_translate_array (pool, 1, 0 /* PR9768 */, die, tail, | |
1748 | index.c_str(), 0); | |
1749 | ++i; | |
1750 | } | |
440f755a | 1751 | else |
c67847a0 JS |
1752 | throw semantic_error ("invalid access '" |
1753 | + lex_cast<string>(c) | |
1754 | + "' for array type", | |
1755 | c.tok); | |
440f755a JS |
1756 | break; |
1757 | ||
1758 | case DW_TAG_structure_type: | |
1759 | case DW_TAG_union_type: | |
c67847a0 JS |
1760 | if (c.type != target_symbol::comp_struct_member) |
1761 | throw semantic_error ("invalid access '" | |
1762 | + lex_cast<string>(c) | |
1763 | + "' for struct/union type", | |
1764 | c.tok); | |
1765 | ||
440f755a JS |
1766 | if (dwarf_hasattr(die, DW_AT_declaration)) |
1767 | { | |
1768 | Dwarf_Die *tmpdie = dwflpp::declaration_resolve(dwarf_diename(die)); | |
1769 | if (tmpdie == NULL) | |
1770 | throw semantic_error ("unresolved struct " | |
23d106b9 | 1771 | + string (dwarf_diename (die) ?: "<anonymous>"), |
c67847a0 | 1772 | c.tok); |
440f755a JS |
1773 | *die_mem = *tmpdie; |
1774 | } | |
1775 | ||
1776 | { | |
b57ba9b8 | 1777 | Dwarf_Die parentdie = *die; |
440f755a | 1778 | vector<Dwarf_Attribute> locs; |
b57ba9b8 | 1779 | if (!find_struct_member(c, &parentdie, die, locs)) |
440f755a JS |
1780 | { |
1781 | string alternatives; | |
1782 | stringstream members; | |
b57ba9b8 | 1783 | print_members(&parentdie, members); |
440f755a JS |
1784 | if (members.str().size() != 0) |
1785 | alternatives = " (alternatives:" + members.str(); | |
1786 | throw semantic_error("unable to find member '" + | |
c67847a0 | 1787 | c.member + "' for struct " |
b57ba9b8 | 1788 | + string(dwarf_diename(&parentdie) ?: "<unknown>") |
440f755a | 1789 | + alternatives, |
c67847a0 | 1790 | c.tok); |
440f755a JS |
1791 | } |
1792 | ||
1793 | for (unsigned j = 0; j < locs.size(); ++j) | |
1794 | translate_location (pool, &locs[j], pc, NULL, tail, e); | |
1795 | } | |
1796 | ||
1797 | ++i; | |
1798 | break; | |
1799 | ||
1800 | case DW_TAG_enumeration_type: | |
c67847a0 JS |
1801 | throw semantic_error ("invalid access '" |
1802 | + lex_cast<string>(c) | |
440f755a | 1803 | + "' vs. enum type " |
23d106b9 | 1804 | + string(dwarf_diename (die) ?: "<anonymous type>"), |
c67847a0 | 1805 | c.tok); |
440f755a JS |
1806 | break; |
1807 | case DW_TAG_base_type: | |
c67847a0 JS |
1808 | throw semantic_error ("invalid access '" |
1809 | + lex_cast<string>(c) | |
440f755a | 1810 | + "' vs. base type " |
23d106b9 | 1811 | + string(dwarf_diename (die) ?: "<anonymous type>"), |
c67847a0 | 1812 | c.tok); |
440f755a JS |
1813 | break; |
1814 | case -1: | |
1815 | throw semantic_error ("cannot find type: " + string(dwarf_errmsg (-1)), | |
c67847a0 | 1816 | c.tok); |
440f755a JS |
1817 | break; |
1818 | ||
1819 | default: | |
23d106b9 | 1820 | throw semantic_error (string(dwarf_diename (die) ?: "<anonymous type>") |
440f755a JS |
1821 | + ": unexpected type tag " |
1822 | + lex_cast<string>(dwarf_tag (die)), | |
c67847a0 | 1823 | c.tok); |
440f755a JS |
1824 | break; |
1825 | } | |
1826 | ||
1827 | /* Now iterate on the type in DIE's attribute. */ | |
1828 | if (dwarf_attr_integrate (die, DW_AT_type, attr_mem) == NULL) | |
c67847a0 JS |
1829 | throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1)), |
1830 | c.tok); | |
440f755a | 1831 | } |
d52761f8 JS |
1832 | |
1833 | /* For an array index, we need to dereference the final DIE */ | |
6fda2dff JS |
1834 | if (e->components.back().type == target_symbol::comp_literal_array_index || |
1835 | e->components.back().type == target_symbol::comp_expression_array_index) | |
d52761f8 JS |
1836 | die = dwarf_formref_die (attr_mem, die_mem); |
1837 | ||
440f755a JS |
1838 | return die; |
1839 | } | |
1840 | ||
1841 | ||
1842 | Dwarf_Die * | |
1843 | dwflpp::resolve_unqualified_inner_typedie (Dwarf_Die *typedie_mem, | |
1844 | Dwarf_Attribute *attr_mem, | |
1845 | const target_symbol *e) | |
1846 | { | |
1847 | Dwarf_Die *typedie; | |
1848 | int typetag = 0; | |
1849 | while (1) | |
1850 | { | |
1851 | typedie = dwarf_formref_die (attr_mem, typedie_mem); | |
1852 | if (typedie == NULL) | |
1853 | throw semantic_error ("cannot get type: " + string(dwarf_errmsg (-1)), e->tok); | |
1854 | typetag = dwarf_tag (typedie); | |
1855 | if (typetag != DW_TAG_typedef && | |
1856 | typetag != DW_TAG_const_type && | |
1857 | typetag != DW_TAG_volatile_type) | |
1858 | break; | |
1859 | if (dwarf_attr_integrate (typedie, DW_AT_type, attr_mem) == NULL) | |
1860 | throw semantic_error ("cannot get type of pointee: " + string(dwarf_errmsg (-1)), e->tok); | |
1861 | } | |
1862 | return typedie; | |
1863 | } | |
1864 | ||
1865 | ||
1866 | void | |
1867 | dwflpp::translate_final_fetch_or_store (struct obstack *pool, | |
1868 | struct location **tail, | |
1869 | Dwarf_Addr module_bias, | |
1870 | Dwarf_Die *die, | |
1871 | Dwarf_Attribute *attr_mem, | |
1872 | bool lvalue, | |
1873 | const target_symbol *e, | |
1874 | string &, | |
1875 | string &, | |
1876 | exp_type & ty) | |
1877 | { | |
1878 | /* First boil away any qualifiers associated with the type DIE of | |
1879 | the final location to be accessed. */ | |
1880 | ||
1881 | Dwarf_Die typedie_mem; | |
1882 | Dwarf_Die *typedie; | |
1883 | int typetag; | |
1884 | char const *dname; | |
1885 | string diestr; | |
1886 | ||
1887 | typedie = resolve_unqualified_inner_typedie (&typedie_mem, attr_mem, e); | |
1888 | typetag = dwarf_tag (typedie); | |
1889 | ||
03c75a4a JS |
1890 | /* If we're looking for an address, then we can just provide what |
1891 | we computed to this point, without using a fetch/store. */ | |
1892 | if (e->addressof) | |
1893 | { | |
1894 | if (lvalue) | |
1895 | throw semantic_error ("cannot write to member address", e->tok); | |
1896 | ||
1897 | if (dwarf_hasattr_integrate (die, DW_AT_bit_offset)) | |
1898 | throw semantic_error ("cannot take address of bit-field", e->tok); | |
1899 | ||
1900 | c_translate_addressof (pool, 1, 0, 0, die, tail, "THIS->__retvalue"); | |
1901 | ty = pe_long; | |
1902 | return; | |
1903 | } | |
1904 | ||
440f755a JS |
1905 | /* Then switch behavior depending on the type of fetch/store we |
1906 | want, and the type and pointer-ness of the final location. */ | |
1907 | ||
1908 | switch (typetag) | |
1909 | { | |
1910 | default: | |
1911 | dname = dwarf_diename(die); | |
1912 | diestr = (dname != NULL) ? dname : "<unknown>"; | |
1913 | throw semantic_error ("unsupported type tag " | |
1914 | + lex_cast<string>(typetag) | |
1915 | + " for " + diestr, e->tok); | |
1916 | break; | |
1917 | ||
1918 | case DW_TAG_structure_type: | |
1919 | case DW_TAG_union_type: | |
1920 | dname = dwarf_diename(die); | |
1921 | diestr = (dname != NULL) ? dname : "<unknown>"; | |
1922 | throw semantic_error ("struct/union '" + diestr | |
1923 | + "' is being accessed instead of a member of the struct/union", e->tok); | |
1924 | break; | |
1925 | ||
1926 | case DW_TAG_enumeration_type: | |
1927 | case DW_TAG_base_type: | |
1928 | ||
1929 | // Reject types we can't handle in systemtap | |
1930 | { | |
1931 | dname = dwarf_diename(die); | |
1932 | diestr = (dname != NULL) ? dname : "<unknown>"; | |
1933 | ||
1934 | Dwarf_Attribute encoding_attr; | |
1935 | Dwarf_Word encoding = (Dwarf_Word) -1; | |
1936 | dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, &encoding_attr), | |
1937 | & encoding); | |
1938 | if (encoding < 0) | |
1939 | { | |
1940 | // clog << "bad type1 " << encoding << " diestr" << endl; | |
1941 | throw semantic_error ("unsupported type (mystery encoding " + lex_cast<string>(encoding) + ")" + | |
1942 | " for " + diestr, e->tok); | |
1943 | } | |
1944 | ||
1945 | if (encoding == DW_ATE_float | |
1946 | || encoding == DW_ATE_complex_float | |
1947 | /* XXX || many others? */) | |
1948 | { | |
1949 | // clog << "bad type " << encoding << " diestr" << endl; | |
1950 | throw semantic_error ("unsupported type (encoding " + lex_cast<string>(encoding) + ")" + | |
1951 | " for " + diestr, e->tok); | |
1952 | } | |
1953 | } | |
1954 | ||
1955 | ty = pe_long; | |
1956 | if (lvalue) | |
1957 | c_translate_store (pool, 1, 0 /* PR9768 */, die, typedie, tail, | |
1958 | "THIS->value"); | |
1959 | else | |
1960 | c_translate_fetch (pool, 1, 0 /* PR9768 */, die, typedie, tail, | |
1961 | "THIS->__retvalue"); | |
1962 | break; | |
1963 | ||
1964 | case DW_TAG_array_type: | |
1965 | case DW_TAG_pointer_type: | |
1966 | ||
1967 | { | |
1968 | Dwarf_Die pointee_typedie_mem; | |
1969 | Dwarf_Die *pointee_typedie; | |
1970 | Dwarf_Word pointee_encoding; | |
1971 | Dwarf_Word pointee_byte_size = 0; | |
1972 | ||
1973 | pointee_typedie = resolve_unqualified_inner_typedie (&pointee_typedie_mem, attr_mem, e); | |
1974 | ||
1975 | if (dwarf_attr_integrate (pointee_typedie, DW_AT_byte_size, attr_mem)) | |
1976 | dwarf_formudata (attr_mem, &pointee_byte_size); | |
1977 | ||
1978 | dwarf_formudata (dwarf_attr_integrate (pointee_typedie, DW_AT_encoding, attr_mem), | |
1979 | &pointee_encoding); | |
1980 | ||
1981 | if (lvalue) | |
1982 | { | |
1983 | ty = pe_long; | |
1984 | if (typetag == DW_TAG_array_type) | |
1985 | throw semantic_error ("cannot write to array address", e->tok); | |
1986 | assert (typetag == DW_TAG_pointer_type); | |
1987 | c_translate_pointer_store (pool, 1, 0 /* PR9768 */, typedie, tail, | |
1988 | "THIS->value"); | |
1989 | } | |
1990 | else | |
1991 | { | |
1992 | // We have the pointer: cast it to an integral type via &(*(...)) | |
1993 | ||
1994 | // NB: per bug #1187, at one point char*-like types were | |
1995 | // automagically converted here to systemtap string values. | |
1996 | // For several reasons, this was taken back out, leaving | |
1997 | // pointer-to-string "conversion" (copying) to tapset functions. | |
1998 | ||
1999 | ty = pe_long; | |
2000 | if (typetag == DW_TAG_array_type) | |
2001 | c_translate_array (pool, 1, 0 /* PR9768 */, typedie, tail, NULL, 0); | |
2002 | else | |
2003 | c_translate_pointer (pool, 1, 0 /* PR9768 */, typedie, tail); | |
2004 | c_translate_addressof (pool, 1, 0 /* PR9768 */, NULL, pointee_typedie, tail, | |
2005 | "THIS->__retvalue"); | |
2006 | } | |
2007 | } | |
2008 | break; | |
2009 | } | |
2010 | } | |
2011 | ||
2012 | ||
2013 | string | |
2014 | dwflpp::express_as_string (string prelude, | |
2015 | string postlude, | |
2016 | struct location *head) | |
2017 | { | |
2018 | size_t bufsz = 1024; | |
2019 | char *buf = static_cast<char*>(malloc(bufsz)); | |
2020 | assert(buf); | |
2021 | ||
2022 | FILE *memstream = open_memstream (&buf, &bufsz); | |
2023 | assert(memstream); | |
2024 | ||
2025 | fprintf(memstream, "{\n"); | |
2026 | fprintf(memstream, "%s", prelude.c_str()); | |
2027 | bool deref = c_emit_location (memstream, head, 1); | |
2028 | fprintf(memstream, "%s", postlude.c_str()); | |
2029 | fprintf(memstream, " goto out;\n"); | |
2030 | ||
2031 | // dummy use of deref_fault label, to disable warning if deref() not used | |
2032 | fprintf(memstream, "if (0) goto deref_fault;\n"); | |
2033 | ||
2034 | // XXX: deref flag not reliable; emit fault label unconditionally | |
2035 | (void) deref; | |
2036 | fprintf(memstream, | |
2037 | "deref_fault:\n" | |
2038 | " goto out;\n"); | |
2039 | fprintf(memstream, "}\n"); | |
2040 | ||
2041 | fclose (memstream); | |
2042 | string result(buf); | |
2043 | free (buf); | |
2044 | return result; | |
2045 | } | |
2046 | ||
2047 | ||
2048 | string | |
2049 | dwflpp::literal_stmt_for_local (Dwarf_Die *scope_die, | |
2050 | Dwarf_Addr pc, | |
2051 | string const & local, | |
2052 | const target_symbol *e, | |
2053 | bool lvalue, | |
2054 | exp_type & ty) | |
2055 | { | |
2056 | Dwarf_Die vardie; | |
2057 | Dwarf_Attribute fb_attr_mem, *fb_attr = NULL; | |
2058 | ||
2059 | fb_attr = find_variable_and_frame_base (scope_die, pc, local, e, | |
2060 | &vardie, &fb_attr_mem); | |
2061 | ||
2062 | if (sess.verbose>2) | |
2063 | clog << "finding location for local '" << local | |
2064 | << "' near address 0x" << hex << pc | |
2065 | << ", module bias 0x" << module_bias << dec | |
2066 | << "\n"; | |
2067 | ||
2068 | Dwarf_Attribute attr_mem; | |
2069 | if (dwarf_attr_integrate (&vardie, DW_AT_location, &attr_mem) == NULL) | |
2070 | { | |
2071 | throw semantic_error("failed to retrieve location " | |
2072 | "attribute for local '" + local | |
2073 | + "' (dieoffset: " | |
2074 | + lex_cast_hex<string>(dwarf_dieoffset (&vardie)) | |
2075 | + ")", | |
2076 | e->tok); | |
2077 | } | |
2078 | ||
2079 | #define obstack_chunk_alloc malloc | |
2080 | #define obstack_chunk_free free | |
2081 | ||
2082 | struct obstack pool; | |
2083 | obstack_init (&pool); | |
2084 | struct location *tail = NULL; | |
2085 | ||
2086 | /* Given $foo->bar->baz[NN], translate the location of foo. */ | |
2087 | ||
2088 | struct location *head = translate_location (&pool, | |
2089 | &attr_mem, pc, fb_attr, &tail, | |
2090 | e); | |
2091 | ||
2092 | if (dwarf_attr_integrate (&vardie, DW_AT_type, &attr_mem) == NULL) | |
2093 | throw semantic_error("failed to retrieve type " | |
2094 | "attribute for local '" + local + "'", | |
2095 | e->tok); | |
2096 | ||
2097 | /* Translate the ->bar->baz[NN] parts. */ | |
2098 | ||
2099 | Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); | |
2100 | die = translate_components (&pool, &tail, pc, e, | |
2101 | die, &die_mem, &attr_mem); | |
2102 | ||
2103 | /* Translate the assignment part, either | |
2104 | x = $foo->bar->baz[NN] | |
2105 | or | |
2106 | $foo->bar->baz[NN] = x | |
2107 | */ | |
2108 | ||
2109 | string prelude, postlude; | |
2110 | translate_final_fetch_or_store (&pool, &tail, module_bias, | |
2111 | die, &attr_mem, lvalue, e, | |
2112 | prelude, postlude, ty); | |
2113 | ||
2114 | /* Write the translation to a string. */ | |
2115 | return express_as_string(prelude, postlude, head); | |
2116 | } | |
2117 | ||
2118 | ||
2119 | string | |
2120 | dwflpp::literal_stmt_for_return (Dwarf_Die *scope_die, | |
2121 | Dwarf_Addr pc, | |
2122 | const target_symbol *e, | |
2123 | bool lvalue, | |
2124 | exp_type & ty) | |
2125 | { | |
2126 | if (sess.verbose>2) | |
2127 | clog << "literal_stmt_for_return: finding return value for " | |
2128 | << (dwarf_diename(scope_die) ?: "<unknown>") | |
2129 | << "(" | |
2130 | << (dwarf_diename(cu) ?: "<unknown>") | |
2131 | << ")\n"; | |
2132 | ||
2133 | struct obstack pool; | |
2134 | obstack_init (&pool); | |
2135 | struct location *tail = NULL; | |
2136 | ||
2137 | /* Given $return->bar->baz[NN], translate the location of return. */ | |
2138 | const Dwarf_Op *locops; | |
2139 | int nlocops = dwfl_module_return_value_location (module, scope_die, | |
2140 | &locops); | |
2141 | if (nlocops < 0) | |
2142 | { | |
2143 | throw semantic_error("failed to retrieve return value location" | |
2144 | " for " | |
2145 | + string(dwarf_diename(scope_die) ?: "<unknown>") | |
2146 | + "(" + string(dwarf_diename(cu) ?: "<unknown>") | |
2147 | + ")", | |
2148 | e->tok); | |
2149 | } | |
2150 | // the function has no return value (e.g. "void" in C) | |
2151 | else if (nlocops == 0) | |
2152 | { | |
2153 | throw semantic_error("function " | |
2154 | + string(dwarf_diename(scope_die) ?: "<unknown>") | |
2155 | + "(" + string(dwarf_diename(cu) ?: "<unknown>") | |
2156 | + ") has no return value", | |
2157 | e->tok); | |
2158 | } | |
2159 | ||
2160 | struct location *head = c_translate_location (&pool, &loc2c_error, this, | |
2161 | &loc2c_emit_address, | |
2162 | 1, 0 /* PR9768 */, | |
2163 | pc, locops, nlocops, | |
00b01a99 | 2164 | &tail, NULL, NULL); |
440f755a JS |
2165 | |
2166 | /* Translate the ->bar->baz[NN] parts. */ | |
2167 | ||
2168 | Dwarf_Attribute attr_mem; | |
2169 | if (dwarf_attr_integrate (scope_die, DW_AT_type, &attr_mem) == NULL) | |
2170 | throw semantic_error("failed to retrieve return value type attribute for " | |
2171 | + string(dwarf_diename(scope_die) ?: "<unknown>") | |
2172 | + "(" + string(dwarf_diename(cu) ?: "<unknown>") | |
2173 | + ")", | |
2174 | e->tok); | |
2175 | ||
2176 | Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); | |
2177 | die = translate_components (&pool, &tail, pc, e, | |
2178 | die, &die_mem, &attr_mem); | |
2179 | ||
2180 | /* Translate the assignment part, either | |
2181 | x = $return->bar->baz[NN] | |
2182 | or | |
2183 | $return->bar->baz[NN] = x | |
2184 | */ | |
2185 | ||
2186 | string prelude, postlude; | |
2187 | translate_final_fetch_or_store (&pool, &tail, module_bias, | |
2188 | die, &attr_mem, lvalue, e, | |
2189 | prelude, postlude, ty); | |
2190 | ||
2191 | /* Write the translation to a string. */ | |
2192 | return express_as_string(prelude, postlude, head); | |
2193 | } | |
2194 | ||
2195 | ||
2196 | string | |
2197 | dwflpp::literal_stmt_for_pointer (Dwarf_Die *type_die, | |
2198 | const target_symbol *e, | |
2199 | bool lvalue, | |
2200 | exp_type & ty) | |
2201 | { | |
2202 | if (sess.verbose>2) | |
2203 | clog << "literal_stmt_for_pointer: finding value for " | |
2204 | << (dwarf_diename(type_die) ?: "<unknown>") | |
2205 | << "(" | |
2206 | << (dwarf_diename(cu) ?: "<unknown>") | |
2207 | << ")\n"; | |
2208 | ||
2209 | struct obstack pool; | |
2210 | obstack_init (&pool); | |
2211 | struct location *head = c_translate_argument (&pool, &loc2c_error, this, | |
2212 | &loc2c_emit_address, | |
2213 | 1, "THIS->pointer"); | |
2214 | struct location *tail = head; | |
2215 | ||
2216 | /* Translate the ->bar->baz[NN] parts. */ | |
2217 | ||
2218 | Dwarf_Attribute attr_mem; | |
2219 | Dwarf_Die die_mem, *die = NULL; | |
2220 | die = translate_components (&pool, &tail, 0, e, | |
2221 | type_die, &die_mem, &attr_mem); | |
2222 | ||
2223 | /* Translate the assignment part, either | |
2224 | x = (THIS->pointer)->bar->baz[NN] | |
2225 | or | |
2226 | (THIS->pointer)->bar->baz[NN] = x | |
2227 | */ | |
2228 | ||
2229 | string prelude, postlude; | |
2230 | translate_final_fetch_or_store (&pool, &tail, module_bias, | |
2231 | die, &attr_mem, lvalue, e, | |
2232 | prelude, postlude, ty); | |
2233 | ||
2234 | /* Write the translation to a string. */ | |
2235 | return express_as_string(prelude, postlude, head); | |
2236 | } | |
2237 | ||
2238 | ||
27646582 JS |
2239 | static bool |
2240 | in_kprobes_function(systemtap_session& sess, Dwarf_Addr addr) | |
2241 | { | |
2242 | if (sess.sym_kprobes_text_start != 0 && sess.sym_kprobes_text_end != 0) | |
2243 | { | |
2244 | // If the probe point address is anywhere in the __kprobes | |
2245 | // address range, we can't use this probe point. | |
2246 | if (addr >= sess.sym_kprobes_text_start && addr < sess.sym_kprobes_text_end) | |
2247 | return true; | |
2248 | } | |
2249 | return false; | |
2250 | } | |
2251 | ||
2252 | ||
2253 | bool | |
2254 | dwflpp::blacklisted_p(const string& funcname, | |
2255 | const string& filename, | |
2256 | int, | |
2257 | const string& module, | |
2258 | const string& section, | |
2259 | Dwarf_Addr addr, | |
2260 | bool has_return) | |
2261 | { | |
2262 | if (!blacklist_enabled) | |
2263 | return false; // no blacklist for userspace | |
2264 | ||
2265 | if (section.substr(0, 6) == string(".init.") || | |
2266 | section.substr(0, 6) == string(".exit.") || | |
2267 | section.substr(0, 9) == string(".devinit.") || | |
2268 | section.substr(0, 9) == string(".devexit.") || | |
2269 | section.substr(0, 9) == string(".cpuinit.") || | |
2270 | section.substr(0, 9) == string(".cpuexit.") || | |
2271 | section.substr(0, 9) == string(".meminit.") || | |
2272 | section.substr(0, 9) == string(".memexit.")) | |
2273 | { | |
2274 | // NB: module .exit. routines could be probed in theory: | |
2275 | // if the exit handler in "struct module" is diverted, | |
2276 | // first inserting the kprobes | |
2277 | // then allowing the exit code to run | |
2278 | // then removing these kprobes | |
2279 | if (sess.verbose>1) | |
2280 | clog << " skipping - init/exit"; | |
2281 | return true; | |
2282 | } | |
2283 | ||
2284 | // Check for function marked '__kprobes'. | |
2285 | if (module == TOK_KERNEL && in_kprobes_function(sess, addr)) | |
2286 | { | |
2287 | if (sess.verbose>1) | |
2288 | clog << " skipping - __kprobes"; | |
2289 | return true; | |
2290 | } | |
2291 | ||
2292 | // Check probe point against blacklist. | |
2293 | int goodfn = regexec (&blacklist_func, funcname.c_str(), 0, NULL, 0); | |
2294 | if (has_return) | |
2295 | goodfn = goodfn && regexec (&blacklist_func_ret, funcname.c_str(), 0, NULL, 0); | |
2296 | int goodfile = regexec (&blacklist_file, filename.c_str(), 0, NULL, 0); | |
2297 | ||
2298 | if (! (goodfn && goodfile)) | |
2299 | { | |
2300 | if (sess.guru_mode) | |
2301 | { | |
2302 | if (sess.verbose>1) | |
2303 | clog << " guru mode enabled - ignoring blacklist"; | |
2304 | } | |
2305 | else | |
2306 | { | |
2307 | if (sess.verbose>1) | |
2308 | clog << " skipping - blacklisted"; | |
2309 | return true; | |
2310 | } | |
2311 | } | |
2312 | ||
2313 | // This probe point is not blacklisted. | |
2314 | return false; | |
2315 | } | |
2316 | ||
2317 | ||
2318 | void | |
2319 | dwflpp::build_blacklist() | |
2320 | { | |
2321 | // We build up the regexps in these strings | |
2322 | ||
2323 | // Add ^ anchors at the front; $ will be added just before regcomp. | |
2324 | ||
2325 | string blfn = "^("; | |
2326 | string blfn_ret = "^("; | |
2327 | string blfile = "^("; | |
2328 | ||
2329 | blfile += "kernel/kprobes.c"; // first alternative, no "|" | |
2330 | blfile += "|arch/.*/kernel/kprobes.c"; | |
2331 | // Older kernels need ... | |
2332 | blfile += "|include/asm/io.h"; | |
2333 | blfile += "|include/asm/bitops.h"; | |
2334 | // While newer ones need ... | |
2335 | blfile += "|arch/.*/include/asm/io.h"; | |
2336 | blfile += "|arch/.*/include/asm/bitops.h"; | |
2337 | blfile += "|drivers/ide/ide-iops.c"; | |
2338 | ||
2339 | // XXX: it would be nice if these blacklisted functions were pulled | |
2340 | // in dynamically, instead of being statically defined here. | |
2341 | // Perhaps it could be populated from script files. A "noprobe | |
2342 | // kernel.function("...")" construct might do the trick. | |
2343 | ||
2344 | // Most of these are marked __kprobes in newer kernels. We list | |
2345 | // them here (anyway) so the translator can block them on older | |
2346 | // kernels that don't have the __kprobes function decorator. This | |
2347 | // also allows detection of problems at translate- rather than | |
2348 | // run-time. | |
2349 | ||
2350 | blfn += "atomic_notifier_call_chain"; // first blfn; no "|" | |
2351 | blfn += "|default_do_nmi"; | |
2352 | blfn += "|__die"; | |
2353 | blfn += "|die_nmi"; | |
2354 | blfn += "|do_debug"; | |
2355 | blfn += "|do_general_protection"; | |
2356 | blfn += "|do_int3"; | |
2357 | blfn += "|do_IRQ"; | |
2358 | blfn += "|do_page_fault"; | |
2359 | blfn += "|do_sparc64_fault"; | |
2360 | blfn += "|do_trap"; | |
2361 | blfn += "|dummy_nmi_callback"; | |
2362 | blfn += "|flush_icache_range"; | |
2363 | blfn += "|ia64_bad_break"; | |
2364 | blfn += "|ia64_do_page_fault"; | |
2365 | blfn += "|ia64_fault"; | |
2366 | blfn += "|io_check_error"; | |
2367 | blfn += "|mem_parity_error"; | |
2368 | blfn += "|nmi_watchdog_tick"; | |
2369 | blfn += "|notifier_call_chain"; | |
2370 | blfn += "|oops_begin"; | |
2371 | blfn += "|oops_end"; | |
2372 | blfn += "|program_check_exception"; | |
2373 | blfn += "|single_step_exception"; | |
2374 | blfn += "|sync_regs"; | |
2375 | blfn += "|unhandled_fault"; | |
2376 | blfn += "|unknown_nmi_error"; | |
2377 | ||
2378 | // Lots of locks | |
2379 | blfn += "|.*raw_.*lock.*"; | |
2380 | blfn += "|.*read_.*lock.*"; | |
2381 | blfn += "|.*write_.*lock.*"; | |
2382 | blfn += "|.*spin_.*lock.*"; | |
2383 | blfn += "|.*rwlock_.*lock.*"; | |
2384 | blfn += "|.*rwsem_.*lock.*"; | |
2385 | blfn += "|.*mutex_.*lock.*"; | |
2386 | blfn += "|raw_.*"; | |
2387 | blfn += "|.*seq_.*lock.*"; | |
2388 | ||
2389 | // atomic functions | |
2390 | blfn += "|atomic_.*"; | |
2391 | blfn += "|atomic64_.*"; | |
2392 | ||
2393 | // few other problematic cases | |
2394 | blfn += "|get_bh"; | |
2395 | blfn += "|put_bh"; | |
2396 | ||
2397 | // Experimental | |
2398 | blfn += "|.*apic.*|.*APIC.*"; | |
2399 | blfn += "|.*softirq.*"; | |
2400 | blfn += "|.*IRQ.*"; | |
2401 | blfn += "|.*_intr.*"; | |
2402 | blfn += "|__delay"; | |
2403 | blfn += "|.*kernel_text.*"; | |
2404 | blfn += "|get_current"; | |
2405 | blfn += "|current_.*"; | |
2406 | blfn += "|.*exception_tables.*"; | |
2407 | blfn += "|.*setup_rt_frame.*"; | |
2408 | ||
2409 | // PR 5759, CONFIG_PREEMPT kernels | |
2410 | blfn += "|.*preempt_count.*"; | |
2411 | blfn += "|preempt_schedule"; | |
2412 | ||
2413 | // These functions don't return, so return probes would never be recovered | |
2414 | blfn_ret += "do_exit"; // no "|" | |
2415 | blfn_ret += "|sys_exit"; | |
2416 | blfn_ret += "|sys_exit_group"; | |
2417 | ||
2418 | // __switch_to changes "current" on x86_64 and i686, so return probes | |
2419 | // would cause kernel panic, and it is marked as "__kprobes" on x86_64 | |
2420 | if (sess.architecture == "x86_64") | |
2421 | blfn += "|__switch_to"; | |
2422 | if (sess.architecture == "i686") | |
2423 | blfn_ret += "|__switch_to"; | |
2424 | ||
2425 | blfn += ")$"; | |
2426 | blfn_ret += ")$"; | |
2427 | blfile += ")$"; | |
2428 | ||
2429 | if (sess.verbose > 2) | |
2430 | { | |
2431 | clog << "blacklist regexps:" << endl; | |
2432 | clog << "blfn: " << blfn << endl; | |
2433 | clog << "blfn_ret: " << blfn_ret << endl; | |
2434 | clog << "blfile: " << blfile << endl; | |
2435 | } | |
2436 | ||
2437 | int rc = regcomp (& blacklist_func, blfn.c_str(), REG_NOSUB|REG_EXTENDED); | |
2438 | if (rc) throw semantic_error ("blacklist_func regcomp failed"); | |
2439 | rc = regcomp (& blacklist_func_ret, blfn_ret.c_str(), REG_NOSUB|REG_EXTENDED); | |
2440 | if (rc) throw semantic_error ("blacklist_func_ret regcomp failed"); | |
2441 | rc = regcomp (& blacklist_file, blfile.c_str(), REG_NOSUB|REG_EXTENDED); | |
2442 | if (rc) throw semantic_error ("blacklist_file regcomp failed"); | |
2443 | ||
2444 | blacklist_enabled = true; | |
2445 | } | |
2446 | ||
2447 | ||
2448 | string | |
2449 | dwflpp::get_blacklist_section(Dwarf_Addr addr) | |
2450 | { | |
2451 | string blacklist_section; | |
2452 | Dwarf_Addr bias; | |
2453 | // We prefer dwfl_module_getdwarf to dwfl_module_getelf here, | |
2454 | // because dwfl_module_getelf can force costly section relocations | |
2455 | // we don't really need, while either will do for this purpose. | |
2456 | Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (module, &bias)) | |
2457 | ?: dwfl_module_getelf (module, &bias)); | |
2458 | ||
2459 | Dwarf_Addr offset = addr - bias; | |
2460 | if (elf) | |
2461 | { | |
2462 | Elf_Scn* scn = 0; | |
2463 | size_t shstrndx; | |
fcc30d6d | 2464 | dwfl_assert ("getshdrstrndx", elf_getshdrstrndx (elf, &shstrndx)); |
27646582 JS |
2465 | while ((scn = elf_nextscn (elf, scn)) != NULL) |
2466 | { | |
2467 | GElf_Shdr shdr_mem; | |
2468 | GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); | |
2469 | if (! shdr) | |
2470 | continue; // XXX error? | |
2471 | ||
2472 | if (!(shdr->sh_flags & SHF_ALLOC)) | |
2473 | continue; | |
2474 | ||
2475 | GElf_Addr start = shdr->sh_addr; | |
2476 | GElf_Addr end = start + shdr->sh_size; | |
2477 | if (! (offset >= start && offset < end)) | |
2478 | continue; | |
2479 | ||
2480 | blacklist_section = elf_strptr (elf, shstrndx, shdr->sh_name); | |
2481 | break; | |
2482 | } | |
2483 | } | |
2484 | return blacklist_section; | |
2485 | } | |
2486 | ||
2487 | ||
2488 | Dwarf_Addr | |
d2309c6c | 2489 | dwflpp::relocate_address(Dwarf_Addr dw_addr, |
27646582 JS |
2490 | string& reloc_section, |
2491 | string& blacklist_section) | |
2492 | { | |
d2309c6c MW |
2493 | // PR10273 |
2494 | // libdw address, so adjust for bias gotten from dwfl_module_getdwarf | |
2495 | Dwarf_Addr reloc_addr = dw_addr + module_bias; | |
27646582 JS |
2496 | if (!module) |
2497 | { | |
2498 | assert(module_name == TOK_KERNEL); | |
2499 | reloc_section = ""; | |
2500 | blacklist_section = ""; | |
2501 | } | |
2502 | else if (dwfl_module_relocations (module) > 0) | |
2503 | { | |
2504 | // This is a relocatable module; libdwfl already knows its | |
2505 | // sections, so we can relativize addr. | |
2506 | int idx = dwfl_module_relocate_address (module, &reloc_addr); | |
2507 | const char* r_s = dwfl_module_relocation_info (module, idx, NULL); | |
2508 | if (r_s) | |
2509 | reloc_section = r_s; | |
2510 | blacklist_section = reloc_section; | |
2511 | ||
2512 | if (reloc_section == "" && dwfl_module_relocations (module) == 1) | |
2513 | { | |
d2309c6c | 2514 | blacklist_section = get_blacklist_section(dw_addr); |
27646582 | 2515 | reloc_section = ".dynamic"; |
27646582 JS |
2516 | } |
2517 | } | |
2518 | else | |
2519 | { | |
d2309c6c | 2520 | blacklist_section = get_blacklist_section(dw_addr); |
27646582 JS |
2521 | reloc_section = ".absolute"; |
2522 | } | |
2523 | return reloc_addr; | |
2524 | } | |
2525 | ||
1f8592d1 MW |
2526 | /* Converts a "global" literal address to the module symbol address |
2527 | * space. If necessary (not for kernel and executables using absolute | |
2528 | * addresses), this adjust the address for the current module symbol | |
2529 | * bias. Literal addresses are provided by the user (or contained on | |
2530 | * the .probes section) based on the "on disk" layout of the module. | |
2531 | */ | |
2532 | Dwarf_Addr | |
2533 | dwflpp::literal_addr_to_sym_addr(Dwarf_Addr lit_addr) | |
2534 | { | |
88eaee9f MW |
2535 | if (sess.verbose > 2) |
2536 | clog << "literal_addr_to_sym_addr 0x" << hex << lit_addr << dec << endl; | |
2537 | ||
1f8592d1 MW |
2538 | // Assume the address came from the symbol list. |
2539 | // If we cannot get the symbol bias fall back on the dw bias. | |
2540 | // The kernel (and other absolute executable modules) is special though. | |
2541 | if (module_name != TOK_KERNEL | |
2542 | && dwfl_module_relocations (module) > 0) | |
2543 | { | |
2544 | Dwarf_Addr symbias = ~0; | |
2545 | if (dwfl_module_getsymtab (module) != -1) | |
2546 | dwfl_module_info (module, NULL, NULL, NULL, NULL, | |
2547 | &symbias, NULL, NULL); | |
88eaee9f MW |
2548 | |
2549 | if (sess.verbose > 3) | |
2550 | clog << "symbias 0x" << hex << symbias << dec | |
2551 | << ", dwbias 0x" << hex << module_bias << dec << endl; | |
2552 | ||
1f8592d1 MW |
2553 | if (symbias == (Dwarf_Addr) ~0) |
2554 | symbias = module_bias; | |
2555 | ||
2556 | lit_addr += symbias; | |
2557 | } | |
2558 | ||
88eaee9f MW |
2559 | if (sess.verbose > 2) |
2560 | clog << "literal_addr_to_sym_addr ret 0x" << hex << lit_addr << dec << endl; | |
2561 | ||
1f8592d1 MW |
2562 | return lit_addr; |
2563 | } | |
27646582 | 2564 | |
c8ad0687 JS |
2565 | int |
2566 | dwflpp::dwarf_getscopes_cached (Dwarf_Addr pc, Dwarf_Die **scopes) | |
2567 | { | |
2568 | if (!cached_scopes || pc != pc_cached_scopes) | |
2569 | { | |
2570 | free(cached_scopes); | |
2571 | cached_scopes = NULL; | |
2572 | pc_cached_scopes = pc; | |
2573 | num_cached_scopes = dwarf_getscopes(cu, pc, &cached_scopes); | |
2574 | } | |
2575 | *scopes = cached_scopes; | |
2576 | return num_cached_scopes; | |
2577 | } | |
2578 | ||
88eaee9f MW |
2579 | /* Returns the call frame address operations for the given program counter |
2580 | * in the libdw address space. | |
2581 | */ | |
00b01a99 MW |
2582 | Dwarf_Op * |
2583 | dwflpp::get_cfa_ops (Dwarf_Addr pc) | |
2584 | { | |
2585 | Dwarf_Op *cfa_ops = NULL; | |
2586 | ||
88eaee9f MW |
2587 | if (sess.verbose > 2) |
2588 | clog << "get_cfa_ops @0x" << hex << pc << dec | |
2589 | << ", module_start @0x" << hex << module_start << dec << endl; | |
2590 | ||
00b01a99 | 2591 | #if _ELFUTILS_PREREQ(0,142) |
6a38401c | 2592 | // Try debug_frame first, then fall back on eh_frame. |
4a8636a3 | 2593 | size_t cfa_nops; |
00b01a99 MW |
2594 | Dwarf_Addr bias; |
2595 | Dwarf_CFI *cfi = dwfl_module_dwarf_cfi (module, &bias); | |
2596 | if (cfi != NULL) | |
2597 | { | |
88eaee9f MW |
2598 | if (sess.verbose > 3) |
2599 | clog << "got dwarf cfi bias: 0x" << hex << bias << dec << endl; | |
00b01a99 | 2600 | Dwarf_Frame *frame = NULL; |
88eaee9f | 2601 | if (dwarf_cfi_addrframe (cfi, pc - bias, &frame) == 0) |
97f529ab | 2602 | dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops); |
88eaee9f MW |
2603 | else if (sess.verbose > 3) |
2604 | clog << "dwarf_cfi_addrframe failed: " << dwarf_errmsg(-1) << endl; | |
00b01a99 | 2605 | } |
88eaee9f MW |
2606 | else if (sess.verbose > 3) |
2607 | clog << "dwfl_module_dwarf_cfi failed: " << dwfl_errmsg(-1) << endl; | |
2608 | ||
00b01a99 MW |
2609 | if (cfa_ops == NULL) |
2610 | { | |
2611 | cfi = dwfl_module_eh_cfi (module, &bias); | |
2612 | if (cfi != NULL) | |
2613 | { | |
88eaee9f MW |
2614 | if (sess.verbose > 3) |
2615 | clog << "got eh cfi bias: 0x" << hex << bias << dec << endl; | |
00b01a99 | 2616 | Dwarf_Frame *frame = NULL; |
88eaee9f | 2617 | if (dwarf_cfi_addrframe (cfi, pc - bias, &frame) == 0) |
97f529ab | 2618 | dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops); |
88eaee9f MW |
2619 | else if (sess.verbose > 3) |
2620 | clog << "dwarf_cfi_addrframe failed: " << dwarf_errmsg(-1) << endl; | |
00b01a99 | 2621 | } |
88eaee9f MW |
2622 | else if (sess.verbose > 3) |
2623 | clog << "dwfl_module_eh_cfi failed: " << dwfl_errmsg(-1) << endl; | |
2624 | ||
00b01a99 | 2625 | } |
00b01a99 MW |
2626 | #endif |
2627 | ||
88eaee9f MW |
2628 | if (sess.verbose > 2) |
2629 | clog << (cfa_ops == NULL ? "not " : " ") << "found cfa" << endl; | |
2630 | ||
00b01a99 MW |
2631 | return cfa_ops; |
2632 | } | |
c8ad0687 | 2633 | |
440f755a | 2634 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |