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