]>
Commit | Line | Data |
---|---|---|
56e12059 FCE |
1 | // tapset resolution |
2 | // Copyright (C) 2005 Red Hat Inc. | |
3 | // | |
4 | // This file is part of systemtap, and is free software. You can | |
5 | // redistribute it and/or modify it under the terms of the GNU General | |
6 | // Public License (GPL); either version 2, or (at your option) any | |
7 | // later version. | |
8 | ||
9 | #include "config.h" | |
10 | #include "staptree.h" | |
11 | #include "elaborate.h" | |
b55bc428 | 12 | #include "tapsets.h" |
56e12059 | 13 | #include "translate.h" |
bd2b1e68 GH |
14 | |
15 | #include <deque> | |
56e12059 | 16 | #include <iostream> |
bd2b1e68 | 17 | #include <map> |
ec4373ff | 18 | #include <set> |
56e12059 | 19 | #include <sstream> |
bd2b1e68 | 20 | #include <stdexcept> |
b55bc428 | 21 | #include <vector> |
e36387d7 | 22 | #include <cstdarg> |
bd2b1e68 GH |
23 | |
24 | extern "C" { | |
df8fadee | 25 | #include <fcntl.h> |
bd2b1e68 | 26 | #include <elfutils/libdwfl.h> |
7a053d3b | 27 | #include <elfutils/libdw.h> |
77de5e9e GH |
28 | #include <dwarf.h> |
29 | #include <elf.h> | |
30 | #include <obstack.h> | |
31 | #include "loc2c.h" | |
4b1ad75e RM |
32 | |
33 | #define __STDC_FORMAT_MACROS | |
34 | #include <inttypes.h> | |
bd2b1e68 | 35 | } |
77de5e9e | 36 | |
bd2b1e68 | 37 | #include <fnmatch.h> |
56e12059 FCE |
38 | |
39 | using namespace std; | |
40 | ||
cc9ee605 FCE |
41 | |
42 | // XXX: should standardize to these functions throughout translator | |
43 | ||
44 | template <typename OUT, typename IN> inline OUT | |
45 | lex_cast(IN const & in) | |
46 | { | |
47 | stringstream ss; | |
48 | OUT out; | |
49 | if (!(ss << in && ss >> out)) | |
50 | throw runtime_error("bad lexical cast"); | |
51 | return out; | |
52 | } | |
53 | ||
54 | template <typename OUT, typename IN> inline OUT | |
55 | lex_cast_hex(IN const & in) | |
56 | { | |
57 | stringstream ss; | |
58 | OUT out; | |
59 | if (!(ss << hex << showbase << in && ss >> out)) | |
60 | throw runtime_error("bad lexical cast"); | |
61 | return out; | |
62 | } | |
63 | ||
64 | ||
65 | // return as quoted string, with at least '"' backslash-escaped | |
66 | template <typename IN> inline string | |
67 | lex_cast_qstring(IN const & in) | |
68 | { | |
69 | stringstream ss; | |
70 | string out, out2; | |
499cf740 | 71 | if (!(ss << in)) |
cc9ee605 | 72 | throw runtime_error("bad lexical cast"); |
499cf740 | 73 | out = ss.str(); |
cc9ee605 FCE |
74 | out2 += '"'; |
75 | for (unsigned i=0; i<out.length(); i++) | |
76 | { | |
77 | if (out[i] == '"') // XXX others? | |
78 | out2 += '\\'; | |
79 | out2 += out[i]; | |
80 | } | |
81 | out2 += '"'; | |
82 | return out2; | |
83 | } | |
84 | ||
85 | ||
b55bc428 FCE |
86 | // ------------------------------------------------------------------------ |
87 | // begin/end probes are run right during registration / deregistration | |
56e12059 FCE |
88 | // ------------------------------------------------------------------------ |
89 | ||
b55bc428 FCE |
90 | struct be_derived_probe: public derived_probe |
91 | { | |
92 | bool begin; | |
93 | be_derived_probe (probe* p, bool b): derived_probe (p), begin (b) {} | |
94 | be_derived_probe (probe* p, probe_point* l, bool b): | |
95 | derived_probe (p, l), begin (b) {} | |
56e12059 | 96 | |
b55bc428 FCE |
97 | void emit_registrations (translator_output* o, unsigned i); |
98 | void emit_deregistrations (translator_output* o, unsigned i); | |
99 | void emit_probe_entries (translator_output* o, unsigned i); | |
100 | }; | |
101 | ||
98afd80e FCE |
102 | |
103 | struct be_builder: public derived_probe_builder | |
b55bc428 FCE |
104 | { |
105 | bool begin; | |
106 | be_builder(bool b) : begin(b) {} | |
5227f1ea | 107 | virtual void build(systemtap_session & sess, |
7a053d3b | 108 | probe * base, |
20c6c071 GH |
109 | probe_point * location, |
110 | std::map<std::string, literal *> const & parameters, | |
111 | vector<probe *> & results_to_expand_further, | |
112 | vector<derived_probe *> & finished_results) | |
b55bc428 | 113 | { |
20c6c071 | 114 | finished_results.push_back(new be_derived_probe(base, location, begin)); |
b55bc428 | 115 | } |
b55bc428 | 116 | }; |
56e12059 FCE |
117 | |
118 | ||
7a053d3b | 119 | void |
56e12059 FCE |
120 | be_derived_probe::emit_registrations (translator_output* o, unsigned j) |
121 | { | |
122 | if (begin) | |
123 | for (unsigned i=0; i<locations.size(); i++) | |
bfb3d2d2 | 124 | o->newline() << "enter_" << j << "_" << i << " ();"; |
56e12059 FCE |
125 | } |
126 | ||
127 | ||
7a053d3b | 128 | void |
56e12059 FCE |
129 | be_derived_probe::emit_deregistrations (translator_output* o, unsigned j) |
130 | { | |
bfb3d2d2 | 131 | if (!begin) |
56e12059 | 132 | for (unsigned i=0; i<locations.size(); i++) |
bfb3d2d2 | 133 | o->newline() << "enter_" << j << "_" << i << " ();"; |
56e12059 FCE |
134 | } |
135 | ||
136 | ||
137 | void | |
138 | be_derived_probe::emit_probe_entries (translator_output* o, unsigned j) | |
139 | { | |
140 | for (unsigned i=0; i<locations.size(); i++) | |
141 | { | |
142 | probe_point *l = locations[i]; | |
143 | o->newline() << "/* location " << i << ": " << *l << " */"; | |
f4b28491 FCE |
144 | o->newline() << "static void enter_" << j << "_" << i << " (void);"; |
145 | o->newline() << "void enter_" << j << "_" << i << " () {"; | |
bfb3d2d2 | 146 | |
7a053d3b | 147 | // While begin/end probes are executed single-threaded, we |
bfb3d2d2 FCE |
148 | // still code defensively and use a per-cpu context. |
149 | o->newline(1) << "struct context* c = & contexts [smp_processor_id()];"; | |
cc9ee605 FCE |
150 | o->newline() << "const char* probe_point = " |
151 | << lex_cast_qstring(*l) << ";"; | |
bfb3d2d2 FCE |
152 | |
153 | // A precondition for running a probe handler is that we're in STARTING | |
154 | // or STOPPING state (not ERROR), and that no one else is already using | |
155 | // this context. | |
156 | o->newline() << "if (atomic_read (&session_state) != "; | |
157 | if (begin) o->line() << "STAP_SESSION_STARTING)"; | |
158 | else o->line() << "STAP_SESSION_STOPPING)"; | |
159 | o->newline(1) << "return;"; | |
cc9ee605 | 160 | o->newline(-1) << "if (atomic_inc_return (&c->busy) != 1) {"; |
499cf740 | 161 | o->newline(1) << "printk (KERN_ERR \"probe reentrancy (%s vs %s)\\n\", " |
cc9ee605 | 162 | << "c->probe_point, probe_point);"; |
bfb3d2d2 FCE |
163 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; |
164 | o->newline() << "return;"; | |
165 | o->newline(-1) << "}"; | |
166 | o->newline(); | |
5e309481 | 167 | o->newline() << "c->last_error = 0;"; |
cc9ee605 | 168 | o->newline() << "c->probe_point = probe_point;"; |
56e12059 | 169 | o->newline() << "c->nesting = 0;"; |
3d49c615 | 170 | o->newline() << "c->regs = 0;"; |
5e309481 | 171 | o->newline() << "c->actioncount = 0;"; |
bfb3d2d2 | 172 | |
56e12059 FCE |
173 | // NB: locals are initialized by probe function itself |
174 | o->newline() << "probe_" << j << " (c);"; | |
bfb3d2d2 | 175 | |
bb788f9f FCE |
176 | o->newline() << "if (c->last_error && c->last_error[0]) {"; |
177 | o->newline(1) << "_stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; | |
5e309481 | 178 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; |
bfb3d2d2 FCE |
179 | o->newline(-1) << "}"; |
180 | ||
cc9ee605 | 181 | o->newline() << "atomic_dec (&c->busy);"; |
56e12059 FCE |
182 | o->newline(-1) << "}" << endl; |
183 | } | |
184 | } | |
185 | ||
186 | ||
187 | // ------------------------------------------------------------------------ | |
bd2b1e68 | 188 | // Dwarf derived probes. |
b55bc428 | 189 | // ------------------------------------------------------------------------ |
bd2b1e68 | 190 | |
c239d28c GH |
191 | static string TOK_PROCESS("process"); |
192 | static string TOK_KERNEL("kernel"); | |
193 | static string TOK_MODULE("module"); | |
194 | ||
195 | static string TOK_FUNCTION("function"); | |
196 | static string TOK_RETURN("return"); | |
197 | static string TOK_CALLEES("callees"); | |
198 | ||
199 | static string TOK_STATEMENT("statement"); | |
200 | static string TOK_LABEL("label"); | |
201 | static string TOK_RELATIVE("relative"); | |
202 | ||
59ff2773 | 203 | |
59ff2773 | 204 | |
59ff2773 | 205 | |
7e1279ea FCE |
206 | struct |
207 | func_info | |
208 | { | |
209 | string name; | |
4cd232e4 GH |
210 | char const * decl_file; |
211 | int decl_line; | |
7e1279ea FCE |
212 | Dwarf_Die die; |
213 | Dwarf_Addr prologue_end; | |
214 | }; | |
215 | ||
216 | struct | |
217 | inline_instance_info | |
218 | { | |
219 | string name; | |
4cd232e4 GH |
220 | char const * decl_file; |
221 | int decl_line; | |
7e1279ea FCE |
222 | Dwarf_Die die; |
223 | }; | |
224 | ||
225 | static int | |
226 | query_cu (Dwarf_Die * cudie, void * arg); | |
59ff2773 FCE |
227 | |
228 | ||
bd2b1e68 GH |
229 | // Helper for dealing with selected portions of libdwfl in a more readable |
230 | // fashion, and with specific cleanup / checking / logging options. | |
231 | ||
91eefb1c GH |
232 | static const char * |
233 | dwarf_diename_integrate (Dwarf_Die *die) | |
234 | { | |
235 | Dwarf_Attribute attr_mem; | |
236 | return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); | |
237 | } | |
238 | ||
bd2b1e68 GH |
239 | struct |
240 | dwflpp | |
241 | { | |
5227f1ea | 242 | systemtap_session & sess; |
bd2b1e68 GH |
243 | Dwfl * dwfl; |
244 | ||
245 | // These are "current" values we focus on. | |
246 | Dwfl_Module * module; | |
247 | Dwarf * module_dwarf; | |
248 | Dwarf_Addr module_bias; | |
50e0d793 GH |
249 | |
250 | // These describe the current module's PC address range | |
251 | Dwarf_Addr module_start; | |
252 | Dwarf_Addr module_end; | |
253 | ||
bd2b1e68 GH |
254 | Dwarf_Die * cu; |
255 | Dwarf_Func * function; | |
256 | ||
257 | string module_name; | |
258 | string cu_name; | |
259 | string function_name; | |
260 | ||
50e0d793 | 261 | |
7a053d3b | 262 | string const default_name(char const * in, |
bd2b1e68 GH |
263 | char const * type) |
264 | { | |
7a053d3b | 265 | if (in) |
bd2b1e68 | 266 | return in; |
24cb178f | 267 | if (false && sess.verbose) |
bd2b1e68 | 268 | clog << "WARNING: no name found for " << type << endl; |
a229fcd7 | 269 | return string(""); |
bd2b1e68 GH |
270 | } |
271 | ||
50e0d793 | 272 | |
5227f1ea GH |
273 | void get_module_dwarf() |
274 | { | |
275 | if (!module_dwarf) | |
276 | module_dwarf = dwfl_module_getdwarf(module, &module_bias); | |
7e1279ea | 277 | |
a229fcd7 | 278 | if (module_dwarf == NULL && sess.verbose) |
d9b516ca | 279 | clog << "WARNING: dwfl_module_getdwarf() : " |
a229fcd7 | 280 | << dwfl_errmsg (dwfl_errno ()) << endl; |
5227f1ea GH |
281 | } |
282 | ||
50e0d793 | 283 | |
bd2b1e68 GH |
284 | void focus_on_module(Dwfl_Module * m) |
285 | { | |
286 | assert(m); | |
287 | module = m; | |
7a053d3b | 288 | module_name = default_name(dwfl_module_info(module, NULL, |
50e0d793 | 289 | &module_start, &module_end, |
bd2b1e68 GH |
290 | NULL, NULL, |
291 | NULL, NULL), | |
292 | "module"); | |
50e0d793 GH |
293 | |
294 | // Reset existing pointers and names | |
295 | ||
296 | module_dwarf = NULL; | |
297 | ||
a229fcd7 | 298 | cu_name.clear(); |
50e0d793 GH |
299 | cu = NULL; |
300 | ||
a229fcd7 | 301 | function_name.clear(); |
50e0d793 | 302 | function = NULL; |
bd2b1e68 GH |
303 | } |
304 | ||
50e0d793 | 305 | |
bd2b1e68 GH |
306 | void focus_on_cu(Dwarf_Die * c) |
307 | { | |
308 | assert(c); | |
50e0d793 GH |
309 | assert(module); |
310 | ||
bd2b1e68 | 311 | cu = c; |
50e0d793 GH |
312 | cu_name = default_name(dwarf_diename(c), "CU"); |
313 | ||
314 | // Reset existing pointers and names | |
a229fcd7 | 315 | function_name.clear(); |
50e0d793 | 316 | function = NULL; |
bd2b1e68 GH |
317 | } |
318 | ||
50e0d793 | 319 | |
bd2b1e68 GH |
320 | void focus_on_function(Dwarf_Func * f) |
321 | { | |
322 | assert(f); | |
50e0d793 GH |
323 | assert(module); |
324 | assert(cu); | |
325 | ||
bd2b1e68 | 326 | function = f; |
7a053d3b | 327 | function_name = default_name(dwarf_func_name(function), |
bd2b1e68 | 328 | "function"); |
bd2b1e68 GH |
329 | } |
330 | ||
50e0d793 | 331 | |
bd2b1e68 GH |
332 | void focus_on_module_containing_global_address(Dwarf_Addr a) |
333 | { | |
334 | assert(dwfl); | |
50e0d793 | 335 | cu = NULL; |
24cb178f | 336 | if (false && sess.verbose) |
bd2b1e68 GH |
337 | clog << "focusing on module containing global addr " << a << endl; |
338 | focus_on_module(dwfl_addrmodule(dwfl, a)); | |
339 | } | |
340 | ||
50e0d793 | 341 | |
7e1279ea | 342 | void query_cu_containing_global_address(Dwarf_Addr a, void *arg) |
bd2b1e68 | 343 | { |
bd2b1e68 | 344 | Dwarf_Addr bias; |
50e0d793 | 345 | assert(dwfl); |
5227f1ea | 346 | get_module_dwarf(); |
aab2b35f | 347 | if (false && sess.verbose) |
50e0d793 | 348 | clog << "focusing on cu containing global addr " << a << endl; |
7e1279ea | 349 | query_cu (dwfl_module_addrdie(module, a, &bias), arg); |
bd2b1e68 GH |
350 | assert(bias == module_bias); |
351 | } | |
352 | ||
50e0d793 | 353 | |
7e1279ea | 354 | void query_cu_containing_module_address(Dwarf_Addr a, void *arg) |
bd2b1e68 | 355 | { |
7e1279ea | 356 | query_cu_containing_global_address(module_address_to_global(a), arg); |
bd2b1e68 GH |
357 | } |
358 | ||
50e0d793 | 359 | |
bd2b1e68 GH |
360 | Dwarf_Addr module_address_to_global(Dwarf_Addr a) |
361 | { | |
50e0d793 | 362 | assert(dwfl); |
bd2b1e68 | 363 | assert(module); |
5227f1ea | 364 | get_module_dwarf(); |
c239d28c GH |
365 | if (module_name == TOK_KERNEL) |
366 | return a; | |
367 | ||
db520b00 FCE |
368 | if (false && sess.verbose) |
369 | clog << "module addr " << hex << a | |
370 | << " + module start " << module_start | |
371 | << " -> global addr " << (a + module_start) << dec << endl; | |
50e0d793 | 372 | return a + module_start; |
bd2b1e68 GH |
373 | } |
374 | ||
50e0d793 | 375 | |
bd2b1e68 GH |
376 | Dwarf_Addr global_address_to_module(Dwarf_Addr a) |
377 | { | |
378 | assert(module); | |
5227f1ea | 379 | get_module_dwarf(); |
db520b00 FCE |
380 | if (false && sess.verbose) |
381 | clog << "global addr " << a | |
382 | << " - module start " << hex << module_start | |
383 | << " -> module addr " << (a - module_start) << dec << endl; | |
bd2b1e68 GH |
384 | return a - module_bias; |
385 | } | |
386 | ||
387 | ||
388 | bool module_name_matches(string pattern) | |
389 | { | |
390 | assert(module); | |
391 | bool t = (fnmatch(pattern.c_str(), module_name.c_str(), 0) == 0); | |
24cb178f | 392 | if (t && sess.verbose) |
bd2b1e68 | 393 | clog << "pattern '" << pattern << "' " |
24cb178f | 394 | << "matches " |
bd2b1e68 GH |
395 | << "module '" << module_name << "'" << endl; |
396 | return t; | |
397 | } | |
398 | ||
50e0d793 | 399 | |
bd2b1e68 GH |
400 | bool function_name_matches(string pattern) |
401 | { | |
402 | assert(function); | |
403 | bool t = (fnmatch(pattern.c_str(), function_name.c_str(), 0) == 0); | |
24cb178f | 404 | if (t && sess.verbose) |
bd2b1e68 | 405 | clog << "pattern '" << pattern << "' " |
24cb178f | 406 | << "matches " |
bd2b1e68 GH |
407 | << "function '" << function_name << "'" << endl; |
408 | return t; | |
409 | } | |
410 | ||
50e0d793 | 411 | |
bd2b1e68 GH |
412 | bool cu_name_matches(string pattern) |
413 | { | |
414 | assert(cu); | |
415 | bool t = (fnmatch(pattern.c_str(), cu_name.c_str(), 0) == 0); | |
24cb178f | 416 | if (t && sess.verbose) |
bd2b1e68 | 417 | clog << "pattern '" << pattern << "' " |
24cb178f | 418 | << "matches " |
bd2b1e68 GH |
419 | << "CU '" << cu_name << "'" << endl; |
420 | return t; | |
421 | } | |
422 | ||
50e0d793 | 423 | |
7e1279ea | 424 | void dwfl_assert(string desc, int rc) // NB: "rc == 0" means OK in this case |
bd2b1e68 | 425 | { |
7e1279ea | 426 | string msg = "libdwfl failure (" + desc + "): "; |
d8067b24 FCE |
427 | if (rc < 0) msg += dwfl_errmsg (rc); |
428 | else if (rc > 0) msg += strerror (rc); | |
bd2b1e68 | 429 | if (rc != 0) |
d8067b24 | 430 | throw semantic_error (msg); |
bd2b1e68 GH |
431 | } |
432 | ||
7e1279ea FCE |
433 | void dwarf_assert(string desc, int rc) // NB: "rc == 0" means OK in this case |
434 | { | |
435 | string msg = "libdw failure (" + desc + "): "; | |
436 | if (rc < 0) msg += dwarf_errmsg (rc); | |
437 | else if (rc > 0) msg += strerror (rc); | |
438 | if (rc != 0) | |
439 | throw semantic_error (msg); | |
440 | } | |
441 | ||
50e0d793 | 442 | |
5227f1ea | 443 | dwflpp(systemtap_session & sess) |
bd2b1e68 | 444 | : |
5227f1ea | 445 | sess(sess), |
bd2b1e68 GH |
446 | dwfl(NULL), |
447 | module(NULL), | |
448 | module_dwarf(NULL), | |
449 | module_bias(0), | |
50e0d793 GH |
450 | module_start(0), |
451 | module_end(0), | |
bd2b1e68 GH |
452 | cu(NULL), |
453 | function(NULL) | |
454 | {} | |
7a053d3b | 455 | |
50e0d793 | 456 | |
bd2b1e68 GH |
457 | void setup(bool kernel) |
458 | { | |
b5d77020 FCE |
459 | // XXX: this is where the session -R parameter could come in |
460 | static char* debuginfo_path = "-:.debug:/usr/lib/debug"; | |
461 | ||
bd2b1e68 GH |
462 | static const Dwfl_Callbacks proc_callbacks = |
463 | { | |
464 | dwfl_linux_proc_find_elf, | |
465 | dwfl_standard_find_debuginfo, | |
466 | NULL, | |
b5d77020 | 467 | & debuginfo_path |
bd2b1e68 | 468 | }; |
7a053d3b | 469 | |
bd2b1e68 GH |
470 | static const Dwfl_Callbacks kernel_callbacks = |
471 | { | |
472 | dwfl_linux_kernel_find_elf, | |
473 | dwfl_standard_find_debuginfo, | |
474 | dwfl_linux_kernel_module_section_address, | |
b5d77020 | 475 | & debuginfo_path |
bd2b1e68 GH |
476 | }; |
477 | ||
478 | if (kernel) | |
479 | { | |
7e1279ea | 480 | dwfl = dwfl_begin (&kernel_callbacks); |
bd2b1e68 | 481 | if (!dwfl) |
7e1279ea FCE |
482 | throw semantic_error ("cannot open dwfl"); |
483 | dwfl_report_begin (dwfl); | |
d8067b24 FCE |
484 | // XXX: if we have only kernel.* probe points, we shouldn't waste time |
485 | // looking for module debug-info (and vice versa). | |
7e1279ea FCE |
486 | dwfl_assert ("dwfl_linux_kernel_report_kernel", |
487 | dwfl_linux_kernel_report_kernel (dwfl)); | |
488 | dwfl_assert ("dwfl_linux_kernel_report_modules", | |
489 | dwfl_linux_kernel_report_modules (dwfl)); | |
bd2b1e68 GH |
490 | } |
491 | else | |
492 | { | |
7e1279ea FCE |
493 | dwfl = dwfl_begin (&proc_callbacks); |
494 | dwfl_report_begin (dwfl); | |
bd2b1e68 | 495 | if (!dwfl) |
7e1279ea | 496 | throw semantic_error ("cannot open dwfl"); |
bd2b1e68 GH |
497 | // XXX: Find pids or processes, do userspace stuff. |
498 | } | |
499 | ||
7e1279ea | 500 | dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); |
bd2b1e68 GH |
501 | } |
502 | ||
503 | void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, | |
504 | const char *, Dwarf_Addr, | |
77de5e9e | 505 | void *), |
bd2b1e68 GH |
506 | void * data) |
507 | { | |
bd2b1e68 GH |
508 | ptrdiff_t off = 0; |
509 | do | |
510 | { | |
77de5e9e | 511 | off = dwfl_getmodules (dwfl, callback, data, off); |
bd2b1e68 GH |
512 | } |
513 | while (off > 0); | |
7e1279ea | 514 | dwfl_assert("dwfl_getmodules", off); |
bd2b1e68 GH |
515 | } |
516 | ||
7e1279ea | 517 | |
7a053d3b | 518 | void iterate_over_cus (int (*callback)(Dwarf_Die * die, void * arg), |
bd2b1e68 GH |
519 | void * data) |
520 | { | |
5227f1ea GH |
521 | get_module_dwarf(); |
522 | ||
bd2b1e68 GH |
523 | if (!module_dwarf) |
524 | { | |
525 | cerr << "WARNING: no dwarf info found for module " << module_name << endl; | |
526 | return; | |
527 | } | |
528 | ||
bd2b1e68 GH |
529 | Dwarf *dw = module_dwarf; |
530 | Dwarf_Off off = 0; | |
531 | size_t cuhl; | |
532 | Dwarf_Off noff; | |
7e1279ea | 533 | while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) |
7a053d3b | 534 | { |
bd2b1e68 GH |
535 | Dwarf_Die die_mem; |
536 | Dwarf_Die *die; | |
7e1279ea FCE |
537 | die = dwarf_offdie (dw, off + cuhl, &die_mem); |
538 | if (callback (die, data) != DWARF_CB_OK) | |
bd2b1e68 GH |
539 | break; |
540 | off = noff; | |
541 | } | |
542 | } | |
543 | ||
bd2b1e68 | 544 | |
7e1279ea | 545 | bool func_is_inline() |
bd2b1e68 | 546 | { |
7e1279ea FCE |
547 | assert (function); |
548 | return dwarf_func_inline (function) != 0; | |
bd2b1e68 GH |
549 | } |
550 | ||
7e1279ea FCE |
551 | void iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * arg), |
552 | void * data) | |
bd2b1e68 | 553 | { |
7e1279ea FCE |
554 | assert (function); |
555 | assert (func_is_inline ()); | |
556 | dwarf_assert ("dwarf_func_inline_instances", | |
557 | dwarf_func_inline_instances (function, callback, data)); | |
4fa7b22b | 558 | } |
bd2b1e68 | 559 | |
50e0d793 | 560 | |
7e1279ea FCE |
561 | void iterate_over_functions (int (* callback)(Dwarf_Func * func, void * arg), |
562 | void * data) | |
4fa7b22b | 563 | { |
7e1279ea FCE |
564 | assert (module); |
565 | assert (cu); | |
566 | dwarf_getfuncs (cu, callback, data, 0); | |
567 | } | |
c239d28c | 568 | |
d9b516ca | 569 | |
7e1279ea FCE |
570 | void iterate_over_srcfile_lines (char const * srcfile, |
571 | int lineno, | |
572 | void (* callback) (Dwarf_Line * line, void * arg), | |
573 | void *data) | |
574 | { | |
6315bd76 GH |
575 | Dwarf_Line **srcsp = NULL; |
576 | size_t nsrcs = 0; | |
bb788f9f | 577 | |
7e1279ea | 578 | get_module_dwarf(); |
bb788f9f | 579 | |
7e1279ea FCE |
580 | dwarf_assert ("dwarf_getsrc_file", |
581 | dwarf_getsrc_file (module_dwarf, | |
582 | srcfile, lineno, 0, | |
583 | &srcsp, &nsrcs)); | |
6315bd76 | 584 | try |
bb788f9f | 585 | { |
6315bd76 GH |
586 | for (size_t i = 0; i < nsrcs; ++i) |
587 | { | |
588 | callback (srcsp[i], data); | |
589 | } | |
bb788f9f | 590 | } |
6315bd76 GH |
591 | catch (...) |
592 | { | |
593 | free (srcsp); | |
594 | throw; | |
595 | } | |
596 | free (srcsp); | |
50e0d793 GH |
597 | } |
598 | ||
599 | ||
7e1279ea FCE |
600 | void collect_srcfiles_matching (string const & pattern, |
601 | set<char const *> & filtered_srcfiles) | |
50e0d793 | 602 | { |
7e1279ea FCE |
603 | assert (module); |
604 | assert (cu); | |
bb788f9f | 605 | |
7e1279ea FCE |
606 | size_t nfiles; |
607 | Dwarf_Files *srcfiles; | |
bb788f9f | 608 | |
7e1279ea FCE |
609 | dwarf_assert ("dwarf_getsrcfiles", |
610 | dwarf_getsrcfiles (cu, &srcfiles, &nfiles)); | |
611 | { | |
612 | for (size_t i = 0; i < nfiles; ++i) | |
50e0d793 | 613 | { |
7e1279ea FCE |
614 | char const * fname = dwarf_filesrc (srcfiles, i, NULL, NULL); |
615 | if (fnmatch (pattern.c_str(), fname, 0) == 0) | |
50e0d793 | 616 | { |
7e1279ea FCE |
617 | filtered_srcfiles.insert (fname); |
618 | if (sess.verbose) | |
619 | clog << "selected source file '" << fname << "'" << endl; | |
50e0d793 GH |
620 | } |
621 | } | |
7e1279ea FCE |
622 | } |
623 | } | |
50e0d793 | 624 | |
7e1279ea FCE |
625 | void resolve_prologue_endings (map<Dwarf_Addr, func_info> & funcs) |
626 | { | |
627 | assert(module); | |
628 | assert(cu); | |
50e0d793 | 629 | |
7e1279ea FCE |
630 | size_t nlines; |
631 | Dwarf_Lines *lines; | |
632 | Dwarf_Addr previous_addr; | |
bb788f9f | 633 | bool choose_next_line = false; |
4fa7b22b | 634 | |
7e1279ea FCE |
635 | dwarf_assert ("dwarf_getsrclines", |
636 | dwarf_getsrclines(cu, &lines, &nlines)); | |
637 | ||
50e0d793 GH |
638 | for (size_t i = 0; i < nlines; ++i) |
639 | { | |
7e1279ea | 640 | Dwarf_Addr addr; |
50e0d793 | 641 | Dwarf_Line * line_rec = dwarf_onesrcline(lines, i); |
7e1279ea FCE |
642 | dwarf_lineaddr (line_rec, &addr); |
643 | ||
50e0d793 GH |
644 | if (choose_next_line) |
645 | { | |
7e1279ea FCE |
646 | map<Dwarf_Addr, func_info>::iterator i = funcs.find (previous_addr); |
647 | assert (i != funcs.end()); | |
648 | i->second.prologue_end = addr; | |
649 | choose_next_line = false; | |
650 | } | |
651 | ||
652 | else | |
653 | { | |
654 | map<Dwarf_Addr, func_info>::const_iterator i = funcs.find (addr); | |
655 | if (i != funcs.end()) | |
656 | choose_next_line = true; | |
50e0d793 | 657 | } |
7e1279ea | 658 | previous_addr = addr; |
50e0d793 | 659 | } |
bd2b1e68 GH |
660 | } |
661 | ||
7e1279ea FCE |
662 | |
663 | bool function_entrypc (Dwarf_Addr * addr) | |
664 | { | |
665 | assert (function); | |
666 | return (dwarf_func_entrypc (function, addr) == 0); | |
667 | } | |
668 | ||
669 | ||
670 | bool die_entrypc (Dwarf_Die * die, Dwarf_Addr * addr) | |
671 | { | |
672 | Dwarf_Attribute attr_mem; | |
673 | Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_entry_pc, &attr_mem); | |
674 | if (attr != NULL) | |
675 | return (dwarf_formaddr (attr, addr) == 0); | |
676 | ||
677 | return ( dwarf_lowpc (die, addr) == 0); | |
678 | } | |
679 | ||
4cd232e4 GH |
680 | void function_die (Dwarf_Die *d) |
681 | { | |
682 | assert (function); | |
683 | dwarf_func_die (function, d); | |
684 | } | |
7e1279ea | 685 | |
4cd232e4 | 686 | void function_file (char const ** c) |
7e1279ea FCE |
687 | { |
688 | assert (function); | |
4cd232e4 GH |
689 | assert (c); |
690 | *c = dwarf_func_file (function); | |
7e1279ea FCE |
691 | } |
692 | ||
4cd232e4 | 693 | void function_line (int *linep) |
7e1279ea FCE |
694 | { |
695 | assert (function); | |
4cd232e4 | 696 | dwarf_func_line (function, linep); |
7e1279ea FCE |
697 | } |
698 | ||
699 | bool die_has_pc (Dwarf_Die * die, Dwarf_Addr pc) | |
700 | { | |
701 | int res = dwarf_haspc (die, pc); | |
702 | if (res == -1) | |
703 | dwarf_assert ("dwarf_haspc", res); | |
704 | return res == 1; | |
705 | } | |
706 | ||
707 | ||
e36387d7 RM |
708 | static void loc2c_error (void *arg, const char *fmt, ...) |
709 | { | |
710 | char *msg = NULL; | |
711 | va_list ap; | |
712 | va_start (ap, fmt); | |
713 | vasprintf (&msg, fmt, ap); | |
714 | va_end (ap); | |
715 | throw semantic_error (msg); | |
716 | } | |
bd2b1e68 | 717 | |
7e1279ea | 718 | |
4b1ad75e RM |
719 | static void loc2c_emit_address (void *arg, struct obstack *pool, |
720 | Dwarf_Addr address) | |
721 | { | |
722 | dwflpp *dwfl = (dwflpp *) arg; | |
723 | obstack_printf (pool, "%#" PRIx64 "UL /* hard-coded %s address */", | |
724 | address, dwfl_module_info (dwfl->module, NULL, NULL, NULL, | |
725 | NULL, NULL, NULL, NULL)); | |
726 | } | |
727 | ||
6e95311e | 728 | string literal_stmt_for_local(Dwarf_Addr pc, |
91eefb1c | 729 | string const & local, |
d9b516ca | 730 | vector<pair<target_symbol::component_type, |
fdfbe4f7 GH |
731 | std::string> > const & components, |
732 | exp_type & ty) | |
77de5e9e GH |
733 | { |
734 | assert (cu); | |
735 | ||
736 | Dwarf_Die *scopes; | |
737 | Dwarf_Die vardie; | |
738 | ||
6e95311e | 739 | int nscopes = dwarf_getscopes (cu, pc, &scopes); |
77de5e9e GH |
740 | if (nscopes == 0) |
741 | { | |
7a053d3b | 742 | throw semantic_error ("unable to find any scopes containing " |
59ff2773 | 743 | + lex_cast_hex<string>(pc) |
77de5e9e GH |
744 | + " while searching for local '" + local + "'"); |
745 | } | |
7a053d3b | 746 | |
77de5e9e | 747 | int declaring_scope = dwarf_getscopevar (scopes, nscopes, |
7a053d3b RM |
748 | local.c_str(), |
749 | 0, NULL, 0, 0, | |
750 | &vardie); | |
77de5e9e GH |
751 | if (declaring_scope < 0) |
752 | { | |
753 | throw semantic_error ("unable to find local '" + local + "'" | |
59ff2773 | 754 | + " near pc " + lex_cast_hex<string>(pc)); |
77de5e9e | 755 | } |
7a053d3b | 756 | |
77de5e9e GH |
757 | Dwarf_Attribute fb_attr_mem, *fb_attr = NULL; |
758 | for (int inner = 0; inner < nscopes; ++inner) | |
759 | { | |
760 | switch (dwarf_tag (&scopes[inner])) | |
761 | { | |
762 | default: | |
763 | continue; | |
764 | case DW_TAG_subprogram: | |
765 | case DW_TAG_entry_point: | |
766 | case DW_TAG_inlined_subroutine: /* XXX */ | |
767 | if (inner >= declaring_scope) | |
768 | fb_attr = dwarf_attr_integrate (&scopes[inner], | |
769 | DW_AT_frame_base, | |
770 | &fb_attr_mem); | |
771 | break; | |
772 | } | |
773 | } | |
774 | ||
775 | if (sess.verbose) | |
7a053d3b | 776 | clog << "finding location for local '" << local |
db520b00 FCE |
777 | << "' near address " << hex << pc |
778 | << ", module bias " << module_bias << dec | |
77de5e9e | 779 | << endl; |
7a053d3b RM |
780 | |
781 | Dwarf_Attribute attr_mem; | |
77de5e9e | 782 | if (dwarf_attr_integrate (&vardie, DW_AT_location, &attr_mem) == NULL) |
7e1279ea FCE |
783 | { |
784 | throw semantic_error("failed to retrieve location " | |
785 | "attribute for local '" + local | |
786 | + "' (dieoffset: " | |
787 | + lex_cast_hex<string>(dwarf_dieoffset (&vardie)) | |
788 | + ")"); | |
789 | } | |
7a053d3b | 790 | |
77de5e9e GH |
791 | #define obstack_chunk_alloc malloc |
792 | #define obstack_chunk_free free | |
7a053d3b | 793 | |
77de5e9e | 794 | struct obstack pool; |
7a053d3b | 795 | obstack_init (&pool); |
77de5e9e | 796 | struct location *tail = NULL; |
e36387d7 | 797 | struct location *head = c_translate_location (&pool, &loc2c_error, this, |
4b1ad75e | 798 | &loc2c_emit_address, |
e36387d7 | 799 | 1, module_bias, |
77de5e9e GH |
800 | &attr_mem, pc, |
801 | &tail, fb_attr); | |
802 | ||
d9b516ca | 803 | if (dwarf_attr_integrate (&vardie, DW_AT_type, &attr_mem) == NULL) |
77de5e9e GH |
804 | throw semantic_error("failed to retrieve type " |
805 | "attribute for local '" + local + "'"); | |
806 | ||
d9b516ca RM |
807 | Dwarf_Die die_mem, *die = &vardie; |
808 | unsigned i = 0; | |
809 | while (i < components.size()) | |
810 | { | |
811 | die = dwarf_formref_die (&attr_mem, &die_mem); | |
812 | const int typetag = dwarf_tag (die); | |
813 | switch (typetag) | |
814 | { | |
815 | case DW_TAG_typedef: | |
fdfbe4f7 GH |
816 | case DW_TAG_const_type: |
817 | case DW_TAG_volatile_type: | |
d9b516ca RM |
818 | /* Just iterate on the referent type. */ |
819 | break; | |
91eefb1c | 820 | |
d9b516ca RM |
821 | case DW_TAG_pointer_type: |
822 | if (components[i].first == target_symbol::comp_literal_array_index) | |
823 | goto subscript; | |
91eefb1c | 824 | |
d9b516ca RM |
825 | c_translate_pointer (&pool, 1, module_bias, die, &tail); |
826 | break; | |
91eefb1c | 827 | |
d9b516ca RM |
828 | case DW_TAG_array_type: |
829 | if (components[i].first == target_symbol::comp_literal_array_index) | |
830 | { | |
831 | subscript: | |
832 | c_translate_array (&pool, 1, module_bias, die, &tail, | |
833 | NULL, lex_cast<Dwarf_Word>(components[i].second)); | |
834 | ++i; | |
835 | } | |
836 | else | |
837 | throw semantic_error("bad field '" | |
838 | + components[i].second | |
839 | + "' for array type"); | |
840 | break; | |
91eefb1c | 841 | |
d9b516ca RM |
842 | case DW_TAG_structure_type: |
843 | case DW_TAG_union_type: | |
844 | switch (dwarf_child (die, &die_mem)) | |
845 | { | |
846 | case 1: /* No children. */ | |
847 | throw semantic_error ("empty struct " | |
848 | + string (dwarf_diename_integrate (die) ?: "<anonymous>")); | |
849 | break; | |
850 | case -1: /* Error. */ | |
851 | default: /* Shouldn't happen */ | |
852 | throw semantic_error (string (typetag == DW_TAG_union_type ? "union" : "struct") | |
853 | + string (dwarf_diename_integrate (die) ?: "<anonymous>") | |
854 | + string (dwarf_errmsg (-1))); | |
855 | break; | |
856 | ||
857 | case 0: | |
858 | break; | |
859 | } | |
860 | ||
861 | while (dwarf_tag (die) != DW_TAG_member | |
862 | || ({ const char *member = dwarf_diename_integrate (die); | |
863 | member == NULL || string(member) != components[i].second; })) | |
864 | if (dwarf_siblingof (die, &die_mem) != 0) | |
865 | throw semantic_error ("field name " + components[i].second + " not found"); | |
866 | ||
867 | if (dwarf_attr_integrate (die, DW_AT_data_member_location, | |
868 | &attr_mem) == NULL) | |
869 | { | |
870 | /* Union members don't usually have a location, | |
871 | but just use the containing union's location. */ | |
872 | if (typetag != DW_TAG_union_type) | |
873 | throw semantic_error ("no location for field " | |
874 | + components[i].second | |
875 | + " :" + string(dwarf_errmsg (-1))); | |
876 | } | |
877 | else | |
4b1ad75e | 878 | c_translate_location (&pool, NULL, NULL, NULL, 1, |
e36387d7 | 879 | module_bias, &attr_mem, pc, |
d9b516ca RM |
880 | &tail, NULL); |
881 | ++i; | |
882 | break; | |
883 | ||
884 | case DW_TAG_base_type: | |
885 | throw semantic_error ("field " | |
886 | + components[i].second | |
887 | + " vs base type " | |
888 | + string(dwarf_diename_integrate (die) ?: "<anonymous type>")); | |
889 | break; | |
890 | case -1: | |
891 | throw semantic_error ("cannot find type: " + string(dwarf_errmsg (-1))); | |
892 | break; | |
893 | ||
894 | default: | |
895 | throw semantic_error (string(dwarf_diename_integrate (die) ?: "<anonymous type>") | |
896 | + ": unexpected type tag " | |
897 | + lex_cast<string>(dwarf_tag (die))); | |
898 | break; | |
899 | } | |
900 | ||
901 | /* Now iterate on the type in DIE's attribute. */ | |
902 | if (dwarf_attr_integrate (die, DW_AT_type, &attr_mem) == NULL) | |
903 | throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1))); | |
904 | } | |
91eefb1c | 905 | |
d9b516ca RM |
906 | /* Fetch the type DIE corresponding to the final location to be accessed. |
907 | It must be a base type or a typedef for one. */ | |
908 | ||
909 | Dwarf_Die typedie_mem; | |
910 | Dwarf_Die *typedie; | |
911 | int typetag; | |
912 | while (1) | |
913 | { | |
914 | typedie = dwarf_formref_die (&attr_mem, &typedie_mem); | |
915 | if (typedie == NULL) | |
916 | throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1))); | |
917 | typetag = dwarf_tag (typedie); | |
fdfbe4f7 GH |
918 | if (typetag != DW_TAG_typedef && |
919 | typetag != DW_TAG_const_type && | |
920 | typetag != DW_TAG_volatile_type) | |
91eefb1c | 921 | break; |
d9b516ca RM |
922 | if (dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem) == NULL) |
923 | throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1))); | |
924 | } | |
91eefb1c | 925 | |
91eefb1c | 926 | |
fdfbe4f7 GH |
927 | // If we have a base type, we will fetch it into pe_long. |
928 | // | |
929 | // If we have a pointer to non-char, we will cast it to uintptr_t, and fetch | |
930 | // into pe_long. | |
931 | // | |
932 | // If we have a pointer to char, we will fetch into pe_string, using | |
933 | // deref_string() over in loc2c-runtime.h | |
934 | ||
935 | string prelude, postlude; | |
936 | switch (typetag) | |
937 | { | |
fdfbe4f7 | 938 | default: |
66d284f4 FCE |
939 | throw semantic_error ("unsupported type tag " |
940 | + lex_cast<string>(typetag)); | |
fdfbe4f7 | 941 | break; |
66d284f4 | 942 | |
e7a012f0 | 943 | case DW_TAG_enumeration_type: |
fdfbe4f7 GH |
944 | case DW_TAG_base_type: |
945 | ty = pe_long; | |
946 | c_translate_fetch (&pool, 1, module_bias, die, typedie, &tail, | |
947 | "THIS->__retvalue"); | |
948 | break; | |
949 | ||
950 | case DW_TAG_array_type: | |
951 | case DW_TAG_pointer_type: | |
952 | { | |
953 | Dwarf_Die pointee_typedie_mem; | |
954 | Dwarf_Die *pointee_typedie; | |
955 | Dwarf_Word pointee_encoding; | |
246b383e | 956 | Dwarf_Word pointee_byte_size = 0; |
fdfbe4f7 GH |
957 | int pointee_typetag; |
958 | ||
959 | if (dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem) == NULL) | |
960 | throw semantic_error ("cannot get type of pointer: " + string(dwarf_errmsg (-1))); | |
961 | ||
962 | while (1) | |
963 | { | |
964 | pointee_typedie = dwarf_formref_die (&attr_mem, &pointee_typedie_mem); | |
965 | ||
966 | if (pointee_typedie == NULL) | |
967 | throw semantic_error ("cannot get type of pointee: " + string(dwarf_errmsg (-1))); | |
968 | ||
969 | pointee_typetag = dwarf_tag (pointee_typedie); | |
970 | ||
971 | if (pointee_typetag != DW_TAG_typedef && | |
972 | pointee_typetag != DW_TAG_const_type && | |
973 | pointee_typetag != DW_TAG_volatile_type) | |
974 | break; | |
975 | if (dwarf_attr_integrate (pointee_typedie, DW_AT_type, &attr_mem) == NULL) | |
976 | throw semantic_error ("cannot get type of pointee: " + string(dwarf_errmsg (-1))); | |
977 | } | |
246b383e GH |
978 | |
979 | if (dwarf_attr_integrate (pointee_typedie, DW_AT_byte_size, &attr_mem)) | |
980 | dwarf_formudata (&attr_mem, &pointee_byte_size); | |
fdfbe4f7 GH |
981 | |
982 | dwarf_formudata (dwarf_attr_integrate (pointee_typedie, DW_AT_encoding, &attr_mem), | |
983 | &pointee_encoding); | |
984 | ||
f9eba66e FCE |
985 | // We have the pointer: cast it to an integral type via &(*(...)) |
986 | ||
987 | // NB: per bug #1187, at one point char*-like types were | |
988 | // automagically converted here to systemtap string values. | |
989 | // For several reasons, this was taken back out, leaving | |
990 | // pointer-to-string "conversion" (copying) to tapset functions. | |
991 | ||
992 | ty = pe_long; | |
993 | if (typetag == DW_TAG_array_type) | |
994 | c_translate_array (&pool, 1, module_bias, typedie, &tail, NULL, 0); | |
fdfbe4f7 | 995 | else |
f9eba66e FCE |
996 | c_translate_pointer (&pool, 1, module_bias, typedie, &tail); |
997 | c_translate_addressof (&pool, 1, module_bias, NULL, pointee_typedie, &tail, | |
998 | "THIS->__retvalue"); | |
fdfbe4f7 GH |
999 | } |
1000 | break; | |
1001 | } | |
f9eba66e | 1002 | |
77de5e9e GH |
1003 | size_t bufsz = 1024; |
1004 | char *buf = static_cast<char*>(malloc(bufsz)); | |
1005 | assert(buf); | |
f9eba66e | 1006 | |
77de5e9e GH |
1007 | FILE *memstream = open_memstream (&buf, &bufsz); |
1008 | assert(memstream); | |
7a053d3b | 1009 | |
fdfbe4f7 GH |
1010 | fprintf(memstream, "{\n"); |
1011 | fprintf(memstream, prelude.c_str()); | |
77de5e9e | 1012 | bool deref = c_emit_location (memstream, head, 1); |
fdfbe4f7 | 1013 | fprintf(memstream, postlude.c_str()); |
a781f401 | 1014 | fprintf(memstream, " goto out;\n"); |
7a053d3b | 1015 | |
a781f401 FCE |
1016 | // dummy use of deref_fault label, to disable warning if deref() not used |
1017 | fprintf(memstream, "if (0) goto deref_fault;\n"); | |
1018 | ||
1019 | // XXX: deref flag not reliable; emit fault label unconditionally | |
1020 | if (deref) ; | |
1021 | fprintf(memstream, | |
1022 | "deref_fault:\n" | |
5e309481 | 1023 | " c->last_error = \"pointer dereference fault\";\n" |
a781f401 | 1024 | " goto out;\n"); |
fdfbe4f7 | 1025 | fprintf(memstream, "}\n"); |
7a053d3b | 1026 | |
77de5e9e GH |
1027 | fclose (memstream); |
1028 | string result(buf); | |
1029 | free (buf); | |
1030 | return result; | |
1031 | } | |
7a053d3b RM |
1032 | |
1033 | ||
77de5e9e | 1034 | |
bd2b1e68 GH |
1035 | ~dwflpp() |
1036 | { | |
1037 | if (dwfl) | |
1038 | dwfl_end(dwfl); | |
1039 | } | |
1040 | }; | |
1041 | ||
20c6c071 | 1042 | |
7a053d3b | 1043 | enum |
bd2b1e68 | 1044 | function_spec_type |
7a053d3b | 1045 | { |
bd2b1e68 GH |
1046 | function_alone, |
1047 | function_and_file, | |
7a053d3b | 1048 | function_file_and_line |
bd2b1e68 GH |
1049 | }; |
1050 | ||
ec4373ff | 1051 | |
bd2b1e68 | 1052 | struct dwarf_builder; |
77de5e9e GH |
1053 | struct dwarf_query; |
1054 | ||
bd2b1e68 | 1055 | struct dwarf_derived_probe : public derived_probe |
b55bc428 | 1056 | { |
4cd232e4 GH |
1057 | dwarf_derived_probe (string const & funcname, |
1058 | char const * filename, | |
1059 | int line, | |
1060 | Dwarf_Addr addr, | |
1061 | dwarf_query & q); | |
d9b516ca | 1062 | |
20c6c071 | 1063 | Dwarf_Addr addr; |
a229fcd7 | 1064 | Dwarf_Addr module_bias; |
fd6602a0 | 1065 | bool has_return; |
7a053d3b | 1066 | |
bd2b1e68 | 1067 | // Pattern registration helpers. |
7a053d3b | 1068 | static void register_relative_variants(match_node * root, |
bd2b1e68 | 1069 | dwarf_builder * dw); |
7a053d3b | 1070 | static void register_statement_variants(match_node * root, |
bd2b1e68 | 1071 | dwarf_builder * dw); |
fd6602a0 FCE |
1072 | static void register_function_variants(match_node * root, |
1073 | dwarf_builder * dw); | |
7a053d3b | 1074 | static void register_function_and_statement_variants(match_node * root, |
bd2b1e68 | 1075 | dwarf_builder * dw); |
20c6c071 | 1076 | static void register_patterns(match_node * root); |
7a053d3b | 1077 | |
20c6c071 GH |
1078 | virtual void emit_registrations (translator_output * o, unsigned i); |
1079 | virtual void emit_deregistrations (translator_output * o, unsigned i); | |
1080 | virtual void emit_probe_entries (translator_output * o, unsigned i); | |
20c6c071 GH |
1081 | }; |
1082 | ||
1083 | // Helper struct to thread through the dwfl callbacks. | |
7a053d3b | 1084 | struct |
20c6c071 GH |
1085 | dwarf_query |
1086 | { | |
5227f1ea GH |
1087 | dwarf_query(systemtap_session & sess, |
1088 | probe * base_probe, | |
20c6c071 GH |
1089 | probe_point * base_loc, |
1090 | dwflpp & dw, | |
1091 | map<string, literal *> const & params, | |
1092 | vector<derived_probe *> & results); | |
bd2b1e68 | 1093 | |
5227f1ea GH |
1094 | systemtap_session & sess; |
1095 | ||
bd2b1e68 | 1096 | // Parameter extractors. |
7a053d3b | 1097 | static bool has_null_param(map<string, literal *> const & params, |
bd2b1e68 | 1098 | string const & k); |
7a053d3b | 1099 | static bool get_string_param(map<string, literal *> const & params, |
bd2b1e68 | 1100 | string const & k, string & v); |
7a053d3b | 1101 | static bool get_number_param(map<string, literal *> const & params, |
bd2b1e68 | 1102 | string const & k, long & v); |
c239d28c GH |
1103 | static bool get_number_param(map<string, literal *> const & params, |
1104 | string const & k, Dwarf_Addr & v); | |
b55bc428 | 1105 | |
77de5e9e GH |
1106 | string pt_regs_member_for_regnum(uint8_t dwarf_regnum); |
1107 | ||
20c6c071 | 1108 | vector<derived_probe *> & results; |
20c6c071 GH |
1109 | |
1110 | bool has_kernel; | |
1111 | bool has_process; | |
1112 | bool has_module; | |
7a053d3b RM |
1113 | string process_val; |
1114 | string module_val; | |
1115 | string function_val; | |
20c6c071 GH |
1116 | |
1117 | bool has_function_str; | |
1118 | bool has_statement_str; | |
1119 | bool has_function_num; | |
1120 | bool has_statement_num; | |
7a053d3b RM |
1121 | string statement_str_val; |
1122 | string function_str_val; | |
c239d28c GH |
1123 | Dwarf_Addr statement_num_val; |
1124 | Dwarf_Addr function_num_val; | |
20c6c071 GH |
1125 | |
1126 | bool has_callees; | |
7a053d3b | 1127 | long callee_val; |
20c6c071 GH |
1128 | |
1129 | bool has_return; | |
1130 | ||
1131 | bool has_label; | |
1132 | string label_val; | |
1133 | ||
1134 | bool has_relative; | |
1135 | long relative_val; | |
1136 | ||
1137 | function_spec_type parse_function_spec(string & spec); | |
1138 | function_spec_type spec_type; | |
1139 | string function; | |
1140 | string file; | |
1141 | int line; | |
1142 | ||
7e1279ea FCE |
1143 | set<char const *> filtered_srcfiles; |
1144 | ||
1145 | // Map official entrypc -> func_info object | |
1146 | map<Dwarf_Addr, inline_instance_info> filtered_inlines; | |
1147 | map<Dwarf_Addr, func_info> filtered_functions; | |
1148 | bool choose_next_line; | |
1149 | Dwarf_Addr entrypc_for_next_line; | |
1150 | ||
20c6c071 GH |
1151 | probe * base_probe; |
1152 | probe_point * base_loc; | |
1153 | dwflpp & dw; | |
b55bc428 FCE |
1154 | }; |
1155 | ||
98afd80e FCE |
1156 | |
1157 | struct dwarf_builder: public derived_probe_builder | |
b55bc428 | 1158 | { |
bd2b1e68 | 1159 | dwarf_builder() {} |
5227f1ea | 1160 | virtual void build(systemtap_session & sess, |
7a053d3b | 1161 | probe * base, |
20c6c071 GH |
1162 | probe_point * location, |
1163 | std::map<std::string, literal *> const & parameters, | |
1164 | vector<probe *> & results_to_expand_further, | |
1165 | vector<derived_probe *> & finished_results); | |
b55bc428 FCE |
1166 | }; |
1167 | ||
7a053d3b RM |
1168 | bool |
1169 | dwarf_query::has_null_param(map<string, literal *> const & params, | |
20c6c071 | 1170 | string const & k) |
bd2b1e68 GH |
1171 | { |
1172 | map<string, literal *>::const_iterator i = params.find(k); | |
1173 | if (i != params.end() && i->second == NULL) | |
1174 | return true; | |
1175 | return false; | |
1176 | } | |
1177 | ||
7a053d3b RM |
1178 | bool |
1179 | dwarf_query::get_string_param(map<string, literal *> const & params, | |
20c6c071 | 1180 | string const & k, string & v) |
bd2b1e68 | 1181 | { |
98afd80e | 1182 | return derived_probe_builder::get_param (params, k, v); |
bd2b1e68 GH |
1183 | } |
1184 | ||
7a053d3b RM |
1185 | bool |
1186 | dwarf_query::get_number_param(map<string, literal *> const & params, | |
20c6c071 | 1187 | string const & k, long & v) |
bd2b1e68 | 1188 | { |
98afd80e FCE |
1189 | int64_t value; |
1190 | bool present = derived_probe_builder::get_param (params, k, value); | |
1191 | v = (long) value; | |
1192 | return present; | |
bd2b1e68 GH |
1193 | } |
1194 | ||
c239d28c GH |
1195 | bool |
1196 | dwarf_query::get_number_param(map<string, literal *> const & params, | |
1197 | string const & k, Dwarf_Addr & v) | |
1198 | { | |
98afd80e FCE |
1199 | int64_t value; |
1200 | bool present = derived_probe_builder::get_param (params, k, value); | |
1201 | v = (Dwarf_Addr) value; | |
1202 | return present; | |
c239d28c GH |
1203 | } |
1204 | ||
77de5e9e | 1205 | |
5227f1ea GH |
1206 | dwarf_query::dwarf_query(systemtap_session & sess, |
1207 | probe * base_probe, | |
20c6c071 GH |
1208 | probe_point * base_loc, |
1209 | dwflpp & dw, | |
1210 | map<string, literal *> const & params, | |
1211 | vector<derived_probe *> & results) | |
5227f1ea GH |
1212 | : sess(sess), |
1213 | results(results), | |
7a053d3b | 1214 | base_probe(base_probe), |
20c6c071 GH |
1215 | base_loc(base_loc), |
1216 | dw(dw) | |
bd2b1e68 | 1217 | { |
20c6c071 | 1218 | |
bd2b1e68 GH |
1219 | // Reduce the query to more reasonable semantic values (booleans, |
1220 | // extracted strings, numbers, etc). | |
1221 | ||
1222 | has_kernel = has_null_param(params, TOK_KERNEL); | |
1223 | has_module = get_string_param(params, TOK_MODULE, module_val); | |
1224 | has_process = get_string_param(params, TOK_PROCESS, process_val); | |
1225 | ||
1226 | has_function_str = get_string_param(params, TOK_FUNCTION, function_str_val); | |
1227 | has_function_num = get_number_param(params, TOK_FUNCTION, function_num_val); | |
1228 | ||
1229 | has_statement_str = get_string_param(params, TOK_STATEMENT, statement_str_val); | |
1230 | has_statement_num = get_number_param(params, TOK_STATEMENT, statement_num_val); | |
1231 | ||
1232 | callee_val = 1; | |
7a053d3b | 1233 | has_callees = (has_null_param(params, TOK_CALLEES) || |
bd2b1e68 GH |
1234 | get_number_param(params, TOK_CALLEES, callee_val)); |
1235 | ||
1236 | has_return = has_null_param(params, TOK_RETURN); | |
1237 | ||
1238 | has_label = get_string_param(params, TOK_LABEL, label_val); | |
1239 | has_relative = get_number_param(params, TOK_RELATIVE, relative_val); | |
7a053d3b | 1240 | |
bd2b1e68 GH |
1241 | if (has_function_str) |
1242 | spec_type = parse_function_spec(function_str_val); | |
1243 | else if (has_statement_str) | |
1244 | spec_type = parse_function_spec(statement_str_val); | |
7a053d3b | 1245 | } |
bd2b1e68 GH |
1246 | |
1247 | ||
bd2b1e68 | 1248 | function_spec_type |
20c6c071 | 1249 | dwarf_query::parse_function_spec(string & spec) |
bd2b1e68 GH |
1250 | { |
1251 | string::const_iterator i = spec.begin(), e = spec.end(); | |
7a053d3b | 1252 | |
bd2b1e68 GH |
1253 | function.clear(); |
1254 | file.clear(); | |
1255 | line = 0; | |
1256 | ||
1257 | while (i != e && *i != '@') | |
1258 | { | |
1259 | if (*i == ':') | |
1260 | goto bad; | |
1261 | function += *i++; | |
1262 | } | |
1263 | ||
1264 | if (i == e) | |
1265 | { | |
5227f1ea | 1266 | if (sess.verbose) |
7a053d3b RM |
1267 | clog << "parsed '" << spec |
1268 | << "' -> func '" << function | |
bd2b1e68 GH |
1269 | << "'" << endl; |
1270 | return function_alone; | |
1271 | } | |
1272 | ||
1273 | if (i++ == e) | |
1274 | goto bad; | |
1275 | ||
1276 | while (i != e && *i != ':') | |
1277 | file += *i++; | |
7a053d3b | 1278 | |
bd2b1e68 GH |
1279 | if (i == e) |
1280 | { | |
5227f1ea | 1281 | if (sess.verbose) |
7a053d3b RM |
1282 | clog << "parsed '" << spec |
1283 | << "' -> func '"<< function | |
1284 | << "', file '" << file | |
bd2b1e68 GH |
1285 | << "'" << endl; |
1286 | return function_and_file; | |
1287 | } | |
1288 | ||
1289 | if (i++ == e) | |
1290 | goto bad; | |
1291 | ||
1292 | try | |
1293 | { | |
1294 | line = lex_cast<int>(string(i, e)); | |
5227f1ea | 1295 | if (sess.verbose) |
7a053d3b RM |
1296 | clog << "parsed '" << spec |
1297 | << "' -> func '"<< function | |
1298 | << "', file '" << file | |
bd2b1e68 GH |
1299 | << "', line " << line << endl; |
1300 | return function_file_and_line; | |
1301 | } | |
1302 | catch (runtime_error & exn) | |
1303 | { | |
1304 | goto bad; | |
1305 | } | |
1306 | ||
1307 | bad: | |
7a053d3b | 1308 | throw semantic_error("malformed specification '" + spec + "'", |
20c6c071 | 1309 | base_probe->tok); |
bd2b1e68 GH |
1310 | } |
1311 | ||
1312 | ||
7e1279ea FCE |
1313 | |
1314 | // The critical determining factor when interpreting a pattern | |
1315 | // string is, perhaps surprisingly: "presence of a lineno". The | |
1316 | // presence of a lineno changes the search strategy completely. | |
1317 | // | |
1318 | // Compare the two cases: | |
1319 | // | |
1320 | // 1. {statement,function}(foo@file.c:lineno) | |
1321 | // - find the files matching file.c | |
1322 | // - in each file, find the functions matching foo | |
1323 | // - query the file for line records matching lineno | |
1324 | // - iterate over the line records, | |
1325 | // - and iterate over the functions, | |
1326 | // - if(haspc(function.DIE, line.addr)) | |
1327 | // - if looking for statements: probe(lineno.addr) | |
1328 | // - if looking for functions: probe(function.{entrypc,return,etc.}) | |
1329 | // | |
1330 | // 2. {statement,function}(foo@file.c) | |
1331 | // - find the files matching file.c | |
1332 | // - in each file, find the functions matching foo | |
1333 | // - probe(function.{entrypc,return,etc.}) | |
1334 | // | |
1335 | // Thus the first decision we make is based on the presence of a | |
1336 | // lineno, and we enter entirely different sets of callbacks | |
1337 | // depending on that decision. | |
1338 | ||
1339 | ||
bd2b1e68 | 1340 | static void |
4cd232e4 GH |
1341 | query_statement (string const & func, |
1342 | char const * file, | |
1343 | int line, | |
1344 | Dwarf_Addr stmt_addr, | |
1345 | dwarf_query * q) | |
bd2b1e68 | 1346 | { |
39bcd429 FCE |
1347 | try |
1348 | { | |
1349 | // XXX: implement | |
1350 | if (q->has_relative) | |
1351 | throw semantic_error("incomplete: do not know how to interpret .relative", | |
1352 | q->base_probe->tok); | |
d9b516ca | 1353 | |
6e95311e | 1354 | q->results.push_back(new dwarf_derived_probe(func, file, line, stmt_addr, *q)); |
39bcd429 FCE |
1355 | } |
1356 | catch (const semantic_error& e) | |
1357 | { | |
1358 | q->sess.print_error (e); | |
1359 | } | |
bd2b1e68 GH |
1360 | } |
1361 | ||
7e1279ea FCE |
1362 | static void |
1363 | query_inline_instance_info (Dwarf_Addr entrypc, | |
6e95311e | 1364 | inline_instance_info const & ii, |
7e1279ea FCE |
1365 | dwarf_query * q) |
1366 | { | |
1367 | if (q->has_return) | |
1368 | { | |
1369 | throw semantic_error ("cannot probe .return of inline function '" + ii.name + "'"); | |
1370 | } | |
1371 | else | |
1372 | { | |
1373 | if (q->sess.verbose) | |
1374 | clog << "querying entrypc " | |
1375 | << hex << entrypc << dec | |
1376 | << " of instance of inline '" << ii.name << "'" << endl; | |
6e95311e | 1377 | query_statement (ii.name, ii.decl_file, ii.decl_line, entrypc, q); |
7e1279ea FCE |
1378 | } |
1379 | } | |
1380 | ||
1381 | static void | |
1382 | query_func_info (Dwarf_Addr entrypc, | |
6e95311e | 1383 | func_info const & fi, |
7e1279ea FCE |
1384 | dwarf_query * q) |
1385 | { | |
1386 | if (q->has_return) | |
1387 | { | |
1388 | // NB. dwarf_derived_probe::emit_registrations will emit a | |
1389 | // kretprobe based on the entrypc in this case. | |
1390 | if (q->sess.verbose) | |
6e95311e FCE |
1391 | clog << "querying entrypc of function '" << fi.name << "' for return probe" << endl; |
1392 | query_statement (fi.name, fi.decl_file, fi.decl_line, entrypc, q); | |
7e1279ea FCE |
1393 | } |
1394 | else | |
1395 | { | |
1396 | if (q->sess.verbose) | |
6e95311e FCE |
1397 | clog << "querying prologue-end of function '" << fi.name << "'" << endl; |
1398 | query_statement (fi.name, fi.decl_file, fi.decl_line, fi.prologue_end, q); | |
7e1279ea FCE |
1399 | } |
1400 | } | |
1401 | ||
1402 | ||
1403 | static void | |
1404 | query_srcfile_line (Dwarf_Line * line, void * arg) | |
1405 | { | |
1406 | dwarf_query * q = static_cast<dwarf_query *>(arg); | |
1407 | ||
1408 | Dwarf_Addr addr; | |
1409 | dwarf_lineaddr(line, &addr); | |
4cd232e4 | 1410 | |
7e1279ea FCE |
1411 | for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin(); |
1412 | i != q->filtered_functions.end(); ++i) | |
1413 | { | |
1414 | if (q->dw.die_has_pc (&(i->second.die), addr)) | |
1415 | { | |
1416 | if (q->sess.verbose) | |
1417 | clog << "function DIE lands on srcfile" << endl; | |
4cd232e4 | 1418 | if (q->has_statement_str) |
6e95311e | 1419 | query_statement (i->second.name, i->second.decl_file, q->line, addr, q); |
4cd232e4 GH |
1420 | else |
1421 | query_func_info (i->first, i->second, q); | |
7e1279ea FCE |
1422 | } |
1423 | } | |
1424 | ||
6e95311e | 1425 | for (map<Dwarf_Addr, inline_instance_info>::iterator i = q->filtered_inlines.begin(); |
4cd232e4 | 1426 | i != q->filtered_inlines.end(); ++i) |
7e1279ea | 1427 | { |
4cd232e4 GH |
1428 | if (q->dw.die_has_pc (&(i->second.die), addr)) |
1429 | { | |
1430 | if (q->sess.verbose) | |
1431 | clog << "inline instance DIE lands on srcfile" << endl; | |
1432 | if (q->has_statement_str) | |
6e95311e | 1433 | query_statement (i->second.name, i->second.decl_file, q->line, addr, q); |
4cd232e4 GH |
1434 | else |
1435 | query_inline_instance_info (i->first, i->second, q); | |
1436 | } | |
1437 | } | |
7e1279ea FCE |
1438 | } |
1439 | ||
1440 | ||
4fa7b22b | 1441 | static int |
7e1279ea | 1442 | query_dwarf_inline_instance (Dwarf_Die * die, void * arg) |
4fa7b22b GH |
1443 | { |
1444 | dwarf_query * q = static_cast<dwarf_query *>(arg); | |
7e1279ea | 1445 | assert (!q->has_statement_num); |
bd2b1e68 | 1446 | |
39bcd429 | 1447 | try |
7a053d3b | 1448 | { |
bb788f9f | 1449 | |
7e1279ea FCE |
1450 | bool record_this_inline = false; |
1451 | ||
1452 | if (q->sess.verbose) | |
1453 | clog << "examining inline instance of " << q->dw.function_name << endl; | |
1454 | ||
1455 | if (q->has_function_str || q->has_statement_str) | |
1456 | record_this_inline = true; | |
1457 | else if (q->has_function_num) | |
1458 | { | |
1459 | Dwarf_Addr query_addr = q->function_num_val; | |
1460 | ||
1461 | if (q->has_module) | |
1462 | query_addr = q->dw.module_address_to_global(query_addr); | |
1463 | ||
1464 | if (q->dw.die_has_pc (die, query_addr)) | |
1465 | record_this_inline = true; | |
1466 | } | |
1467 | ||
1468 | if (record_this_inline) | |
1469 | { | |
1470 | if (q->sess.verbose) | |
1471 | clog << "selected inline instance of " << q->dw.function_name << endl; | |
1472 | ||
1473 | Dwarf_Addr entrypc; | |
1474 | if (q->dw.die_entrypc (die, &entrypc)) | |
1475 | { | |
1476 | inline_instance_info inl; | |
1477 | inl.die = *die; | |
1478 | inl.name = q->dw.function_name; | |
4cd232e4 GH |
1479 | q->dw.function_file (&inl.decl_file); |
1480 | q->dw.function_line (&inl.decl_line); | |
7e1279ea FCE |
1481 | q->filtered_inlines[entrypc] = inl; |
1482 | } | |
1483 | } | |
1484 | return DWARF_CB_OK; | |
1485 | } | |
1486 | catch (const semantic_error& e) | |
1487 | { | |
1488 | q->sess.print_error (e); | |
1489 | return DWARF_CB_ABORT; | |
1490 | } | |
1491 | } | |
bb788f9f | 1492 | |
7e1279ea FCE |
1493 | static int |
1494 | query_dwarf_func (Dwarf_Func * func, void * arg) | |
1495 | { | |
1496 | dwarf_query * q = static_cast<dwarf_query *>(arg); | |
1497 | assert (!q->has_statement_num); | |
bb788f9f | 1498 | |
7e1279ea FCE |
1499 | try |
1500 | { | |
1501 | // XXX: implement | |
1502 | if (q->has_callees) | |
1503 | throw semantic_error ("incomplete: do not know how to interpret .callees", | |
1504 | q->base_probe->tok); | |
1505 | ||
1506 | if (q->has_label) | |
1507 | throw semantic_error ("incomplete: do not know how to interpret .label", | |
1508 | q->base_probe->tok); | |
1509 | ||
1510 | q->dw.focus_on_function (func); | |
1511 | ||
1512 | if (q->dw.func_is_inline () | |
1513 | && (((q->has_statement_str || q->has_function_str) | |
1514 | && q->dw.function_name_matches(q->function)) | |
1515 | || q->has_function_num)) | |
1516 | { | |
1517 | if (q->sess.verbose) | |
1518 | clog << "checking instances of inline " << q->dw.function_name << endl; | |
1519 | q->dw.iterate_over_inline_instances (query_dwarf_inline_instance, arg); | |
1520 | } | |
39bcd429 | 1521 | else |
7e1279ea FCE |
1522 | { |
1523 | bool record_this_function = false; | |
1524 | ||
1525 | if ((q->has_statement_str || q->has_function_str) | |
1526 | && q->dw.function_name_matches(q->function)) | |
1527 | { | |
1528 | record_this_function = true; | |
1529 | } | |
1530 | else if (q->has_function_num) | |
1531 | { | |
1532 | Dwarf_Addr query_addr = q->function_num_val; | |
1533 | ||
1534 | if (q->has_module) | |
1535 | query_addr = q->dw.module_address_to_global(query_addr); | |
1536 | ||
1537 | Dwarf_Die d; | |
1538 | q->dw.function_die (&d); | |
1539 | ||
1540 | if (q->dw.die_has_pc (&d, query_addr)) | |
1541 | record_this_function = true; | |
1542 | } | |
1543 | ||
1544 | if (record_this_function) | |
1545 | { | |
1546 | if (q->sess.verbose) | |
1547 | clog << "selected function " << q->dw.function_name << endl; | |
1548 | ||
1549 | Dwarf_Addr entrypc; | |
1550 | if (q->dw.function_entrypc (&entrypc)) | |
1551 | { | |
1552 | func_info func; | |
1553 | q->dw.function_die (&func.die); | |
1554 | func.name = q->dw.function_name; | |
4cd232e4 GH |
1555 | q->dw.function_file (&func.decl_file); |
1556 | q->dw.function_line (&func.decl_line); | |
7e1279ea FCE |
1557 | q->filtered_functions[entrypc] = func; |
1558 | } | |
1559 | } | |
1560 | } | |
39bcd429 | 1561 | return DWARF_CB_OK; |
bd2b1e68 | 1562 | } |
39bcd429 | 1563 | catch (const semantic_error& e) |
bd2b1e68 | 1564 | { |
39bcd429 FCE |
1565 | q->sess.print_error (e); |
1566 | return DWARF_CB_ABORT; | |
bd2b1e68 | 1567 | } |
bd2b1e68 GH |
1568 | } |
1569 | ||
1570 | static int | |
1571 | query_cu (Dwarf_Die * cudie, void * arg) | |
1572 | { | |
20c6c071 | 1573 | dwarf_query * q = static_cast<dwarf_query *>(arg); |
7a053d3b | 1574 | |
39bcd429 | 1575 | try |
bd2b1e68 | 1576 | { |
7e1279ea | 1577 | q->dw.focus_on_cu (cudie); |
b5d77020 FCE |
1578 | |
1579 | if (false && q->sess.verbose) | |
1580 | clog << "focused on CU '" << q->dw.cu_name | |
1581 | << "', in module '" << q->dw.module_name << "'" << endl; | |
d9b516ca | 1582 | |
7e1279ea FCE |
1583 | if (q->has_statement_str || q->has_function_str || q->has_function_num) |
1584 | { | |
1585 | q->filtered_srcfiles.clear(); | |
1586 | q->filtered_functions.clear(); | |
1587 | q->filtered_inlines.clear(); | |
1588 | ||
1589 | // In this path, we find "abstract functions", record | |
1590 | // information about them, and then (depending on lineno | |
1591 | // matching) possibly emit one or more of the function's | |
1592 | // associated addresses. Unfortunately the control of this | |
1593 | // cannot easily be turned inside out. | |
1594 | ||
1595 | if ((q->has_statement_str || q->has_function_str) | |
1596 | && (q->spec_type != function_alone)) | |
1597 | { | |
1598 | // If we have a pattern string with a filename, we need | |
1599 | // to elaborate the srcfile mask in question first. | |
1600 | q->dw.collect_srcfiles_matching (q->file, q->filtered_srcfiles); | |
1601 | ||
1602 | // If we have a file pattern and *no* srcfile matches, there's | |
1603 | // no need to look further into this CU, so skip. | |
1604 | if (q->filtered_srcfiles.empty()) | |
1605 | return DWARF_CB_OK; | |
1606 | } | |
1607 | ||
1608 | // Pick up [entrypc, name, DIE] tuples for all the functions | |
1609 | // matching the query, and fill in the prologue endings of them | |
1610 | // all in a single pass. | |
1611 | q->dw.iterate_over_functions (query_dwarf_func, q); | |
1612 | q->dw.resolve_prologue_endings (q->filtered_functions); | |
1613 | ||
1614 | if ((q->has_statement_str || q->has_function_str) | |
1615 | && (q->spec_type == function_file_and_line)) | |
1616 | { | |
1617 | // If we have a pattern string with target *line*, we | |
1618 | // have to look at lines in all the matched srcfiles. | |
1619 | for (set<char const *>::const_iterator i = q->filtered_srcfiles.begin(); | |
1620 | i != q->filtered_srcfiles.end(); ++i) | |
1621 | q->dw.iterate_over_srcfile_lines (*i, q->line, query_srcfile_line, q); | |
1622 | } | |
1623 | else | |
1624 | { | |
1625 | // Otherwise, simply probe all resolved functions... | |
6e95311e | 1626 | for (map<Dwarf_Addr, func_info>::const_iterator i = q->filtered_functions.begin(); |
7e1279ea FCE |
1627 | i != q->filtered_functions.end(); ++i) |
1628 | query_func_info (i->first, i->second, q); | |
1629 | ||
1630 | // And all inline instances. | |
6e95311e | 1631 | for (map<Dwarf_Addr, inline_instance_info>::const_iterator i |
7e1279ea FCE |
1632 | = q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i) |
1633 | query_inline_instance_info (i->first, i->second, q); | |
1634 | ||
1635 | } | |
1636 | } | |
39bcd429 FCE |
1637 | else |
1638 | { | |
7e1279ea FCE |
1639 | // Otherwise we have a statement number, and we can just |
1640 | // query it directly within this module. | |
1641 | ||
1642 | assert (q->has_statement_num); | |
1643 | Dwarf_Addr query_addr = q->statement_num_val; | |
1644 | if (q->has_module) | |
1645 | query_addr = q->dw.module_address_to_global(query_addr); | |
1646 | ||
6e95311e | 1647 | query_statement ("", "", -1, query_addr, q); |
39bcd429 FCE |
1648 | } |
1649 | return DWARF_CB_OK; | |
bd2b1e68 | 1650 | } |
39bcd429 | 1651 | catch (const semantic_error& e) |
bd2b1e68 | 1652 | { |
39bcd429 FCE |
1653 | q->sess.print_error (e); |
1654 | return DWARF_CB_ABORT; | |
bd2b1e68 | 1655 | } |
bd2b1e68 GH |
1656 | } |
1657 | ||
1658 | static int | |
1659 | query_module (Dwfl_Module *mod __attribute__ ((unused)), | |
1660 | void **userdata __attribute__ ((unused)), | |
1661 | const char *name, Dwarf_Addr base, | |
bd2b1e68 GH |
1662 | void *arg __attribute__ ((unused))) |
1663 | { | |
20c6c071 | 1664 | dwarf_query * q = static_cast<dwarf_query *>(arg); |
bd2b1e68 | 1665 | |
39bcd429 | 1666 | try |
bd2b1e68 | 1667 | { |
39bcd429 | 1668 | q->dw.focus_on_module(mod); |
d9b516ca | 1669 | |
39bcd429 FCE |
1670 | // If we have enough information in the pattern to skip a module and |
1671 | // the module does not match that information, return early. | |
d9b516ca | 1672 | |
39bcd429 FCE |
1673 | if (q->has_kernel && !q->dw.module_name_matches(TOK_KERNEL)) |
1674 | return DWARF_CB_OK; | |
d9b516ca | 1675 | |
39bcd429 FCE |
1676 | if (q->has_module && !q->dw.module_name_matches(q->module_val)) |
1677 | return DWARF_CB_OK; | |
b5d77020 FCE |
1678 | |
1679 | if (q->sess.verbose) | |
d9b516ca RM |
1680 | clog << "focused on module '" << q->dw.module_name |
1681 | << "' = [" << hex << q->dw.module_start | |
1682 | << "-" << q->dw.module_end | |
c0de7a8d | 1683 | << ", bias " << q->dw.module_bias << "]" << dec << endl; |
b5d77020 | 1684 | |
39bcd429 FCE |
1685 | if (q->has_function_num || q->has_statement_num) |
1686 | { | |
1687 | // If we have module("foo").function(0xbeef) or | |
1688 | // module("foo").statement(0xbeef), the address is relative | |
1689 | // to the start of the module, so we seek the function | |
1690 | // number plus the module's bias. | |
7e1279ea | 1691 | |
39bcd429 FCE |
1692 | Dwarf_Addr addr; |
1693 | if (q->has_function_num) | |
1694 | addr = q->function_num_val; | |
1695 | else | |
1696 | addr = q->statement_num_val; | |
d9b516ca | 1697 | |
7e1279ea FCE |
1698 | // NB: We should not have kernel.* here; global addresses |
1699 | // should have bypassed query_module in dwarf_builder::build | |
1700 | // and gone directly to query_cu. | |
d9b516ca | 1701 | |
7e1279ea FCE |
1702 | assert (!q->has_kernel); |
1703 | assert (q->has_module); | |
1704 | q->dw.query_cu_containing_module_address(addr, q); | |
39bcd429 | 1705 | } |
50e0d793 | 1706 | else |
39bcd429 FCE |
1707 | { |
1708 | // Otherwise if we have a function("foo") or statement("foo") | |
1709 | // specifier, we have to scan over all the CUs looking for | |
7e1279ea FCE |
1710 | // the function(s) in question |
1711 | ||
39bcd429 FCE |
1712 | assert(q->has_function_str || q->has_statement_str); |
1713 | q->dw.iterate_over_cus(&query_cu, q); | |
d9b516ca | 1714 | |
7e1279ea FCE |
1715 | // If we just processed the module "kernel", and the user asked for |
1716 | // the kernel pattern, there's no need to iterate over any further | |
1717 | // modules | |
1718 | ||
1719 | if (q->has_kernel && q->dw.module_name_matches(TOK_KERNEL)) | |
1720 | return DWARF_CB_ABORT; | |
1721 | } | |
bb788f9f | 1722 | |
39bcd429 | 1723 | return DWARF_CB_OK; |
7a053d3b | 1724 | } |
39bcd429 | 1725 | catch (const semantic_error& e) |
bd2b1e68 | 1726 | { |
39bcd429 FCE |
1727 | q->sess.print_error (e); |
1728 | return DWARF_CB_ABORT; | |
bd2b1e68 | 1729 | } |
bd2b1e68 GH |
1730 | } |
1731 | ||
77de5e9e GH |
1732 | struct |
1733 | var_expanding_copy_visitor | |
1734 | : public deep_copy_visitor | |
1735 | { | |
77de5e9e GH |
1736 | static unsigned tick; |
1737 | ||
1738 | dwarf_query & q; | |
77de5e9e GH |
1739 | Dwarf_Addr addr; |
1740 | ||
6e95311e FCE |
1741 | var_expanding_copy_visitor(dwarf_query & q, Dwarf_Addr a) |
1742 | : q(q), addr(a) | |
77de5e9e | 1743 | {} |
d7f3e0c5 | 1744 | void visit_target_symbol (target_symbol* e); |
77de5e9e GH |
1745 | }; |
1746 | ||
1747 | ||
1748 | unsigned var_expanding_copy_visitor::tick = 0; | |
1749 | ||
1750 | ||
1751 | void | |
d7f3e0c5 | 1752 | var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) |
77de5e9e | 1753 | { |
d7f3e0c5 | 1754 | assert(e->base_name.size() > 0 && e->base_name[0] == '$'); |
d9b516ca | 1755 | |
d7f3e0c5 | 1756 | if (is_active_lvalue(e)) |
77de5e9e | 1757 | { |
d7f3e0c5 GH |
1758 | throw semantic_error("read-only special variable " |
1759 | + e->base_name + " used as lvalue", e->tok); | |
77de5e9e | 1760 | } |
d9b516ca | 1761 | |
d7f3e0c5 GH |
1762 | string fname = "get_" + e->base_name.substr(1) + "_" + lex_cast<string>(tick++); |
1763 | ||
1764 | // synthesize a function | |
1765 | functiondecl *fdecl = new functiondecl; | |
1766 | embeddedcode *ec = new embeddedcode; | |
5e309481 | 1767 | ec->tok = e->tok; |
66d284f4 | 1768 | try |
6e95311e FCE |
1769 | { |
1770 | ec->code = q.dw.literal_stmt_for_local(addr, | |
66d284f4 FCE |
1771 | e->base_name.substr(1), |
1772 | e->components, | |
1773 | fdecl->type); | |
1774 | } | |
1775 | catch (const semantic_error& er) | |
1776 | { | |
1777 | semantic_error er2 (er); | |
1778 | er2.tok1 = e->tok; | |
1779 | throw er2; | |
1780 | } | |
d7f3e0c5 GH |
1781 | fdecl->name = fname; |
1782 | fdecl->body = ec; | |
d7f3e0c5 | 1783 | q.sess.functions.push_back(fdecl); |
d9b516ca | 1784 | |
d7f3e0c5 GH |
1785 | // synthesize a call |
1786 | functioncall* n = new functioncall; | |
1787 | n->tok = e->tok; | |
1788 | n->function = fname; | |
1789 | n->referent = NULL; | |
d9b516ca | 1790 | provide <functioncall*> (this, n); |
77de5e9e GH |
1791 | } |
1792 | ||
1793 | ||
4cd232e4 GH |
1794 | dwarf_derived_probe::dwarf_derived_probe (string const & funcname, |
1795 | char const * filename, | |
1796 | int line, | |
1797 | Dwarf_Addr addr, | |
1798 | dwarf_query & q) | |
a229fcd7 | 1799 | : derived_probe (NULL), |
fd6602a0 | 1800 | addr(addr), |
a229fcd7 | 1801 | module_bias(q.dw.module_bias), |
fd6602a0 | 1802 | has_return (q.has_return) |
bd2b1e68 | 1803 | { |
4cd232e4 | 1804 | string module_name(q.dw.module_name); |
df8fadee FCE |
1805 | // Lock the kernel module in memory. |
1806 | if (module_name != TOK_KERNEL) | |
1807 | { | |
1808 | // XXX: There is a race window here, between the time that libdw | |
1809 | // opened up this same file for its relocation duties, and now. | |
1810 | int fd = q.sess.module_fds[module_name]; | |
1811 | if (fd == 0) | |
1812 | { | |
1813 | string sys_module = "/sys/module/" + module_name + "/sections/.text"; | |
1814 | fd = open (sys_module.c_str(), O_RDONLY); | |
1815 | if (fd < 0) | |
1816 | throw semantic_error ("error opening module refcount-bumping file."); | |
1817 | q.sess.module_fds[module_name] = fd; | |
1818 | } | |
1819 | } | |
1820 | ||
a229fcd7 GH |
1821 | // first synthesize an "expanded" location |
1822 | vector<probe_point::component*> comps; | |
1823 | comps.push_back | |
1824 | (module_name == TOK_KERNEL | |
1825 | ? new probe_point::component(TOK_KERNEL) | |
db520b00 | 1826 | : new probe_point::component(TOK_MODULE, new literal_string(module_name))); |
b5d77020 | 1827 | |
db520b00 FCE |
1828 | string fn_or_stmt; |
1829 | if (q.has_function_str || q.has_function_num) | |
1830 | fn_or_stmt = "function"; | |
1831 | else | |
1832 | fn_or_stmt = "statement"; | |
a229fcd7 | 1833 | |
db520b00 FCE |
1834 | if (q.has_function_str || q.has_statement_str) |
1835 | { | |
4cd232e4 GH |
1836 | string retro_name = funcname; |
1837 | if (filename && !string (filename).empty()) | |
1838 | retro_name += ("@" + string (filename)); | |
1839 | if (line != -1) | |
1840 | retro_name += (":" + lex_cast<string> (line)); | |
db520b00 FCE |
1841 | comps.push_back |
1842 | (new probe_point::component | |
1843 | (fn_or_stmt, new literal_string (retro_name))); | |
1844 | } | |
1845 | else if (q.has_function_num || q.has_statement_num) | |
1846 | { | |
1847 | Dwarf_Addr retro_addr; | |
1848 | if (q.has_function_num) | |
1849 | retro_addr = q.function_num_val; | |
1850 | else | |
1851 | retro_addr = q.statement_num_val; | |
1852 | ||
1853 | comps.push_back (new probe_point::component | |
1854 | (fn_or_stmt, | |
1855 | new literal_number(retro_addr))); // XXX: should be hex if possible | |
a229fcd7 GH |
1856 | } |
1857 | ||
db520b00 | 1858 | if (has_return) |
a229fcd7 | 1859 | comps.push_back |
db520b00 | 1860 | (new probe_point::component(TOK_RETURN)); |
d9b516ca | 1861 | |
a229fcd7 GH |
1862 | assert(q.base_probe->locations.size() > 0); |
1863 | locations.push_back(new probe_point(comps, q.base_probe->locations[0]->tok)); | |
1864 | ||
1865 | // Now make a local-variable-expanded copy of the probe body | |
6e95311e | 1866 | var_expanding_copy_visitor v (q, addr); |
77de5e9e GH |
1867 | require <block*> (&v, &(this->body), q.base_probe->body); |
1868 | this->tok = q.base_probe->tok; | |
bd2b1e68 GH |
1869 | } |
1870 | ||
7a053d3b | 1871 | void |
20c6c071 | 1872 | dwarf_derived_probe::register_relative_variants(match_node * root, |
bd2b1e68 GH |
1873 | dwarf_builder * dw) |
1874 | { | |
1875 | // Here we match 2 forms: | |
1876 | // | |
1877 | // . | |
1878 | // .relative(NN) | |
1879 | ||
20c6c071 GH |
1880 | root->bind(dw); |
1881 | root->bind_num(TOK_RELATIVE)->bind(dw); | |
bd2b1e68 GH |
1882 | } |
1883 | ||
7a053d3b | 1884 | void |
20c6c071 | 1885 | dwarf_derived_probe::register_statement_variants(match_node * root, |
bd2b1e68 GH |
1886 | dwarf_builder * dw) |
1887 | { | |
1888 | // Here we match 3 forms: | |
1889 | // | |
1890 | // . | |
1891 | // .return | |
1892 | // .label("foo") | |
7a053d3b | 1893 | |
bd2b1e68 | 1894 | register_relative_variants(root, dw); |
20c6c071 | 1895 | register_relative_variants(root->bind_str(TOK_LABEL), dw); |
bd2b1e68 GH |
1896 | } |
1897 | ||
7a053d3b | 1898 | void |
fd6602a0 | 1899 | dwarf_derived_probe::register_function_variants(match_node * root, |
bd2b1e68 GH |
1900 | dwarf_builder * dw) |
1901 | { | |
a229fcd7 | 1902 | // Here we match 4 forms: |
bd2b1e68 GH |
1903 | // |
1904 | // . | |
fd6602a0 | 1905 | // .return |
bd2b1e68 GH |
1906 | // .callees |
1907 | // .callees(N) | |
1908 | // | |
1909 | // The last form permits N-level callee resolving without any | |
1910 | // recursive .callees.callees.callees... pattern-matching on our part. | |
1911 | ||
fd6602a0 FCE |
1912 | root->bind(dw); |
1913 | root->bind(TOK_RETURN)->bind(dw); | |
1914 | root->bind(TOK_CALLEES)->bind(dw); | |
1915 | root->bind_num(TOK_CALLEES)->bind(dw); | |
bd2b1e68 GH |
1916 | } |
1917 | ||
7a053d3b | 1918 | void |
20c6c071 | 1919 | dwarf_derived_probe::register_function_and_statement_variants(match_node * root, |
bd2b1e68 GH |
1920 | dwarf_builder * dw) |
1921 | { | |
1922 | // Here we match 4 forms: | |
1923 | // | |
1924 | // .function("foo") | |
1925 | // .function(0xdeadbeef) | |
1926 | // .statement("foo") | |
1927 | // .statement(0xdeadbeef) | |
1928 | ||
fd6602a0 FCE |
1929 | register_function_variants(root->bind_str(TOK_FUNCTION), dw); |
1930 | register_function_variants(root->bind_num(TOK_FUNCTION), dw); | |
20c6c071 GH |
1931 | register_statement_variants(root->bind_str(TOK_STATEMENT), dw); |
1932 | register_statement_variants(root->bind_num(TOK_STATEMENT), dw); | |
bd2b1e68 GH |
1933 | } |
1934 | ||
1935 | void | |
20c6c071 | 1936 | dwarf_derived_probe::register_patterns(match_node * root) |
bd2b1e68 GH |
1937 | { |
1938 | dwarf_builder *dw = new dwarf_builder(); | |
1939 | ||
1940 | // Here we match 3 forms: | |
1941 | // | |
1942 | // .kernel | |
1943 | // .module("foo") | |
1944 | // .process("foo") | |
1945 | ||
20c6c071 | 1946 | register_function_and_statement_variants(root->bind(TOK_KERNEL), dw); |
fe3d01fa | 1947 | // XXX: may need to disable these for 2005-08 release |
20c6c071 GH |
1948 | register_function_and_statement_variants(root->bind_str(TOK_MODULE), dw); |
1949 | register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw); | |
bd2b1e68 GH |
1950 | } |
1951 | ||
7a053d3b | 1952 | static string |
ec4373ff | 1953 | probe_entry_function_name(unsigned probenum) |
b55bc428 | 1954 | { |
ec4373ff GH |
1955 | return "dwarf_kprobe_" + lex_cast<string>(probenum) + "_enter"; |
1956 | } | |
1957 | ||
7a053d3b | 1958 | static string |
20c6c071 | 1959 | probe_entry_struct_kprobe_name(unsigned probenum) |
ec4373ff | 1960 | { |
20c6c071 | 1961 | return "dwarf_kprobe_" + lex_cast<string>(probenum); |
ec4373ff GH |
1962 | } |
1963 | ||
7a053d3b | 1964 | void |
20c6c071 | 1965 | dwarf_derived_probe::emit_registrations (translator_output* o, unsigned probenum) |
ec4373ff | 1966 | { |
59ff2773 FCE |
1967 | if (has_return) |
1968 | { | |
1969 | o->newline() << probe_entry_struct_kprobe_name(probenum) | |
db520b00 | 1970 | << ".kp.addr = (void *) 0x" << hex << addr << ";" << dec; |
59ff2773 FCE |
1971 | o->newline() << "rc = register_kretprobe (&" |
1972 | << probe_entry_struct_kprobe_name(probenum) | |
1973 | << ");"; | |
ec4373ff | 1974 | } |
20c6c071 | 1975 | else |
bd2b1e68 | 1976 | { |
59ff2773 | 1977 | o->newline() << probe_entry_struct_kprobe_name(probenum) |
db520b00 | 1978 | << ".addr = (void *) 0x" << hex << addr << ";" << dec; |
7a053d3b | 1979 | o->newline() << "rc = register_kprobe (&" |
59ff2773 FCE |
1980 | << probe_entry_struct_kprobe_name(probenum) |
1981 | << ");"; | |
bd2b1e68 | 1982 | } |
b55bc428 FCE |
1983 | } |
1984 | ||
7a053d3b | 1985 | void |
ec4373ff | 1986 | dwarf_derived_probe::emit_deregistrations (translator_output* o, unsigned probenum) |
b55bc428 | 1987 | { |
fd6602a0 FCE |
1988 | if (has_return) |
1989 | o->newline() << "unregister_kretprobe (& " | |
1990 | << probe_entry_struct_kprobe_name(probenum) | |
1991 | << ");"; | |
1992 | else | |
1993 | o->newline() << "unregister_kprobe (& " | |
1994 | << probe_entry_struct_kprobe_name(probenum) | |
1995 | << ");"; | |
ec4373ff GH |
1996 | } |
1997 | ||
7a053d3b | 1998 | void |
ec4373ff GH |
1999 | dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned probenum) |
2000 | { | |
499cf740 FCE |
2001 | static unsigned already_emitted_fault_handler = 0; |
2002 | ||
2003 | if (! already_emitted_fault_handler) | |
2004 | { | |
2005 | o->newline() << "int stap_kprobe_fault_handler (struct kprobe* kp, " | |
2006 | << "struct pt_regs* regs, int trapnr) {"; | |
2007 | o->newline(1) << "struct context *c = & contexts [smp_processor_id()];"; | |
2008 | o->newline() << "printk (KERN_ERR \"systemtap probe fault\\n\");"; | |
2009 | o->newline() << "printk (KERN_ERR \"cpu %d, probe %s, near %s\\n\", "; | |
2010 | o->newline(1) << "smp_processor_id(), "; | |
2011 | o->newline() << "c->probe_point ? c->probe_point : \"unknown\", "; | |
2012 | o->newline() << "c->last_stmt ? c->last_stmt : \"unknown\");"; | |
2013 | o->newline() << "c->last_error = \"probe faulted\";"; | |
2014 | o->newline(-1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
2015 | ||
2016 | o->newline() << "return 0;"; // defer to kernel fault handler | |
2017 | // NB: We might prefer to use "return 1" instead, to consider | |
2018 | // the fault "handled". But we may get into an infinite loop | |
2019 | // of traps if the faulting instruction is simply restarted. | |
2020 | ||
2021 | o->newline(-1) << "}"; | |
2022 | already_emitted_fault_handler ++; | |
2023 | } | |
2024 | ||
7a053d3b | 2025 | // Construct a single entry function, and a struct kprobe pointing into |
20c6c071 | 2026 | // the entry function. The entry function will call the probe function. |
20c6c071 | 2027 | o->newline(); |
3d49c615 | 2028 | o->newline() << "static int "; |
9e6edd10 FCE |
2029 | o->newline() << probe_entry_function_name(probenum) << " ("; |
2030 | if (has_return) | |
2031 | o->line() << "struct kretprobe_instance *_ignored"; | |
2032 | else | |
2033 | o->line() << "struct kprobe *_ignored"; | |
2034 | o->line() << ", struct pt_regs *regs) {"; | |
3d49c615 | 2035 | o->newline(1) << "struct context *c = & contexts [smp_processor_id()];"; |
cc9ee605 FCE |
2036 | o->newline() << "const char* probe_point = " |
2037 | << lex_cast_qstring(*locations[0]) << ";"; | |
bfb3d2d2 FCE |
2038 | |
2039 | // A precondition for running a probe handler is that we're in RUNNING | |
2040 | // state (not ERROR), and that no one else is already using this context. | |
2041 | o->newline() << "if (atomic_read (&session_state) != STAP_SESSION_RUNNING)"; | |
3d49c615 | 2042 | o->newline(1) << "return 0;"; |
cc9ee605 | 2043 | o->newline(-1) << "if (atomic_inc_return (&c->busy) != 1) {"; |
499cf740 | 2044 | o->newline(1) << "printk (KERN_ERR \"probe reentrancy (%s vs %s)\\n\", " |
cc9ee605 | 2045 | << "c->probe_point, probe_point);"; |
bfb3d2d2 | 2046 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; |
3d49c615 | 2047 | o->newline() << "return 0;"; |
bfb3d2d2 FCE |
2048 | o->newline(-1) << "}"; |
2049 | o->newline(); | |
2050 | ||
5e309481 | 2051 | o->newline() << "c->last_error = 0;"; |
cc9ee605 | 2052 | o->newline() << "c->probe_point = probe_point;"; |
ec4373ff | 2053 | o->newline() << "c->nesting = 0;"; |
3d49c615 | 2054 | o->newline() << "c->regs = regs;"; |
5e309481 FCE |
2055 | o->newline() << "c->actioncount = 0;"; |
2056 | ||
ec4373ff GH |
2057 | // NB: locals are initialized by probe function itself |
2058 | o->newline() << "probe_" << probenum << " (c);"; | |
bfb3d2d2 | 2059 | |
bb788f9f FCE |
2060 | o->newline() << "if (c->last_error && c->last_error[0]) {"; |
2061 | o->newline(1) << "_stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; | |
5e309481 | 2062 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; |
bfb3d2d2 | 2063 | o->newline(-1) << "}"; |
bb788f9f | 2064 | |
cc9ee605 | 2065 | o->newline() << "atomic_dec (& c->busy);"; |
3d49c615 | 2066 | o->newline() << "return 0;"; |
ec4373ff GH |
2067 | o->newline(-1) << "}" << endl; |
2068 | ||
20c6c071 | 2069 | o->newline(); |
fd6602a0 FCE |
2070 | if (has_return) |
2071 | { | |
2072 | o->newline() << "static struct kretprobe " | |
2073 | << probe_entry_struct_kprobe_name(probenum) | |
2074 | << "= {"; | |
db520b00 | 2075 | o->newline(1) << ".kp.addr = 0," ; |
bb788f9f FCE |
2076 | o->newline() << ".handler = &" |
2077 | << probe_entry_function_name(probenum) << ","; | |
2c89cb8b FCE |
2078 | // XXX: pending PR 1289 |
2079 | // o->newline() << ".kp.fault_handler = &stap_kprobe_fault_handler,"; | |
bb788f9f | 2080 | o->newline() << ".maxactive = 1"; |
fd6602a0 FCE |
2081 | o->newline(-1) << "};"; |
2082 | } | |
2083 | else | |
2084 | { | |
2085 | o->newline() << "static struct kprobe " | |
2086 | << probe_entry_struct_kprobe_name(probenum) | |
2087 | << "= {"; | |
db520b00 | 2088 | o->newline(1) << ".addr = 0," ; |
2c89cb8b FCE |
2089 | // XXX: pending PR 1289 |
2090 | // o->newline() << ".fault_handler = &stap_kprobe_fault_handler,"; | |
fd6602a0 FCE |
2091 | o->newline() << ".pre_handler = &" << probe_entry_function_name(probenum); |
2092 | o->newline(-1) << "};"; | |
2093 | } | |
20c6c071 GH |
2094 | o->newline(); |
2095 | } | |
ec4373ff | 2096 | |
20c6c071 GH |
2097 | |
2098 | void | |
5227f1ea | 2099 | dwarf_builder::build(systemtap_session & sess, |
7a053d3b | 2100 | probe * base, |
20c6c071 GH |
2101 | probe_point * location, |
2102 | std::map<std::string, literal *> const & parameters, | |
2103 | vector<probe *> & results_to_expand_further, | |
2104 | vector<derived_probe *> & finished_results) | |
2105 | { | |
2106 | ||
5227f1ea GH |
2107 | dwflpp dw(sess); |
2108 | dwarf_query q(sess, base, location, dw, parameters, finished_results); | |
20c6c071 GH |
2109 | |
2110 | dw.setup(q.has_kernel || q.has_module); | |
2111 | ||
7e1279ea | 2112 | if (q.has_kernel && (q.has_function_num || q.has_statement_num)) |
20c6c071 | 2113 | { |
50e0d793 GH |
2114 | // If we have kernel.function(0xbeef), or |
2115 | // kernel.statement(0xbeef) the address is global (relative to | |
2116 | // the kernel) and we can seek directly to the module and cudie | |
2117 | // in question. | |
d9b516ca RM |
2118 | Dwarf_Addr a = (q.has_function_num |
2119 | ? q.function_num_val | |
50e0d793 GH |
2120 | : q.statement_num_val); |
2121 | dw.focus_on_module_containing_global_address(a); | |
7e1279ea | 2122 | dw.query_cu_containing_global_address(a, &q); |
20c6c071 | 2123 | } |
7a053d3b | 2124 | else |
20c6c071 GH |
2125 | { |
2126 | // Otherwise we have module("foo"), kernel.statement("foo"), or | |
2127 | // kernel.function("foo"); in these cases we need to scan all | |
2128 | // the modules. | |
7a053d3b | 2129 | assert((q.has_kernel && q.has_function_str) || |
20c6c071 GH |
2130 | (q.has_kernel && q.has_statement_str) || |
2131 | (q.has_module)); | |
2132 | dw.iterate_over_modules(&query_module, &q); | |
2133 | } | |
b55bc428 FCE |
2134 | } |
2135 | ||
2136 | ||
98afd80e FCE |
2137 | |
2138 | // ------------------------------------------------------------------------ | |
2139 | // timer derived probes | |
2140 | // ------------------------------------------------------------------------ | |
2141 | ||
2142 | ||
2143 | struct timer_derived_probe: public derived_probe | |
2144 | { | |
2145 | int64_t interval, randomize; | |
2146 | ||
2147 | timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r); | |
2148 | ||
2149 | virtual void emit_registrations (translator_output * o, unsigned i); | |
2150 | virtual void emit_deregistrations (translator_output * o, unsigned i); | |
2151 | virtual void emit_probe_entries (translator_output * o, unsigned i); | |
2152 | }; | |
2153 | ||
2154 | ||
2155 | timer_derived_probe::timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r): | |
2156 | derived_probe (p, l), interval (i), randomize (r) | |
2157 | { | |
2158 | if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints | |
2159 | throw semantic_error ("invalid interval for jiffies timer"); | |
2160 | // randomize = 0 means no randomization | |
2161 | if (randomize < 0 || randomize > interval) | |
2162 | throw semantic_error ("invalid randomize for jiffies timer"); | |
2163 | ||
2164 | if (locations.size() != 1) | |
2165 | throw semantic_error ("expect single probe point"); | |
2166 | // so we don't have to loop over them in the other functions | |
2167 | } | |
2168 | ||
2169 | ||
2170 | void | |
2171 | timer_derived_probe::emit_registrations (translator_output* o, unsigned j) | |
2172 | { | |
2173 | o->newline() << "init_timer (& timer_" << j << ");"; | |
2174 | o->newline() << "timer_" << j << ".expires = jiffies + " << interval << ";"; | |
2175 | o->newline() << "timer_" << j << ".function = & enter_" << j << ";"; | |
2176 | o->newline() << "add_timer (& timer_" << j << ");"; | |
2177 | } | |
2178 | ||
2179 | ||
2180 | void | |
2181 | timer_derived_probe::emit_deregistrations (translator_output* o, unsigned j) | |
2182 | { | |
2183 | o->newline() << "del_timer_sync (& timer_" << j << ");"; | |
2184 | } | |
2185 | ||
2186 | ||
2187 | void | |
2188 | timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j) | |
2189 | { | |
2190 | o->newline() << "static struct timer_list timer_" << j << ";"; | |
2191 | ||
2192 | o->newline() << "void enter_" << j << " (unsigned long val) {"; | |
2193 | o->newline(1) << "struct context* c = & contexts [smp_processor_id()];"; | |
cc9ee605 FCE |
2194 | o->newline() << "const char* probe_point = " |
2195 | << lex_cast_qstring(*locations[0]) << ";"; | |
98afd80e FCE |
2196 | o->newline() << "(void) val;"; |
2197 | ||
2198 | // A precondition for running a probe handler is that we're in | |
2199 | // RUNNING state (not ERROR), and that no one else is already using | |
2200 | // this context. | |
2201 | o->newline() << "if (atomic_read (&session_state) != STAP_SESSION_RUNNING)"; | |
2202 | o->newline(1) << "return;"; | |
2203 | ||
cc9ee605 | 2204 | o->newline(-1) << "if (atomic_inc_return (&c->busy) != 1) {"; |
499cf740 | 2205 | o->newline(1) << "printk (KERN_ERR \"probe reentrancy (%s vs %s)\\n\", " |
cc9ee605 | 2206 | << "c->probe_point, probe_point);"; |
98afd80e FCE |
2207 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; |
2208 | o->newline() << "return;"; | |
2209 | o->newline(-1) << "}"; | |
2210 | o->newline(); | |
2211 | ||
2212 | o->newline() << "mod_timer (& timer_" << j << ", " | |
2213 | << "jiffies + " << interval; | |
2214 | if (randomize) | |
2215 | o->line() << " + _stp_random_pm(" << randomize << ")"; | |
2216 | o->line() << ");"; | |
2217 | ||
cc9ee605 | 2218 | o->newline() << "c->probe_point = probe_point;"; |
5e309481 | 2219 | o->newline() << "c->last_error = 0;"; |
98afd80e | 2220 | o->newline() << "c->nesting = 0;"; |
cc9ee605 | 2221 | o->newline() << "if (in_interrupt())"; |
98afd80e FCE |
2222 | o->newline(1) << "c->regs = 0;"; |
2223 | o->newline(-1) << "else"; | |
2224 | o->newline(1) << "c->regs = task_pt_regs (current);"; | |
2225 | o->indent(-1); | |
5e309481 | 2226 | o->newline() << "c->actioncount = 0;"; |
98afd80e FCE |
2227 | |
2228 | // NB: locals are initialized by probe function itself | |
2229 | o->newline() << "probe_" << j << " (c);"; | |
2230 | ||
bb788f9f FCE |
2231 | o->newline() << "if (c->last_error && c->last_error[0]) {"; |
2232 | o->newline(1) << "_stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; | |
5e309481 | 2233 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; |
98afd80e FCE |
2234 | o->newline(-1) << "}"; |
2235 | ||
cc9ee605 | 2236 | o->newline() << "atomic_dec (&c->busy);"; |
98afd80e FCE |
2237 | o->newline(-1) << "}" << endl; |
2238 | } | |
2239 | ||
2240 | ||
2241 | struct timer_builder: public derived_probe_builder | |
2242 | { | |
2243 | timer_builder() {} | |
2244 | virtual void build(systemtap_session & sess, | |
2245 | probe * base, | |
2246 | probe_point * location, | |
2247 | std::map<std::string, literal *> const & parameters, | |
2248 | vector<probe *> &, | |
2249 | vector<derived_probe *> & finished_results) | |
2250 | { | |
2251 | int64_t jn, rn; | |
2252 | bool jn_p, rn_p; | |
2253 | ||
2254 | jn_p = get_param (parameters, "jiffies", jn); | |
2255 | rn_p = get_param (parameters, "randomize", rn); | |
2256 | ||
2257 | finished_results.push_back(new timer_derived_probe(base, location, | |
2258 | jn, rn_p ? rn : 0)); | |
2259 | } | |
2260 | }; | |
2261 | ||
2262 | ||
2263 | ||
b55bc428 | 2264 | // ------------------------------------------------------------------------ |
bd2b1e68 | 2265 | // Standard tapset registry. |
b55bc428 FCE |
2266 | // ------------------------------------------------------------------------ |
2267 | ||
7a053d3b | 2268 | void |
f8220a7b | 2269 | register_standard_tapsets(systemtap_session & s) |
b55bc428 | 2270 | { |
bd2b1e68 | 2271 | // Rudimentary binders for begin and end targets |
f8220a7b GH |
2272 | s.pattern_root->bind("begin")->bind(new be_builder(true)); |
2273 | s.pattern_root->bind("end")->bind(new be_builder(false)); | |
98afd80e FCE |
2274 | s.pattern_root->bind("timer")->bind_num("jiffies")->bind(new timer_builder()); |
2275 | s.pattern_root->bind("timer")->bind_num("jiffies")->bind_num("randomize")->bind(new timer_builder()); | |
b98a8d73 | 2276 | |
14d0763f | 2277 | // kernel/module parts |
f8220a7b | 2278 | dwarf_derived_probe::register_patterns(s.pattern_root); |
b55bc428 | 2279 | } |