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