]>
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" { | |
25 | #include <elfutils/libdwfl.h> | |
7a053d3b | 26 | #include <elfutils/libdw.h> |
77de5e9e GH |
27 | #include <dwarf.h> |
28 | #include <elf.h> | |
29 | #include <obstack.h> | |
30 | #include "loc2c.h" | |
4b1ad75e RM |
31 | |
32 | #define __STDC_FORMAT_MACROS | |
33 | #include <inttypes.h> | |
bd2b1e68 | 34 | } |
77de5e9e | 35 | |
bd2b1e68 | 36 | #include <fnmatch.h> |
56e12059 FCE |
37 | |
38 | using namespace std; | |
39 | ||
b55bc428 FCE |
40 | // ------------------------------------------------------------------------ |
41 | // begin/end probes are run right during registration / deregistration | |
56e12059 FCE |
42 | // ------------------------------------------------------------------------ |
43 | ||
b55bc428 FCE |
44 | struct be_derived_probe: public derived_probe |
45 | { | |
46 | bool begin; | |
47 | be_derived_probe (probe* p, bool b): derived_probe (p), begin (b) {} | |
48 | be_derived_probe (probe* p, probe_point* l, bool b): | |
49 | derived_probe (p, l), begin (b) {} | |
56e12059 | 50 | |
b55bc428 FCE |
51 | void emit_registrations (translator_output* o, unsigned i); |
52 | void emit_deregistrations (translator_output* o, unsigned i); | |
53 | void emit_probe_entries (translator_output* o, unsigned i); | |
54 | }; | |
55 | ||
98afd80e FCE |
56 | |
57 | struct be_builder: public derived_probe_builder | |
b55bc428 FCE |
58 | { |
59 | bool begin; | |
60 | be_builder(bool b) : begin(b) {} | |
5227f1ea | 61 | virtual void build(systemtap_session & sess, |
7a053d3b | 62 | probe * base, |
20c6c071 GH |
63 | probe_point * location, |
64 | std::map<std::string, literal *> const & parameters, | |
65 | vector<probe *> & results_to_expand_further, | |
66 | vector<derived_probe *> & finished_results) | |
b55bc428 | 67 | { |
20c6c071 | 68 | finished_results.push_back(new be_derived_probe(base, location, begin)); |
b55bc428 | 69 | } |
b55bc428 | 70 | }; |
56e12059 FCE |
71 | |
72 | ||
7a053d3b | 73 | void |
56e12059 FCE |
74 | be_derived_probe::emit_registrations (translator_output* o, unsigned j) |
75 | { | |
76 | if (begin) | |
77 | for (unsigned i=0; i<locations.size(); i++) | |
bfb3d2d2 | 78 | o->newline() << "enter_" << j << "_" << i << " ();"; |
56e12059 FCE |
79 | } |
80 | ||
81 | ||
7a053d3b | 82 | void |
56e12059 FCE |
83 | be_derived_probe::emit_deregistrations (translator_output* o, unsigned j) |
84 | { | |
bfb3d2d2 | 85 | if (!begin) |
56e12059 | 86 | for (unsigned i=0; i<locations.size(); i++) |
bfb3d2d2 | 87 | o->newline() << "enter_" << j << "_" << i << " ();"; |
56e12059 FCE |
88 | } |
89 | ||
90 | ||
91 | void | |
92 | be_derived_probe::emit_probe_entries (translator_output* o, unsigned j) | |
93 | { | |
94 | for (unsigned i=0; i<locations.size(); i++) | |
95 | { | |
96 | probe_point *l = locations[i]; | |
97 | o->newline() << "/* location " << i << ": " << *l << " */"; | |
f4b28491 FCE |
98 | o->newline() << "static void enter_" << j << "_" << i << " (void);"; |
99 | o->newline() << "void enter_" << j << "_" << i << " () {"; | |
bfb3d2d2 | 100 | |
7a053d3b | 101 | // While begin/end probes are executed single-threaded, we |
bfb3d2d2 FCE |
102 | // still code defensively and use a per-cpu context. |
103 | o->newline(1) << "struct context* c = & contexts [smp_processor_id()];"; | |
104 | ||
105 | // A precondition for running a probe handler is that we're in STARTING | |
106 | // or STOPPING state (not ERROR), and that no one else is already using | |
107 | // this context. | |
108 | o->newline() << "if (atomic_read (&session_state) != "; | |
109 | if (begin) o->line() << "STAP_SESSION_STARTING)"; | |
110 | else o->line() << "STAP_SESSION_STOPPING)"; | |
111 | o->newline(1) << "return;"; | |
112 | o->newline(-1) << "if (c->busy) {"; | |
113 | o->newline(1) << "printk (KERN_ERR \"probe reentrancy\");"; | |
114 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
115 | o->newline() << "return;"; | |
116 | o->newline(-1) << "}"; | |
117 | o->newline(); | |
7a053d3b | 118 | |
56e12059 | 119 | o->newline() << "c->busy ++;"; |
bfb3d2d2 | 120 | o->newline() << "mb ();"; // for smp |
5e309481 | 121 | o->newline() << "c->last_error = 0;"; |
56e12059 | 122 | o->newline() << "c->nesting = 0;"; |
3d49c615 | 123 | o->newline() << "c->regs = 0;"; |
5e309481 | 124 | o->newline() << "c->actioncount = 0;"; |
bfb3d2d2 | 125 | |
56e12059 FCE |
126 | // NB: locals are initialized by probe function itself |
127 | o->newline() << "probe_" << j << " (c);"; | |
bfb3d2d2 | 128 | |
5e309481 FCE |
129 | o->newline() << "if (c->last_error) {"; |
130 | o->newline(1) << "if (c->last_error[0]) _stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; | |
131 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
bfb3d2d2 FCE |
132 | o->newline(-1) << "}"; |
133 | ||
56e12059 | 134 | o->newline() << "c->busy --;"; |
bfb3d2d2 | 135 | o->newline() << "mb ();"; |
56e12059 FCE |
136 | o->newline(-1) << "}" << endl; |
137 | } | |
138 | } | |
139 | ||
140 | ||
141 | // ------------------------------------------------------------------------ | |
bd2b1e68 | 142 | // Dwarf derived probes. |
b55bc428 | 143 | // ------------------------------------------------------------------------ |
bd2b1e68 | 144 | |
c239d28c GH |
145 | static string TOK_PROCESS("process"); |
146 | static string TOK_KERNEL("kernel"); | |
147 | static string TOK_MODULE("module"); | |
148 | ||
149 | static string TOK_FUNCTION("function"); | |
150 | static string TOK_RETURN("return"); | |
151 | static string TOK_CALLEES("callees"); | |
152 | ||
153 | static string TOK_STATEMENT("statement"); | |
154 | static string TOK_LABEL("label"); | |
155 | static string TOK_RELATIVE("relative"); | |
156 | ||
59ff2773 FCE |
157 | |
158 | // XXX: should standardize to these functions throughout translator | |
159 | ||
7a053d3b | 160 | template <typename OUT, typename IN> inline OUT |
77de5e9e GH |
161 | lex_cast(IN const & in) |
162 | { | |
163 | stringstream ss; | |
164 | OUT out; | |
165 | if (!(ss << in && ss >> out)) | |
166 | throw runtime_error("bad lexical cast"); | |
167 | return out; | |
168 | } | |
169 | ||
59ff2773 FCE |
170 | template <typename OUT, typename IN> inline OUT |
171 | lex_cast_hex(IN const & in) | |
172 | { | |
173 | stringstream ss; | |
174 | OUT out; | |
175 | if (!(ss << hex << showbase << in && ss >> out)) | |
176 | throw runtime_error("bad lexical cast"); | |
177 | return out; | |
178 | } | |
179 | ||
180 | ||
181 | ||
bd2b1e68 GH |
182 | // Helper for dealing with selected portions of libdwfl in a more readable |
183 | // fashion, and with specific cleanup / checking / logging options. | |
184 | ||
91eefb1c GH |
185 | static const char * |
186 | dwarf_diename_integrate (Dwarf_Die *die) | |
187 | { | |
188 | Dwarf_Attribute attr_mem; | |
189 | return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); | |
190 | } | |
191 | ||
bd2b1e68 GH |
192 | struct |
193 | dwflpp | |
194 | { | |
5227f1ea | 195 | systemtap_session & sess; |
bd2b1e68 GH |
196 | Dwfl * dwfl; |
197 | ||
198 | // These are "current" values we focus on. | |
199 | Dwfl_Module * module; | |
200 | Dwarf * module_dwarf; | |
201 | Dwarf_Addr module_bias; | |
50e0d793 GH |
202 | |
203 | // These describe the current module's PC address range | |
204 | Dwarf_Addr module_start; | |
205 | Dwarf_Addr module_end; | |
206 | ||
bd2b1e68 GH |
207 | Dwarf_Die * cu; |
208 | Dwarf_Func * function; | |
209 | ||
210 | string module_name; | |
211 | string cu_name; | |
212 | string function_name; | |
213 | ||
50e0d793 | 214 | |
7a053d3b | 215 | string const default_name(char const * in, |
bd2b1e68 GH |
216 | char const * type) |
217 | { | |
7a053d3b | 218 | if (in) |
bd2b1e68 | 219 | return in; |
24cb178f | 220 | if (false && sess.verbose) |
bd2b1e68 | 221 | clog << "WARNING: no name found for " << type << endl; |
a229fcd7 | 222 | return string(""); |
bd2b1e68 GH |
223 | } |
224 | ||
50e0d793 | 225 | |
5227f1ea GH |
226 | void get_module_dwarf() |
227 | { | |
228 | if (!module_dwarf) | |
229 | module_dwarf = dwfl_module_getdwarf(module, &module_bias); | |
a229fcd7 | 230 | if (module_dwarf == NULL && sess.verbose) |
d9b516ca | 231 | clog << "WARNING: dwfl_module_getdwarf() : " |
a229fcd7 | 232 | << dwfl_errmsg (dwfl_errno ()) << endl; |
5227f1ea GH |
233 | } |
234 | ||
50e0d793 | 235 | |
bd2b1e68 GH |
236 | void focus_on_module(Dwfl_Module * m) |
237 | { | |
238 | assert(m); | |
239 | module = m; | |
7a053d3b | 240 | module_name = default_name(dwfl_module_info(module, NULL, |
50e0d793 | 241 | &module_start, &module_end, |
bd2b1e68 GH |
242 | NULL, NULL, |
243 | NULL, NULL), | |
244 | "module"); | |
50e0d793 GH |
245 | |
246 | // Reset existing pointers and names | |
247 | ||
248 | module_dwarf = NULL; | |
249 | ||
a229fcd7 | 250 | cu_name.clear(); |
50e0d793 GH |
251 | cu = NULL; |
252 | ||
a229fcd7 | 253 | function_name.clear(); |
50e0d793 | 254 | function = NULL; |
bd2b1e68 GH |
255 | } |
256 | ||
50e0d793 | 257 | |
bd2b1e68 GH |
258 | void focus_on_cu(Dwarf_Die * c) |
259 | { | |
260 | assert(c); | |
50e0d793 GH |
261 | assert(module); |
262 | ||
bd2b1e68 | 263 | cu = c; |
50e0d793 GH |
264 | cu_name = default_name(dwarf_diename(c), "CU"); |
265 | ||
266 | // Reset existing pointers and names | |
a229fcd7 | 267 | function_name.clear(); |
50e0d793 | 268 | function = NULL; |
bd2b1e68 GH |
269 | } |
270 | ||
50e0d793 | 271 | |
bd2b1e68 GH |
272 | void focus_on_function(Dwarf_Func * f) |
273 | { | |
274 | assert(f); | |
50e0d793 GH |
275 | assert(module); |
276 | assert(cu); | |
277 | ||
bd2b1e68 | 278 | function = f; |
7a053d3b | 279 | function_name = default_name(dwarf_func_name(function), |
bd2b1e68 | 280 | "function"); |
bd2b1e68 GH |
281 | } |
282 | ||
50e0d793 | 283 | |
bd2b1e68 GH |
284 | void focus_on_module_containing_global_address(Dwarf_Addr a) |
285 | { | |
286 | assert(dwfl); | |
50e0d793 | 287 | cu = NULL; |
24cb178f | 288 | if (false && sess.verbose) |
bd2b1e68 GH |
289 | clog << "focusing on module containing global addr " << a << endl; |
290 | focus_on_module(dwfl_addrmodule(dwfl, a)); | |
291 | } | |
292 | ||
50e0d793 GH |
293 | |
294 | void focus_on_cu_containing_global_address(Dwarf_Addr a) | |
bd2b1e68 | 295 | { |
bd2b1e68 | 296 | Dwarf_Addr bias; |
50e0d793 | 297 | assert(dwfl); |
5227f1ea | 298 | get_module_dwarf(); |
aab2b35f | 299 | if (false && sess.verbose) |
50e0d793 | 300 | clog << "focusing on cu containing global addr " << a << endl; |
bd2b1e68 GH |
301 | focus_on_cu(dwfl_module_addrdie(module, a, &bias)); |
302 | assert(bias == module_bias); | |
303 | } | |
304 | ||
50e0d793 GH |
305 | |
306 | void focus_on_cu_containing_module_address(Dwarf_Addr a) | |
bd2b1e68 | 307 | { |
50e0d793 | 308 | focus_on_cu_containing_global_address(module_address_to_global(a)); |
bd2b1e68 GH |
309 | } |
310 | ||
50e0d793 | 311 | |
bd2b1e68 GH |
312 | Dwarf_Addr module_address_to_global(Dwarf_Addr a) |
313 | { | |
50e0d793 | 314 | assert(dwfl); |
bd2b1e68 | 315 | assert(module); |
5227f1ea | 316 | get_module_dwarf(); |
c239d28c GH |
317 | if (module_name == TOK_KERNEL) |
318 | return a; | |
319 | ||
db520b00 FCE |
320 | if (false && sess.verbose) |
321 | clog << "module addr " << hex << a | |
322 | << " + module start " << module_start | |
323 | << " -> global addr " << (a + module_start) << dec << endl; | |
50e0d793 | 324 | return a + module_start; |
bd2b1e68 GH |
325 | } |
326 | ||
50e0d793 | 327 | |
bd2b1e68 GH |
328 | Dwarf_Addr global_address_to_module(Dwarf_Addr a) |
329 | { | |
330 | assert(module); | |
5227f1ea | 331 | get_module_dwarf(); |
db520b00 FCE |
332 | if (false && sess.verbose) |
333 | clog << "global addr " << a | |
334 | << " - module start " << hex << module_start | |
335 | << " -> module addr " << (a - module_start) << dec << endl; | |
bd2b1e68 GH |
336 | return a - module_bias; |
337 | } | |
338 | ||
339 | ||
340 | bool module_name_matches(string pattern) | |
341 | { | |
342 | assert(module); | |
343 | bool t = (fnmatch(pattern.c_str(), module_name.c_str(), 0) == 0); | |
24cb178f | 344 | if (t && sess.verbose) |
bd2b1e68 | 345 | clog << "pattern '" << pattern << "' " |
24cb178f | 346 | << "matches " |
bd2b1e68 GH |
347 | << "module '" << module_name << "'" << endl; |
348 | return t; | |
349 | } | |
350 | ||
50e0d793 | 351 | |
bd2b1e68 GH |
352 | bool function_name_matches(string pattern) |
353 | { | |
354 | assert(function); | |
355 | bool t = (fnmatch(pattern.c_str(), function_name.c_str(), 0) == 0); | |
24cb178f | 356 | if (t && sess.verbose) |
bd2b1e68 | 357 | clog << "pattern '" << pattern << "' " |
24cb178f | 358 | << "matches " |
bd2b1e68 GH |
359 | << "function '" << function_name << "'" << endl; |
360 | return t; | |
361 | } | |
362 | ||
50e0d793 | 363 | |
bd2b1e68 GH |
364 | bool cu_name_matches(string pattern) |
365 | { | |
366 | assert(cu); | |
367 | bool t = (fnmatch(pattern.c_str(), cu_name.c_str(), 0) == 0); | |
24cb178f | 368 | if (t && sess.verbose) |
bd2b1e68 | 369 | clog << "pattern '" << pattern << "' " |
24cb178f | 370 | << "matches " |
bd2b1e68 GH |
371 | << "CU '" << cu_name << "'" << endl; |
372 | return t; | |
373 | } | |
374 | ||
50e0d793 | 375 | |
d8067b24 | 376 | void dwflpp_assert(string desc, int rc) // NB: "rc == 0" means OK in this case |
bd2b1e68 | 377 | { |
d8067b24 FCE |
378 | string msg = "dwfl failure (" + desc + "): "; |
379 | if (rc < 0) msg += dwfl_errmsg (rc); | |
380 | else if (rc > 0) msg += strerror (rc); | |
bd2b1e68 | 381 | if (rc != 0) |
d8067b24 | 382 | throw semantic_error (msg); |
bd2b1e68 GH |
383 | } |
384 | ||
50e0d793 | 385 | |
5227f1ea | 386 | dwflpp(systemtap_session & sess) |
bd2b1e68 | 387 | : |
5227f1ea | 388 | sess(sess), |
bd2b1e68 GH |
389 | dwfl(NULL), |
390 | module(NULL), | |
391 | module_dwarf(NULL), | |
392 | module_bias(0), | |
50e0d793 GH |
393 | module_start(0), |
394 | module_end(0), | |
bd2b1e68 GH |
395 | cu(NULL), |
396 | function(NULL) | |
397 | {} | |
7a053d3b | 398 | |
50e0d793 | 399 | |
bd2b1e68 GH |
400 | void setup(bool kernel) |
401 | { | |
b5d77020 FCE |
402 | // XXX: this is where the session -R parameter could come in |
403 | static char* debuginfo_path = "-:.debug:/usr/lib/debug"; | |
404 | ||
bd2b1e68 GH |
405 | static const Dwfl_Callbacks proc_callbacks = |
406 | { | |
407 | dwfl_linux_proc_find_elf, | |
408 | dwfl_standard_find_debuginfo, | |
409 | NULL, | |
b5d77020 | 410 | & debuginfo_path |
bd2b1e68 | 411 | }; |
7a053d3b | 412 | |
bd2b1e68 GH |
413 | static const Dwfl_Callbacks kernel_callbacks = |
414 | { | |
415 | dwfl_linux_kernel_find_elf, | |
416 | dwfl_standard_find_debuginfo, | |
417 | dwfl_linux_kernel_module_section_address, | |
b5d77020 | 418 | & debuginfo_path |
bd2b1e68 GH |
419 | }; |
420 | ||
421 | if (kernel) | |
422 | { | |
423 | dwfl = dwfl_begin(&kernel_callbacks); | |
424 | if (!dwfl) | |
425 | throw semantic_error("cannot open dwfl"); | |
426 | dwfl_report_begin(dwfl); | |
d8067b24 FCE |
427 | // XXX: if we have only kernel.* probe points, we shouldn't waste time |
428 | // looking for module debug-info (and vice versa). | |
429 | dwflpp_assert("find kernel debug-info", dwfl_linux_kernel_report_kernel(dwfl)); | |
430 | dwflpp_assert("find modules debug-info", dwfl_linux_kernel_report_modules(dwfl)); | |
bd2b1e68 GH |
431 | } |
432 | else | |
433 | { | |
434 | dwfl = dwfl_begin(&proc_callbacks); | |
435 | dwfl_report_begin(dwfl); | |
436 | if (!dwfl) | |
437 | throw semantic_error("cannot open dwfl"); | |
438 | // XXX: Find pids or processes, do userspace stuff. | |
439 | } | |
440 | ||
377b8831 | 441 | dwflpp_assert("report_end", dwfl_report_end(dwfl, NULL, NULL)); |
bd2b1e68 GH |
442 | } |
443 | ||
444 | void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, | |
445 | const char *, Dwarf_Addr, | |
77de5e9e | 446 | void *), |
bd2b1e68 GH |
447 | void * data) |
448 | { | |
bd2b1e68 GH |
449 | ptrdiff_t off = 0; |
450 | do | |
451 | { | |
77de5e9e | 452 | off = dwfl_getmodules (dwfl, callback, data, off); |
bd2b1e68 GH |
453 | } |
454 | while (off > 0); | |
377b8831 | 455 | dwflpp_assert("getdwarf", off); |
bd2b1e68 GH |
456 | } |
457 | ||
7a053d3b | 458 | void iterate_over_cus (int (*callback)(Dwarf_Die * die, void * arg), |
bd2b1e68 GH |
459 | void * data) |
460 | { | |
5227f1ea GH |
461 | get_module_dwarf(); |
462 | ||
bd2b1e68 GH |
463 | if (!module_dwarf) |
464 | { | |
465 | cerr << "WARNING: no dwarf info found for module " << module_name << endl; | |
466 | return; | |
467 | } | |
468 | ||
bd2b1e68 GH |
469 | Dwarf *dw = module_dwarf; |
470 | Dwarf_Off off = 0; | |
471 | size_t cuhl; | |
472 | Dwarf_Off noff; | |
473 | while (dwarf_nextcu(dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) | |
7a053d3b | 474 | { |
bd2b1e68 GH |
475 | Dwarf_Die die_mem; |
476 | Dwarf_Die *die; | |
477 | die = dwarf_offdie(dw, off + cuhl, &die_mem); | |
478 | if (callback(die, data) != DWARF_CB_OK) | |
479 | break; | |
480 | off = noff; | |
481 | } | |
482 | } | |
483 | ||
484 | void iterate_over_functions(int (* callback)(Dwarf_Func * func, void * arg), | |
485 | void * data) | |
486 | { | |
487 | assert(module); | |
488 | assert(cu); | |
bd2b1e68 GH |
489 | dwarf_getfuncs(cu, callback, data, 0); |
490 | } | |
491 | ||
492 | bool function_entrypc(Dwarf_Addr * addr) | |
493 | { | |
494 | return (dwarf_func_entrypc(function, addr) == 0); | |
495 | } | |
496 | ||
497 | bool function_includes_global_addr(Dwarf_Addr addr) | |
498 | { | |
499 | assert(module_dwarf); | |
500 | assert(cu); | |
501 | assert(function); | |
502 | Dwarf_Addr lo, hi; | |
503 | if (dwarf_func_lowpc(function, &lo) != 0) | |
504 | { | |
db520b00 | 505 | if (false && sess.verbose) |
bd2b1e68 GH |
506 | clog << "WARNING: cannot find low PC value for function " << function_name << endl; |
507 | return false; | |
508 | } | |
7a053d3b | 509 | |
bd2b1e68 GH |
510 | if (dwarf_func_highpc(function, &hi) != 0) |
511 | { | |
db520b00 | 512 | if (false && sess.verbose) |
bd2b1e68 GH |
513 | clog << "WARNING: cannot find high PC value for function " << function_name << endl; |
514 | return false; | |
515 | } | |
7a053d3b | 516 | |
bd2b1e68 | 517 | bool t = lo <= addr && addr <= hi; |
db520b00 FCE |
518 | if (t && sess.verbose) |
519 | clog << "function " << function_name << " = [" << hex << lo << "," << hi << "] " | |
520 | << "contains global addr " << addr << dec << endl; | |
bd2b1e68 GH |
521 | return t; |
522 | } | |
523 | ||
bd2b1e68 GH |
524 | |
525 | Dwarf_Addr global_addr_of_line_in_cu(int line) | |
526 | { | |
527 | Dwarf_Lines * lines; | |
bd2b1e68 | 528 | Dwarf_Addr addr; |
c239d28c GH |
529 | size_t nlines; |
530 | int best_line = -1; | |
bd2b1e68 GH |
531 | |
532 | assert(module); | |
533 | assert(cu); | |
377b8831 | 534 | dwflpp_assert("getsrclines", dwarf_getsrclines(cu, &lines, &nlines)); |
50e0d793 GH |
535 | |
536 | for (size_t i = 0; i < nlines; ++i) | |
537 | { | |
538 | int curr_line; | |
539 | Dwarf_Line * line_rec = dwarf_onesrcline(lines, i); | |
d9b516ca | 540 | dwflpp_assert("lineno", dwarf_lineno (line_rec, &curr_line)); |
c239d28c GH |
541 | |
542 | if (curr_line >= line && (best_line == -1 || curr_line < best_line)) | |
50e0d793 | 543 | { |
c239d28c | 544 | best_line = curr_line; |
50e0d793 | 545 | dwflpp_assert("lineaddr", dwarf_lineaddr(line_rec, &addr)); |
50e0d793 GH |
546 | } |
547 | } | |
d9b516ca | 548 | |
c239d28c | 549 | if (best_line != -1) |
d9b516ca | 550 | { |
c239d28c GH |
551 | if (sess.verbose) |
552 | clog << "line " << best_line | |
553 | << " (given query line " << line << ")" | |
554 | << " of CU " << cu_name | |
db520b00 FCE |
555 | << " has module address " << hex << addr |
556 | << " in " << module_name << dec << endl; | |
c239d28c GH |
557 | return module_address_to_global(addr); |
558 | } | |
50e0d793 | 559 | |
5227f1ea | 560 | if (sess.verbose) |
d9b516ca | 561 | clog << "WARNING: could not find line " << line |
50e0d793 GH |
562 | << " in CU " << cu_name << endl; |
563 | return 0; | |
564 | } | |
565 | ||
566 | ||
567 | bool function_prologue_end(Dwarf_Addr * addr) | |
568 | { | |
50e0d793 GH |
569 | Dwarf_Lines * lines; |
570 | size_t nlines; | |
571 | ||
572 | assert(addr); | |
573 | dwflpp_assert("getsrclines", dwarf_getsrclines(cu, &lines, &nlines)); | |
574 | ||
575 | ||
576 | // If GCC output the right information we would do this: | |
577 | /* | |
578 | ||
579 | for (size_t i = 0; i < nlines; ++i) | |
580 | { | |
581 | bool flag; | |
582 | Dwarf_Line * line_rec = dwarf_onesrcline(lines, i); | |
d9b516ca | 583 | |
50e0d793 GH |
584 | dwflpp_assert("lineprologueend", dwarf_lineprologueend (line_rec, &flag)); |
585 | ||
586 | if (sess.verbose) | |
d9b516ca RM |
587 | clog << "checked line record " << i |
588 | << ", is " << (flag ? "" : " not") | |
50e0d793 GH |
589 | << " prologue end" << endl; |
590 | ||
591 | if (flag) | |
592 | { | |
593 | dwflpp_assert("lineaddr", dwarf_lineaddr(line_rec, addr)); | |
594 | return true; | |
595 | } | |
596 | } | |
597 | return false; | |
598 | */ | |
599 | ||
600 | // Since GCC does not output the right information, we do this: | |
d9b516ca | 601 | |
50e0d793 GH |
602 | Dwarf_Addr entrypc; |
603 | if (!function_entrypc(&entrypc)) | |
604 | return false; | |
605 | ||
606 | bool choose_next_line = false; | |
607 | ||
608 | for (size_t i = 0; i < nlines; ++i) | |
609 | { | |
610 | Dwarf_Addr line_addr; | |
611 | Dwarf_Line * line_rec = dwarf_onesrcline(lines, i); | |
612 | dwflpp_assert("lineaddr", dwarf_lineaddr(line_rec, &line_addr)); | |
613 | if (choose_next_line) | |
614 | { | |
615 | *addr = line_addr; | |
616 | if (sess.verbose) | |
617 | clog << "function " << function_name | |
c0de7a8d FCE |
618 | << " entrypc: " << hex << entrypc |
619 | << " prologue-end: " << line_addr << dec | |
50e0d793 GH |
620 | << endl; |
621 | return true; | |
622 | } | |
623 | else if (line_addr == entrypc) | |
624 | choose_next_line = true; | |
625 | } | |
626 | return false; | |
bd2b1e68 GH |
627 | } |
628 | ||
e36387d7 RM |
629 | static void loc2c_error (void *arg, const char *fmt, ...) |
630 | { | |
631 | char *msg = NULL; | |
632 | va_list ap; | |
633 | va_start (ap, fmt); | |
634 | vasprintf (&msg, fmt, ap); | |
635 | va_end (ap); | |
636 | throw semantic_error (msg); | |
637 | } | |
bd2b1e68 | 638 | |
4b1ad75e RM |
639 | static void loc2c_emit_address (void *arg, struct obstack *pool, |
640 | Dwarf_Addr address) | |
641 | { | |
642 | dwflpp *dwfl = (dwflpp *) arg; | |
643 | obstack_printf (pool, "%#" PRIx64 "UL /* hard-coded %s address */", | |
644 | address, dwfl_module_info (dwfl->module, NULL, NULL, NULL, | |
645 | NULL, NULL, NULL, NULL)); | |
646 | } | |
647 | ||
77de5e9e | 648 | string literal_stmt_for_local(Dwarf_Addr pc, |
91eefb1c | 649 | string const & local, |
d9b516ca | 650 | vector<pair<target_symbol::component_type, |
91eefb1c | 651 | std::string> > const & components) |
77de5e9e GH |
652 | { |
653 | assert (cu); | |
654 | ||
655 | Dwarf_Die *scopes; | |
656 | Dwarf_Die vardie; | |
657 | ||
7a053d3b | 658 | int nscopes = dwarf_getscopes (cu, pc, &scopes); |
77de5e9e GH |
659 | if (nscopes == 0) |
660 | { | |
7a053d3b | 661 | throw semantic_error ("unable to find any scopes containing " |
59ff2773 | 662 | + lex_cast_hex<string>(pc) |
77de5e9e GH |
663 | + " while searching for local '" + local + "'"); |
664 | } | |
7a053d3b | 665 | |
77de5e9e | 666 | int declaring_scope = dwarf_getscopevar (scopes, nscopes, |
7a053d3b RM |
667 | local.c_str(), |
668 | 0, NULL, 0, 0, | |
669 | &vardie); | |
77de5e9e GH |
670 | if (declaring_scope < 0) |
671 | { | |
672 | throw semantic_error ("unable to find local '" + local + "'" | |
59ff2773 | 673 | + " near pc " + lex_cast_hex<string>(pc)); |
77de5e9e | 674 | } |
7a053d3b | 675 | |
77de5e9e GH |
676 | Dwarf_Attribute fb_attr_mem, *fb_attr = NULL; |
677 | for (int inner = 0; inner < nscopes; ++inner) | |
678 | { | |
679 | switch (dwarf_tag (&scopes[inner])) | |
680 | { | |
681 | default: | |
682 | continue; | |
683 | case DW_TAG_subprogram: | |
684 | case DW_TAG_entry_point: | |
685 | case DW_TAG_inlined_subroutine: /* XXX */ | |
686 | if (inner >= declaring_scope) | |
687 | fb_attr = dwarf_attr_integrate (&scopes[inner], | |
688 | DW_AT_frame_base, | |
689 | &fb_attr_mem); | |
690 | break; | |
691 | } | |
692 | } | |
693 | ||
694 | if (sess.verbose) | |
7a053d3b | 695 | clog << "finding location for local '" << local |
db520b00 FCE |
696 | << "' near address " << hex << pc |
697 | << ", module bias " << module_bias << dec | |
77de5e9e | 698 | << endl; |
7a053d3b RM |
699 | |
700 | Dwarf_Attribute attr_mem; | |
77de5e9e GH |
701 | if (dwarf_attr_integrate (&vardie, DW_AT_location, &attr_mem) == NULL) |
702 | throw semantic_error("failed to retrieve location " | |
703 | "attribute for local '" + local + "'"); | |
7a053d3b | 704 | |
77de5e9e GH |
705 | #define obstack_chunk_alloc malloc |
706 | #define obstack_chunk_free free | |
7a053d3b | 707 | |
77de5e9e | 708 | struct obstack pool; |
7a053d3b | 709 | obstack_init (&pool); |
77de5e9e | 710 | struct location *tail = NULL; |
e36387d7 | 711 | struct location *head = c_translate_location (&pool, &loc2c_error, this, |
4b1ad75e | 712 | &loc2c_emit_address, |
e36387d7 | 713 | 1, module_bias, |
77de5e9e GH |
714 | &attr_mem, pc, |
715 | &tail, fb_attr); | |
716 | ||
d9b516ca | 717 | if (dwarf_attr_integrate (&vardie, DW_AT_type, &attr_mem) == NULL) |
77de5e9e GH |
718 | throw semantic_error("failed to retrieve type " |
719 | "attribute for local '" + local + "'"); | |
720 | ||
d9b516ca RM |
721 | Dwarf_Die die_mem, *die = &vardie; |
722 | unsigned i = 0; | |
723 | while (i < components.size()) | |
724 | { | |
725 | die = dwarf_formref_die (&attr_mem, &die_mem); | |
726 | const int typetag = dwarf_tag (die); | |
727 | switch (typetag) | |
728 | { | |
729 | case DW_TAG_typedef: | |
730 | /* Just iterate on the referent type. */ | |
731 | break; | |
91eefb1c | 732 | |
d9b516ca RM |
733 | case DW_TAG_pointer_type: |
734 | if (components[i].first == target_symbol::comp_literal_array_index) | |
735 | goto subscript; | |
91eefb1c | 736 | |
d9b516ca RM |
737 | c_translate_pointer (&pool, 1, module_bias, die, &tail); |
738 | break; | |
91eefb1c | 739 | |
d9b516ca RM |
740 | case DW_TAG_array_type: |
741 | if (components[i].first == target_symbol::comp_literal_array_index) | |
742 | { | |
743 | subscript: | |
744 | c_translate_array (&pool, 1, module_bias, die, &tail, | |
745 | NULL, lex_cast<Dwarf_Word>(components[i].second)); | |
746 | ++i; | |
747 | } | |
748 | else | |
749 | throw semantic_error("bad field '" | |
750 | + components[i].second | |
751 | + "' for array type"); | |
752 | break; | |
91eefb1c | 753 | |
d9b516ca RM |
754 | case DW_TAG_structure_type: |
755 | case DW_TAG_union_type: | |
756 | switch (dwarf_child (die, &die_mem)) | |
757 | { | |
758 | case 1: /* No children. */ | |
759 | throw semantic_error ("empty struct " | |
760 | + string (dwarf_diename_integrate (die) ?: "<anonymous>")); | |
761 | break; | |
762 | case -1: /* Error. */ | |
763 | default: /* Shouldn't happen */ | |
764 | throw semantic_error (string (typetag == DW_TAG_union_type ? "union" : "struct") | |
765 | + string (dwarf_diename_integrate (die) ?: "<anonymous>") | |
766 | + string (dwarf_errmsg (-1))); | |
767 | break; | |
768 | ||
769 | case 0: | |
770 | break; | |
771 | } | |
772 | ||
773 | while (dwarf_tag (die) != DW_TAG_member | |
774 | || ({ const char *member = dwarf_diename_integrate (die); | |
775 | member == NULL || string(member) != components[i].second; })) | |
776 | if (dwarf_siblingof (die, &die_mem) != 0) | |
777 | throw semantic_error ("field name " + components[i].second + " not found"); | |
778 | ||
779 | if (dwarf_attr_integrate (die, DW_AT_data_member_location, | |
780 | &attr_mem) == NULL) | |
781 | { | |
782 | /* Union members don't usually have a location, | |
783 | but just use the containing union's location. */ | |
784 | if (typetag != DW_TAG_union_type) | |
785 | throw semantic_error ("no location for field " | |
786 | + components[i].second | |
787 | + " :" + string(dwarf_errmsg (-1))); | |
788 | } | |
789 | else | |
4b1ad75e | 790 | c_translate_location (&pool, NULL, NULL, NULL, 1, |
e36387d7 | 791 | module_bias, &attr_mem, pc, |
d9b516ca RM |
792 | &tail, NULL); |
793 | ++i; | |
794 | break; | |
795 | ||
796 | case DW_TAG_base_type: | |
797 | throw semantic_error ("field " | |
798 | + components[i].second | |
799 | + " vs base type " | |
800 | + string(dwarf_diename_integrate (die) ?: "<anonymous type>")); | |
801 | break; | |
802 | case -1: | |
803 | throw semantic_error ("cannot find type: " + string(dwarf_errmsg (-1))); | |
804 | break; | |
805 | ||
806 | default: | |
807 | throw semantic_error (string(dwarf_diename_integrate (die) ?: "<anonymous type>") | |
808 | + ": unexpected type tag " | |
809 | + lex_cast<string>(dwarf_tag (die))); | |
810 | break; | |
811 | } | |
812 | ||
813 | /* Now iterate on the type in DIE's attribute. */ | |
814 | if (dwarf_attr_integrate (die, DW_AT_type, &attr_mem) == NULL) | |
815 | throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1))); | |
816 | } | |
91eefb1c | 817 | |
d9b516ca RM |
818 | /* Fetch the type DIE corresponding to the final location to be accessed. |
819 | It must be a base type or a typedef for one. */ | |
820 | ||
821 | Dwarf_Die typedie_mem; | |
822 | Dwarf_Die *typedie; | |
823 | int typetag; | |
824 | while (1) | |
825 | { | |
826 | typedie = dwarf_formref_die (&attr_mem, &typedie_mem); | |
827 | if (typedie == NULL) | |
828 | throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1))); | |
829 | typetag = dwarf_tag (typedie); | |
830 | if (typetag != DW_TAG_typedef) | |
91eefb1c | 831 | break; |
d9b516ca RM |
832 | if (dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem) == NULL) |
833 | throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1))); | |
834 | } | |
91eefb1c | 835 | |
d9b516ca RM |
836 | if (typetag != DW_TAG_base_type) |
837 | throw semantic_error ("target location not a base type"); | |
91eefb1c | 838 | |
d9b516ca | 839 | c_translate_fetch (&pool, 1, module_bias, die, typedie, &tail, |
77de5e9e | 840 | "THIS->__retvalue"); |
7a053d3b | 841 | |
77de5e9e GH |
842 | size_t bufsz = 1024; |
843 | char *buf = static_cast<char*>(malloc(bufsz)); | |
844 | assert(buf); | |
7a053d3b | 845 | |
77de5e9e GH |
846 | FILE *memstream = open_memstream (&buf, &bufsz); |
847 | assert(memstream); | |
7a053d3b | 848 | |
77de5e9e | 849 | bool deref = c_emit_location (memstream, head, 1); |
a781f401 | 850 | fprintf(memstream, " goto out;\n"); |
7a053d3b | 851 | |
a781f401 FCE |
852 | // dummy use of deref_fault label, to disable warning if deref() not used |
853 | fprintf(memstream, "if (0) goto deref_fault;\n"); | |
854 | ||
855 | // XXX: deref flag not reliable; emit fault label unconditionally | |
856 | if (deref) ; | |
857 | fprintf(memstream, | |
858 | "deref_fault:\n" | |
5e309481 | 859 | " c->last_error = \"pointer dereference fault\";\n" |
a781f401 | 860 | " goto out;\n"); |
7a053d3b | 861 | |
77de5e9e GH |
862 | fclose (memstream); |
863 | string result(buf); | |
864 | free (buf); | |
865 | return result; | |
866 | } | |
7a053d3b RM |
867 | |
868 | ||
77de5e9e | 869 | |
bd2b1e68 GH |
870 | ~dwflpp() |
871 | { | |
872 | if (dwfl) | |
873 | dwfl_end(dwfl); | |
874 | } | |
875 | }; | |
876 | ||
20c6c071 | 877 | |
7a053d3b | 878 | enum |
bd2b1e68 | 879 | function_spec_type |
7a053d3b | 880 | { |
bd2b1e68 GH |
881 | function_alone, |
882 | function_and_file, | |
7a053d3b | 883 | function_file_and_line |
bd2b1e68 GH |
884 | }; |
885 | ||
ec4373ff | 886 | |
bd2b1e68 | 887 | struct dwarf_builder; |
77de5e9e GH |
888 | struct dwarf_query; |
889 | ||
bd2b1e68 | 890 | struct dwarf_derived_probe : public derived_probe |
b55bc428 | 891 | { |
77de5e9e | 892 | dwarf_derived_probe (dwarf_query & q, |
20c6c071 | 893 | Dwarf_Addr addr); |
d9b516ca | 894 | |
20c6c071 | 895 | string module_name; |
a229fcd7 GH |
896 | string function_name; |
897 | bool has_statement; | |
20c6c071 | 898 | Dwarf_Addr addr; |
a229fcd7 | 899 | Dwarf_Addr module_bias; |
fd6602a0 | 900 | bool has_return; |
7a053d3b | 901 | |
bd2b1e68 | 902 | // Pattern registration helpers. |
7a053d3b | 903 | static void register_relative_variants(match_node * root, |
bd2b1e68 | 904 | dwarf_builder * dw); |
7a053d3b | 905 | static void register_statement_variants(match_node * root, |
bd2b1e68 | 906 | dwarf_builder * dw); |
fd6602a0 FCE |
907 | static void register_function_variants(match_node * root, |
908 | dwarf_builder * dw); | |
7a053d3b | 909 | static void register_function_and_statement_variants(match_node * root, |
bd2b1e68 | 910 | dwarf_builder * dw); |
20c6c071 | 911 | static void register_patterns(match_node * root); |
7a053d3b | 912 | |
20c6c071 GH |
913 | virtual void emit_registrations (translator_output * o, unsigned i); |
914 | virtual void emit_deregistrations (translator_output * o, unsigned i); | |
915 | virtual void emit_probe_entries (translator_output * o, unsigned i); | |
20c6c071 GH |
916 | }; |
917 | ||
918 | // Helper struct to thread through the dwfl callbacks. | |
7a053d3b | 919 | struct |
20c6c071 GH |
920 | dwarf_query |
921 | { | |
5227f1ea GH |
922 | dwarf_query(systemtap_session & sess, |
923 | probe * base_probe, | |
20c6c071 GH |
924 | probe_point * base_loc, |
925 | dwflpp & dw, | |
926 | map<string, literal *> const & params, | |
927 | vector<derived_probe *> & results); | |
bd2b1e68 | 928 | |
5227f1ea GH |
929 | systemtap_session & sess; |
930 | ||
bd2b1e68 | 931 | // Parameter extractors. |
7a053d3b | 932 | static bool has_null_param(map<string, literal *> const & params, |
bd2b1e68 | 933 | string const & k); |
7a053d3b | 934 | static bool get_string_param(map<string, literal *> const & params, |
bd2b1e68 | 935 | string const & k, string & v); |
7a053d3b | 936 | static bool get_number_param(map<string, literal *> const & params, |
bd2b1e68 | 937 | string const & k, long & v); |
c239d28c GH |
938 | static bool get_number_param(map<string, literal *> const & params, |
939 | string const & k, Dwarf_Addr & v); | |
b55bc428 | 940 | |
77de5e9e GH |
941 | string pt_regs_member_for_regnum(uint8_t dwarf_regnum); |
942 | ||
20c6c071 | 943 | vector<derived_probe *> & results; |
20c6c071 GH |
944 | |
945 | bool has_kernel; | |
946 | bool has_process; | |
947 | bool has_module; | |
7a053d3b RM |
948 | string process_val; |
949 | string module_val; | |
950 | string function_val; | |
20c6c071 GH |
951 | |
952 | bool has_function_str; | |
953 | bool has_statement_str; | |
954 | bool has_function_num; | |
955 | bool has_statement_num; | |
7a053d3b RM |
956 | string statement_str_val; |
957 | string function_str_val; | |
c239d28c GH |
958 | Dwarf_Addr statement_num_val; |
959 | Dwarf_Addr function_num_val; | |
20c6c071 GH |
960 | |
961 | bool has_callees; | |
7a053d3b | 962 | long callee_val; |
20c6c071 GH |
963 | |
964 | bool has_return; | |
965 | ||
966 | bool has_label; | |
967 | string label_val; | |
968 | ||
969 | bool has_relative; | |
970 | long relative_val; | |
971 | ||
972 | function_spec_type parse_function_spec(string & spec); | |
973 | function_spec_type spec_type; | |
974 | string function; | |
975 | string file; | |
976 | int line; | |
977 | ||
978 | probe * base_probe; | |
979 | probe_point * base_loc; | |
980 | dwflpp & dw; | |
b55bc428 FCE |
981 | }; |
982 | ||
98afd80e FCE |
983 | |
984 | struct dwarf_builder: public derived_probe_builder | |
b55bc428 | 985 | { |
bd2b1e68 | 986 | dwarf_builder() {} |
5227f1ea | 987 | virtual void build(systemtap_session & sess, |
7a053d3b | 988 | probe * base, |
20c6c071 GH |
989 | probe_point * location, |
990 | std::map<std::string, literal *> const & parameters, | |
991 | vector<probe *> & results_to_expand_further, | |
992 | vector<derived_probe *> & finished_results); | |
b55bc428 FCE |
993 | }; |
994 | ||
7a053d3b RM |
995 | bool |
996 | dwarf_query::has_null_param(map<string, literal *> const & params, | |
20c6c071 | 997 | string const & k) |
bd2b1e68 GH |
998 | { |
999 | map<string, literal *>::const_iterator i = params.find(k); | |
1000 | if (i != params.end() && i->second == NULL) | |
1001 | return true; | |
1002 | return false; | |
1003 | } | |
1004 | ||
7a053d3b RM |
1005 | bool |
1006 | dwarf_query::get_string_param(map<string, literal *> const & params, | |
20c6c071 | 1007 | string const & k, string & v) |
bd2b1e68 | 1008 | { |
98afd80e | 1009 | return derived_probe_builder::get_param (params, k, v); |
bd2b1e68 GH |
1010 | } |
1011 | ||
7a053d3b RM |
1012 | bool |
1013 | dwarf_query::get_number_param(map<string, literal *> const & params, | |
20c6c071 | 1014 | string const & k, long & v) |
bd2b1e68 | 1015 | { |
98afd80e FCE |
1016 | int64_t value; |
1017 | bool present = derived_probe_builder::get_param (params, k, value); | |
1018 | v = (long) value; | |
1019 | return present; | |
bd2b1e68 GH |
1020 | } |
1021 | ||
c239d28c GH |
1022 | bool |
1023 | dwarf_query::get_number_param(map<string, literal *> const & params, | |
1024 | string const & k, Dwarf_Addr & v) | |
1025 | { | |
98afd80e FCE |
1026 | int64_t value; |
1027 | bool present = derived_probe_builder::get_param (params, k, value); | |
1028 | v = (Dwarf_Addr) value; | |
1029 | return present; | |
c239d28c GH |
1030 | } |
1031 | ||
77de5e9e | 1032 | |
5227f1ea GH |
1033 | dwarf_query::dwarf_query(systemtap_session & sess, |
1034 | probe * base_probe, | |
20c6c071 GH |
1035 | probe_point * base_loc, |
1036 | dwflpp & dw, | |
1037 | map<string, literal *> const & params, | |
1038 | vector<derived_probe *> & results) | |
5227f1ea GH |
1039 | : sess(sess), |
1040 | results(results), | |
7a053d3b | 1041 | base_probe(base_probe), |
20c6c071 GH |
1042 | base_loc(base_loc), |
1043 | dw(dw) | |
bd2b1e68 | 1044 | { |
20c6c071 | 1045 | |
bd2b1e68 GH |
1046 | // Reduce the query to more reasonable semantic values (booleans, |
1047 | // extracted strings, numbers, etc). | |
1048 | ||
1049 | has_kernel = has_null_param(params, TOK_KERNEL); | |
1050 | has_module = get_string_param(params, TOK_MODULE, module_val); | |
1051 | has_process = get_string_param(params, TOK_PROCESS, process_val); | |
1052 | ||
1053 | has_function_str = get_string_param(params, TOK_FUNCTION, function_str_val); | |
1054 | has_function_num = get_number_param(params, TOK_FUNCTION, function_num_val); | |
1055 | ||
1056 | has_statement_str = get_string_param(params, TOK_STATEMENT, statement_str_val); | |
1057 | has_statement_num = get_number_param(params, TOK_STATEMENT, statement_num_val); | |
1058 | ||
1059 | callee_val = 1; | |
7a053d3b | 1060 | has_callees = (has_null_param(params, TOK_CALLEES) || |
bd2b1e68 GH |
1061 | get_number_param(params, TOK_CALLEES, callee_val)); |
1062 | ||
1063 | has_return = has_null_param(params, TOK_RETURN); | |
1064 | ||
1065 | has_label = get_string_param(params, TOK_LABEL, label_val); | |
1066 | has_relative = get_number_param(params, TOK_RELATIVE, relative_val); | |
7a053d3b | 1067 | |
bd2b1e68 GH |
1068 | if (has_function_str) |
1069 | spec_type = parse_function_spec(function_str_val); | |
1070 | else if (has_statement_str) | |
1071 | spec_type = parse_function_spec(statement_str_val); | |
7a053d3b | 1072 | } |
bd2b1e68 GH |
1073 | |
1074 | ||
bd2b1e68 | 1075 | function_spec_type |
20c6c071 | 1076 | dwarf_query::parse_function_spec(string & spec) |
bd2b1e68 GH |
1077 | { |
1078 | string::const_iterator i = spec.begin(), e = spec.end(); | |
7a053d3b | 1079 | |
bd2b1e68 GH |
1080 | function.clear(); |
1081 | file.clear(); | |
1082 | line = 0; | |
1083 | ||
1084 | while (i != e && *i != '@') | |
1085 | { | |
1086 | if (*i == ':') | |
1087 | goto bad; | |
1088 | function += *i++; | |
1089 | } | |
1090 | ||
1091 | if (i == e) | |
1092 | { | |
5227f1ea | 1093 | if (sess.verbose) |
7a053d3b RM |
1094 | clog << "parsed '" << spec |
1095 | << "' -> func '" << function | |
bd2b1e68 GH |
1096 | << "'" << endl; |
1097 | return function_alone; | |
1098 | } | |
1099 | ||
1100 | if (i++ == e) | |
1101 | goto bad; | |
1102 | ||
1103 | while (i != e && *i != ':') | |
1104 | file += *i++; | |
7a053d3b | 1105 | |
bd2b1e68 GH |
1106 | if (i == e) |
1107 | { | |
5227f1ea | 1108 | if (sess.verbose) |
7a053d3b RM |
1109 | clog << "parsed '" << spec |
1110 | << "' -> func '"<< function | |
1111 | << "', file '" << file | |
bd2b1e68 GH |
1112 | << "'" << endl; |
1113 | return function_and_file; | |
1114 | } | |
1115 | ||
1116 | if (i++ == e) | |
1117 | goto bad; | |
1118 | ||
1119 | try | |
1120 | { | |
1121 | line = lex_cast<int>(string(i, e)); | |
5227f1ea | 1122 | if (sess.verbose) |
7a053d3b RM |
1123 | clog << "parsed '" << spec |
1124 | << "' -> func '"<< function | |
1125 | << "', file '" << file | |
bd2b1e68 GH |
1126 | << "', line " << line << endl; |
1127 | return function_file_and_line; | |
1128 | } | |
1129 | catch (runtime_error & exn) | |
1130 | { | |
1131 | goto bad; | |
1132 | } | |
1133 | ||
1134 | bad: | |
7a053d3b | 1135 | throw semantic_error("malformed specification '" + spec + "'", |
20c6c071 | 1136 | base_probe->tok); |
bd2b1e68 GH |
1137 | } |
1138 | ||
1139 | ||
1140 | static void | |
20c6c071 | 1141 | query_statement(Dwarf_Addr stmt_addr, dwarf_query * q) |
bd2b1e68 | 1142 | { |
39bcd429 FCE |
1143 | try |
1144 | { | |
1145 | // XXX: implement | |
1146 | if (q->has_relative) | |
1147 | throw semantic_error("incomplete: do not know how to interpret .relative", | |
1148 | q->base_probe->tok); | |
d9b516ca | 1149 | |
39bcd429 FCE |
1150 | q->results.push_back(new dwarf_derived_probe(*q, stmt_addr)); |
1151 | } | |
1152 | catch (const semantic_error& e) | |
1153 | { | |
1154 | q->sess.print_error (e); | |
1155 | } | |
bd2b1e68 GH |
1156 | } |
1157 | ||
1158 | static int | |
1159 | query_function(Dwarf_Func * func, void * arg) | |
1160 | { | |
20c6c071 | 1161 | dwarf_query * q = static_cast<dwarf_query *>(arg); |
bd2b1e68 | 1162 | |
39bcd429 | 1163 | try |
7a053d3b | 1164 | { |
39bcd429 FCE |
1165 | // XXX: implement |
1166 | if (q->has_callees) | |
1167 | throw semantic_error("incomplete: do not know how to interpret .callees", | |
1168 | q->base_probe->tok); | |
d9b516ca | 1169 | |
39bcd429 FCE |
1170 | if (q->has_label) |
1171 | throw semantic_error("incomplete: do not know how to interpret .label", | |
1172 | q->base_probe->tok); | |
d9b516ca | 1173 | |
39bcd429 | 1174 | q->dw.focus_on_function(func); |
d9b516ca | 1175 | |
39bcd429 | 1176 | Dwarf_Addr entry_addr; |
d9b516ca | 1177 | |
39bcd429 | 1178 | if (q->has_statement_str || q->has_function_str) |
d9b516ca | 1179 | { |
39bcd429 FCE |
1180 | if (q->dw.function_name_matches(q->function)) |
1181 | { | |
b5d77020 FCE |
1182 | if (q->sess.verbose) |
1183 | clog << "focused on function '" << q->dw.function_name | |
1184 | << "', in CU '" << q->dw.cu_name | |
1185 | << "', module '" << q->dw.module_name << "'" << endl; | |
1186 | ||
39bcd429 FCE |
1187 | // XXX: This code is duplicated below, but it's important |
1188 | // for performance reasons to test things in this order. | |
b5d77020 | 1189 | |
db520b00 | 1190 | if (q->has_statement_str) |
39bcd429 | 1191 | { |
db520b00 FCE |
1192 | // XXX: look up address corresponding to statement string, |
1193 | // which could be any old line within a function definition. | |
1194 | cerr << "WARNING: cannot handle statement " | |
1195 | << q->statement_str_val << " address" << endl; | |
39bcd429 FCE |
1196 | return DWARF_CB_OK; |
1197 | } | |
db520b00 FCE |
1198 | if (q->has_return) |
1199 | { | |
1200 | bool ok = q->dw.function_entrypc (& entry_addr); | |
1201 | if (! ok) | |
1202 | { | |
1203 | if (q->sess.verbose) | |
1204 | cerr << "WARNING: cannot find entry-pc for function " | |
1205 | << q->dw.function_name << endl; | |
1206 | return DWARF_CB_OK; | |
1207 | } | |
1208 | if (q->sess.verbose) | |
d9b516ca | 1209 | clog << "function " << q->dw.function_name |
db520b00 FCE |
1210 | << " entrypc: " << hex << entry_addr << dec << endl; |
1211 | } | |
1212 | else | |
1213 | { | |
1214 | bool ok = q->dw.function_prologue_end(& entry_addr); | |
1215 | if (! ok) | |
1216 | { | |
1217 | // XXX: but this is actually OK for inlined function instances | |
1218 | if (q->sess.verbose) | |
1219 | cerr << "WARNING: cannot find prologue-end PC for function " | |
1220 | << q->dw.function_name << endl; | |
1221 | return DWARF_CB_OK; | |
1222 | } | |
1223 | } | |
d9b516ca | 1224 | |
39bcd429 FCE |
1225 | // If this function's name matches a function or statement |
1226 | // pattern, we use its entry pc, but we do not abort iteration | |
1227 | // since there might be other functions matching the pattern. | |
1228 | query_statement(entry_addr, q); | |
1229 | } | |
1230 | } | |
1231 | else | |
1232 | { | |
1233 | if (q->has_function_num || q->has_statement_num) | |
1234 | { | |
1235 | Dwarf_Addr query_addr = (q->has_function_num | |
1236 | ? q->function_num_val | |
1237 | : q->statement_num_val); | |
d9b516ca | 1238 | |
39bcd429 | 1239 | // Adjust module-relative address to global |
d9b516ca | 1240 | |
39bcd429 FCE |
1241 | if (q->has_module) |
1242 | query_addr = q->dw.module_address_to_global(query_addr); | |
d9b516ca | 1243 | |
39bcd429 FCE |
1244 | if (q->dw.function_includes_global_addr(query_addr)) |
1245 | { | |
db520b00 FCE |
1246 | if (q->has_statement_num) // has_statement |
1247 | entry_addr = 0; // unused, see below | |
1248 | else if (q->has_return) // has_function | |
39bcd429 | 1249 | { |
db520b00 FCE |
1250 | bool ok = q->dw.function_entrypc (& entry_addr); |
1251 | if (! ok) | |
1252 | { | |
1253 | if (q->sess.verbose) | |
1254 | cerr << "WARNING: cannot find entry-pc for function " | |
1255 | << q->dw.function_name << endl; | |
1256 | return DWARF_CB_OK; | |
1257 | } | |
1258 | if (q->sess.verbose) | |
d9b516ca | 1259 | clog << "function " << q->dw.function_name |
db520b00 FCE |
1260 | << " entrypc: " << hex << entry_addr << dec << endl; |
1261 | } | |
1262 | else // has_function | |
1263 | { | |
1264 | bool ok = q->dw.function_prologue_end(& entry_addr); | |
1265 | if (! ok) | |
1266 | { | |
1267 | // XXX: but this is actually OK for inlined function instances | |
1268 | if (q->sess.verbose) | |
1269 | cerr << "WARNING: cannot find prologue-end PC for function " | |
1270 | << q->dw.function_name << endl; | |
1271 | return DWARF_CB_OK; | |
1272 | } | |
39bcd429 | 1273 | } |
d9b516ca | 1274 | |
39bcd429 FCE |
1275 | query_statement(q->has_function_num ? entry_addr : query_addr, q); |
1276 | return DWARF_CB_ABORT; | |
1277 | } | |
1278 | } | |
1279 | } | |
d9b516ca | 1280 | |
39bcd429 | 1281 | return DWARF_CB_OK; |
bd2b1e68 | 1282 | } |
39bcd429 | 1283 | catch (const semantic_error& e) |
bd2b1e68 | 1284 | { |
39bcd429 FCE |
1285 | q->sess.print_error (e); |
1286 | return DWARF_CB_ABORT; | |
bd2b1e68 | 1287 | } |
bd2b1e68 GH |
1288 | } |
1289 | ||
1290 | static int | |
1291 | query_cu (Dwarf_Die * cudie, void * arg) | |
1292 | { | |
20c6c071 | 1293 | dwarf_query * q = static_cast<dwarf_query *>(arg); |
7a053d3b | 1294 | |
39bcd429 | 1295 | try |
bd2b1e68 | 1296 | { |
39bcd429 | 1297 | q->dw.focus_on_cu(cudie); |
d9b516ca | 1298 | |
39bcd429 FCE |
1299 | // If we have enough information in the pattern to skip a CU |
1300 | // and the CU does not match that information, return early. | |
1301 | if ((q->has_statement_str || q->has_function_str) | |
1302 | && (q->spec_type == function_file_and_line || | |
1303 | q->spec_type == function_and_file) | |
1304 | && (!q->dw.cu_name_matches(q->file))) | |
1305 | return DWARF_CB_OK; | |
b5d77020 FCE |
1306 | |
1307 | if (false && q->sess.verbose) | |
1308 | clog << "focused on CU '" << q->dw.cu_name | |
1309 | << "', in module '" << q->dw.module_name << "'" << endl; | |
d9b516ca | 1310 | |
39bcd429 FCE |
1311 | if (q->has_statement_str |
1312 | && (q->spec_type == function_file_and_line) | |
1313 | && q->dw.cu_name_matches(q->file)) | |
1314 | { | |
1315 | // If we have a complete file:line statement | |
1316 | // functor (not function functor) landing on | |
1317 | // this CU, we can look up a specific address | |
1318 | // for the statement, and skip scanning | |
1319 | // the remaining functions within the CU. | |
1320 | query_statement(q->dw.global_addr_of_line_in_cu(q->line), q); | |
1321 | } | |
c239d28c GH |
1322 | else if (q->has_function_str |
1323 | && (q->spec_type == function_file_and_line) | |
1324 | && q->dw.cu_name_matches(q->file)) | |
1325 | { | |
1326 | // If we have a complete file:line *function* functor | |
1327 | // landing on this CU, we need to select only the functions | |
1328 | // which land on the line in question. We *could* check each | |
1329 | // function individually but the line->addr lookup is | |
1330 | // expensive, so we do it once here, then temporarily switch | |
1331 | // to a .function(addr) query for the remaining function | |
1332 | // iteration, switching back when we complete. | |
1333 | q->function_num_val = q->dw.global_addr_of_line_in_cu(q->line); | |
1334 | swap(q->has_function_str, q->has_function_num); | |
1335 | q->dw.iterate_over_functions(&query_function, q); | |
1336 | swap(q->has_function_str, q->has_function_num); | |
1337 | } | |
39bcd429 FCE |
1338 | else |
1339 | { | |
c239d28c GH |
1340 | // Otherwise we need to scan all the functions in this CU, |
1341 | // matching by function name or address, as requested. | |
39bcd429 FCE |
1342 | q->dw.iterate_over_functions(&query_function, q); |
1343 | } | |
1344 | return DWARF_CB_OK; | |
bd2b1e68 | 1345 | } |
39bcd429 | 1346 | catch (const semantic_error& e) |
bd2b1e68 | 1347 | { |
39bcd429 FCE |
1348 | q->sess.print_error (e); |
1349 | return DWARF_CB_ABORT; | |
bd2b1e68 | 1350 | } |
bd2b1e68 GH |
1351 | } |
1352 | ||
1353 | static int | |
1354 | query_module (Dwfl_Module *mod __attribute__ ((unused)), | |
1355 | void **userdata __attribute__ ((unused)), | |
1356 | const char *name, Dwarf_Addr base, | |
bd2b1e68 GH |
1357 | void *arg __attribute__ ((unused))) |
1358 | { | |
20c6c071 | 1359 | dwarf_query * q = static_cast<dwarf_query *>(arg); |
bd2b1e68 | 1360 | |
39bcd429 | 1361 | try |
bd2b1e68 | 1362 | { |
39bcd429 | 1363 | q->dw.focus_on_module(mod); |
d9b516ca | 1364 | |
39bcd429 FCE |
1365 | // If we have enough information in the pattern to skip a module and |
1366 | // the module does not match that information, return early. | |
d9b516ca | 1367 | |
39bcd429 FCE |
1368 | if (q->has_kernel && !q->dw.module_name_matches(TOK_KERNEL)) |
1369 | return DWARF_CB_OK; | |
d9b516ca | 1370 | |
39bcd429 FCE |
1371 | if (q->has_module && !q->dw.module_name_matches(q->module_val)) |
1372 | return DWARF_CB_OK; | |
b5d77020 FCE |
1373 | |
1374 | if (q->sess.verbose) | |
d9b516ca RM |
1375 | clog << "focused on module '" << q->dw.module_name |
1376 | << "' = [" << hex << q->dw.module_start | |
1377 | << "-" << q->dw.module_end | |
c0de7a8d | 1378 | << ", bias " << q->dw.module_bias << "]" << dec << endl; |
b5d77020 | 1379 | |
39bcd429 FCE |
1380 | if (q->has_function_num || q->has_statement_num) |
1381 | { | |
1382 | // If we have module("foo").function(0xbeef) or | |
1383 | // module("foo").statement(0xbeef), the address is relative | |
1384 | // to the start of the module, so we seek the function | |
1385 | // number plus the module's bias. | |
1386 | Dwarf_Addr addr; | |
1387 | if (q->has_function_num) | |
1388 | addr = q->function_num_val; | |
1389 | else | |
1390 | addr = q->statement_num_val; | |
d9b516ca | 1391 | |
39bcd429 FCE |
1392 | if (q->has_kernel) |
1393 | q->dw.focus_on_cu_containing_global_address(addr); | |
1394 | else | |
1395 | q->dw.focus_on_cu_containing_module_address(addr); | |
d9b516ca | 1396 | |
39bcd429 FCE |
1397 | q->dw.iterate_over_functions(&query_function, q); |
1398 | } | |
50e0d793 | 1399 | else |
39bcd429 FCE |
1400 | { |
1401 | // Otherwise if we have a function("foo") or statement("foo") | |
1402 | // specifier, we have to scan over all the CUs looking for | |
1403 | // the function in question | |
1404 | assert(q->has_function_str || q->has_statement_str); | |
1405 | q->dw.iterate_over_cus(&query_cu, q); | |
1406 | } | |
d9b516ca | 1407 | |
39bcd429 FCE |
1408 | // If we just processed the module "kernel", and the user asked for |
1409 | // the kernel pattern, there's no need to iterate over any further | |
1410 | // modules | |
d9b516ca | 1411 | |
39bcd429 FCE |
1412 | if (q->has_kernel && q->dw.module_name_matches(TOK_KERNEL)) |
1413 | return DWARF_CB_ABORT; | |
d9b516ca | 1414 | |
39bcd429 | 1415 | return DWARF_CB_OK; |
7a053d3b | 1416 | } |
39bcd429 | 1417 | catch (const semantic_error& e) |
bd2b1e68 | 1418 | { |
39bcd429 FCE |
1419 | q->sess.print_error (e); |
1420 | return DWARF_CB_ABORT; | |
bd2b1e68 | 1421 | } |
bd2b1e68 GH |
1422 | } |
1423 | ||
77de5e9e GH |
1424 | struct |
1425 | var_expanding_copy_visitor | |
1426 | : public deep_copy_visitor | |
1427 | { | |
77de5e9e GH |
1428 | static unsigned tick; |
1429 | ||
1430 | dwarf_query & q; | |
77de5e9e GH |
1431 | Dwarf_Addr addr; |
1432 | ||
7a053d3b | 1433 | var_expanding_copy_visitor(dwarf_query & q, Dwarf_Addr a) |
d7f3e0c5 | 1434 | : q(q), addr(a) |
77de5e9e | 1435 | {} |
d7f3e0c5 | 1436 | void visit_target_symbol (target_symbol* e); |
77de5e9e GH |
1437 | }; |
1438 | ||
1439 | ||
1440 | unsigned var_expanding_copy_visitor::tick = 0; | |
1441 | ||
1442 | ||
1443 | void | |
d7f3e0c5 | 1444 | var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) |
77de5e9e | 1445 | { |
d7f3e0c5 | 1446 | assert(e->base_name.size() > 0 && e->base_name[0] == '$'); |
d9b516ca | 1447 | |
d7f3e0c5 | 1448 | if (is_active_lvalue(e)) |
77de5e9e | 1449 | { |
d7f3e0c5 GH |
1450 | throw semantic_error("read-only special variable " |
1451 | + e->base_name + " used as lvalue", e->tok); | |
77de5e9e | 1452 | } |
d9b516ca | 1453 | |
d7f3e0c5 GH |
1454 | string fname = "get_" + e->base_name.substr(1) + "_" + lex_cast<string>(tick++); |
1455 | ||
1456 | // synthesize a function | |
1457 | functiondecl *fdecl = new functiondecl; | |
1458 | embeddedcode *ec = new embeddedcode; | |
5e309481 | 1459 | ec->tok = e->tok; |
d9b516ca | 1460 | ec->code = q.dw.literal_stmt_for_local(addr, |
91eefb1c GH |
1461 | e->base_name.substr(1), |
1462 | e->components); | |
d7f3e0c5 GH |
1463 | fdecl->name = fname; |
1464 | fdecl->body = ec; | |
1465 | fdecl->type = pe_long; | |
1466 | q.sess.functions.push_back(fdecl); | |
d9b516ca | 1467 | |
d7f3e0c5 GH |
1468 | // synthesize a call |
1469 | functioncall* n = new functioncall; | |
1470 | n->tok = e->tok; | |
1471 | n->function = fname; | |
1472 | n->referent = NULL; | |
d9b516ca | 1473 | provide <functioncall*> (this, n); |
77de5e9e GH |
1474 | } |
1475 | ||
1476 | ||
7a053d3b | 1477 | dwarf_derived_probe::dwarf_derived_probe (dwarf_query & q, |
20c6c071 | 1478 | Dwarf_Addr addr) |
a229fcd7 GH |
1479 | : derived_probe (NULL), |
1480 | module_name(q.dw.module_name), | |
1481 | function_name(q.dw.function_name), | |
1482 | has_statement(q.has_statement_str || q.has_statement_num), | |
fd6602a0 | 1483 | addr(addr), |
a229fcd7 | 1484 | module_bias(q.dw.module_bias), |
fd6602a0 | 1485 | has_return (q.has_return) |
bd2b1e68 | 1486 | { |
a229fcd7 GH |
1487 | // first synthesize an "expanded" location |
1488 | vector<probe_point::component*> comps; | |
1489 | comps.push_back | |
1490 | (module_name == TOK_KERNEL | |
1491 | ? new probe_point::component(TOK_KERNEL) | |
db520b00 | 1492 | : new probe_point::component(TOK_MODULE, new literal_string(module_name))); |
b5d77020 | 1493 | |
db520b00 FCE |
1494 | string fn_or_stmt; |
1495 | if (q.has_function_str || q.has_function_num) | |
1496 | fn_or_stmt = "function"; | |
1497 | else | |
1498 | fn_or_stmt = "statement"; | |
a229fcd7 | 1499 | |
db520b00 FCE |
1500 | if (q.has_function_str || q.has_statement_str) |
1501 | { | |
1502 | string retro_name;; | |
1503 | if (! function_name.empty()) | |
1504 | retro_name = function_name + "@" + q.dw.cu_name; // XXX: add line number | |
1505 | else if (q.has_function_str) | |
1506 | retro_name = q.function_str_val; | |
1507 | else // has_statement_str | |
1508 | retro_name = q.statement_str_val; | |
1509 | // XXX: actually the statement_str case is not yet adequately | |
1510 | // handled in the search code | |
1511 | ||
1512 | comps.push_back | |
1513 | (new probe_point::component | |
1514 | (fn_or_stmt, new literal_string (retro_name))); | |
1515 | } | |
1516 | else if (q.has_function_num || q.has_statement_num) | |
1517 | { | |
1518 | Dwarf_Addr retro_addr; | |
1519 | if (q.has_function_num) | |
1520 | retro_addr = q.function_num_val; | |
1521 | else | |
1522 | retro_addr = q.statement_num_val; | |
1523 | ||
1524 | comps.push_back (new probe_point::component | |
1525 | (fn_or_stmt, | |
1526 | new literal_number(retro_addr))); // XXX: should be hex if possible | |
a229fcd7 GH |
1527 | } |
1528 | ||
db520b00 | 1529 | if (has_return) |
a229fcd7 | 1530 | comps.push_back |
db520b00 | 1531 | (new probe_point::component(TOK_RETURN)); |
d9b516ca | 1532 | |
a229fcd7 GH |
1533 | assert(q.base_probe->locations.size() > 0); |
1534 | locations.push_back(new probe_point(comps, q.base_probe->locations[0]->tok)); | |
1535 | ||
1536 | // Now make a local-variable-expanded copy of the probe body | |
77de5e9e GH |
1537 | var_expanding_copy_visitor v (q, addr); |
1538 | require <block*> (&v, &(this->body), q.base_probe->body); | |
1539 | this->tok = q.base_probe->tok; | |
bd2b1e68 GH |
1540 | } |
1541 | ||
7a053d3b | 1542 | void |
20c6c071 | 1543 | dwarf_derived_probe::register_relative_variants(match_node * root, |
bd2b1e68 GH |
1544 | dwarf_builder * dw) |
1545 | { | |
1546 | // Here we match 2 forms: | |
1547 | // | |
1548 | // . | |
1549 | // .relative(NN) | |
1550 | ||
20c6c071 GH |
1551 | root->bind(dw); |
1552 | root->bind_num(TOK_RELATIVE)->bind(dw); | |
bd2b1e68 GH |
1553 | } |
1554 | ||
7a053d3b | 1555 | void |
20c6c071 | 1556 | dwarf_derived_probe::register_statement_variants(match_node * root, |
bd2b1e68 GH |
1557 | dwarf_builder * dw) |
1558 | { | |
1559 | // Here we match 3 forms: | |
1560 | // | |
1561 | // . | |
1562 | // .return | |
1563 | // .label("foo") | |
7a053d3b | 1564 | |
bd2b1e68 | 1565 | register_relative_variants(root, dw); |
20c6c071 | 1566 | register_relative_variants(root->bind_str(TOK_LABEL), dw); |
bd2b1e68 GH |
1567 | } |
1568 | ||
7a053d3b | 1569 | void |
fd6602a0 | 1570 | dwarf_derived_probe::register_function_variants(match_node * root, |
bd2b1e68 GH |
1571 | dwarf_builder * dw) |
1572 | { | |
a229fcd7 | 1573 | // Here we match 4 forms: |
bd2b1e68 GH |
1574 | // |
1575 | // . | |
fd6602a0 | 1576 | // .return |
bd2b1e68 GH |
1577 | // .callees |
1578 | // .callees(N) | |
1579 | // | |
1580 | // The last form permits N-level callee resolving without any | |
1581 | // recursive .callees.callees.callees... pattern-matching on our part. | |
1582 | ||
fd6602a0 FCE |
1583 | root->bind(dw); |
1584 | root->bind(TOK_RETURN)->bind(dw); | |
1585 | root->bind(TOK_CALLEES)->bind(dw); | |
1586 | root->bind_num(TOK_CALLEES)->bind(dw); | |
bd2b1e68 GH |
1587 | } |
1588 | ||
7a053d3b | 1589 | void |
20c6c071 | 1590 | dwarf_derived_probe::register_function_and_statement_variants(match_node * root, |
bd2b1e68 GH |
1591 | dwarf_builder * dw) |
1592 | { | |
1593 | // Here we match 4 forms: | |
1594 | // | |
1595 | // .function("foo") | |
1596 | // .function(0xdeadbeef) | |
1597 | // .statement("foo") | |
1598 | // .statement(0xdeadbeef) | |
1599 | ||
fd6602a0 FCE |
1600 | register_function_variants(root->bind_str(TOK_FUNCTION), dw); |
1601 | register_function_variants(root->bind_num(TOK_FUNCTION), dw); | |
20c6c071 GH |
1602 | register_statement_variants(root->bind_str(TOK_STATEMENT), dw); |
1603 | register_statement_variants(root->bind_num(TOK_STATEMENT), dw); | |
bd2b1e68 GH |
1604 | } |
1605 | ||
1606 | void | |
20c6c071 | 1607 | dwarf_derived_probe::register_patterns(match_node * root) |
bd2b1e68 GH |
1608 | { |
1609 | dwarf_builder *dw = new dwarf_builder(); | |
1610 | ||
1611 | // Here we match 3 forms: | |
1612 | // | |
1613 | // .kernel | |
1614 | // .module("foo") | |
1615 | // .process("foo") | |
1616 | ||
20c6c071 | 1617 | register_function_and_statement_variants(root->bind(TOK_KERNEL), dw); |
fe3d01fa | 1618 | // XXX: may need to disable these for 2005-08 release |
20c6c071 GH |
1619 | register_function_and_statement_variants(root->bind_str(TOK_MODULE), dw); |
1620 | register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw); | |
bd2b1e68 GH |
1621 | } |
1622 | ||
7a053d3b | 1623 | static string |
ec4373ff | 1624 | probe_entry_function_name(unsigned probenum) |
b55bc428 | 1625 | { |
ec4373ff GH |
1626 | return "dwarf_kprobe_" + lex_cast<string>(probenum) + "_enter"; |
1627 | } | |
1628 | ||
7a053d3b | 1629 | static string |
20c6c071 | 1630 | probe_entry_struct_kprobe_name(unsigned probenum) |
ec4373ff | 1631 | { |
20c6c071 | 1632 | return "dwarf_kprobe_" + lex_cast<string>(probenum); |
ec4373ff GH |
1633 | } |
1634 | ||
7a053d3b | 1635 | void |
20c6c071 | 1636 | dwarf_derived_probe::emit_registrations (translator_output* o, unsigned probenum) |
ec4373ff | 1637 | { |
59ff2773 | 1638 | if (! (module_name.empty() || module_name == "kernel")) |
ec4373ff | 1639 | { |
59ff2773 FCE |
1640 | // XXX: lock module_name in memory |
1641 | } | |
1642 | ||
1643 | if (has_return) | |
1644 | { | |
1645 | o->newline() << probe_entry_struct_kprobe_name(probenum) | |
db520b00 | 1646 | << ".kp.addr = (void *) 0x" << hex << addr << ";" << dec; |
59ff2773 FCE |
1647 | o->newline() << "rc = register_kretprobe (&" |
1648 | << probe_entry_struct_kprobe_name(probenum) | |
1649 | << ");"; | |
ec4373ff | 1650 | } |
20c6c071 | 1651 | else |
bd2b1e68 | 1652 | { |
59ff2773 | 1653 | o->newline() << probe_entry_struct_kprobe_name(probenum) |
db520b00 | 1654 | << ".addr = (void *) 0x" << hex << addr << ";" << dec; |
7a053d3b | 1655 | o->newline() << "rc = register_kprobe (&" |
59ff2773 FCE |
1656 | << probe_entry_struct_kprobe_name(probenum) |
1657 | << ");"; | |
bd2b1e68 | 1658 | } |
b55bc428 FCE |
1659 | } |
1660 | ||
7a053d3b | 1661 | void |
ec4373ff | 1662 | dwarf_derived_probe::emit_deregistrations (translator_output* o, unsigned probenum) |
b55bc428 | 1663 | { |
fd6602a0 FCE |
1664 | if (has_return) |
1665 | o->newline() << "unregister_kretprobe (& " | |
1666 | << probe_entry_struct_kprobe_name(probenum) | |
1667 | << ");"; | |
1668 | else | |
1669 | o->newline() << "unregister_kprobe (& " | |
1670 | << probe_entry_struct_kprobe_name(probenum) | |
1671 | << ");"; | |
59ff2773 FCE |
1672 | |
1673 | if (! (module_name.empty() || module_name == "kernel")) | |
1674 | { | |
1675 | // XXX: unlock module_name | |
1676 | } | |
ec4373ff GH |
1677 | } |
1678 | ||
7a053d3b | 1679 | void |
ec4373ff GH |
1680 | dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned probenum) |
1681 | { | |
ec4373ff | 1682 | |
7a053d3b | 1683 | // Construct a single entry function, and a struct kprobe pointing into |
20c6c071 | 1684 | // the entry function. The entry function will call the probe function. |
20c6c071 | 1685 | o->newline(); |
3d49c615 | 1686 | o->newline() << "static int "; |
9e6edd10 FCE |
1687 | o->newline() << probe_entry_function_name(probenum) << " ("; |
1688 | if (has_return) | |
1689 | o->line() << "struct kretprobe_instance *_ignored"; | |
1690 | else | |
1691 | o->line() << "struct kprobe *_ignored"; | |
1692 | o->line() << ", struct pt_regs *regs) {"; | |
3d49c615 | 1693 | o->newline(1) << "struct context *c = & contexts [smp_processor_id()];"; |
bfb3d2d2 FCE |
1694 | o->newline(); |
1695 | ||
1696 | // A precondition for running a probe handler is that we're in RUNNING | |
1697 | // state (not ERROR), and that no one else is already using this context. | |
1698 | o->newline() << "if (atomic_read (&session_state) != STAP_SESSION_RUNNING)"; | |
3d49c615 | 1699 | o->newline(1) << "return 0;"; |
bfb3d2d2 FCE |
1700 | o->newline(-1) << "if (c->busy) {"; |
1701 | o->newline(1) << "printk (KERN_ERR \"probe reentrancy\");"; | |
1702 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
3d49c615 | 1703 | o->newline() << "return 0;"; |
bfb3d2d2 FCE |
1704 | o->newline(-1) << "}"; |
1705 | o->newline(); | |
1706 | ||
ec4373ff | 1707 | o->newline() << "c->busy ++;"; |
bfb3d2d2 | 1708 | o->newline() << "mb ();"; // for smp |
5e309481 | 1709 | o->newline() << "c->last_error = 0;"; |
ec4373ff | 1710 | o->newline() << "c->nesting = 0;"; |
3d49c615 | 1711 | o->newline() << "c->regs = regs;"; |
5e309481 FCE |
1712 | o->newline() << "c->actioncount = 0;"; |
1713 | ||
ec4373ff GH |
1714 | // NB: locals are initialized by probe function itself |
1715 | o->newline() << "probe_" << probenum << " (c);"; | |
bfb3d2d2 | 1716 | |
5e309481 FCE |
1717 | o->newline() << "if (c->last_error) {"; |
1718 | o->newline(1) << "if (c->last_error[0]) _stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; | |
1719 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
bfb3d2d2 FCE |
1720 | o->newline(-1) << "}"; |
1721 | ||
ec4373ff | 1722 | o->newline() << "c->busy --;"; |
bfb3d2d2 FCE |
1723 | o->newline() << "mb ();"; |
1724 | ||
3d49c615 | 1725 | o->newline() << "return 0;"; |
ec4373ff GH |
1726 | o->newline(-1) << "}" << endl; |
1727 | ||
20c6c071 | 1728 | o->newline(); |
fd6602a0 FCE |
1729 | if (has_return) |
1730 | { | |
1731 | o->newline() << "static struct kretprobe " | |
1732 | << probe_entry_struct_kprobe_name(probenum) | |
1733 | << "= {"; | |
db520b00 | 1734 | o->newline(1) << ".kp.addr = 0," ; |
fd6602a0 FCE |
1735 | o->newline() << ".handler = &" << probe_entry_function_name(probenum); |
1736 | o->newline(-1) << "};"; | |
1737 | } | |
1738 | else | |
1739 | { | |
1740 | o->newline() << "static struct kprobe " | |
1741 | << probe_entry_struct_kprobe_name(probenum) | |
1742 | << "= {"; | |
db520b00 | 1743 | o->newline(1) << ".addr = 0," ; |
fd6602a0 FCE |
1744 | o->newline() << ".pre_handler = &" << probe_entry_function_name(probenum); |
1745 | o->newline(-1) << "};"; | |
1746 | } | |
20c6c071 GH |
1747 | o->newline(); |
1748 | } | |
ec4373ff | 1749 | |
20c6c071 GH |
1750 | |
1751 | void | |
5227f1ea | 1752 | dwarf_builder::build(systemtap_session & sess, |
7a053d3b | 1753 | probe * base, |
20c6c071 GH |
1754 | probe_point * location, |
1755 | std::map<std::string, literal *> const & parameters, | |
1756 | vector<probe *> & results_to_expand_further, | |
1757 | vector<derived_probe *> & finished_results) | |
1758 | { | |
1759 | ||
5227f1ea GH |
1760 | dwflpp dw(sess); |
1761 | dwarf_query q(sess, base, location, dw, parameters, finished_results); | |
20c6c071 GH |
1762 | |
1763 | dw.setup(q.has_kernel || q.has_module); | |
1764 | ||
d9b516ca | 1765 | if (q.has_kernel |
50e0d793 | 1766 | && (q.has_function_num || q.has_statement_num)) |
20c6c071 | 1767 | { |
50e0d793 GH |
1768 | // If we have kernel.function(0xbeef), or |
1769 | // kernel.statement(0xbeef) the address is global (relative to | |
1770 | // the kernel) and we can seek directly to the module and cudie | |
1771 | // in question. | |
d9b516ca RM |
1772 | Dwarf_Addr a = (q.has_function_num |
1773 | ? q.function_num_val | |
50e0d793 GH |
1774 | : q.statement_num_val); |
1775 | dw.focus_on_module_containing_global_address(a); | |
1776 | dw.focus_on_cu_containing_global_address(a); | |
20c6c071 GH |
1777 | dw.iterate_over_functions(&query_function, &q); |
1778 | } | |
7a053d3b | 1779 | else |
20c6c071 GH |
1780 | { |
1781 | // Otherwise we have module("foo"), kernel.statement("foo"), or | |
1782 | // kernel.function("foo"); in these cases we need to scan all | |
1783 | // the modules. | |
7a053d3b | 1784 | assert((q.has_kernel && q.has_function_str) || |
20c6c071 GH |
1785 | (q.has_kernel && q.has_statement_str) || |
1786 | (q.has_module)); | |
1787 | dw.iterate_over_modules(&query_module, &q); | |
1788 | } | |
b55bc428 FCE |
1789 | } |
1790 | ||
1791 | ||
98afd80e FCE |
1792 | |
1793 | // ------------------------------------------------------------------------ | |
1794 | // timer derived probes | |
1795 | // ------------------------------------------------------------------------ | |
1796 | ||
1797 | ||
1798 | struct timer_derived_probe: public derived_probe | |
1799 | { | |
1800 | int64_t interval, randomize; | |
1801 | ||
1802 | timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r); | |
1803 | ||
1804 | virtual void emit_registrations (translator_output * o, unsigned i); | |
1805 | virtual void emit_deregistrations (translator_output * o, unsigned i); | |
1806 | virtual void emit_probe_entries (translator_output * o, unsigned i); | |
1807 | }; | |
1808 | ||
1809 | ||
1810 | timer_derived_probe::timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r): | |
1811 | derived_probe (p, l), interval (i), randomize (r) | |
1812 | { | |
1813 | if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints | |
1814 | throw semantic_error ("invalid interval for jiffies timer"); | |
1815 | // randomize = 0 means no randomization | |
1816 | if (randomize < 0 || randomize > interval) | |
1817 | throw semantic_error ("invalid randomize for jiffies timer"); | |
1818 | ||
1819 | if (locations.size() != 1) | |
1820 | throw semantic_error ("expect single probe point"); | |
1821 | // so we don't have to loop over them in the other functions | |
1822 | } | |
1823 | ||
1824 | ||
1825 | void | |
1826 | timer_derived_probe::emit_registrations (translator_output* o, unsigned j) | |
1827 | { | |
1828 | o->newline() << "init_timer (& timer_" << j << ");"; | |
1829 | o->newline() << "timer_" << j << ".expires = jiffies + " << interval << ";"; | |
1830 | o->newline() << "timer_" << j << ".function = & enter_" << j << ";"; | |
1831 | o->newline() << "add_timer (& timer_" << j << ");"; | |
1832 | } | |
1833 | ||
1834 | ||
1835 | void | |
1836 | timer_derived_probe::emit_deregistrations (translator_output* o, unsigned j) | |
1837 | { | |
1838 | o->newline() << "del_timer_sync (& timer_" << j << ");"; | |
1839 | } | |
1840 | ||
1841 | ||
1842 | void | |
1843 | timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j) | |
1844 | { | |
1845 | o->newline() << "static struct timer_list timer_" << j << ";"; | |
1846 | ||
1847 | o->newline() << "void enter_" << j << " (unsigned long val) {"; | |
1848 | o->newline(1) << "struct context* c = & contexts [smp_processor_id()];"; | |
1849 | ||
1850 | o->newline() << "(void) val;"; | |
1851 | ||
1852 | // A precondition for running a probe handler is that we're in | |
1853 | // RUNNING state (not ERROR), and that no one else is already using | |
1854 | // this context. | |
1855 | o->newline() << "if (atomic_read (&session_state) != STAP_SESSION_RUNNING)"; | |
1856 | o->newline(1) << "return;"; | |
1857 | ||
1858 | o->newline(-1) << "if (c->busy) {"; | |
1859 | o->newline(1) << "printk (KERN_ERR \"probe reentrancy\");"; | |
1860 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
1861 | o->newline() << "return;"; | |
1862 | o->newline(-1) << "}"; | |
1863 | o->newline(); | |
1864 | ||
1865 | o->newline() << "mod_timer (& timer_" << j << ", " | |
1866 | << "jiffies + " << interval; | |
1867 | if (randomize) | |
1868 | o->line() << " + _stp_random_pm(" << randomize << ")"; | |
1869 | o->line() << ");"; | |
1870 | ||
1871 | o->newline() << "c->busy ++;"; | |
1872 | o->newline() << "mb ();"; // for smp | |
5e309481 | 1873 | o->newline() << "c->last_error = 0;"; |
98afd80e | 1874 | o->newline() << "c->nesting = 0;"; |
98afd80e FCE |
1875 | o->newline() << "if (! in_interrupt())"; |
1876 | o->newline(1) << "c->regs = 0;"; | |
1877 | o->newline(-1) << "else"; | |
1878 | o->newline(1) << "c->regs = task_pt_regs (current);"; | |
1879 | o->indent(-1); | |
5e309481 | 1880 | o->newline() << "c->actioncount = 0;"; |
98afd80e FCE |
1881 | |
1882 | // NB: locals are initialized by probe function itself | |
1883 | o->newline() << "probe_" << j << " (c);"; | |
1884 | ||
5e309481 FCE |
1885 | o->newline() << "if (c->last_error) {"; |
1886 | o->newline(1) << "if (c->last_error[0]) _stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; | |
1887 | o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
98afd80e FCE |
1888 | o->newline(-1) << "}"; |
1889 | ||
1890 | o->newline() << "c->busy --;"; | |
1891 | o->newline() << "mb ();"; | |
1892 | o->newline(-1) << "}" << endl; | |
1893 | } | |
1894 | ||
1895 | ||
1896 | struct timer_builder: public derived_probe_builder | |
1897 | { | |
1898 | timer_builder() {} | |
1899 | virtual void build(systemtap_session & sess, | |
1900 | probe * base, | |
1901 | probe_point * location, | |
1902 | std::map<std::string, literal *> const & parameters, | |
1903 | vector<probe *> &, | |
1904 | vector<derived_probe *> & finished_results) | |
1905 | { | |
1906 | int64_t jn, rn; | |
1907 | bool jn_p, rn_p; | |
1908 | ||
1909 | jn_p = get_param (parameters, "jiffies", jn); | |
1910 | rn_p = get_param (parameters, "randomize", rn); | |
1911 | ||
1912 | finished_results.push_back(new timer_derived_probe(base, location, | |
1913 | jn, rn_p ? rn : 0)); | |
1914 | } | |
1915 | }; | |
1916 | ||
1917 | ||
1918 | ||
b55bc428 | 1919 | // ------------------------------------------------------------------------ |
bd2b1e68 | 1920 | // Standard tapset registry. |
b55bc428 FCE |
1921 | // ------------------------------------------------------------------------ |
1922 | ||
7a053d3b | 1923 | void |
f8220a7b | 1924 | register_standard_tapsets(systemtap_session & s) |
b55bc428 | 1925 | { |
bd2b1e68 | 1926 | // Rudimentary binders for begin and end targets |
f8220a7b GH |
1927 | s.pattern_root->bind("begin")->bind(new be_builder(true)); |
1928 | s.pattern_root->bind("end")->bind(new be_builder(false)); | |
98afd80e FCE |
1929 | s.pattern_root->bind("timer")->bind_num("jiffies")->bind(new timer_builder()); |
1930 | s.pattern_root->bind("timer")->bind_num("jiffies")->bind_num("randomize")->bind(new timer_builder()); | |
b98a8d73 | 1931 | |
14d0763f | 1932 | // kernel/module parts |
f8220a7b | 1933 | dwarf_derived_probe::register_patterns(s.pattern_root); |
b55bc428 | 1934 | } |