]>
Commit | Line | Data |
---|---|---|
56e12059 | 1 | // tapset resolution |
9a604fac | 2 | // Copyright (C) 2005, 2006 Red Hat Inc. |
77a5c1f9 | 3 | // Copyright (C) 2005, 2006 Intel Corporation. |
56e12059 FCE |
4 | // |
5 | // This file is part of systemtap, and is free software. You can | |
6 | // redistribute it and/or modify it under the terms of the GNU General | |
7 | // Public License (GPL); either version 2, or (at your option) any | |
8 | // later version. | |
9 | ||
10 | #include "config.h" | |
11 | #include "staptree.h" | |
12 | #include "elaborate.h" | |
b55bc428 | 13 | #include "tapsets.h" |
56e12059 | 14 | #include "translate.h" |
dc38c0ae | 15 | #include "session.h" |
bd2b1e68 GH |
16 | |
17 | #include <deque> | |
56e12059 | 18 | #include <iostream> |
bd2b1e68 | 19 | #include <map> |
ec4373ff | 20 | #include <set> |
56e12059 | 21 | #include <sstream> |
bd2b1e68 | 22 | #include <stdexcept> |
b55bc428 | 23 | #include <vector> |
e36387d7 | 24 | #include <cstdarg> |
29e64872 | 25 | #include <cassert> |
bd2b1e68 GH |
26 | |
27 | extern "C" { | |
df8fadee | 28 | #include <fcntl.h> |
bd2b1e68 | 29 | #include <elfutils/libdwfl.h> |
7a053d3b | 30 | #include <elfutils/libdw.h> |
77de5e9e GH |
31 | #include <dwarf.h> |
32 | #include <elf.h> | |
33 | #include <obstack.h> | |
30a279be FCE |
34 | #include <regex.h> |
35 | #include <fnmatch.h> | |
4b1ad75e | 36 | |
30a279be | 37 | #include "loc2c.h" |
4b1ad75e RM |
38 | #define __STDC_FORMAT_MACROS |
39 | #include <inttypes.h> | |
bd2b1e68 | 40 | } |
77de5e9e | 41 | |
56e12059 | 42 | |
47dd066d WC |
43 | #ifdef PERFMON |
44 | #include <perfmon/pfmlib.h> | |
45 | #include <perfmon/perfmon.h> | |
46 | #endif | |
47 | ||
48 | ||
56e12059 FCE |
49 | using namespace std; |
50 | ||
cc9ee605 FCE |
51 | |
52 | // XXX: should standardize to these functions throughout translator | |
53 | ||
54 | template <typename OUT, typename IN> inline OUT | |
55 | lex_cast(IN const & in) | |
56 | { | |
57 | stringstream ss; | |
58 | OUT out; | |
59 | if (!(ss << in && ss >> out)) | |
60 | throw runtime_error("bad lexical cast"); | |
61 | return out; | |
62 | } | |
63 | ||
64 | template <typename OUT, typename IN> inline OUT | |
65 | lex_cast_hex(IN const & in) | |
66 | { | |
67 | stringstream ss; | |
68 | OUT out; | |
69 | if (!(ss << hex << showbase << in && ss >> out)) | |
70 | throw runtime_error("bad lexical cast"); | |
71 | return out; | |
72 | } | |
73 | ||
74 | ||
75 | // return as quoted string, with at least '"' backslash-escaped | |
76 | template <typename IN> inline string | |
77 | lex_cast_qstring(IN const & in) | |
78 | { | |
79 | stringstream ss; | |
80 | string out, out2; | |
499cf740 | 81 | if (!(ss << in)) |
cc9ee605 | 82 | throw runtime_error("bad lexical cast"); |
499cf740 | 83 | out = ss.str(); |
cc9ee605 FCE |
84 | out2 += '"'; |
85 | for (unsigned i=0; i<out.length(); i++) | |
86 | { | |
87 | if (out[i] == '"') // XXX others? | |
88 | out2 += '\\'; | |
89 | out2 += out[i]; | |
90 | } | |
91 | out2 += '"'; | |
92 | return out2; | |
93 | } | |
94 | ||
95 | ||
46b84a80 DS |
96 | static void |
97 | emit_probe_timing(derived_probe* p, translator_output* o) | |
98 | { | |
99 | static set<string> basest_names; | |
100 | ||
101 | string nm = p->basest()->name; | |
102 | if (basest_names.find(nm) == basest_names.end()) | |
103 | { | |
104 | basest_names.insert (nm); | |
105 | ||
106 | o->newline() << "#ifdef STP_TIMING"; | |
107 | o->newline() << "{"; | |
108 | o->newline(1) << "const char *probe_point = " | |
109 | << lex_cast_qstring (*p->basest()->locations[0]) | |
110 | << ";"; | |
111 | o->newline() << "const char *decl_location = " | |
112 | << lex_cast_qstring (p->basest()->tok->location) | |
113 | << ";"; | |
114 | o->newline() << "struct stat_data *stats = _stp_stat_get (time_" | |
115 | << p->basest()->name | |
116 | << ", 0);"; | |
117 | o->newline() << "const char *error;"; | |
118 | o->newline() << "if (stats->count) {"; | |
119 | o->newline(1) << "int64_t avg = _stp_div64 (&error, stats->sum, stats->count);"; | |
120 | o->newline() << "_stp_printf (\"probe %s (%s), %lld hits taking %lldmin/%lldavg/%lldmax cycles.\\n\","; | |
121 | o->newline() << "probe_point, decl_location, (long long) stats->count, (long long) stats->min, (long long) avg, (long long) stats->max);"; | |
122 | o->newline() << "_stp_print_flush();"; | |
123 | o->newline(-1) << "}"; | |
124 | o->newline(-1) << "}"; | |
125 | o->newline() << "#endif"; | |
126 | } | |
127 | } | |
128 | ||
129 | ||
9a604fac FCE |
130 | // ------------------------------------------------------------------------ |
131 | ||
132 | void | |
a44a0785 | 133 | derived_probe::emit_common_header (translator_output* o) |
9a604fac | 134 | { |
47dd066d WC |
135 | |
136 | #ifdef PERFMON | |
137 | o->newline() << "static struct pfarg_ctx _pfm_context;"; | |
138 | o->newline() << "static void *_pfm_desc;"; | |
139 | o->newline() << "static struct pfarg_pmc *_pfm_pmc_x;"; | |
140 | o->newline() << "static int _pfm_num_pmc_x;"; | |
141 | o->newline() << "static struct pfarg_pmd *_pfm_pmd_x;"; | |
142 | o->newline() << "static int _pfm_num_pmd_x;"; | |
143 | #endif | |
144 | ||
a44a0785 FCE |
145 | o->newline(); |
146 | o->newline() << "static struct context* common_probe_prologue (int state) {"; | |
147 | o->newline(1); | |
03d569d3 | 148 | o->newline() << "struct context* c;"; |
a44a0785 FCE |
149 | o->newline() << "if (atomic_read (&session_state) != state)"; |
150 | o->newline(1) << "return NULL;"; | |
9a604fac | 151 | |
a44a0785 | 152 | o->newline() << "c = per_cpu_ptr (contexts, smp_processor_id());"; |
9a604fac | 153 | o->newline(-1) << "if (unlikely (atomic_inc_return (&c->busy) != 1)) {"; |
9a604fac FCE |
154 | o->newline(1) << "if (atomic_inc_return (& skipped_count) > MAXSKIPPED) {"; |
155 | o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
156 | // NB: We don't assume that we can safely call stp_error etc. in such | |
157 | // a reentrant context. But this is OK: | |
158 | o->newline() << "_stp_exit ();"; | |
159 | o->newline(-1) << "}"; | |
9a604fac | 160 | o->newline() << "atomic_dec (& c->busy);"; |
a44a0785 | 161 | o->newline() << "return NULL;"; |
9a604fac FCE |
162 | o->newline(-1) << "}"; |
163 | o->newline(); | |
164 | o->newline() << "c->last_error = 0;"; | |
9a604fac FCE |
165 | o->newline() << "c->nesting = 0;"; |
166 | o->newline() << "c->regs = 0;"; | |
167 | o->newline() << "c->actioncount = 0;"; | |
a44a0785 FCE |
168 | o->newline() << "return c;"; |
169 | o->newline(-1) << "}"; | |
170 | o->newline(); | |
9a604fac | 171 | |
a44a0785 FCE |
172 | |
173 | o->newline() << "static void common_probe_epilogue (struct context* c) {"; | |
174 | o->newline(1) ; | |
9a604fac FCE |
175 | o->newline() << "if (unlikely (c->last_error && c->last_error[0])) {"; |
176 | o->newline(1) << "if (c->last_stmt != NULL)"; | |
177 | o->newline(1) << "_stp_softerror (\"%s near %s\", c->last_error, c->last_stmt);"; | |
178 | o->newline(-1) << "else"; | |
179 | o->newline(1) << "_stp_softerror (\"%s\", c->last_error);"; | |
180 | o->indent(-1); | |
181 | o->newline() << "atomic_inc (& error_count);"; | |
9a604fac FCE |
182 | o->newline() << "if (atomic_read (& error_count) > MAXERRORS) {"; |
183 | o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
184 | o->newline() << "_stp_exit ();"; | |
185 | o->newline(-1) << "}"; | |
9a604fac | 186 | o->newline(-1) << "}"; |
e38d6504 | 187 | |
9a604fac | 188 | o->newline() << "atomic_dec (&c->busy);"; |
a44a0785 FCE |
189 | o->newline(-1) << "}"; |
190 | } | |
191 | ||
192 | ||
193 | void | |
194 | derived_probe::emit_probe_prologue (translator_output* o, | |
195 | const std::string& statereq) | |
196 | { | |
197 | o->newline() << "struct context* c;"; | |
198 | o->newline() << "unsigned long flags;"; | |
199 | ||
e38d6504 | 200 | // NB: this cycles_t stuff might go into the common header block above |
a44a0785 FCE |
201 | o->newline() << "#ifdef STP_TIMING"; |
202 | o->newline() << "cycles_t cycles_atstart;"; | |
203 | o->newline() << "#endif"; | |
204 | o->newline() << "local_irq_save (flags);"; | |
205 | o->newline() << "#ifdef STP_TIMING"; | |
206 | o->newline() << "cycles_atstart = get_cycles ();"; | |
207 | o->newline() << "#endif"; | |
208 | o->newline() << "c = common_probe_prologue (" << statereq << ");"; | |
209 | o->newline() << "if (c == NULL) goto probe_epilogue;"; | |
210 | o->newline() << "c->probe_point = probe_point;"; | |
211 | } | |
212 | ||
213 | void | |
214 | derived_probe::emit_probe_epilogue (translator_output* o) | |
215 | { | |
216 | o->newline() << "common_probe_epilogue (c);"; | |
217 | ||
213bee8f | 218 | o->newline(-1) << "probe_epilogue:"; |
4b17d6af WC |
219 | o->newline(1) << "#ifdef STP_TIMING"; |
220 | o->newline() << "{"; | |
221 | o->newline(1) << "cycles_t cycles_atend = get_cycles ();"; | |
a44a0785 FCE |
222 | |
223 | // XXX: get_cycles() may return fewer significant digits than | |
224 | // cycles_t can carry. On some machines, cycles_t is 64 bits wide | |
225 | // but get_cycles() is only 52. So we should investigate truncating | |
226 | // these get_cycles() return values to some reasonable smaller | |
227 | // number of bits, perhaps 32 or even 24. | |
228 | ||
4b17d6af WC |
229 | o->newline() << "int64_t cycles_elapsed = (cycles_atend > cycles_atstart)"; |
230 | o->newline(1) << "? (int64_t) (cycles_atend - cycles_atstart)"; | |
231 | o->newline() << ": (int64_t) (~(cycles_t)0) - cycles_atstart + cycles_atend + 1;"; | |
c1d5f3f6 | 232 | o->newline() << "_stp_stat_add(time_" << basest()->name << ",cycles_elapsed);"; |
4b17d6af WC |
233 | o->indent(-1); |
234 | o->newline(-1) << "}"; | |
235 | o->newline() << "#endif"; | |
236 | o->newline() << "local_irq_restore (flags);"; | |
9a604fac FCE |
237 | } |
238 | ||
239 | ||
240 | ||
b55bc428 FCE |
241 | // ------------------------------------------------------------------------ |
242 | // begin/end probes are run right during registration / deregistration | |
56e12059 FCE |
243 | // ------------------------------------------------------------------------ |
244 | ||
b55bc428 FCE |
245 | struct be_derived_probe: public derived_probe |
246 | { | |
247 | bool begin; | |
248 | be_derived_probe (probe* p, bool b): derived_probe (p), begin (b) {} | |
249 | be_derived_probe (probe* p, probe_point* l, bool b): | |
250 | derived_probe (p, l), begin (b) {} | |
56e12059 | 251 | |
dc38c0ae DS |
252 | void register_probe (systemtap_session& s); |
253 | ||
46b84a80 DS |
254 | void emit_registrations_start (translator_output* o, unsigned index=0); |
255 | void emit_registrations_end (translator_output* o, unsigned index) {} | |
35d4ab18 FCE |
256 | void emit_deregistrations (translator_output* o); |
257 | void emit_probe_entries (translator_output* o); | |
b55bc428 FCE |
258 | }; |
259 | ||
98afd80e | 260 | |
dc38c0ae DS |
261 | struct be_derived_probe_group: public derived_probe_group |
262 | { | |
263 | private: | |
264 | vector<be_derived_probe*> probes; | |
265 | ||
266 | public: | |
267 | virtual void register_probe(be_derived_probe* p) { probes.push_back (p); } | |
268 | virtual size_t size () { return probes.size (); } | |
269 | ||
270 | virtual void emit_probes (translator_output* op, unparser* up); | |
46b84a80 | 271 | virtual void emit_module_init (translator_output* o); |
dc38c0ae DS |
272 | }; |
273 | ||
274 | ||
98afd80e | 275 | struct be_builder: public derived_probe_builder |
b55bc428 FCE |
276 | { |
277 | bool begin; | |
278 | be_builder(bool b) : begin(b) {} | |
5227f1ea | 279 | virtual void build(systemtap_session & sess, |
7a053d3b | 280 | probe * base, |
20c6c071 GH |
281 | probe_point * location, |
282 | std::map<std::string, literal *> const & parameters, | |
20c6c071 | 283 | vector<derived_probe *> & finished_results) |
b55bc428 | 284 | { |
20c6c071 | 285 | finished_results.push_back(new be_derived_probe(base, location, begin)); |
b55bc428 | 286 | } |
b55bc428 | 287 | }; |
56e12059 FCE |
288 | |
289 | ||
dc38c0ae DS |
290 | void |
291 | be_derived_probe::register_probe(systemtap_session& s) | |
292 | { | |
293 | s.probes.register_probe(this); | |
294 | } | |
295 | ||
296 | ||
7a053d3b | 297 | void |
46b84a80 DS |
298 | be_derived_probe::emit_registrations_start (translator_output* o, |
299 | unsigned index) | |
56e12059 FCE |
300 | { |
301 | if (begin) | |
302 | for (unsigned i=0; i<locations.size(); i++) | |
35d4ab18 | 303 | o->newline() << "enter_" << name << "_" << i << " ();"; |
56e12059 FCE |
304 | } |
305 | ||
306 | ||
7a053d3b | 307 | void |
35d4ab18 | 308 | be_derived_probe::emit_deregistrations (translator_output* o) |
56e12059 | 309 | { |
bfb3d2d2 | 310 | if (!begin) |
56e12059 | 311 | for (unsigned i=0; i<locations.size(); i++) |
35d4ab18 | 312 | o->newline() << "enter_" << name << "_" << i << " ();"; |
56e12059 FCE |
313 | } |
314 | ||
315 | ||
316 | void | |
35d4ab18 | 317 | be_derived_probe::emit_probe_entries (translator_output* o) |
56e12059 | 318 | { |
4b17d6af | 319 | o->newline() << "#ifdef STP_TIMING"; |
c1d5f3f6 | 320 | o->newline() << "static __cacheline_aligned Stat " << "time_" << basest()->name << ";"; |
4b17d6af WC |
321 | o->newline() << "#endif"; |
322 | ||
56e12059 FCE |
323 | for (unsigned i=0; i<locations.size(); i++) |
324 | { | |
325 | probe_point *l = locations[i]; | |
326 | o->newline() << "/* location " << i << ": " << *l << " */"; | |
ffd1346f | 327 | o->newline() << "static void enter_" << name << "_" << i << " (void) {"; |
bfb3d2d2 | 328 | |
7a053d3b | 329 | // While begin/end probes are executed single-threaded, we |
bfb3d2d2 | 330 | // still code defensively and use a per-cpu context. |
9a604fac | 331 | o->indent(1); |
cc9ee605 | 332 | o->newline() << "const char* probe_point = " |
9a604fac FCE |
333 | << lex_cast_qstring(*l) << ";"; |
334 | emit_probe_prologue (o, | |
335 | (begin ? | |
336 | "STAP_SESSION_STARTING" : | |
337 | "STAP_SESSION_STOPPING")); | |
bfb3d2d2 | 338 | |
56e12059 | 339 | // NB: locals are initialized by probe function itself |
35d4ab18 | 340 | o->newline() << name << " (c);"; |
bfb3d2d2 | 341 | |
9a604fac | 342 | emit_probe_epilogue (o); |
bfb3d2d2 | 343 | |
db22e55f | 344 | o->newline(-1) << "}\n"; |
56e12059 FCE |
345 | } |
346 | } | |
347 | ||
348 | ||
dc38c0ae DS |
349 | void |
350 | be_derived_probe_group::emit_probes (translator_output* op, unparser* up) | |
351 | { | |
352 | for (unsigned i=0; i < probes.size(); i++) | |
353 | { | |
354 | op->newline (); | |
355 | up->emit_probe (probes[i]); | |
356 | } | |
357 | } | |
358 | ||
46b84a80 DS |
359 | void |
360 | be_derived_probe_group::emit_module_init (translator_output* o) | |
361 | { | |
362 | if (probes.size () == 0) | |
363 | return; | |
364 | ||
365 | // Output the be probes create function | |
366 | o->newline() << "static int register_be_probes (void) {"; | |
367 | o->indent(1); | |
368 | ||
369 | for (unsigned i=0; i < probes.size (); i++) | |
370 | probes[i]->emit_registrations_start (o); | |
371 | ||
372 | o->newline() << "return 0;"; | |
373 | o->newline(-1) << "}\n"; | |
374 | ||
375 | // Output the be probes destroy function | |
376 | o->newline() << "static void unregister_be_probes (void) {"; | |
377 | o->indent(1); | |
378 | ||
379 | for (unsigned i=0; i < probes.size (); i++) | |
380 | { | |
381 | probes[i]->emit_deregistrations (o); | |
382 | emit_probe_timing(probes[i], o); | |
383 | } | |
384 | ||
385 | o->newline(-1) << "}\n"; | |
386 | } | |
387 | ||
dc38c0ae | 388 | |
6e3347a9 FCE |
389 | // ------------------------------------------------------------------------ |
390 | // never probes are never run | |
391 | // ------------------------------------------------------------------------ | |
392 | ||
393 | struct never_derived_probe: public derived_probe | |
394 | { | |
395 | never_derived_probe (probe* p): derived_probe (p) {} | |
396 | never_derived_probe (probe* p, probe_point* l): derived_probe (p, l) {} | |
397 | ||
dc38c0ae DS |
398 | void register_probe (systemtap_session& s); |
399 | ||
46b84a80 DS |
400 | void emit_registrations_start (translator_output* o, unsigned index) {} |
401 | void emit_registrations_end (translator_output* o, unsigned index) {} | |
402 | void emit_deregistrations (translator_output* o) {} | |
403 | void emit_probe_entries (translator_output* o) {} | |
6e3347a9 FCE |
404 | }; |
405 | ||
406 | ||
dc38c0ae DS |
407 | struct never_derived_probe_group: public derived_probe_group |
408 | { | |
409 | private: | |
410 | vector<never_derived_probe*> probes; | |
411 | ||
412 | public: | |
413 | virtual void register_probe(never_derived_probe* p) { probes.push_back (p); } | |
414 | virtual size_t size () { return probes.size (); } | |
415 | ||
46b84a80 DS |
416 | virtual void emit_probes (translator_output* op, unparser* up) {} |
417 | virtual void emit_module_init (translator_output* o) {} | |
dc38c0ae DS |
418 | }; |
419 | ||
420 | ||
421 | void | |
422 | never_derived_probe::register_probe(systemtap_session& s) | |
423 | { | |
424 | s.probes.register_probe(this); | |
425 | } | |
426 | ||
427 | ||
6e3347a9 FCE |
428 | struct never_builder: public derived_probe_builder |
429 | { | |
430 | never_builder() {} | |
431 | virtual void build(systemtap_session & sess, | |
432 | probe * base, | |
433 | probe_point * location, | |
434 | std::map<std::string, literal *> const & parameters, | |
435 | vector<derived_probe *> & finished_results) | |
436 | { | |
437 | finished_results.push_back(new never_derived_probe(base, location)); | |
438 | } | |
439 | }; | |
440 | ||
441 | ||
56e12059 | 442 | // ------------------------------------------------------------------------ |
bd2b1e68 | 443 | // Dwarf derived probes. |
b55bc428 | 444 | // ------------------------------------------------------------------------ |
bd2b1e68 | 445 | |
c239d28c GH |
446 | static string TOK_PROCESS("process"); |
447 | static string TOK_KERNEL("kernel"); | |
448 | static string TOK_MODULE("module"); | |
449 | ||
450 | static string TOK_FUNCTION("function"); | |
54efe513 | 451 | static string TOK_INLINE("inline"); |
c239d28c GH |
452 | static string TOK_RETURN("return"); |
453 | static string TOK_CALLEES("callees"); | |
454 | ||
455 | static string TOK_STATEMENT("statement"); | |
456 | static string TOK_LABEL("label"); | |
457 | static string TOK_RELATIVE("relative"); | |
458 | ||
59ff2773 | 459 | |
59ff2773 | 460 | |
59ff2773 | 461 | |
20e4a32c | 462 | struct |
7e1279ea FCE |
463 | func_info |
464 | { | |
20e4a32c | 465 | func_info() |
b6581717 GH |
466 | : decl_file(NULL), decl_line(-1), prologue_end(0) |
467 | { | |
468 | memset(&die, 0, sizeof(die)); | |
469 | } | |
7e1279ea | 470 | string name; |
4cd232e4 GH |
471 | char const * decl_file; |
472 | int decl_line; | |
7e1279ea FCE |
473 | Dwarf_Die die; |
474 | Dwarf_Addr prologue_end; | |
475 | }; | |
476 | ||
477 | struct | |
478 | inline_instance_info | |
479 | { | |
20e4a32c | 480 | inline_instance_info() |
b6581717 GH |
481 | : decl_file(NULL), decl_line(-1) |
482 | { | |
483 | memset(&die, 0, sizeof(die)); | |
484 | } | |
7e1279ea | 485 | string name; |
4cd232e4 GH |
486 | char const * decl_file; |
487 | int decl_line; | |
7e1279ea FCE |
488 | Dwarf_Die die; |
489 | }; | |
490 | ||
c8959a29 GH |
491 | class |
492 | symbol_cache | |
493 | { | |
494 | // For each module, we keep a multimap from function names to | |
495 | // (cudie, funcdie*) pairs. The first time we pass over a module, | |
496 | // we build up this multimap as an index. Our iteration over the | |
497 | // module's CUs and functions is then driven by the function or | |
498 | // statement pattern string we're scanning for. | |
499 | struct entry | |
500 | { | |
501 | Dwarf_Die cu; | |
502 | Dwarf_Die function; | |
503 | }; | |
504 | typedef multimap<string, entry> index; | |
505 | map<Dwarf *, index*> indices; | |
506 | index *curr_index; | |
507 | Dwarf_Die * cu_die; | |
508 | void make_entry_for_function(Dwarf_Die *func_die); | |
509 | static int function_callback(Dwarf_Die * func, void * arg); | |
510 | void index_module(Dwarf * mod); | |
e38d6504 | 511 | public: |
c8959a29 GH |
512 | void select_die_subsets(Dwarf * mod, |
513 | string const & pattern, | |
514 | set<Dwarf_Die> & cus, | |
515 | multimap<Dwarf_Die, Dwarf_Die> & funcs); | |
516 | }; | |
517 | ||
518 | void | |
519 | symbol_cache::make_entry_for_function(Dwarf_Die *func_die) | |
520 | { | |
521 | entry e; | |
522 | assert(this->cu_die); | |
523 | assert(this->curr_index); | |
524 | e.cu = *(this->cu_die); | |
525 | e.function = *(func_die); | |
526 | char const * fname = dwarf_diename(func_die); | |
527 | if (fname) | |
528 | curr_index->insert(make_pair(string(fname), e)); | |
529 | } | |
530 | ||
531 | int | |
532 | symbol_cache::function_callback(Dwarf_Die * func, void * arg) | |
533 | { | |
534 | symbol_cache *sym = static_cast<symbol_cache*>(arg); | |
535 | sym->make_entry_for_function(func); | |
536 | return DWARF_CB_OK; | |
537 | } | |
538 | ||
539 | void | |
540 | symbol_cache::index_module(Dwarf *module_dwarf) | |
541 | { | |
542 | Dwarf_Off off = 0; | |
543 | size_t cuhl = 0; | |
544 | Dwarf_Off noff = 0; | |
545 | this->cu_die = NULL; | |
546 | while (dwarf_nextcu (module_dwarf, off, &noff, &cuhl, NULL, NULL, NULL) == 0) | |
547 | { | |
548 | Dwarf_Die die_mem; | |
549 | this->cu_die = dwarf_offdie (module_dwarf, off + cuhl, &die_mem); | |
550 | dwarf_getfuncs (this->cu_die, function_callback, this, 0); | |
551 | off = noff; | |
552 | } | |
553 | this->cu_die = NULL; | |
554 | } | |
555 | ||
556 | inline bool | |
e38d6504 | 557 | operator<(Dwarf_Die const & a, |
c8959a29 GH |
558 | Dwarf_Die const & b) |
559 | { | |
560 | return (a.addr < b.addr) | |
561 | || ((a.addr == b.addr) && (a.cu < b.cu)) | |
562 | || ((a.addr == b.addr) && (a.cu == b.cu) && (a.abbrev < b.abbrev)); | |
563 | } | |
564 | ||
565 | inline bool | |
e38d6504 | 566 | operator==(Dwarf_Die const & a, |
c8959a29 GH |
567 | Dwarf_Die const & b) |
568 | { | |
569 | return !((a < b) || (b < a)); | |
570 | } | |
571 | ||
e38d6504 | 572 | void |
c8959a29 GH |
573 | symbol_cache::select_die_subsets(Dwarf *mod, |
574 | string const & pattern, | |
575 | set<Dwarf_Die> & cus, | |
576 | multimap<Dwarf_Die, Dwarf_Die> & funcs) | |
577 | { | |
578 | cus.clear(); | |
579 | funcs.clear(); | |
580 | index *ix = NULL; | |
581 | ||
582 | // First find the index for this module. If there's no index, build | |
583 | // one. | |
584 | map<Dwarf *, index*>::const_iterator i = indices.find(mod); | |
585 | if (i == indices.end()) | |
586 | { | |
587 | this->curr_index = new index; | |
e38d6504 | 588 | index_module(mod); |
c8959a29 GH |
589 | indices.insert(make_pair(mod, this->curr_index)); |
590 | ix = this->curr_index; | |
591 | this->curr_index = NULL; | |
592 | this->cu_die = NULL; | |
593 | } | |
594 | else | |
595 | ix = i->second; | |
596 | ||
597 | assert(ix); | |
598 | ||
599 | // Now stem the pattern such that we have a minimal non-wildcard | |
600 | // prefix to search in the multimap for. We will use the full pattern | |
601 | // to narrow this set further. | |
602 | string stem; | |
603 | for (string::const_iterator i = pattern.begin(); | |
604 | i != pattern.end(); ++i) | |
605 | { | |
606 | if (*i == '?' || *i == '*' || *i == '[' || *i == ']') | |
607 | break; | |
608 | stem += *i; | |
609 | } | |
610 | ||
611 | // Now perform a lower-bound on the multimap, refine that result | |
612 | // set, and copy the CU and function DIEs into the parameter sets. | |
613 | index::const_iterator j = stem.empty() ? ix->begin() : ix->lower_bound(stem); | |
e38d6504 | 614 | while (j != ix->end() && |
c8959a29 GH |
615 | (stem.empty() || j->first.compare(0, stem.size(), stem) == 0)) |
616 | { | |
617 | if (fnmatch(pattern.c_str(), j->first.c_str(), 0) == 0) | |
618 | { | |
619 | cus.insert(j->second.cu); | |
620 | funcs.insert(make_pair(j->second.cu, j->second.function)); | |
621 | } | |
e38d6504 | 622 | ++j; |
c8959a29 GH |
623 | } |
624 | } | |
e38d6504 | 625 | |
c8959a29 GH |
626 | |
627 | ||
7e1279ea FCE |
628 | static int |
629 | query_cu (Dwarf_Die * cudie, void * arg); | |
59ff2773 FCE |
630 | |
631 | ||
bd2b1e68 GH |
632 | // Helper for dealing with selected portions of libdwfl in a more readable |
633 | // fashion, and with specific cleanup / checking / logging options. | |
634 | ||
91eefb1c GH |
635 | static const char * |
636 | dwarf_diename_integrate (Dwarf_Die *die) | |
637 | { | |
638 | Dwarf_Attribute attr_mem; | |
639 | return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); | |
640 | } | |
641 | ||
bd2b1e68 GH |
642 | struct |
643 | dwflpp | |
644 | { | |
5227f1ea | 645 | systemtap_session & sess; |
bd2b1e68 GH |
646 | Dwfl * dwfl; |
647 | ||
c8959a29 GH |
648 | symbol_cache cache; |
649 | ||
bd2b1e68 GH |
650 | // These are "current" values we focus on. |
651 | Dwfl_Module * module; | |
652 | Dwarf * module_dwarf; | |
653 | Dwarf_Addr module_bias; | |
50e0d793 GH |
654 | |
655 | // These describe the current module's PC address range | |
656 | Dwarf_Addr module_start; | |
657 | Dwarf_Addr module_end; | |
658 | ||
bd2b1e68 | 659 | Dwarf_Die * cu; |
20e4a32c | 660 | Dwarf_Die * function; |
bd2b1e68 | 661 | |
c8959a29 GH |
662 | set<Dwarf_Die> pattern_limited_cus; |
663 | multimap<Dwarf_Die, Dwarf_Die> pattern_limited_funcs; | |
664 | ||
bd2b1e68 GH |
665 | string module_name; |
666 | string cu_name; | |
667 | string function_name; | |
668 | ||
50e0d793 | 669 | |
7a053d3b | 670 | string const default_name(char const * in, |
bd2b1e68 GH |
671 | char const * type) |
672 | { | |
7a053d3b | 673 | if (in) |
bd2b1e68 | 674 | return in; |
a229fcd7 | 675 | return string(""); |
bd2b1e68 GH |
676 | } |
677 | ||
50e0d793 | 678 | |
8d695876 | 679 | void get_module_dwarf(bool required = false) |
5227f1ea GH |
680 | { |
681 | if (!module_dwarf) | |
682 | module_dwarf = dwfl_module_getdwarf(module, &module_bias); | |
7e1279ea | 683 | |
0ce64fb8 FCE |
684 | if (!module_dwarf) |
685 | { | |
686 | string msg = "cannot find "; | |
687 | if (module_name == "") | |
688 | msg += "kernel"; | |
689 | else | |
690 | msg += string("module ") + module_name; | |
691 | msg += " debuginfo"; | |
692 | ||
693 | int i = dwfl_errno(); | |
694 | if (i) | |
695 | msg += string(": ") + dwfl_errmsg (i); | |
696 | ||
697 | if (required) | |
698 | throw semantic_error (msg); | |
699 | else | |
db22e55f | 700 | cerr << "WARNING: " << msg << "\n"; |
0ce64fb8 | 701 | } |
5227f1ea GH |
702 | } |
703 | ||
c8959a29 GH |
704 | void limit_search_to_function_pattern(string const & pattern) |
705 | { | |
8d695876 | 706 | get_module_dwarf(false); |
e38d6504 RM |
707 | cache.select_die_subsets(module_dwarf, pattern, |
708 | pattern_limited_cus, | |
c8959a29 GH |
709 | pattern_limited_funcs); |
710 | } | |
50e0d793 | 711 | |
bd2b1e68 GH |
712 | void focus_on_module(Dwfl_Module * m) |
713 | { | |
714 | assert(m); | |
715 | module = m; | |
7a053d3b | 716 | module_name = default_name(dwfl_module_info(module, NULL, |
50e0d793 | 717 | &module_start, &module_end, |
bd2b1e68 GH |
718 | NULL, NULL, |
719 | NULL, NULL), | |
720 | "module"); | |
50e0d793 GH |
721 | |
722 | // Reset existing pointers and names | |
723 | ||
724 | module_dwarf = NULL; | |
725 | ||
c8959a29 GH |
726 | pattern_limited_cus.clear(); |
727 | pattern_limited_funcs.clear(); | |
e38d6504 | 728 | |
a229fcd7 | 729 | cu_name.clear(); |
50e0d793 GH |
730 | cu = NULL; |
731 | ||
a229fcd7 | 732 | function_name.clear(); |
50e0d793 | 733 | function = NULL; |
bd2b1e68 GH |
734 | } |
735 | ||
50e0d793 | 736 | |
bd2b1e68 GH |
737 | void focus_on_cu(Dwarf_Die * c) |
738 | { | |
739 | assert(c); | |
50e0d793 GH |
740 | assert(module); |
741 | ||
bd2b1e68 | 742 | cu = c; |
50e0d793 GH |
743 | cu_name = default_name(dwarf_diename(c), "CU"); |
744 | ||
745 | // Reset existing pointers and names | |
a229fcd7 | 746 | function_name.clear(); |
50e0d793 | 747 | function = NULL; |
bd2b1e68 GH |
748 | } |
749 | ||
50e0d793 | 750 | |
20e4a32c | 751 | void focus_on_function(Dwarf_Die * f) |
bd2b1e68 GH |
752 | { |
753 | assert(f); | |
50e0d793 GH |
754 | assert(module); |
755 | assert(cu); | |
756 | ||
bd2b1e68 | 757 | function = f; |
20e4a32c | 758 | function_name = default_name(dwarf_diename(function), |
bd2b1e68 | 759 | "function"); |
bd2b1e68 GH |
760 | } |
761 | ||
50e0d793 | 762 | |
bd2b1e68 GH |
763 | void focus_on_module_containing_global_address(Dwarf_Addr a) |
764 | { | |
765 | assert(dwfl); | |
50e0d793 | 766 | cu = NULL; |
0ce64fb8 FCE |
767 | Dwfl_Module* mod = dwfl_addrmodule(dwfl, a); |
768 | if (mod) // address could be wildly out of range | |
769 | focus_on_module(mod); | |
bd2b1e68 GH |
770 | } |
771 | ||
50e0d793 | 772 | |
7e1279ea | 773 | void query_cu_containing_global_address(Dwarf_Addr a, void *arg) |
bd2b1e68 | 774 | { |
bd2b1e68 | 775 | Dwarf_Addr bias; |
50e0d793 | 776 | assert(dwfl); |
5227f1ea | 777 | get_module_dwarf(); |
ab55a5ae FCE |
778 | Dwarf_Die* cudie = dwfl_module_addrdie(module, a, &bias); |
779 | if (cudie) // address could be wildly out of range | |
780 | query_cu (cudie, arg); | |
bd2b1e68 GH |
781 | assert(bias == module_bias); |
782 | } | |
783 | ||
50e0d793 | 784 | |
7e1279ea | 785 | void query_cu_containing_module_address(Dwarf_Addr a, void *arg) |
bd2b1e68 | 786 | { |
7e1279ea | 787 | query_cu_containing_global_address(module_address_to_global(a), arg); |
bd2b1e68 GH |
788 | } |
789 | ||
50e0d793 | 790 | |
bd2b1e68 GH |
791 | Dwarf_Addr module_address_to_global(Dwarf_Addr a) |
792 | { | |
50e0d793 | 793 | assert(dwfl); |
bd2b1e68 | 794 | assert(module); |
5227f1ea | 795 | get_module_dwarf(); |
c239d28c GH |
796 | if (module_name == TOK_KERNEL) |
797 | return a; | |
50e0d793 | 798 | return a + module_start; |
bd2b1e68 GH |
799 | } |
800 | ||
50e0d793 | 801 | |
bd2b1e68 GH |
802 | Dwarf_Addr global_address_to_module(Dwarf_Addr a) |
803 | { | |
804 | assert(module); | |
5227f1ea | 805 | get_module_dwarf(); |
bd2b1e68 GH |
806 | return a - module_bias; |
807 | } | |
808 | ||
809 | ||
810 | bool module_name_matches(string pattern) | |
811 | { | |
812 | assert(module); | |
813 | bool t = (fnmatch(pattern.c_str(), module_name.c_str(), 0) == 0); | |
b0ee93c4 | 814 | if (t && sess.verbose>2) |
bd2b1e68 | 815 | clog << "pattern '" << pattern << "' " |
24cb178f | 816 | << "matches " |
db22e55f | 817 | << "module '" << module_name << "'" << "\n"; |
bd2b1e68 GH |
818 | return t; |
819 | } | |
820 | ||
50e0d793 | 821 | |
bd2b1e68 GH |
822 | bool function_name_matches(string pattern) |
823 | { | |
824 | assert(function); | |
825 | bool t = (fnmatch(pattern.c_str(), function_name.c_str(), 0) == 0); | |
b0ee93c4 | 826 | if (t && sess.verbose>2) |
bd2b1e68 | 827 | clog << "pattern '" << pattern << "' " |
24cb178f | 828 | << "matches " |
db22e55f | 829 | << "function '" << function_name << "'" << "\n"; |
bd2b1e68 GH |
830 | return t; |
831 | } | |
832 | ||
50e0d793 | 833 | |
bd2b1e68 GH |
834 | bool cu_name_matches(string pattern) |
835 | { | |
836 | assert(cu); | |
837 | bool t = (fnmatch(pattern.c_str(), cu_name.c_str(), 0) == 0); | |
b0ee93c4 | 838 | if (t && sess.verbose>2) |
bd2b1e68 | 839 | clog << "pattern '" << pattern << "' " |
24cb178f | 840 | << "matches " |
db22e55f | 841 | << "CU '" << cu_name << "'" << "\n"; |
bd2b1e68 GH |
842 | return t; |
843 | } | |
844 | ||
50e0d793 | 845 | |
b40af7ee DS |
846 | // NB: "rc == 0" means OK in this case |
847 | void dwfl_assert(string desc, int rc, string extra_msg = "") | |
bd2b1e68 | 848 | { |
7e1279ea | 849 | string msg = "libdwfl failure (" + desc + "): "; |
d8067b24 FCE |
850 | if (rc < 0) msg += dwfl_errmsg (rc); |
851 | else if (rc > 0) msg += strerror (rc); | |
bd2b1e68 | 852 | if (rc != 0) |
b40af7ee DS |
853 | { |
854 | if (extra_msg.length() > 0) | |
855 | msg += "\n" + extra_msg; | |
856 | throw semantic_error (msg); | |
857 | } | |
bd2b1e68 GH |
858 | } |
859 | ||
7e1279ea FCE |
860 | void dwarf_assert(string desc, int rc) // NB: "rc == 0" means OK in this case |
861 | { | |
862 | string msg = "libdw failure (" + desc + "): "; | |
863 | if (rc < 0) msg += dwarf_errmsg (rc); | |
864 | else if (rc > 0) msg += strerror (rc); | |
865 | if (rc != 0) | |
866 | throw semantic_error (msg); | |
867 | } | |
868 | ||
50e0d793 | 869 | |
5227f1ea | 870 | dwflpp(systemtap_session & sess) |
bd2b1e68 | 871 | : |
5227f1ea | 872 | sess(sess), |
bd2b1e68 GH |
873 | dwfl(NULL), |
874 | module(NULL), | |
875 | module_dwarf(NULL), | |
876 | module_bias(0), | |
50e0d793 GH |
877 | module_start(0), |
878 | module_end(0), | |
bd2b1e68 GH |
879 | cu(NULL), |
880 | function(NULL) | |
881 | {} | |
7a053d3b | 882 | |
50e0d793 | 883 | |
bd2b1e68 GH |
884 | void setup(bool kernel) |
885 | { | |
b5d77020 | 886 | // XXX: this is where the session -R parameter could come in |
c72dc86c JS |
887 | static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug"; |
888 | static char *debuginfo_path = debuginfo_path_arr; | |
b5d77020 | 889 | |
bd2b1e68 GH |
890 | static const Dwfl_Callbacks proc_callbacks = |
891 | { | |
892 | dwfl_linux_proc_find_elf, | |
893 | dwfl_standard_find_debuginfo, | |
894 | NULL, | |
b5d77020 | 895 | & debuginfo_path |
bd2b1e68 | 896 | }; |
7a053d3b | 897 | |
bd2b1e68 GH |
898 | static const Dwfl_Callbacks kernel_callbacks = |
899 | { | |
900 | dwfl_linux_kernel_find_elf, | |
901 | dwfl_standard_find_debuginfo, | |
902 | dwfl_linux_kernel_module_section_address, | |
b5d77020 | 903 | & debuginfo_path |
bd2b1e68 GH |
904 | }; |
905 | ||
906 | if (kernel) | |
907 | { | |
7e1279ea | 908 | dwfl = dwfl_begin (&kernel_callbacks); |
bd2b1e68 | 909 | if (!dwfl) |
7e1279ea FCE |
910 | throw semantic_error ("cannot open dwfl"); |
911 | dwfl_report_begin (dwfl); | |
d8067b24 FCE |
912 | // XXX: if we have only kernel.* probe points, we shouldn't waste time |
913 | // looking for module debug-info (and vice versa). | |
20e4a32c | 914 | dwfl_assert ("dwfl_linux_kernel_report_kernel", |
b40af7ee DS |
915 | dwfl_linux_kernel_report_kernel (dwfl), |
916 | "Ensure kernel debuginfo is installed"); | |
20e4a32c | 917 | dwfl_assert ("dwfl_linux_kernel_report_modules", |
b40af7ee DS |
918 | dwfl_linux_kernel_report_modules (dwfl), |
919 | "Ensure kernel debuginfo is installed"); | |
bd2b1e68 GH |
920 | } |
921 | else | |
922 | { | |
7e1279ea FCE |
923 | dwfl = dwfl_begin (&proc_callbacks); |
924 | dwfl_report_begin (dwfl); | |
bd2b1e68 | 925 | if (!dwfl) |
7e1279ea | 926 | throw semantic_error ("cannot open dwfl"); |
bd2b1e68 GH |
927 | // XXX: Find pids or processes, do userspace stuff. |
928 | } | |
929 | ||
7e1279ea | 930 | dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); |
bd2b1e68 GH |
931 | } |
932 | ||
933 | void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, | |
934 | const char *, Dwarf_Addr, | |
77de5e9e | 935 | void *), |
bd2b1e68 GH |
936 | void * data) |
937 | { | |
bd2b1e68 GH |
938 | ptrdiff_t off = 0; |
939 | do | |
940 | { | |
77de5e9e | 941 | off = dwfl_getmodules (dwfl, callback, data, off); |
bd2b1e68 GH |
942 | } |
943 | while (off > 0); | |
7e1279ea | 944 | dwfl_assert("dwfl_getmodules", off); |
bd2b1e68 GH |
945 | } |
946 | ||
7e1279ea | 947 | |
7a053d3b | 948 | void iterate_over_cus (int (*callback)(Dwarf_Die * die, void * arg), |
bd2b1e68 GH |
949 | void * data) |
950 | { | |
0ce64fb8 | 951 | get_module_dwarf(false); |
5227f1ea | 952 | |
bd2b1e68 | 953 | if (!module_dwarf) |
0ce64fb8 | 954 | return; |
bd2b1e68 | 955 | |
c8959a29 GH |
956 | for (set<Dwarf_Die>::const_iterator i = pattern_limited_cus.begin(); |
957 | i != pattern_limited_cus.end(); ++i) | |
7a053d3b | 958 | { |
c8959a29 GH |
959 | Dwarf_Die die = *i; |
960 | if (callback (&die, data) != DWARF_CB_OK) | |
bd2b1e68 | 961 | break; |
bd2b1e68 GH |
962 | } |
963 | } | |
964 | ||
bd2b1e68 | 965 | |
7e1279ea | 966 | bool func_is_inline() |
bd2b1e68 | 967 | { |
7e1279ea FCE |
968 | assert (function); |
969 | return dwarf_func_inline (function) != 0; | |
bd2b1e68 GH |
970 | } |
971 | ||
7e1279ea FCE |
972 | void iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * arg), |
973 | void * data) | |
bd2b1e68 | 974 | { |
7e1279ea FCE |
975 | assert (function); |
976 | assert (func_is_inline ()); | |
20e4a32c | 977 | dwarf_assert ("dwarf_func_inline_instances", |
7e1279ea | 978 | dwarf_func_inline_instances (function, callback, data)); |
4fa7b22b | 979 | } |
bd2b1e68 | 980 | |
50e0d793 | 981 | |
20e4a32c | 982 | void iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg), |
7e1279ea | 983 | void * data) |
4fa7b22b | 984 | { |
7e1279ea FCE |
985 | assert (module); |
986 | assert (cu); | |
c8959a29 GH |
987 | multimap<Dwarf_Die, Dwarf_Die>::const_iterator i = pattern_limited_funcs.lower_bound(*cu); |
988 | while (i != pattern_limited_funcs.end() && (i->first == *cu)) | |
989 | { | |
990 | Dwarf_Die func_die = i->second; | |
991 | if (callback (&func_die, data) != DWARF_CB_OK) | |
992 | break; | |
993 | ||
994 | ++i; | |
995 | } | |
7e1279ea | 996 | } |
c239d28c | 997 | |
d9b516ca | 998 | |
897820ca GH |
999 | bool has_single_line_record (char const * srcfile, int lineno) |
1000 | { | |
1001 | if (lineno < 0) | |
1002 | return false; | |
1003 | ||
1004 | Dwarf_Line **srcsp = NULL; | |
1005 | size_t nsrcs = 0; | |
1006 | ||
1007 | dwarf_assert ("dwarf_getsrc_file", | |
20e4a32c | 1008 | dwarf_getsrc_file (module_dwarf, |
897820ca GH |
1009 | srcfile, lineno, 0, |
1010 | &srcsp, &nsrcs)); | |
20e4a32c | 1011 | |
897820ca GH |
1012 | return nsrcs == 1; |
1013 | } | |
1014 | ||
7e1279ea | 1015 | void iterate_over_srcfile_lines (char const * srcfile, |
20e4a32c | 1016 | int lineno, |
897820ca | 1017 | bool need_single_match, |
20e4a32c | 1018 | void (* callback) (Dwarf_Line * line, void * arg), |
7e1279ea FCE |
1019 | void *data) |
1020 | { | |
6315bd76 GH |
1021 | Dwarf_Line **srcsp = NULL; |
1022 | size_t nsrcs = 0; | |
bb788f9f | 1023 | |
7e1279ea | 1024 | get_module_dwarf(); |
bb788f9f | 1025 | |
7e1279ea | 1026 | dwarf_assert ("dwarf_getsrc_file", |
20e4a32c | 1027 | dwarf_getsrc_file (module_dwarf, |
7e1279ea FCE |
1028 | srcfile, lineno, 0, |
1029 | &srcsp, &nsrcs)); | |
20e4a32c | 1030 | |
114ffac2 | 1031 | if (need_single_match && nsrcs > 1) |
897820ca GH |
1032 | { |
1033 | // We wanted a single line record (a unique address for the | |
1034 | // line) and we got a bunch of line records. We're going to | |
1035 | // skip this probe (throw an exception) but before we throw | |
1036 | // we're going to look around a bit to see if there's a low or | |
1037 | // high line number nearby which *doesn't* have this problem, | |
1038 | // so we can give the user some advice. | |
1039 | ||
1040 | int lo_try = -1; | |
1041 | int hi_try = -1; | |
114ffac2 | 1042 | for (size_t i = 1; i < 6; ++i) |
897820ca GH |
1043 | { |
1044 | if (lo_try == -1 && has_single_line_record(srcfile, lineno - i)) | |
1045 | lo_try = lineno - i; | |
1046 | ||
1047 | if (hi_try == -1 && has_single_line_record(srcfile, lineno + i)) | |
1048 | hi_try = lineno + i; | |
1049 | } | |
1050 | ||
1051 | string advice = ""; | |
1052 | if (lo_try > 0 || hi_try > 0) | |
20e4a32c RM |
1053 | advice = " (try " |
1054 | + (lo_try > 0 | |
897820ca GH |
1055 | ? (string(srcfile) + ":" + lex_cast<string>(lo_try)) |
1056 | : string("")) | |
1057 | + (lo_try > 0 && hi_try > 0 ? " or " : "") | |
20e4a32c | 1058 | + (hi_try > 0 |
897820ca GH |
1059 | ? (string(srcfile) + ":"+ lex_cast<string>(hi_try)) |
1060 | : string("")) | |
1061 | + ")"; | |
1062 | ||
20e4a32c RM |
1063 | throw semantic_error("multiple addresses for " |
1064 | + string(srcfile) | |
897820ca GH |
1065 | + ":" |
1066 | + lex_cast<string>(lineno) | |
1067 | + advice); | |
1068 | } | |
1069 | ||
20e4a32c | 1070 | try |
bb788f9f | 1071 | { |
6315bd76 GH |
1072 | for (size_t i = 0; i < nsrcs; ++i) |
1073 | { | |
1074 | callback (srcsp[i], data); | |
1075 | } | |
bb788f9f | 1076 | } |
6315bd76 GH |
1077 | catch (...) |
1078 | { | |
1079 | free (srcsp); | |
1080 | throw; | |
20e4a32c | 1081 | } |
6315bd76 | 1082 | free (srcsp); |
50e0d793 GH |
1083 | } |
1084 | ||
1085 | ||
7e1279ea FCE |
1086 | void collect_srcfiles_matching (string const & pattern, |
1087 | set<char const *> & filtered_srcfiles) | |
50e0d793 | 1088 | { |
7e1279ea FCE |
1089 | assert (module); |
1090 | assert (cu); | |
bb788f9f | 1091 | |
7e1279ea FCE |
1092 | size_t nfiles; |
1093 | Dwarf_Files *srcfiles; | |
bb788f9f | 1094 | |
20e4a32c | 1095 | dwarf_assert ("dwarf_getsrcfiles", |
7e1279ea FCE |
1096 | dwarf_getsrcfiles (cu, &srcfiles, &nfiles)); |
1097 | { | |
1098 | for (size_t i = 0; i < nfiles; ++i) | |
50e0d793 | 1099 | { |
7e1279ea FCE |
1100 | char const * fname = dwarf_filesrc (srcfiles, i, NULL, NULL); |
1101 | if (fnmatch (pattern.c_str(), fname, 0) == 0) | |
50e0d793 | 1102 | { |
7e1279ea | 1103 | filtered_srcfiles.insert (fname); |
b0ee93c4 | 1104 | if (sess.verbose>2) |
db22e55f | 1105 | clog << "selected source file '" << fname << "'\n"; |
50e0d793 GH |
1106 | } |
1107 | } | |
7e1279ea | 1108 | } |
20e4a32c | 1109 | } |
50e0d793 | 1110 | |
7e1279ea | 1111 | void resolve_prologue_endings (map<Dwarf_Addr, func_info> & funcs) |
7d71e1d5 FCE |
1112 | { |
1113 | // This heuristic attempts to pick the first address that has a | |
34ca7d84 FCE |
1114 | // source line distinct from the function declaration's. In a |
1115 | // perfect world, this would be the first statement *past* the | |
1116 | // prologue. | |
1117 | ||
7d71e1d5 FCE |
1118 | assert(module); |
1119 | assert(cu); | |
1120 | ||
456aa31c FCE |
1121 | size_t nlines = 0; |
1122 | Dwarf_Lines *lines = NULL; | |
7d71e1d5 | 1123 | |
dc223023 FCE |
1124 | /* trouble cases: |
1125 | malloc do_symlink in init/initramfs.c tail-recursive/tiny then no-prologue | |
1126 | sys_get?id in kernel/timer.c no-prologue | |
1127 | sys_exit_group tail-recursive | |
1128 | {do_,}sys_open extra-long-prologue (gcc 3.4) | |
1129 | cpu_to_logical_apicid NULL-decl_file | |
1130 | */ | |
1131 | ||
1132 | // Fetch all srcline records, sorted by address. | |
20e4a32c RM |
1133 | dwarf_assert ("dwarf_getsrclines", |
1134 | dwarf_getsrclines(cu, &lines, &nlines)); | |
dc223023 | 1135 | // XXX: free lines[] later, but how? |
7d71e1d5 | 1136 | |
dc223023 | 1137 | for(map<Dwarf_Addr,func_info>::iterator it = funcs.begin(); it != funcs.end(); it++) |
7d71e1d5 | 1138 | { |
dc223023 FCE |
1139 | #if 0 /* someday */ |
1140 | Dwarf_Addr* bkpts = 0; | |
1141 | int n = dwarf_entry_breakpoints (& it->second.die, & bkpts); | |
1142 | // ... | |
1143 | free (bkpts); | |
1144 | #endif | |
20e4a32c | 1145 | |
dc223023 FCE |
1146 | Dwarf_Addr entrypc = it->first; |
1147 | Dwarf_Addr highpc; // NB: highpc is exclusive: [entrypc,highpc) | |
1148 | func_info* func = &it->second; | |
e38d6504 | 1149 | dwfl_assert ("dwarf_highpc", dwarf_highpc (& func->die, |
dc223023 FCE |
1150 | & highpc)); |
1151 | ||
1152 | if (func->decl_file == 0) func->decl_file = ""; | |
e38d6504 | 1153 | |
dc223023 FCE |
1154 | unsigned entrypc_srcline_idx = 0; |
1155 | Dwarf_Line* entrypc_srcline = 0; | |
1156 | // open-code binary search for exact match | |
1157 | { | |
1158 | unsigned l = 0, h = nlines; | |
1159 | while (l < h) | |
1160 | { | |
1161 | entrypc_srcline_idx = (l + h) / 2; | |
1162 | Dwarf_Addr addr; | |
1163 | Dwarf_Line *lr = dwarf_onesrcline(lines, entrypc_srcline_idx); | |
1164 | dwarf_lineaddr (lr, &addr); | |
1165 | if (addr == entrypc) { entrypc_srcline = lr; break; } | |
1166 | else if (l + 1 == h) { break; } // ran off bottom of tree | |
1167 | else if (addr < entrypc) { l = entrypc_srcline_idx; } | |
1168 | else { h = entrypc_srcline_idx; } | |
e38d6504 | 1169 | } |
dc223023 | 1170 | } |
e38d6504 RM |
1171 | if (entrypc_srcline == 0) |
1172 | throw semantic_error ("missing entrypc dwarf line record for function '" | |
dc223023 FCE |
1173 | + func->name + "'"); |
1174 | ||
1175 | if (sess.verbose>2) | |
1176 | clog << "prologue searching function '" << func->name << "'" | |
5fe3e97f | 1177 | << " 0x" << hex << entrypc << "-0x" << highpc << dec |
dc223023 FCE |
1178 | << "@" << func->decl_file << ":" << func->decl_line |
1179 | << "\n"; | |
1180 | ||
1181 | // Now we go searching for the first line record that has a | |
1182 | // file/line different from the one in the declaration. | |
1183 | // Normally, this will be the next one. BUT: | |
1184 | // | |
1185 | // We may have to skip a few because some old compilers plop | |
1186 | // in dummy line records for longer prologues. If we go too | |
1187 | // far (addr >= highpc), we take the previous one. Or, it may | |
1188 | // be the first one, if the function had no prologue, and thus | |
1189 | // the entrypc maps to a statement in the body rather than the | |
1190 | // declaration. | |
1191 | ||
1192 | unsigned postprologue_srcline_idx = entrypc_srcline_idx; | |
1193 | bool ranoff_end = false; | |
35f5f091 | 1194 | while (postprologue_srcline_idx < nlines) |
7d71e1d5 | 1195 | { |
dc223023 FCE |
1196 | Dwarf_Addr postprologue_addr; |
1197 | Dwarf_Line *lr = dwarf_onesrcline(lines, postprologue_srcline_idx); | |
1198 | dwarf_lineaddr (lr, &postprologue_addr); | |
1199 | const char* postprologue_file = dwarf_linesrc (lr, NULL, NULL); | |
1200 | int postprologue_lineno; | |
7d71e1d5 | 1201 | dwfl_assert ("dwarf_lineno", |
dc223023 | 1202 | dwarf_lineno (lr, & postprologue_lineno)); |
456aa31c | 1203 | |
b0ee93c4 | 1204 | if (sess.verbose>2) |
dc223023 FCE |
1205 | clog << "checking line record 0x" << hex << postprologue_addr << dec |
1206 | << "@" << postprologue_file << ":" << postprologue_lineno << "\n"; | |
1207 | ||
1208 | if (postprologue_addr >= highpc) | |
e38d6504 RM |
1209 | { |
1210 | ranoff_end = true; | |
1211 | postprologue_srcline_idx --; | |
dc223023 FCE |
1212 | continue; |
1213 | } | |
1214 | if (ranoff_end || | |
1215 | (strcmp (postprologue_file, func->decl_file) || // We have a winner! | |
1216 | (postprologue_lineno != func->decl_line))) | |
1217 | { | |
1218 | func->prologue_end = postprologue_addr; | |
1219 | ||
1220 | if (sess.verbose>2) | |
1221 | { | |
1222 | clog << "prologue found function '" << func->name << "'"; | |
1223 | // Add a little classification datum | |
1224 | if (postprologue_srcline_idx == entrypc_srcline_idx) clog << " (naked)"; | |
1225 | if (ranoff_end) clog << " (tail-call?)"; | |
1226 | clog << " = 0x" << hex << postprologue_addr << dec << "\n"; | |
1227 | } | |
1228 | ||
1229 | break; | |
1230 | } | |
e38d6504 | 1231 | |
dc223023 FCE |
1232 | // Let's try the next srcline. |
1233 | postprologue_srcline_idx ++; | |
1234 | } // loop over srclines | |
7d71e1d5 | 1235 | |
dc223023 FCE |
1236 | // if (strlen(func->decl_file) == 0) func->decl_file = NULL; |
1237 | ||
1238 | } // loop over functions | |
bd2b1e68 GH |
1239 | } |
1240 | ||
7e1279ea FCE |
1241 | |
1242 | bool function_entrypc (Dwarf_Addr * addr) | |
1243 | { | |
1244 | assert (function); | |
20e4a32c | 1245 | return (dwarf_entrypc (function, addr) == 0); |
7e1279ea FCE |
1246 | } |
1247 | ||
1248 | ||
1249 | bool die_entrypc (Dwarf_Die * die, Dwarf_Addr * addr) | |
1250 | { | |
1251 | Dwarf_Attribute attr_mem; | |
1252 | Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_entry_pc, &attr_mem); | |
1253 | if (attr != NULL) | |
1254 | return (dwarf_formaddr (attr, addr) == 0); | |
1255 | ||
1256 | return ( dwarf_lowpc (die, addr) == 0); | |
1257 | } | |
1258 | ||
4cd232e4 GH |
1259 | void function_die (Dwarf_Die *d) |
1260 | { | |
1261 | assert (function); | |
20e4a32c | 1262 | *d = *function; |
4cd232e4 | 1263 | } |
7e1279ea | 1264 | |
4cd232e4 | 1265 | void function_file (char const ** c) |
7e1279ea FCE |
1266 | { |
1267 | assert (function); | |
4cd232e4 | 1268 | assert (c); |
20e4a32c | 1269 | *c = dwarf_decl_file (function); |
7e1279ea FCE |
1270 | } |
1271 | ||
4cd232e4 | 1272 | void function_line (int *linep) |
7e1279ea FCE |
1273 | { |
1274 | assert (function); | |
20e4a32c | 1275 | dwarf_decl_line (function, linep); |
7e1279ea FCE |
1276 | } |
1277 | ||
1278 | bool die_has_pc (Dwarf_Die * die, Dwarf_Addr pc) | |
1279 | { | |
1280 | int res = dwarf_haspc (die, pc); | |
1281 | if (res == -1) | |
1282 | dwarf_assert ("dwarf_haspc", res); | |
1283 | return res == 1; | |
1284 | } | |
1285 | ||
1286 | ||
e36387d7 RM |
1287 | static void loc2c_error (void *arg, const char *fmt, ...) |
1288 | { | |
1289 | char *msg = NULL; | |
1290 | va_list ap; | |
1291 | va_start (ap, fmt); | |
1292 | vasprintf (&msg, fmt, ap); | |
1293 | va_end (ap); | |
1294 | throw semantic_error (msg); | |
1295 | } | |
bd2b1e68 | 1296 | |
e38d6504 RM |
1297 | void emit_address (struct obstack *pool, Dwarf_Addr address) |
1298 | { | |
1299 | // For now what we actually use is just a hard-wired constant. | |
1300 | obstack_printf (pool, "%#" PRIx64 "UL", address); | |
1301 | ||
1302 | // Turn this address into a section-relative offset if it should be one. | |
1303 | // We emit a comment approximating the variable+offset expression that | |
1304 | // relocatable module probing code will need to have. | |
1305 | Dwfl_Module *mod = dwfl_addrmodule (dwfl, address); | |
1306 | dwfl_assert ("dwfl_addrmodule", mod == NULL); | |
1307 | int n = dwfl_module_relocations (mod); | |
1308 | dwfl_assert ("dwfl_module_relocations", n < 0); | |
1309 | if (n > 0) | |
1310 | { | |
1311 | int i = dwfl_module_relocate_address (mod, &address); | |
1312 | dwfl_assert ("dwfl_module_relocate_address", i < 0); | |
1313 | const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, | |
1314 | NULL, NULL, NULL, NULL); | |
1315 | dwfl_assert ("dwfl_module_info", modname == NULL); | |
1316 | const char *secname = dwfl_module_relocation_info (mod, i, NULL); | |
1317 | dwfl_assert ("dwfl_module_relocation_info", secname == NULL); | |
1318 | if (n > 1 || secname[0] != '\0') | |
1319 | // This gives us the module name, and section name within the | |
1320 | // module, for a kernel module (or other ET_REL module object). | |
1321 | obstack_printf (pool, " /* %s(%s)+%#" PRIx64 " */", | |
1322 | modname, secname, address); | |
1323 | else | |
1324 | // This would happen for a Dwfl_Module that's a user-level DSO. | |
1325 | obstack_printf (pool, " /* %s+%#" PRIx64 " */", | |
1326 | modname, address); | |
1327 | } | |
1328 | } | |
7e1279ea | 1329 | |
4b1ad75e RM |
1330 | static void loc2c_emit_address (void *arg, struct obstack *pool, |
1331 | Dwarf_Addr address) | |
1332 | { | |
1333 | dwflpp *dwfl = (dwflpp *) arg; | |
e38d6504 | 1334 | dwfl->emit_address (pool, address); |
4b1ad75e RM |
1335 | } |
1336 | ||
e57b735a GH |
1337 | Dwarf_Attribute * |
1338 | find_variable_and_frame_base (Dwarf_Die *scope_die, | |
20e4a32c | 1339 | Dwarf_Addr pc, |
91eefb1c | 1340 | string const & local, |
e57b735a GH |
1341 | Dwarf_Die *vardie, |
1342 | Dwarf_Attribute *fb_attr_mem) | |
77de5e9e | 1343 | { |
77de5e9e | 1344 | Dwarf_Die *scopes; |
bcc12710 | 1345 | int nscopes = 0; |
e57b735a GH |
1346 | Dwarf_Attribute *fb_attr = NULL; |
1347 | ||
1348 | assert (cu); | |
bcc12710 FCE |
1349 | |
1350 | if (scope_die) | |
1351 | nscopes = dwarf_getscopes_die (scope_die, &scopes); | |
1352 | else | |
1353 | nscopes = dwarf_getscopes (cu, pc, &scopes); | |
77de5e9e | 1354 | |
77de5e9e GH |
1355 | if (nscopes == 0) |
1356 | { | |
7a053d3b | 1357 | throw semantic_error ("unable to find any scopes containing " |
59ff2773 | 1358 | + lex_cast_hex<string>(pc) |
77de5e9e GH |
1359 | + " while searching for local '" + local + "'"); |
1360 | } | |
7a053d3b | 1361 | |
77de5e9e | 1362 | int declaring_scope = dwarf_getscopevar (scopes, nscopes, |
7a053d3b RM |
1363 | local.c_str(), |
1364 | 0, NULL, 0, 0, | |
e57b735a | 1365 | vardie); |
77de5e9e GH |
1366 | if (declaring_scope < 0) |
1367 | { | |
1368 | throw semantic_error ("unable to find local '" + local + "'" | |
59ff2773 | 1369 | + " near pc " + lex_cast_hex<string>(pc)); |
77de5e9e | 1370 | } |
7a053d3b | 1371 | |
77de5e9e GH |
1372 | for (int inner = 0; inner < nscopes; ++inner) |
1373 | { | |
1374 | switch (dwarf_tag (&scopes[inner])) | |
1375 | { | |
1376 | default: | |
1377 | continue; | |
1378 | case DW_TAG_subprogram: | |
1379 | case DW_TAG_entry_point: | |
1380 | case DW_TAG_inlined_subroutine: /* XXX */ | |
1381 | if (inner >= declaring_scope) | |
1382 | fb_attr = dwarf_attr_integrate (&scopes[inner], | |
1383 | DW_AT_frame_base, | |
e57b735a | 1384 | fb_attr_mem); |
77de5e9e GH |
1385 | break; |
1386 | } | |
1387 | } | |
e57b735a GH |
1388 | return fb_attr; |
1389 | } | |
77de5e9e | 1390 | |
77de5e9e | 1391 | |
d1531387 RM |
1392 | struct location * |
1393 | translate_location(struct obstack *pool, | |
1394 | Dwarf_Attribute *attr, Dwarf_Addr pc, | |
1395 | Dwarf_Attribute *fb_attr, | |
1396 | struct location **tail) | |
1397 | { | |
1398 | Dwarf_Op *expr; | |
1399 | size_t len; | |
1400 | ||
1401 | switch (dwarf_getlocation_addr (attr, pc - module_bias, &expr, &len, 1)) | |
1402 | { | |
1403 | case 1: /* Should always happen. */ | |
1404 | if (len > 0) | |
1405 | break; | |
1406 | /* Fall through. */ | |
1407 | ||
1408 | case 0: /* Shouldn't happen. */ | |
1409 | throw semantic_error ("not accessible at this address"); | |
1410 | ||
1411 | default: /* Shouldn't happen. */ | |
1412 | case -1: | |
1413 | throw semantic_error (string ("dwarf_getlocation_addr failed") + | |
1414 | string (dwarf_errmsg (-1))); | |
1415 | } | |
1416 | ||
1417 | return c_translate_location (pool, &loc2c_error, this, | |
1418 | &loc2c_emit_address, | |
1419 | 1, module_bias, | |
1420 | pc, expr, len, tail, fb_attr); | |
1421 | } | |
1422 | ||
e57b735a GH |
1423 | Dwarf_Die * |
1424 | translate_components(struct obstack *pool, | |
20e4a32c RM |
1425 | struct location **tail, |
1426 | Dwarf_Addr pc, | |
e57b735a GH |
1427 | vector<pair<target_symbol::component_type, |
1428 | std::string> > const & components, | |
1429 | Dwarf_Die *vardie, | |
1430 | Dwarf_Die *die_mem, | |
1431 | Dwarf_Attribute *attr_mem) | |
1432 | { | |
1433 | Dwarf_Die *die = vardie; | |
d9b516ca RM |
1434 | unsigned i = 0; |
1435 | while (i < components.size()) | |
1436 | { | |
e57b735a | 1437 | die = dwarf_formref_die (attr_mem, die_mem); |
d9b516ca RM |
1438 | const int typetag = dwarf_tag (die); |
1439 | switch (typetag) | |
1440 | { | |
1441 | case DW_TAG_typedef: | |
fdfbe4f7 GH |
1442 | case DW_TAG_const_type: |
1443 | case DW_TAG_volatile_type: | |
d9b516ca RM |
1444 | /* Just iterate on the referent type. */ |
1445 | break; | |
91eefb1c | 1446 | |
d9b516ca RM |
1447 | case DW_TAG_pointer_type: |
1448 | if (components[i].first == target_symbol::comp_literal_array_index) | |
1449 | goto subscript; | |
91eefb1c | 1450 | |
e57b735a | 1451 | c_translate_pointer (pool, 1, module_bias, die, tail); |
d9b516ca | 1452 | break; |
91eefb1c | 1453 | |
d9b516ca RM |
1454 | case DW_TAG_array_type: |
1455 | if (components[i].first == target_symbol::comp_literal_array_index) | |
1456 | { | |
1457 | subscript: | |
e57b735a | 1458 | c_translate_array (pool, 1, module_bias, die, tail, |
d9b516ca RM |
1459 | NULL, lex_cast<Dwarf_Word>(components[i].second)); |
1460 | ++i; | |
1461 | } | |
1462 | else | |
1463 | throw semantic_error("bad field '" | |
1464 | + components[i].second | |
1465 | + "' for array type"); | |
1466 | break; | |
91eefb1c | 1467 | |
d9b516ca RM |
1468 | case DW_TAG_structure_type: |
1469 | case DW_TAG_union_type: | |
e57b735a | 1470 | switch (dwarf_child (die, die_mem)) |
d9b516ca RM |
1471 | { |
1472 | case 1: /* No children. */ | |
1473 | throw semantic_error ("empty struct " | |
1474 | + string (dwarf_diename_integrate (die) ?: "<anonymous>")); | |
1475 | break; | |
1476 | case -1: /* Error. */ | |
1477 | default: /* Shouldn't happen */ | |
1478 | throw semantic_error (string (typetag == DW_TAG_union_type ? "union" : "struct") | |
1479 | + string (dwarf_diename_integrate (die) ?: "<anonymous>") | |
1480 | + string (dwarf_errmsg (-1))); | |
1481 | break; | |
1482 | ||
1483 | case 0: | |
1484 | break; | |
1485 | } | |
1486 | ||
1487 | while (dwarf_tag (die) != DW_TAG_member | |
1488 | || ({ const char *member = dwarf_diename_integrate (die); | |
1489 | member == NULL || string(member) != components[i].second; })) | |
e57b735a | 1490 | if (dwarf_siblingof (die, die_mem) != 0) |
d9b516ca RM |
1491 | throw semantic_error ("field name " + components[i].second + " not found"); |
1492 | ||
1493 | if (dwarf_attr_integrate (die, DW_AT_data_member_location, | |
e57b735a | 1494 | attr_mem) == NULL) |
d9b516ca RM |
1495 | { |
1496 | /* Union members don't usually have a location, | |
1497 | but just use the containing union's location. */ | |
1498 | if (typetag != DW_TAG_union_type) | |
1499 | throw semantic_error ("no location for field " | |
1500 | + components[i].second | |
1501 | + " :" + string(dwarf_errmsg (-1))); | |
1502 | } | |
1503 | else | |
d1531387 | 1504 | translate_location (pool, attr_mem, pc, NULL, tail); |
d9b516ca RM |
1505 | ++i; |
1506 | break; | |
1507 | ||
1508 | case DW_TAG_base_type: | |
1509 | throw semantic_error ("field " | |
1510 | + components[i].second | |
1511 | + " vs base type " | |
1512 | + string(dwarf_diename_integrate (die) ?: "<anonymous type>")); | |
1513 | break; | |
1514 | case -1: | |
1515 | throw semantic_error ("cannot find type: " + string(dwarf_errmsg (-1))); | |
1516 | break; | |
1517 | ||
1518 | default: | |
1519 | throw semantic_error (string(dwarf_diename_integrate (die) ?: "<anonymous type>") | |
1520 | + ": unexpected type tag " | |
1521 | + lex_cast<string>(dwarf_tag (die))); | |
1522 | break; | |
1523 | } | |
1524 | ||
1525 | /* Now iterate on the type in DIE's attribute. */ | |
e57b735a | 1526 | if (dwarf_attr_integrate (die, DW_AT_type, attr_mem) == NULL) |
d9b516ca RM |
1527 | throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1))); |
1528 | } | |
e57b735a GH |
1529 | return die; |
1530 | } | |
91eefb1c | 1531 | |
d9b516ca | 1532 | |
e57b735a GH |
1533 | Dwarf_Die * |
1534 | resolve_unqualified_inner_typedie (Dwarf_Die *typedie_mem, | |
1535 | Dwarf_Attribute *attr_mem) | |
1536 | { | |
1537 | ; | |
d9b516ca | 1538 | Dwarf_Die *typedie; |
e57b735a | 1539 | int typetag = 0; |
d9b516ca | 1540 | while (1) |
20e4a32c | 1541 | { |
e57b735a | 1542 | typedie = dwarf_formref_die (attr_mem, typedie_mem); |
d9b516ca | 1543 | if (typedie == NULL) |
e57b735a | 1544 | throw semantic_error ("cannot get type: " + string(dwarf_errmsg (-1))); |
d9b516ca | 1545 | typetag = dwarf_tag (typedie); |
20e4a32c | 1546 | if (typetag != DW_TAG_typedef && |
fdfbe4f7 GH |
1547 | typetag != DW_TAG_const_type && |
1548 | typetag != DW_TAG_volatile_type) | |
91eefb1c | 1549 | break; |
e57b735a GH |
1550 | if (dwarf_attr_integrate (typedie, DW_AT_type, attr_mem) == NULL) |
1551 | throw semantic_error ("cannot get type of pointee: " + string(dwarf_errmsg (-1))); | |
d9b516ca | 1552 | } |
e57b735a GH |
1553 | return typedie; |
1554 | } | |
91eefb1c | 1555 | |
91eefb1c | 1556 | |
20e4a32c | 1557 | void |
e57b735a GH |
1558 | translate_final_fetch_or_store (struct obstack *pool, |
1559 | struct location **tail, | |
1560 | Dwarf_Addr module_bias, | |
1561 | Dwarf_Die *die, | |
1562 | Dwarf_Attribute *attr_mem, | |
1563 | bool lvalue, | |
1564 | string & prelude, | |
1565 | string & postlude, | |
1566 | exp_type & ty) | |
1567 | { | |
1568 | /* First boil away any qualifiers associated with the type DIE of | |
1569 | the final location to be accessed. */ | |
fdfbe4f7 | 1570 | |
e57b735a GH |
1571 | Dwarf_Die typedie_mem; |
1572 | Dwarf_Die *typedie; | |
1573 | int typetag; | |
1574 | ||
1575 | typedie = resolve_unqualified_inner_typedie (&typedie_mem, attr_mem); | |
1576 | typetag = dwarf_tag (typedie); | |
1577 | ||
1578 | /* Then switch behavior depending on the type of fetch/store we | |
1579 | want, and the type and pointer-ness of the final location. */ | |
20e4a32c | 1580 | |
fdfbe4f7 GH |
1581 | switch (typetag) |
1582 | { | |
fdfbe4f7 | 1583 | default: |
66d284f4 FCE |
1584 | throw semantic_error ("unsupported type tag " |
1585 | + lex_cast<string>(typetag)); | |
fdfbe4f7 | 1586 | break; |
66d284f4 | 1587 | |
e7a012f0 | 1588 | case DW_TAG_enumeration_type: |
fdfbe4f7 GH |
1589 | case DW_TAG_base_type: |
1590 | ty = pe_long; | |
e57b735a GH |
1591 | if (lvalue) |
1592 | c_translate_store (pool, 1, module_bias, die, typedie, tail, | |
1593 | "THIS->value"); | |
20e4a32c | 1594 | else |
e57b735a GH |
1595 | c_translate_fetch (pool, 1, module_bias, die, typedie, tail, |
1596 | "THIS->__retvalue"); | |
fdfbe4f7 GH |
1597 | break; |
1598 | ||
1599 | case DW_TAG_array_type: | |
1600 | case DW_TAG_pointer_type: | |
e57b735a GH |
1601 | |
1602 | if (lvalue) | |
1603 | throw semantic_error ("cannot store into target pointer value"); | |
1604 | ||
fdfbe4f7 GH |
1605 | { |
1606 | Dwarf_Die pointee_typedie_mem; | |
1607 | Dwarf_Die *pointee_typedie; | |
1608 | Dwarf_Word pointee_encoding; | |
246b383e | 1609 | Dwarf_Word pointee_byte_size = 0; |
fdfbe4f7 | 1610 | |
e57b735a GH |
1611 | pointee_typedie = resolve_unqualified_inner_typedie (&pointee_typedie_mem, attr_mem); |
1612 | ||
1613 | if (dwarf_attr_integrate (pointee_typedie, DW_AT_byte_size, attr_mem)) | |
1614 | dwarf_formudata (attr_mem, &pointee_byte_size); | |
20e4a32c RM |
1615 | |
1616 | dwarf_formudata (dwarf_attr_integrate (pointee_typedie, DW_AT_encoding, attr_mem), | |
fdfbe4f7 GH |
1617 | &pointee_encoding); |
1618 | ||
f9eba66e FCE |
1619 | // We have the pointer: cast it to an integral type via &(*(...)) |
1620 | ||
1621 | // NB: per bug #1187, at one point char*-like types were | |
1622 | // automagically converted here to systemtap string values. | |
1623 | // For several reasons, this was taken back out, leaving | |
1624 | // pointer-to-string "conversion" (copying) to tapset functions. | |
1625 | ||
1626 | ty = pe_long; | |
1627 | if (typetag == DW_TAG_array_type) | |
e57b735a | 1628 | c_translate_array (pool, 1, module_bias, typedie, tail, NULL, 0); |
fdfbe4f7 | 1629 | else |
e57b735a | 1630 | c_translate_pointer (pool, 1, module_bias, typedie, tail); |
20e4a32c | 1631 | c_translate_addressof (pool, 1, module_bias, NULL, pointee_typedie, tail, |
f9eba66e | 1632 | "THIS->__retvalue"); |
fdfbe4f7 | 1633 | } |
20e4a32c | 1634 | break; |
fdfbe4f7 | 1635 | } |
20e4a32c | 1636 | } |
e57b735a | 1637 | |
e19fda4e DS |
1638 | string |
1639 | express_as_string (string prelude, | |
1640 | string postlude, | |
1641 | struct location *head) | |
1642 | { | |
1643 | size_t bufsz = 1024; | |
1644 | char *buf = static_cast<char*>(malloc(bufsz)); | |
1645 | assert(buf); | |
1646 | ||
1647 | FILE *memstream = open_memstream (&buf, &bufsz); | |
1648 | assert(memstream); | |
1649 | ||
1650 | fprintf(memstream, "{\n"); | |
1651 | fprintf(memstream, prelude.c_str()); | |
1652 | bool deref = c_emit_location (memstream, head, 1); | |
1653 | fprintf(memstream, postlude.c_str()); | |
1654 | fprintf(memstream, " goto out;\n"); | |
1655 | ||
1656 | // dummy use of deref_fault label, to disable warning if deref() not used | |
1657 | fprintf(memstream, "if (0) goto deref_fault;\n"); | |
1658 | ||
1659 | // XXX: deref flag not reliable; emit fault label unconditionally | |
1660 | // XXX: print the faulting address, like the user_string/kernel_string | |
1661 | // tapset functions do | |
1662 | if (deref) ; | |
1663 | fprintf(memstream, | |
1664 | "deref_fault:\n" | |
1665 | " c->last_error = \"pointer dereference fault\";\n" | |
1666 | " goto out;\n"); | |
1667 | fprintf(memstream, "}\n"); | |
1668 | ||
1669 | fclose (memstream); | |
1670 | string result(buf); | |
1671 | free (buf); | |
1672 | return result; | |
1673 | } | |
e57b735a | 1674 | |
20e4a32c | 1675 | string |
e57b735a | 1676 | literal_stmt_for_local (Dwarf_Die *scope_die, |
20e4a32c | 1677 | Dwarf_Addr pc, |
e57b735a GH |
1678 | string const & local, |
1679 | vector<pair<target_symbol::component_type, | |
1680 | std::string> > const & components, | |
1681 | bool lvalue, | |
1682 | exp_type & ty) | |
1683 | { | |
1684 | Dwarf_Die vardie; | |
1685 | Dwarf_Attribute fb_attr_mem, *fb_attr = NULL; | |
1686 | ||
20e4a32c | 1687 | fb_attr = find_variable_and_frame_base (scope_die, pc, local, |
e57b735a GH |
1688 | &vardie, &fb_attr_mem); |
1689 | ||
b0ee93c4 | 1690 | if (sess.verbose>2) |
e57b735a GH |
1691 | clog << "finding location for local '" << local |
1692 | << "' near address " << hex << pc | |
1693 | << ", module bias " << module_bias << dec | |
db22e55f | 1694 | << "\n"; |
e57b735a GH |
1695 | |
1696 | Dwarf_Attribute attr_mem; | |
1697 | if (dwarf_attr_integrate (&vardie, DW_AT_location, &attr_mem) == NULL) | |
1698 | { | |
1699 | throw semantic_error("failed to retrieve location " | |
20e4a32c RM |
1700 | "attribute for local '" + local |
1701 | + "' (dieoffset: " | |
1702 | + lex_cast_hex<string>(dwarf_dieoffset (&vardie)) | |
e57b735a GH |
1703 | + ")"); |
1704 | } | |
1705 | ||
1706 | #define obstack_chunk_alloc malloc | |
1707 | #define obstack_chunk_free free | |
1708 | ||
1709 | struct obstack pool; | |
1710 | obstack_init (&pool); | |
1711 | struct location *tail = NULL; | |
1712 | ||
1713 | /* Given $foo->bar->baz[NN], translate the location of foo. */ | |
1714 | ||
d1531387 RM |
1715 | struct location *head = translate_location (&pool, |
1716 | &attr_mem, pc, fb_attr, &tail); | |
e57b735a GH |
1717 | |
1718 | if (dwarf_attr_integrate (&vardie, DW_AT_type, &attr_mem) == NULL) | |
1719 | throw semantic_error("failed to retrieve type " | |
1720 | "attribute for local '" + local + "'"); | |
1721 | ||
1722 | ||
1723 | /* Translate the ->bar->baz[NN] parts. */ | |
1724 | ||
1725 | Dwarf_Die die_mem, *die = NULL; | |
20e4a32c | 1726 | die = translate_components (&pool, &tail, pc, components, |
e57b735a GH |
1727 | &vardie, &die_mem, &attr_mem); |
1728 | ||
20e4a32c RM |
1729 | /* Translate the assignment part, either |
1730 | x = $foo->bar->baz[NN] | |
1731 | or | |
e57b735a GH |
1732 | $foo->bar->baz[NN] = x |
1733 | */ | |
1734 | ||
1735 | string prelude, postlude; | |
20e4a32c | 1736 | translate_final_fetch_or_store (&pool, &tail, module_bias, |
e57b735a GH |
1737 | die, &attr_mem, lvalue, |
1738 | prelude, postlude, ty); | |
1739 | ||
1740 | /* Write the translation to a string. */ | |
e19fda4e DS |
1741 | return express_as_string(prelude, postlude, head); |
1742 | } | |
20e4a32c | 1743 | |
20e4a32c | 1744 | |
e19fda4e DS |
1745 | string |
1746 | literal_stmt_for_return (Dwarf_Die *scope_die, | |
1747 | Dwarf_Addr pc, | |
1748 | vector<pair<target_symbol::component_type, | |
1749 | std::string> > const & components, | |
1750 | bool lvalue, | |
1751 | exp_type & ty) | |
1752 | { | |
1753 | if (sess.verbose>2) | |
1754 | clog << "literal_stmt_for_return: finding return value for " | |
1755 | << dwarf_diename (scope_die) | |
1756 | << "(" | |
1757 | << dwarf_diename (cu) | |
1758 | << ")\n"; | |
7a053d3b | 1759 | |
e19fda4e DS |
1760 | struct obstack pool; |
1761 | obstack_init (&pool); | |
1762 | struct location *tail = NULL; | |
7a053d3b | 1763 | |
e19fda4e DS |
1764 | /* Given $return->bar->baz[NN], translate the location of return. */ |
1765 | const Dwarf_Op *locops; | |
1766 | int nlocops = dwfl_module_return_value_location (module, scope_die, | |
1767 | &locops); | |
1768 | if (nlocops < 0) | |
1769 | { | |
1770 | throw semantic_error("failed to retrieve return value location"); | |
1771 | } | |
1772 | // the function has no return value (e.g. "void" in C) | |
1773 | else if (nlocops == 0) | |
1774 | { | |
1775 | throw semantic_error("function has no return value"); | |
1776 | } | |
a781f401 | 1777 | |
e19fda4e DS |
1778 | struct location *head = c_translate_location (&pool, &loc2c_error, this, |
1779 | &loc2c_emit_address, | |
1780 | 1, module_bias, | |
1781 | pc, locops, nlocops, | |
1782 | &tail, NULL); | |
7a053d3b | 1783 | |
e19fda4e | 1784 | /* Translate the ->bar->baz[NN] parts. */ |
7a053d3b | 1785 | |
e19fda4e DS |
1786 | Dwarf_Attribute attr_mem; |
1787 | Dwarf_Attribute *attr = dwarf_attr (scope_die, DW_AT_type, &attr_mem); | |
1788 | ||
1789 | Dwarf_Die vardie_mem; | |
1790 | Dwarf_Die *vardie = dwarf_formref_die (attr, &vardie_mem); | |
1791 | ||
1792 | Dwarf_Die die_mem, *die = NULL; | |
1793 | die = translate_components (&pool, &tail, pc, components, | |
1794 | vardie, &die_mem, &attr_mem); | |
1795 | ||
1796 | /* Translate the assignment part, either | |
1797 | x = $return->bar->baz[NN] | |
1798 | or | |
1799 | $return->bar->baz[NN] = x | |
1800 | */ | |
1801 | ||
1802 | string prelude, postlude; | |
1803 | translate_final_fetch_or_store (&pool, &tail, module_bias, | |
1804 | die, &attr_mem, lvalue, | |
1805 | prelude, postlude, ty); | |
1806 | ||
1807 | /* Write the translation to a string. */ | |
1808 | return express_as_string(prelude, postlude, head); | |
1809 | } | |
7a053d3b | 1810 | |
77de5e9e | 1811 | |
bd2b1e68 GH |
1812 | ~dwflpp() |
1813 | { | |
1814 | if (dwfl) | |
1815 | dwfl_end(dwfl); | |
1816 | } | |
1817 | }; | |
1818 | ||
20c6c071 | 1819 | |
7a053d3b | 1820 | enum |
bd2b1e68 | 1821 | function_spec_type |
7a053d3b | 1822 | { |
bd2b1e68 GH |
1823 | function_alone, |
1824 | function_and_file, | |
7a053d3b | 1825 | function_file_and_line |
bd2b1e68 GH |
1826 | }; |
1827 | ||
ec4373ff | 1828 | |
bd2b1e68 | 1829 | struct dwarf_builder; |
77de5e9e GH |
1830 | struct dwarf_query; |
1831 | ||
2930abc7 | 1832 | |
bd2b1e68 | 1833 | struct dwarf_derived_probe : public derived_probe |
b55bc428 | 1834 | { |
2930abc7 FCE |
1835 | dwarf_derived_probe (Dwarf_Die *scope_die, |
1836 | Dwarf_Addr addr, | |
1837 | dwarf_query & q); | |
20e4a32c | 1838 | |
2930abc7 FCE |
1839 | vector<Dwarf_Addr> probe_points; |
1840 | bool has_return; | |
1841 | ||
dc38c0ae DS |
1842 | void register_probe (systemtap_session& s); |
1843 | ||
2930abc7 | 1844 | void add_probe_point(string const & funcname, |
4cd232e4 GH |
1845 | char const * filename, |
1846 | int line, | |
1847 | Dwarf_Addr addr, | |
1848 | dwarf_query & q); | |
d9b516ca | 1849 | |
bd2b1e68 | 1850 | // Pattern registration helpers. |
7a053d3b | 1851 | static void register_relative_variants(match_node * root, |
bd2b1e68 | 1852 | dwarf_builder * dw); |
7a053d3b | 1853 | static void register_statement_variants(match_node * root, |
bd2b1e68 | 1854 | dwarf_builder * dw); |
fd6602a0 FCE |
1855 | static void register_function_variants(match_node * root, |
1856 | dwarf_builder * dw); | |
54efe513 GH |
1857 | static void register_inline_variants(match_node * root, |
1858 | dwarf_builder * dw); | |
7a053d3b | 1859 | static void register_function_and_statement_variants(match_node * root, |
bd2b1e68 | 1860 | dwarf_builder * dw); |
20c6c071 | 1861 | static void register_patterns(match_node * root); |
7a053d3b | 1862 | |
46b84a80 DS |
1863 | virtual void emit_registrations_start (translator_output* o, unsigned index); |
1864 | virtual void emit_registrations_end (translator_output * o, unsigned index); | |
35d4ab18 FCE |
1865 | virtual void emit_deregistrations (translator_output * o); |
1866 | virtual void emit_probe_entries (translator_output * o); | |
20c6c071 GH |
1867 | }; |
1868 | ||
dc38c0ae DS |
1869 | |
1870 | struct dwarf_derived_probe_group: public derived_probe_group | |
1871 | { | |
1872 | private: | |
1873 | vector<dwarf_derived_probe*> probes; | |
1874 | ||
1875 | public: | |
1876 | virtual void register_probe(dwarf_derived_probe* p) { probes.push_back (p); } | |
1877 | virtual size_t size () { return probes.size (); } | |
1878 | ||
1879 | virtual void emit_probes (translator_output* op, unparser* up); | |
46b84a80 | 1880 | virtual void emit_module_init (translator_output* o); |
dc38c0ae DS |
1881 | }; |
1882 | ||
1883 | ||
20c6c071 | 1884 | // Helper struct to thread through the dwfl callbacks. |
7a053d3b | 1885 | struct |
20c6c071 GH |
1886 | dwarf_query |
1887 | { | |
5227f1ea GH |
1888 | dwarf_query(systemtap_session & sess, |
1889 | probe * base_probe, | |
20c6c071 GH |
1890 | probe_point * base_loc, |
1891 | dwflpp & dw, | |
1892 | map<string, literal *> const & params, | |
1893 | vector<derived_probe *> & results); | |
bd2b1e68 | 1894 | |
5227f1ea GH |
1895 | systemtap_session & sess; |
1896 | ||
bd2b1e68 | 1897 | // Parameter extractors. |
7a053d3b | 1898 | static bool has_null_param(map<string, literal *> const & params, |
bd2b1e68 | 1899 | string const & k); |
7a053d3b | 1900 | static bool get_string_param(map<string, literal *> const & params, |
bd2b1e68 | 1901 | string const & k, string & v); |
7a053d3b | 1902 | static bool get_number_param(map<string, literal *> const & params, |
bd2b1e68 | 1903 | string const & k, long & v); |
c239d28c GH |
1904 | static bool get_number_param(map<string, literal *> const & params, |
1905 | string const & k, Dwarf_Addr & v); | |
b55bc428 | 1906 | |
77de5e9e GH |
1907 | string pt_regs_member_for_regnum(uint8_t dwarf_regnum); |
1908 | ||
2930abc7 | 1909 | // Result vector and flavour-sorting mechanism. |
20c6c071 | 1910 | vector<derived_probe *> & results; |
2930abc7 FCE |
1911 | bool probe_has_no_target_variables; |
1912 | map<string, dwarf_derived_probe *> probe_flavours; | |
1913 | void add_probe_point(string const & funcname, | |
1914 | char const * filename, | |
1915 | int line, | |
1916 | Dwarf_Die *scope_die, | |
1917 | Dwarf_Addr addr); | |
20c6c071 | 1918 | |
0daad364 JS |
1919 | set<string> blacklisted_probes; |
1920 | set<string> blacklisted_return_probes; | |
1921 | void build_blacklist(); | |
1922 | ||
36f9dd1d FCE |
1923 | bool blacklisted_p(string const & funcname, |
1924 | char const * filename, | |
1925 | int line, | |
1926 | Dwarf_Die *scope_die, | |
1927 | Dwarf_Addr addr); | |
1928 | ||
2930abc7 | 1929 | // Extracted parameters. |
20c6c071 GH |
1930 | bool has_kernel; |
1931 | bool has_process; | |
1932 | bool has_module; | |
7a053d3b RM |
1933 | string process_val; |
1934 | string module_val; | |
1935 | string function_val; | |
20c6c071 | 1936 | |
54efe513 | 1937 | bool has_inline_str; |
20c6c071 GH |
1938 | bool has_function_str; |
1939 | bool has_statement_str; | |
54efe513 | 1940 | bool has_inline_num; |
20c6c071 GH |
1941 | bool has_function_num; |
1942 | bool has_statement_num; | |
7a053d3b RM |
1943 | string statement_str_val; |
1944 | string function_str_val; | |
54efe513 | 1945 | string inline_str_val; |
c239d28c GH |
1946 | Dwarf_Addr statement_num_val; |
1947 | Dwarf_Addr function_num_val; | |
54efe513 | 1948 | Dwarf_Addr inline_num_val; |
20c6c071 GH |
1949 | |
1950 | bool has_callees; | |
7a053d3b | 1951 | long callee_val; |
20c6c071 GH |
1952 | |
1953 | bool has_return; | |
1954 | ||
1955 | bool has_label; | |
1956 | string label_val; | |
1957 | ||
1958 | bool has_relative; | |
1959 | long relative_val; | |
1960 | ||
1961 | function_spec_type parse_function_spec(string & spec); | |
1962 | function_spec_type spec_type; | |
1963 | string function; | |
1964 | string file; | |
1965 | int line; | |
1966 | ||
7e1279ea FCE |
1967 | set<char const *> filtered_srcfiles; |
1968 | ||
1969 | // Map official entrypc -> func_info object | |
1970 | map<Dwarf_Addr, inline_instance_info> filtered_inlines; | |
1971 | map<Dwarf_Addr, func_info> filtered_functions; | |
1972 | bool choose_next_line; | |
1973 | Dwarf_Addr entrypc_for_next_line; | |
1974 | ||
20c6c071 GH |
1975 | probe * base_probe; |
1976 | probe_point * base_loc; | |
1977 | dwflpp & dw; | |
b55bc428 FCE |
1978 | }; |
1979 | ||
98afd80e FCE |
1980 | |
1981 | struct dwarf_builder: public derived_probe_builder | |
b55bc428 | 1982 | { |
e38d6504 RM |
1983 | dwflpp *kern_dw; |
1984 | dwflpp *user_dw; | |
1985 | dwarf_builder() | |
1986 | : kern_dw(NULL), user_dw(NULL) | |
c8959a29 | 1987 | {} |
e38d6504 RM |
1988 | ~dwarf_builder() |
1989 | { | |
1990 | if (kern_dw) | |
c8959a29 | 1991 | delete kern_dw; |
e38d6504 | 1992 | if (user_dw) |
c8959a29 GH |
1993 | delete user_dw; |
1994 | } | |
5227f1ea | 1995 | virtual void build(systemtap_session & sess, |
7a053d3b | 1996 | probe * base, |
20c6c071 GH |
1997 | probe_point * location, |
1998 | std::map<std::string, literal *> const & parameters, | |
20c6c071 | 1999 | vector<derived_probe *> & finished_results); |
b55bc428 FCE |
2000 | }; |
2001 | ||
7a053d3b RM |
2002 | bool |
2003 | dwarf_query::has_null_param(map<string, literal *> const & params, | |
20c6c071 | 2004 | string const & k) |
bd2b1e68 GH |
2005 | { |
2006 | map<string, literal *>::const_iterator i = params.find(k); | |
2007 | if (i != params.end() && i->second == NULL) | |
2008 | return true; | |
2009 | return false; | |
2010 | } | |
2011 | ||
7a053d3b RM |
2012 | bool |
2013 | dwarf_query::get_string_param(map<string, literal *> const & params, | |
20c6c071 | 2014 | string const & k, string & v) |
bd2b1e68 | 2015 | { |
98afd80e | 2016 | return derived_probe_builder::get_param (params, k, v); |
bd2b1e68 GH |
2017 | } |
2018 | ||
7a053d3b RM |
2019 | bool |
2020 | dwarf_query::get_number_param(map<string, literal *> const & params, | |
20c6c071 | 2021 | string const & k, long & v) |
bd2b1e68 | 2022 | { |
98afd80e FCE |
2023 | int64_t value; |
2024 | bool present = derived_probe_builder::get_param (params, k, value); | |
2025 | v = (long) value; | |
2026 | return present; | |
bd2b1e68 GH |
2027 | } |
2028 | ||
c239d28c GH |
2029 | bool |
2030 | dwarf_query::get_number_param(map<string, literal *> const & params, | |
2031 | string const & k, Dwarf_Addr & v) | |
2032 | { | |
98afd80e FCE |
2033 | int64_t value; |
2034 | bool present = derived_probe_builder::get_param (params, k, value); | |
2035 | v = (Dwarf_Addr) value; | |
2036 | return present; | |
c239d28c GH |
2037 | } |
2038 | ||
77de5e9e | 2039 | |
5227f1ea GH |
2040 | dwarf_query::dwarf_query(systemtap_session & sess, |
2041 | probe * base_probe, | |
20c6c071 GH |
2042 | probe_point * base_loc, |
2043 | dwflpp & dw, | |
2044 | map<string, literal *> const & params, | |
2045 | vector<derived_probe *> & results) | |
5227f1ea GH |
2046 | : sess(sess), |
2047 | results(results), | |
2930abc7 | 2048 | probe_has_no_target_variables(false), |
7a053d3b | 2049 | base_probe(base_probe), |
20c6c071 GH |
2050 | base_loc(base_loc), |
2051 | dw(dw) | |
bd2b1e68 | 2052 | { |
20c6c071 | 2053 | |
bd2b1e68 GH |
2054 | // Reduce the query to more reasonable semantic values (booleans, |
2055 | // extracted strings, numbers, etc). | |
2056 | ||
2057 | has_kernel = has_null_param(params, TOK_KERNEL); | |
2058 | has_module = get_string_param(params, TOK_MODULE, module_val); | |
2059 | has_process = get_string_param(params, TOK_PROCESS, process_val); | |
2060 | ||
2061 | has_function_str = get_string_param(params, TOK_FUNCTION, function_str_val); | |
2062 | has_function_num = get_number_param(params, TOK_FUNCTION, function_num_val); | |
2063 | ||
54efe513 GH |
2064 | has_inline_str = get_string_param(params, TOK_INLINE, inline_str_val); |
2065 | has_inline_num = get_number_param(params, TOK_INLINE, inline_num_val); | |
2066 | ||
bd2b1e68 GH |
2067 | has_statement_str = get_string_param(params, TOK_STATEMENT, statement_str_val); |
2068 | has_statement_num = get_number_param(params, TOK_STATEMENT, statement_num_val); | |
2069 | ||
2070 | callee_val = 1; | |
7a053d3b | 2071 | has_callees = (has_null_param(params, TOK_CALLEES) || |
bd2b1e68 GH |
2072 | get_number_param(params, TOK_CALLEES, callee_val)); |
2073 | ||
2074 | has_return = has_null_param(params, TOK_RETURN); | |
2075 | ||
2076 | has_label = get_string_param(params, TOK_LABEL, label_val); | |
2077 | has_relative = get_number_param(params, TOK_RELATIVE, relative_val); | |
7a053d3b | 2078 | |
bd2b1e68 GH |
2079 | if (has_function_str) |
2080 | spec_type = parse_function_spec(function_str_val); | |
54efe513 GH |
2081 | else if (has_inline_str) |
2082 | spec_type = parse_function_spec(inline_str_val); | |
bd2b1e68 GH |
2083 | else if (has_statement_str) |
2084 | spec_type = parse_function_spec(statement_str_val); | |
0daad364 JS |
2085 | |
2086 | build_blacklist(); | |
2087 | } | |
2088 | ||
2089 | ||
2090 | void | |
2091 | dwarf_query::build_blacklist() | |
2092 | { | |
2093 | // FIXME: it would be nice if these blacklisted functions were pulled in | |
2094 | // dynamically, instead of being statically defined here. | |
2095 | ||
2096 | // Most of these are marked __kprobes in newer kernels. We list them here so | |
2097 | // the translator can block them on older kernels that don't have the | |
2098 | // __kprobes function decorator. | |
2099 | blacklisted_probes.insert("default_do_nmi"); | |
2100 | blacklisted_probes.insert("__die"); | |
2101 | blacklisted_probes.insert("die_nmi"); | |
2102 | blacklisted_probes.insert("do_debug"); | |
2103 | blacklisted_probes.insert("do_general_protection"); | |
2104 | blacklisted_probes.insert("do_int3"); | |
2105 | blacklisted_probes.insert("do_IRQ"); | |
2106 | blacklisted_probes.insert("do_page_fault"); | |
2107 | blacklisted_probes.insert("do_sparc64_fault"); | |
2108 | blacklisted_probes.insert("do_trap"); | |
2109 | blacklisted_probes.insert("dummy_nmi_callback"); | |
2110 | blacklisted_probes.insert("flush_icache_range"); | |
2111 | blacklisted_probes.insert("ia64_bad_break"); | |
2112 | blacklisted_probes.insert("ia64_do_page_fault"); | |
2113 | blacklisted_probes.insert("ia64_fault"); | |
2114 | blacklisted_probes.insert("io_check_error"); | |
2115 | blacklisted_probes.insert("mem_parity_error"); | |
2116 | blacklisted_probes.insert("nmi_watchdog_tick"); | |
2117 | blacklisted_probes.insert("notifier_call_chain"); | |
2118 | blacklisted_probes.insert("oops_begin"); | |
2119 | blacklisted_probes.insert("oops_end"); | |
2120 | blacklisted_probes.insert("program_check_exception"); | |
2121 | blacklisted_probes.insert("single_step_exception"); | |
2122 | blacklisted_probes.insert("sync_regs"); | |
2123 | blacklisted_probes.insert("unhandled_fault"); | |
2124 | blacklisted_probes.insert("unknown_nmi_error"); | |
2125 | ||
2126 | // __switch_to is only disallowed on x86_64 | |
2127 | if (sess.architecture == "x86_64") | |
2128 | blacklisted_probes.insert("__switch_to"); | |
2129 | ||
2130 | // These functions don't return, so return probes would never be recovered | |
2131 | blacklisted_return_probes.insert("do_exit"); | |
2132 | blacklisted_return_probes.insert("sys_exit"); | |
2133 | blacklisted_return_probes.insert("sys_exit_group"); | |
7a053d3b | 2134 | } |
bd2b1e68 GH |
2135 | |
2136 | ||
bd2b1e68 | 2137 | function_spec_type |
20c6c071 | 2138 | dwarf_query::parse_function_spec(string & spec) |
bd2b1e68 GH |
2139 | { |
2140 | string::const_iterator i = spec.begin(), e = spec.end(); | |
7a053d3b | 2141 | |
bd2b1e68 GH |
2142 | function.clear(); |
2143 | file.clear(); | |
2144 | line = 0; | |
2145 | ||
2146 | while (i != e && *i != '@') | |
2147 | { | |
2148 | if (*i == ':') | |
2149 | goto bad; | |
2150 | function += *i++; | |
2151 | } | |
2152 | ||
2153 | if (i == e) | |
2154 | { | |
b0ee93c4 | 2155 | if (sess.verbose>2) |
7a053d3b RM |
2156 | clog << "parsed '" << spec |
2157 | << "' -> func '" << function | |
db22e55f | 2158 | << "'\n"; |
bd2b1e68 GH |
2159 | return function_alone; |
2160 | } | |
2161 | ||
2162 | if (i++ == e) | |
2163 | goto bad; | |
2164 | ||
2165 | while (i != e && *i != ':') | |
2166 | file += *i++; | |
7a053d3b | 2167 | |
bd2b1e68 GH |
2168 | if (i == e) |
2169 | { | |
b0ee93c4 | 2170 | if (sess.verbose>2) |
7a053d3b RM |
2171 | clog << "parsed '" << spec |
2172 | << "' -> func '"<< function | |
2173 | << "', file '" << file | |
db22e55f | 2174 | << "'\n"; |
bd2b1e68 GH |
2175 | return function_and_file; |
2176 | } | |
2177 | ||
2178 | if (i++ == e) | |
2179 | goto bad; | |
2180 | ||
2181 | try | |
2182 | { | |
2183 | line = lex_cast<int>(string(i, e)); | |
b0ee93c4 | 2184 | if (sess.verbose>2) |
7a053d3b RM |
2185 | clog << "parsed '" << spec |
2186 | << "' -> func '"<< function | |
2187 | << "', file '" << file | |
db22e55f | 2188 | << "', line " << line << "\n"; |
bd2b1e68 GH |
2189 | return function_file_and_line; |
2190 | } | |
2191 | catch (runtime_error & exn) | |
2192 | { | |
2193 | goto bad; | |
2194 | } | |
2195 | ||
2196 | bad: | |
7a053d3b | 2197 | throw semantic_error("malformed specification '" + spec + "'", |
20c6c071 | 2198 | base_probe->tok); |
bd2b1e68 GH |
2199 | } |
2200 | ||
2201 | ||
7e1279ea | 2202 | |
2930abc7 FCE |
2203 | // Our goal here is to calculate a "flavour", a string which |
2204 | // characterizes the way in which this probe body depends on target | |
2205 | // variables. The flavour is used to separate instances of a dwarf | |
2206 | // probe which have different contextual bindings for the target | |
2207 | // variables which occur within the probe body. If two die/addr | |
2208 | // combinations have the same flavour string, they will be directed | |
2209 | // into the same probe function. | |
2210 | ||
2211 | struct | |
2212 | target_variable_flavour_calculating_visitor | |
2213 | : public traversing_visitor | |
2214 | { | |
2215 | string flavour; | |
2216 | ||
2217 | dwarf_query & q; | |
2218 | Dwarf_Die *scope_die; | |
2219 | Dwarf_Addr addr; | |
2220 | ||
20e4a32c RM |
2221 | target_variable_flavour_calculating_visitor(dwarf_query & q, |
2222 | Dwarf_Die *sd, | |
2930abc7 FCE |
2223 | Dwarf_Addr a) |
2224 | : q(q), scope_die(sd), addr(a) | |
2225 | {} | |
2226 | void visit_target_symbol (target_symbol* e); | |
2227 | }; | |
2228 | ||
2229 | void | |
2230 | target_variable_flavour_calculating_visitor::visit_target_symbol (target_symbol *e) | |
2231 | { | |
2232 | assert(e->base_name.size() > 0 && e->base_name[0] == '$'); | |
2233 | ||
cbfbbf69 FCE |
2234 | // NB: if for whatever reason this variable does not resolve, |
2235 | // or is illegally used (write in non-guru mode for instance), | |
35d4ab18 | 2236 | // just pretend that it's OK anyway. dwarf_var_expanding_copy_visitor |
cbfbbf69 | 2237 | // will take care of throwing the appropriate exception. |
e38d6504 | 2238 | |
cbfbbf69 FCE |
2239 | bool lvalue = is_active_lvalue(e); |
2240 | flavour += lvalue ? 'w' : 'r'; | |
2241 | exp_type ty; | |
2242 | string expr; | |
e38d6504 | 2243 | try |
20e4a32c | 2244 | { |
e19fda4e DS |
2245 | if (q.has_return && e->base_name == "$return") |
2246 | expr = q.dw.literal_stmt_for_return (scope_die, | |
2247 | addr, | |
2248 | e->components, | |
2249 | lvalue, | |
2250 | ty); | |
2251 | else | |
2252 | expr = q.dw.literal_stmt_for_local(scope_die, | |
2253 | addr, | |
2254 | e->base_name.substr(1), | |
2255 | e->components, | |
2256 | lvalue, | |
2257 | ty); | |
2930abc7 | 2258 | } |
9b48ce88 | 2259 | catch (const semantic_error& x) |
2930abc7 | 2260 | { |
9b48ce88 FCE |
2261 | e->saved_conversion_error = new semantic_error (x); |
2262 | e->saved_conversion_error->tok1 = e->tok; | |
cbfbbf69 | 2263 | ty = pe_unknown; |
2930abc7 | 2264 | } |
e38d6504 | 2265 | |
cbfbbf69 FCE |
2266 | switch (ty) |
2267 | { | |
2268 | case pe_unknown: | |
2269 | flavour += 'U'; | |
2270 | break; | |
2271 | case pe_long: | |
2272 | flavour += 'L'; | |
2273 | break; | |
2274 | case pe_string: | |
2275 | flavour += 'S'; | |
2276 | break; | |
2277 | case pe_stats: | |
2278 | flavour += 'T'; | |
2279 | break; | |
2280 | } | |
2281 | flavour += lex_cast<string>(expr.size()); | |
2282 | flavour += '{'; | |
2283 | flavour += expr; | |
2284 | flavour += '}'; | |
2930abc7 FCE |
2285 | } |
2286 | ||
703621ae | 2287 | |
20e4a32c | 2288 | |
36f9dd1d FCE |
2289 | bool |
2290 | dwarf_query::blacklisted_p(string const & funcname, | |
2291 | char const * filename, | |
2292 | int line, | |
2293 | Dwarf_Die *scope_die, | |
2294 | Dwarf_Addr addr) | |
2295 | { | |
fd64709f | 2296 | // Check whether the given address points into an .init/.exit section, |
703621ae FCE |
2297 | // which will have been unmapped by the kernel by the time we get to |
2298 | // insert the probe. In this case, just ignore this call. | |
ae6f054a | 2299 | if (dwfl_module_relocations (dw.module) > 0) |
703621ae | 2300 | { |
ae6f054a RM |
2301 | // This is a relocatable module; libdwfl has noted its sections. |
2302 | Dwarf_Addr rel_addr = addr; | |
2303 | int idx = dwfl_module_relocate_address (dw.module, &rel_addr); | |
2304 | const char *name = dwfl_module_relocation_info (dw.module, idx, NULL); | |
fd64709f JS |
2305 | if (name && ((strncmp (name, ".init.", 6) == 0) || |
2306 | (strncmp (name, ".exit.", 6) == 0))) | |
ae6f054a | 2307 | { |
b0ee93c4 | 2308 | if (sess.verbose>1) |
ae6f054a RM |
2309 | clog << "skipping function '" << funcname << "' base 0x" |
2310 | << hex << addr << dec << " is within section '" | |
db22e55f | 2311 | << name << "'\n"; |
36f9dd1d | 2312 | return true; |
ae6f054a RM |
2313 | } |
2314 | } | |
2315 | else | |
2316 | { | |
2317 | Dwarf_Addr baseaddr; | |
2318 | Elf* elf = dwfl_module_getelf (dw.module, & baseaddr); | |
2319 | Dwarf_Addr rel_addr = addr - baseaddr; | |
2320 | if (elf) | |
2321 | { | |
2322 | // Iterate through section headers to find which one | |
2323 | // contains the given rel_addr. | |
2324 | Elf_Scn* scn = 0; | |
2325 | size_t shstrndx; | |
2326 | dw.dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); | |
2327 | while ((scn = elf_nextscn (elf, scn)) != NULL) | |
2328 | { | |
2329 | GElf_Shdr shdr_mem; | |
2330 | GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); | |
2331 | if (! shdr) continue; // XXX error? | |
2332 | ||
2333 | // check for address inclusion | |
2334 | GElf_Addr start = shdr->sh_addr; | |
2335 | GElf_Addr end = start + shdr->sh_size; | |
2336 | if (! (rel_addr >= start && rel_addr < end)) | |
2337 | continue; | |
2338 | ||
2339 | // check for section name | |
2340 | const char* name = elf_strptr (elf, shstrndx, shdr->sh_name); | |
fd64709f JS |
2341 | if (name && ((strncmp (name, ".init.", 6) == 0) || |
2342 | (strncmp (name, ".exit.", 6) == 0))) | |
ae6f054a | 2343 | { |
b0ee93c4 | 2344 | if (sess.verbose>1) |
ae6f054a RM |
2345 | clog << "skipping function '" << funcname << "' base 0x" |
2346 | << hex << addr << dec << " is within section '" | |
db22e55f | 2347 | << name << "'\n"; |
36f9dd1d | 2348 | return true; |
ae6f054a RM |
2349 | } |
2350 | } | |
2351 | } | |
703621ae FCE |
2352 | } |
2353 | ||
36f9dd1d FCE |
2354 | // Check probe point against blacklist. XXX: This has to be |
2355 | // properly generalized, perhaps via a table populated from script | |
2356 | // files. A "noprobe kernel.function("...")" construct might do | |
2357 | // the trick. | |
4893e4b2 FCE |
2358 | if (filename == 0) filename = ""; // possibly 0 |
2359 | string filename_s = filename; // is passed as const char* | |
0daad364 JS |
2360 | if (blacklisted_probes.count(funcname) > 0 || |
2361 | (has_return && blacklisted_return_probes.count(funcname) > 0) || | |
36f9dd1d | 2362 | filename_s == "kernel/kprobes.c" || |
0daad364 | 2363 | 0 == fnmatch ("arch/*/kernel/kprobes.c", filename, 0)) |
36f9dd1d | 2364 | { |
b0ee93c4 | 2365 | if (sess.verbose>1) |
36f9dd1d | 2366 | clog << "skipping function '" << funcname << "' file '" |
db22e55f | 2367 | << filename << "' is blacklisted\n"; |
36f9dd1d FCE |
2368 | return true; |
2369 | } | |
2370 | ||
2371 | // This probe point is not blacklisted. | |
2372 | return false; | |
2373 | } | |
2374 | ||
2375 | ||
2376 | void | |
2377 | dwarf_query::add_probe_point(string const & funcname, | |
2378 | char const * filename, | |
2379 | int line, | |
2380 | Dwarf_Die *scope_die, | |
2381 | Dwarf_Addr addr) | |
2382 | { | |
2383 | dwarf_derived_probe *probe = NULL; | |
2384 | ||
2385 | if (blacklisted_p (funcname, filename, line, scope_die, addr)) | |
2386 | return; | |
2387 | ||
2930abc7 FCE |
2388 | if (probe_has_no_target_variables) |
2389 | { | |
2390 | assert(probe_flavours.size() == 1); | |
2391 | probe = probe_flavours.begin()->second; | |
2392 | } | |
2393 | else | |
2394 | { | |
20e4a32c | 2395 | |
2930abc7 FCE |
2396 | target_variable_flavour_calculating_visitor flav(*this, scope_die, addr); |
2397 | base_probe->body->visit(&flav); | |
20e4a32c RM |
2398 | |
2399 | map<string, dwarf_derived_probe *>::iterator i | |
2930abc7 | 2400 | = probe_flavours.find(flav.flavour); |
20e4a32c | 2401 | |
2930abc7 FCE |
2402 | if (i != probe_flavours.end()) |
2403 | probe = i->second; | |
2404 | else | |
2405 | { | |
2406 | probe = new dwarf_derived_probe(scope_die, addr, *this); | |
2407 | probe_flavours.insert(make_pair(flav.flavour, probe)); | |
2408 | results.push_back(probe); | |
2409 | } | |
20e4a32c | 2410 | |
2930abc7 FCE |
2411 | // Cache result in degenerate case to avoid recomputing. |
2412 | if (flav.flavour.empty()) | |
2413 | probe_has_no_target_variables = true; | |
2414 | } | |
2415 | ||
7f9f3386 FCE |
2416 | if (sess.verbose > 1) |
2417 | { | |
2418 | clog << "probe " << funcname << "@" << filename << ":" << line | |
2419 | << " pc=0x" << hex << addr << dec << endl; | |
2420 | } | |
2421 | ||
2930abc7 FCE |
2422 | probe->add_probe_point(funcname, filename, line, addr, *this); |
2423 | } | |
2424 | ||
2425 | ||
2426 | ||
2427 | ||
7e1279ea FCE |
2428 | // The critical determining factor when interpreting a pattern |
2429 | // string is, perhaps surprisingly: "presence of a lineno". The | |
2430 | // presence of a lineno changes the search strategy completely. | |
2431 | // | |
2432 | // Compare the two cases: | |
2433 | // | |
2434 | // 1. {statement,function}(foo@file.c:lineno) | |
2435 | // - find the files matching file.c | |
2436 | // - in each file, find the functions matching foo | |
2437 | // - query the file for line records matching lineno | |
2438 | // - iterate over the line records, | |
20e4a32c RM |
2439 | // - and iterate over the functions, |
2440 | // - if(haspc(function.DIE, line.addr)) | |
7e1279ea FCE |
2441 | // - if looking for statements: probe(lineno.addr) |
2442 | // - if looking for functions: probe(function.{entrypc,return,etc.}) | |
20e4a32c | 2443 | // |
7e1279ea FCE |
2444 | // 2. {statement,function}(foo@file.c) |
2445 | // - find the files matching file.c | |
2446 | // - in each file, find the functions matching foo | |
2447 | // - probe(function.{entrypc,return,etc.}) | |
2448 | // | |
2449 | // Thus the first decision we make is based on the presence of a | |
2450 | // lineno, and we enter entirely different sets of callbacks | |
2451 | // depending on that decision. | |
2452 | ||
2453 | ||
bd2b1e68 | 2454 | static void |
4cd232e4 | 2455 | query_statement (string const & func, |
20e4a32c | 2456 | char const * file, |
4cd232e4 | 2457 | int line, |
bcc12710 | 2458 | Dwarf_Die *scope_die, |
20e4a32c | 2459 | Dwarf_Addr stmt_addr, |
4cd232e4 | 2460 | dwarf_query * q) |
bd2b1e68 | 2461 | { |
39bcd429 FCE |
2462 | try |
2463 | { | |
2464 | // XXX: implement | |
2465 | if (q->has_relative) | |
2466 | throw semantic_error("incomplete: do not know how to interpret .relative", | |
2467 | q->base_probe->tok); | |
d9b516ca | 2468 | |
2930abc7 | 2469 | q->add_probe_point(func, file, line, scope_die, stmt_addr); |
39bcd429 FCE |
2470 | } |
2471 | catch (const semantic_error& e) | |
2472 | { | |
2473 | q->sess.print_error (e); | |
2474 | } | |
bd2b1e68 GH |
2475 | } |
2476 | ||
7e1279ea FCE |
2477 | static void |
2478 | query_inline_instance_info (Dwarf_Addr entrypc, | |
bcc12710 | 2479 | inline_instance_info & ii, |
7e1279ea FCE |
2480 | dwarf_query * q) |
2481 | { | |
b6581717 | 2482 | try |
7e1279ea | 2483 | { |
b6581717 GH |
2484 | if (q->has_return) |
2485 | { | |
2486 | throw semantic_error ("cannot probe .return of inline function '" + ii.name + "'"); | |
2487 | } | |
2488 | else | |
2489 | { | |
b0ee93c4 | 2490 | if (q->sess.verbose>2) |
20e4a32c RM |
2491 | clog << "querying entrypc " |
2492 | << hex << entrypc << dec | |
db22e55f | 2493 | << " of instance of inline '" << ii.name << "'\n"; |
20e4a32c | 2494 | query_statement (ii.name, ii.decl_file, ii.decl_line, |
b6581717 GH |
2495 | &ii.die, entrypc, q); |
2496 | } | |
7e1279ea | 2497 | } |
b6581717 | 2498 | catch (semantic_error &e) |
7e1279ea | 2499 | { |
b6581717 | 2500 | q->sess.print_error (e); |
7e1279ea FCE |
2501 | } |
2502 | } | |
2503 | ||
2504 | static void | |
2505 | query_func_info (Dwarf_Addr entrypc, | |
bcc12710 | 2506 | func_info & fi, |
7e1279ea FCE |
2507 | dwarf_query * q) |
2508 | { | |
b6581717 | 2509 | try |
7e1279ea | 2510 | { |
b6581717 GH |
2511 | if (q->has_return) |
2512 | { | |
2513 | // NB. dwarf_derived_probe::emit_registrations will emit a | |
2514 | // kretprobe based on the entrypc in this case. | |
20e4a32c | 2515 | query_statement (fi.name, fi.decl_file, fi.decl_line, |
b6581717 GH |
2516 | &fi.die, entrypc, q); |
2517 | } | |
2518 | else | |
2519 | { | |
1c9db4fd AK |
2520 | #ifdef __ia64__ |
2521 | // In IA64 platform function probe point is set at its | |
2522 | // entry point rather than prologue end pointer | |
20e4a32c | 2523 | query_statement (fi.name, fi.decl_file, fi.decl_line, |
1c9db4fd AK |
2524 | &fi.die, entrypc, q); |
2525 | ||
2526 | #else | |
20e4a32c | 2527 | if (fi.prologue_end == 0) |
b6581717 GH |
2528 | throw semantic_error("could not find prologue-end " |
2529 | "for probed function '" + fi.name + "'"); | |
20e4a32c | 2530 | query_statement (fi.name, fi.decl_file, fi.decl_line, |
b6581717 | 2531 | &fi.die, fi.prologue_end, q); |
1c9db4fd | 2532 | #endif |
b6581717 | 2533 | } |
7e1279ea | 2534 | } |
b6581717 | 2535 | catch (semantic_error &e) |
7e1279ea | 2536 | { |
b6581717 | 2537 | q->sess.print_error (e); |
7e1279ea FCE |
2538 | } |
2539 | } | |
2540 | ||
2541 | ||
2542 | static void | |
2543 | query_srcfile_line (Dwarf_Line * line, void * arg) | |
2544 | { | |
2545 | dwarf_query * q = static_cast<dwarf_query *>(arg); | |
2546 | ||
2547 | Dwarf_Addr addr; | |
2548 | dwarf_lineaddr(line, &addr); | |
4cd232e4 | 2549 | |
7e1279ea FCE |
2550 | for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin(); |
2551 | i != q->filtered_functions.end(); ++i) | |
2552 | { | |
2553 | if (q->dw.die_has_pc (&(i->second.die), addr)) | |
2554 | { | |
b0ee93c4 | 2555 | if (q->sess.verbose>3) |
db22e55f | 2556 | clog << "function DIE lands on srcfile\n"; |
4cd232e4 | 2557 | if (q->has_statement_str) |
20e4a32c | 2558 | query_statement (i->second.name, i->second.decl_file, |
bcc12710 | 2559 | q->line, NULL, addr, q); |
4cd232e4 GH |
2560 | else |
2561 | query_func_info (i->first, i->second, q); | |
7e1279ea | 2562 | } |
20e4a32c RM |
2563 | } |
2564 | ||
2565 | for (map<Dwarf_Addr, inline_instance_info>::iterator i | |
897820ca GH |
2566 | = q->filtered_inlines.begin(); |
2567 | i != q->filtered_inlines.end(); ++i) | |
2568 | { | |
2569 | if (q->dw.die_has_pc (&(i->second.die), addr)) | |
7e1279ea | 2570 | { |
b0ee93c4 | 2571 | if (q->sess.verbose>3) |
db22e55f | 2572 | clog << "inline instance DIE lands on srcfile\n"; |
897820ca | 2573 | if (q->has_statement_str) |
20e4a32c | 2574 | query_statement (i->second.name, i->second.decl_file, |
897820ca GH |
2575 | q->line, NULL, addr, q); |
2576 | else | |
2577 | query_inline_instance_info (i->first, i->second, q); | |
2578 | } | |
20e4a32c | 2579 | } |
7e1279ea FCE |
2580 | } |
2581 | ||
2582 | ||
4fa7b22b | 2583 | static int |
7e1279ea | 2584 | query_dwarf_inline_instance (Dwarf_Die * die, void * arg) |
4fa7b22b GH |
2585 | { |
2586 | dwarf_query * q = static_cast<dwarf_query *>(arg); | |
7e1279ea | 2587 | assert (!q->has_statement_num); |
bd2b1e68 | 2588 | |
39bcd429 | 2589 | try |
7a053d3b | 2590 | { |
bb788f9f | 2591 | |
7e1279ea FCE |
2592 | bool record_this_inline = false; |
2593 | ||
b0ee93c4 | 2594 | if (q->sess.verbose>2) |
db22e55f | 2595 | clog << "examining inline instance of " << q->dw.function_name << "\n"; |
7e1279ea | 2596 | |
54efe513 | 2597 | if (q->has_inline_str || q->has_statement_str) |
7e1279ea | 2598 | record_this_inline = true; |
54efe513 GH |
2599 | |
2600 | else if (q->has_inline_num) | |
7e1279ea | 2601 | { |
54efe513 | 2602 | Dwarf_Addr query_addr = q->inline_num_val; |
20e4a32c | 2603 | |
7e1279ea FCE |
2604 | if (q->has_module) |
2605 | query_addr = q->dw.module_address_to_global(query_addr); | |
20e4a32c | 2606 | |
7e1279ea | 2607 | if (q->dw.die_has_pc (die, query_addr)) |
20e4a32c | 2608 | record_this_inline = true; |
7e1279ea FCE |
2609 | } |
2610 | ||
2611 | if (record_this_inline) | |
2612 | { | |
b0ee93c4 | 2613 | if (q->sess.verbose>2) |
db22e55f FCE |
2614 | clog << "selected inline instance of " << q->dw.function_name |
2615 | << "\n"; | |
7e1279ea FCE |
2616 | |
2617 | Dwarf_Addr entrypc; | |
2618 | if (q->dw.die_entrypc (die, &entrypc)) | |
2619 | { | |
2620 | inline_instance_info inl; | |
2621 | inl.die = *die; | |
2622 | inl.name = q->dw.function_name; | |
4cd232e4 GH |
2623 | q->dw.function_file (&inl.decl_file); |
2624 | q->dw.function_line (&inl.decl_line); | |
7e1279ea FCE |
2625 | q->filtered_inlines[entrypc] = inl; |
2626 | } | |
2627 | } | |
2628 | return DWARF_CB_OK; | |
2629 | } | |
2630 | catch (const semantic_error& e) | |
2631 | { | |
2632 | q->sess.print_error (e); | |
2633 | return DWARF_CB_ABORT; | |
2634 | } | |
2635 | } | |
bb788f9f | 2636 | |
7e1279ea | 2637 | static int |
20e4a32c | 2638 | query_dwarf_func (Dwarf_Die * func, void * arg) |
7e1279ea FCE |
2639 | { |
2640 | dwarf_query * q = static_cast<dwarf_query *>(arg); | |
2641 | assert (!q->has_statement_num); | |
bb788f9f | 2642 | |
7e1279ea FCE |
2643 | try |
2644 | { | |
2645 | // XXX: implement | |
2646 | if (q->has_callees) | |
2647 | throw semantic_error ("incomplete: do not know how to interpret .callees", | |
2648 | q->base_probe->tok); | |
20e4a32c | 2649 | |
7e1279ea FCE |
2650 | if (q->has_label) |
2651 | throw semantic_error ("incomplete: do not know how to interpret .label", | |
2652 | q->base_probe->tok); | |
2653 | ||
2654 | q->dw.focus_on_function (func); | |
2655 | ||
20e4a32c | 2656 | if (q->dw.func_is_inline () |
54efe513 | 2657 | && (((q->has_statement_str || q->has_inline_str) |
7e1279ea | 2658 | && q->dw.function_name_matches(q->function)) |
54efe513 | 2659 | || q->has_inline_num)) |
7e1279ea | 2660 | { |
b0ee93c4 | 2661 | if (q->sess.verbose>3) |
db22e55f FCE |
2662 | clog << "checking instances of inline " << q->dw.function_name |
2663 | << "\n"; | |
7e1279ea FCE |
2664 | q->dw.iterate_over_inline_instances (query_dwarf_inline_instance, arg); |
2665 | } | |
54efe513 | 2666 | else if (!q->dw.func_is_inline ()) |
20e4a32c | 2667 | { |
7e1279ea FCE |
2668 | bool record_this_function = false; |
2669 | ||
2670 | if ((q->has_statement_str || q->has_function_str) | |
2671 | && q->dw.function_name_matches(q->function)) | |
2672 | { | |
2673 | record_this_function = true; | |
2674 | } | |
2675 | else if (q->has_function_num) | |
2676 | { | |
2677 | Dwarf_Addr query_addr = q->function_num_val; | |
20e4a32c | 2678 | |
7e1279ea FCE |
2679 | if (q->has_module) |
2680 | query_addr = q->dw.module_address_to_global(query_addr); | |
2681 | ||
2682 | Dwarf_Die d; | |
2683 | q->dw.function_die (&d); | |
20e4a32c | 2684 | |
7e1279ea FCE |
2685 | if (q->dw.die_has_pc (&d, query_addr)) |
2686 | record_this_function = true; | |
2687 | } | |
2688 | ||
2689 | if (record_this_function) | |
2690 | { | |
b0ee93c4 | 2691 | if (q->sess.verbose>2) |
db22e55f | 2692 | clog << "selected function " << q->dw.function_name << "\n"; |
7e1279ea FCE |
2693 | |
2694 | Dwarf_Addr entrypc; | |
2695 | if (q->dw.function_entrypc (&entrypc)) | |
2696 | { | |
2697 | func_info func; | |
2698 | q->dw.function_die (&func.die); | |
2699 | func.name = q->dw.function_name; | |
4cd232e4 GH |
2700 | q->dw.function_file (&func.decl_file); |
2701 | q->dw.function_line (&func.decl_line); | |
7e1279ea FCE |
2702 | q->filtered_functions[entrypc] = func; |
2703 | } | |
20e4a32c RM |
2704 | else |
2705 | throw semantic_error("no entrypc found for function '" | |
2706 | + q->dw.function_name + "'"); | |
7e1279ea FCE |
2707 | } |
2708 | } | |
39bcd429 | 2709 | return DWARF_CB_OK; |
bd2b1e68 | 2710 | } |
39bcd429 | 2711 | catch (const semantic_error& e) |
bd2b1e68 | 2712 | { |
39bcd429 FCE |
2713 | q->sess.print_error (e); |
2714 | return DWARF_CB_ABORT; | |
bd2b1e68 | 2715 | } |
bd2b1e68 GH |
2716 | } |
2717 | ||
2718 | static int | |
2719 | query_cu (Dwarf_Die * cudie, void * arg) | |
2720 | { | |
20c6c071 | 2721 | dwarf_query * q = static_cast<dwarf_query *>(arg); |
7a053d3b | 2722 | |
39bcd429 | 2723 | try |
bd2b1e68 | 2724 | { |
7e1279ea | 2725 | q->dw.focus_on_cu (cudie); |
b5d77020 | 2726 | |
b0ee93c4 | 2727 | if (false && q->sess.verbose>2) |
b5d77020 | 2728 | clog << "focused on CU '" << q->dw.cu_name |
db22e55f | 2729 | << "', in module '" << q->dw.module_name << "'\n"; |
d9b516ca | 2730 | |
20e4a32c | 2731 | if (q->has_statement_str |
54efe513 GH |
2732 | || q->has_inline_str || q->has_inline_num |
2733 | || q->has_function_str || q->has_function_num) | |
7e1279ea FCE |
2734 | { |
2735 | q->filtered_srcfiles.clear(); | |
2736 | q->filtered_functions.clear(); | |
2737 | q->filtered_inlines.clear(); | |
2738 | ||
2739 | // In this path, we find "abstract functions", record | |
2740 | // information about them, and then (depending on lineno | |
2741 | // matching) possibly emit one or more of the function's | |
2742 | // associated addresses. Unfortunately the control of this | |
2743 | // cannot easily be turned inside out. | |
2744 | ||
54efe513 | 2745 | if ((q->has_statement_str || q->has_function_str || q->has_inline_str) |
7e1279ea FCE |
2746 | && (q->spec_type != function_alone)) |
2747 | { | |
2748 | // If we have a pattern string with a filename, we need | |
2749 | // to elaborate the srcfile mask in question first. | |
2750 | q->dw.collect_srcfiles_matching (q->file, q->filtered_srcfiles); | |
2751 | ||
2752 | // If we have a file pattern and *no* srcfile matches, there's | |
2753 | // no need to look further into this CU, so skip. | |
2754 | if (q->filtered_srcfiles.empty()) | |
2755 | return DWARF_CB_OK; | |
2756 | } | |
2757 | ||
2758 | // Pick up [entrypc, name, DIE] tuples for all the functions | |
2759 | // matching the query, and fill in the prologue endings of them | |
2760 | // all in a single pass. | |
2761 | q->dw.iterate_over_functions (query_dwarf_func, q); | |
dc223023 FCE |
2762 | if (! q->filtered_functions.empty()) |
2763 | q->dw.resolve_prologue_endings (q->filtered_functions); | |
7e1279ea | 2764 | |
54efe513 | 2765 | if ((q->has_statement_str || q->has_function_str || q->has_inline_str) |
7e1279ea FCE |
2766 | && (q->spec_type == function_file_and_line)) |
2767 | { | |
2768 | // If we have a pattern string with target *line*, we | |
20e4a32c | 2769 | // have to look at lines in all the matched srcfiles. |
7e1279ea FCE |
2770 | for (set<char const *>::const_iterator i = q->filtered_srcfiles.begin(); |
2771 | i != q->filtered_srcfiles.end(); ++i) | |
897820ca GH |
2772 | q->dw.iterate_over_srcfile_lines (*i, q->line, q->has_statement_str, |
2773 | query_srcfile_line, q); | |
7e1279ea FCE |
2774 | } |
2775 | else | |
2776 | { | |
54efe513 GH |
2777 | // Otherwise, simply probe all resolved functions (if |
2778 | // we're scanning functions) | |
2779 | if (q->has_statement_str || q->has_function_str || q->has_function_num) | |
2780 | for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin(); | |
2781 | i != q->filtered_functions.end(); ++i) | |
2782 | query_func_info (i->first, i->second, q); | |
20e4a32c | 2783 | |
54efe513 GH |
2784 | // Or all inline instances (if we're scanning inlines) |
2785 | if (q->has_statement_str || q->has_inline_str || q->has_inline_num) | |
20e4a32c | 2786 | for (map<Dwarf_Addr, inline_instance_info>::iterator i |
54efe513 GH |
2787 | = q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i) |
2788 | query_inline_instance_info (i->first, i->second, q); | |
7e1279ea FCE |
2789 | |
2790 | } | |
2791 | } | |
39bcd429 FCE |
2792 | else |
2793 | { | |
7e1279ea FCE |
2794 | // Otherwise we have a statement number, and we can just |
2795 | // query it directly within this module. | |
2796 | ||
2797 | assert (q->has_statement_num); | |
2798 | Dwarf_Addr query_addr = q->statement_num_val; | |
2799 | if (q->has_module) | |
2800 | query_addr = q->dw.module_address_to_global(query_addr); | |
2801 | ||
bcc12710 | 2802 | query_statement ("", "", -1, NULL, query_addr, q); |
39bcd429 FCE |
2803 | } |
2804 | return DWARF_CB_OK; | |
bd2b1e68 | 2805 | } |
39bcd429 | 2806 | catch (const semantic_error& e) |
bd2b1e68 | 2807 | { |
39bcd429 FCE |
2808 | q->sess.print_error (e); |
2809 | return DWARF_CB_ABORT; | |
bd2b1e68 | 2810 | } |
bd2b1e68 GH |
2811 | } |
2812 | ||
0ce64fb8 FCE |
2813 | |
2814 | static int | |
2815 | query_kernel_exists (Dwfl_Module *mod __attribute__ ((unused)), | |
2816 | void **userdata __attribute__ ((unused)), | |
2817 | const char *name, | |
2818 | Dwarf_Addr base __attribute__ ((unused)), | |
2819 | void *arg) | |
2820 | { | |
2821 | int *flagp = (int *) arg; | |
2822 | if (TOK_KERNEL == name) | |
2823 | *flagp = 1; | |
2824 | return DWARF_CB_OK; | |
2825 | } | |
2826 | ||
2827 | ||
bd2b1e68 GH |
2828 | static int |
2829 | query_module (Dwfl_Module *mod __attribute__ ((unused)), | |
2830 | void **userdata __attribute__ ((unused)), | |
2831 | const char *name, Dwarf_Addr base, | |
bd2b1e68 GH |
2832 | void *arg __attribute__ ((unused))) |
2833 | { | |
20c6c071 | 2834 | dwarf_query * q = static_cast<dwarf_query *>(arg); |
bd2b1e68 | 2835 | |
39bcd429 | 2836 | try |
e38d6504 | 2837 | { |
39bcd429 | 2838 | q->dw.focus_on_module(mod); |
d9b516ca | 2839 | |
39bcd429 FCE |
2840 | // If we have enough information in the pattern to skip a module and |
2841 | // the module does not match that information, return early. | |
d9b516ca | 2842 | |
39bcd429 FCE |
2843 | if (q->has_kernel && !q->dw.module_name_matches(TOK_KERNEL)) |
2844 | return DWARF_CB_OK; | |
d9b516ca | 2845 | |
39bcd429 FCE |
2846 | if (q->has_module && !q->dw.module_name_matches(q->module_val)) |
2847 | return DWARF_CB_OK; | |
b5d77020 | 2848 | |
b0ee93c4 | 2849 | if (q->sess.verbose>2) |
0ce64fb8 FCE |
2850 | clog << "focused on module '" << q->dw.module_name |
2851 | << "' = [" << hex << q->dw.module_start | |
2852 | << "-" << q->dw.module_end | |
db22e55f | 2853 | << ", bias " << q->dw.module_bias << "]" << dec << "\n"; |
b5d77020 | 2854 | |
54efe513 | 2855 | if (q->has_inline_num || q->has_function_num || q->has_statement_num) |
39bcd429 FCE |
2856 | { |
2857 | // If we have module("foo").function(0xbeef) or | |
2858 | // module("foo").statement(0xbeef), the address is relative | |
2859 | // to the start of the module, so we seek the function | |
2860 | // number plus the module's bias. | |
7e1279ea | 2861 | |
39bcd429 FCE |
2862 | Dwarf_Addr addr; |
2863 | if (q->has_function_num) | |
2864 | addr = q->function_num_val; | |
54efe513 GH |
2865 | else if (q->has_inline_num) |
2866 | addr = q->inline_num_val; | |
39bcd429 FCE |
2867 | else |
2868 | addr = q->statement_num_val; | |
d9b516ca | 2869 | |
7e1279ea FCE |
2870 | // NB: We should not have kernel.* here; global addresses |
2871 | // should have bypassed query_module in dwarf_builder::build | |
2872 | // and gone directly to query_cu. | |
d9b516ca | 2873 | |
7e1279ea FCE |
2874 | assert (!q->has_kernel); |
2875 | assert (q->has_module); | |
2876 | q->dw.query_cu_containing_module_address(addr, q); | |
39bcd429 | 2877 | } |
50e0d793 | 2878 | else |
39bcd429 FCE |
2879 | { |
2880 | // Otherwise if we have a function("foo") or statement("foo") | |
2881 | // specifier, we have to scan over all the CUs looking for | |
7e1279ea | 2882 | // the function(s) in question |
e38d6504 | 2883 | |
c8959a29 | 2884 | q->dw.limit_search_to_function_pattern(q->function); |
7e1279ea | 2885 | |
54efe513 | 2886 | assert(q->has_function_str || q->has_inline_str || q->has_statement_str); |
39bcd429 | 2887 | q->dw.iterate_over_cus(&query_cu, q); |
d9b516ca | 2888 | |
7e1279ea FCE |
2889 | // If we just processed the module "kernel", and the user asked for |
2890 | // the kernel pattern, there's no need to iterate over any further | |
2891 | // modules | |
20e4a32c | 2892 | |
7e1279ea FCE |
2893 | if (q->has_kernel && q->dw.module_name_matches(TOK_KERNEL)) |
2894 | return DWARF_CB_ABORT; | |
2895 | } | |
bb788f9f | 2896 | |
39bcd429 | 2897 | return DWARF_CB_OK; |
7a053d3b | 2898 | } |
39bcd429 | 2899 | catch (const semantic_error& e) |
bd2b1e68 | 2900 | { |
39bcd429 FCE |
2901 | q->sess.print_error (e); |
2902 | return DWARF_CB_ABORT; | |
bd2b1e68 | 2903 | } |
bd2b1e68 GH |
2904 | } |
2905 | ||
2930abc7 | 2906 | |
35d4ab18 | 2907 | struct var_expanding_copy_visitor: public deep_copy_visitor |
77de5e9e | 2908 | { |
77de5e9e | 2909 | static unsigned tick; |
e57b735a | 2910 | stack<functioncall**> target_symbol_setter_functioncalls; |
77de5e9e | 2911 | |
35d4ab18 FCE |
2912 | var_expanding_copy_visitor() {} |
2913 | void visit_assignment (assignment* e); | |
2914 | }; | |
2915 | ||
2916 | ||
2917 | struct dwarf_var_expanding_copy_visitor: public var_expanding_copy_visitor | |
2918 | { | |
77de5e9e | 2919 | dwarf_query & q; |
bcc12710 | 2920 | Dwarf_Die *scope_die; |
77de5e9e GH |
2921 | Dwarf_Addr addr; |
2922 | ||
35d4ab18 FCE |
2923 | dwarf_var_expanding_copy_visitor(dwarf_query & q, Dwarf_Die *sd, Dwarf_Addr a): |
2924 | q(q), scope_die(sd), addr(a) {} | |
d7f3e0c5 | 2925 | void visit_target_symbol (target_symbol* e); |
77de5e9e GH |
2926 | }; |
2927 | ||
2928 | ||
35d4ab18 | 2929 | |
77de5e9e GH |
2930 | unsigned var_expanding_copy_visitor::tick = 0; |
2931 | ||
77de5e9e | 2932 | void |
e57b735a | 2933 | var_expanding_copy_visitor::visit_assignment (assignment* e) |
77de5e9e | 2934 | { |
e57b735a GH |
2935 | // Our job would normally be to require() the left and right sides |
2936 | // into a new assignment. What we're doing is slightly trickier: | |
2937 | // we're pushing a functioncall** onto a stack, and if our left | |
2938 | // child sets the functioncall* for that value, we're going to | |
2939 | // assume our left child was a target symbol -- transformed into a | |
2940 | // set_target_foo(value) call, and it wants to take our right child | |
2941 | // as the argument "value". | |
2942 | // | |
2943 | // This is why some people claim that languages with | |
2944 | // constructor-decomposing case expressions have a leg up on | |
2945 | // visitors. | |
2946 | ||
2947 | functioncall *fcall = NULL; | |
2948 | expression *new_left, *new_right; | |
d9b516ca | 2949 | |
e57b735a GH |
2950 | target_symbol_setter_functioncalls.push (&fcall); |
2951 | require<expression*> (this, &new_left, e->left); | |
2952 | target_symbol_setter_functioncalls.pop (); | |
2953 | require<expression*> (this, &new_right, e->right); | |
2954 | ||
2955 | if (fcall != NULL) | |
77de5e9e | 2956 | { |
e57b735a GH |
2957 | // Our left child is informing us that it was a target variable |
2958 | // and it has been replaced with a set_target_foo() function | |
2959 | // call; we are going to provide that function call -- with the | |
2960 | // right child spliced in as sole argument -- in place of | |
2961 | // ourselves, in the deep copy we're in the middle of making. | |
2962 | ||
2963 | // FIXME: for the time being, we only support plan $foo = bar, | |
2964 | // not += or any other op= variant. This is fixable, but a bit | |
2965 | // ugly. | |
2966 | if (e->op != "=") | |
2967 | throw semantic_error ("Operator-assign expressions on target " | |
2968 | "variables not implemented", e->tok); | |
2969 | ||
2970 | assert (new_left == fcall); | |
2971 | fcall->args.push_back (new_right); | |
2972 | provide <expression*> (this, fcall); | |
77de5e9e | 2973 | } |
e57b735a GH |
2974 | else |
2975 | { | |
2976 | assignment* n = new assignment; | |
2977 | n->op = e->op; | |
2978 | n->tok = e->tok; | |
2979 | n->left = new_left; | |
2980 | n->right = new_right; | |
2981 | provide <assignment*> (this, n); | |
2982 | } | |
2983 | } | |
d9b516ca | 2984 | |
d7f3e0c5 | 2985 | |
e57b735a | 2986 | void |
35d4ab18 | 2987 | dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) |
e57b735a GH |
2988 | { |
2989 | assert(e->base_name.size() > 0 && e->base_name[0] == '$'); | |
2990 | ||
2991 | // Synthesize a function. | |
d7f3e0c5 | 2992 | functiondecl *fdecl = new functiondecl; |
7b99c7d3 | 2993 | fdecl->tok = e->tok; |
d7f3e0c5 | 2994 | embeddedcode *ec = new embeddedcode; |
5e309481 | 2995 | ec->tok = e->tok; |
e57b735a | 2996 | bool lvalue = is_active_lvalue(e); |
e8fbc5e8 GH |
2997 | |
2998 | if (lvalue && !q.sess.guru_mode) | |
2fae2e30 | 2999 | throw semantic_error("write to target variable not permitted", e->tok); |
e8fbc5e8 | 3000 | |
1b07c728 | 3001 | string fname = (string(lvalue ? "_dwarf_tvar_set" : "_dwarf_tvar_get") |
20e4a32c | 3002 | + "_" + e->base_name.substr(1) |
e57b735a GH |
3003 | + "_" + lex_cast<string>(tick++)); |
3004 | ||
e19fda4e | 3005 | if (q.has_return && e->base_name != "$return") |
2fae2e30 FCE |
3006 | throw semantic_error ("target variables not available to .return probes"); |
3007 | ||
66d284f4 | 3008 | try |
e57b735a | 3009 | { |
e19fda4e DS |
3010 | if (q.has_return && e->base_name == "$return") |
3011 | { | |
3012 | ec->code = q.dw.literal_stmt_for_return (scope_die, | |
3013 | addr, | |
3014 | e->components, | |
3015 | lvalue, | |
3016 | fdecl->type); | |
3017 | } | |
3018 | else | |
3019 | { | |
3020 | ec->code = q.dw.literal_stmt_for_local (scope_die, | |
3021 | addr, | |
3022 | e->base_name.substr(1), | |
3023 | e->components, | |
3024 | lvalue, | |
3025 | fdecl->type); | |
3026 | } | |
3027 | ||
1b07c728 FCE |
3028 | if (! lvalue) |
3029 | ec->code += "/* pure */"; | |
66d284f4 FCE |
3030 | } |
3031 | catch (const semantic_error& er) | |
3032 | { | |
cbfbbf69 FCE |
3033 | // We suppress this error message, and pass the unresolved |
3034 | // target_symbol to the next pass. We hope that this value ends | |
3035 | // up not being referenced after all, so it can be optimized out | |
3036 | // quietly. | |
3037 | provide <target_symbol*> (this, e); | |
1cde5ba5 JS |
3038 | delete fdecl; |
3039 | delete ec; | |
cbfbbf69 | 3040 | return; |
66d284f4 | 3041 | } |
e57b735a | 3042 | |
d7f3e0c5 GH |
3043 | fdecl->name = fname; |
3044 | fdecl->body = ec; | |
e57b735a GH |
3045 | if (lvalue) |
3046 | { | |
3047 | // Modify the fdecl so it carries a single pe_long formal | |
3048 | // argument called "value". | |
3049 | ||
3050 | // FIXME: For the time being we only support setting target | |
3051 | // variables which have base types; these are 'pe_long' in | |
3052 | // stap's type vocabulary. Strings and pointers might be | |
3053 | // reasonable, some day, but not today. | |
3054 | ||
3055 | vardecl *v = new vardecl; | |
3056 | v->type = pe_long; | |
3057 | v->name = "value"; | |
3058 | v->tok = e->tok; | |
3059 | fdecl->formal_args.push_back(v); | |
3060 | } | |
d7f3e0c5 | 3061 | q.sess.functions.push_back(fdecl); |
d9b516ca | 3062 | |
e57b735a | 3063 | // Synthesize a functioncall. |
d7f3e0c5 GH |
3064 | functioncall* n = new functioncall; |
3065 | n->tok = e->tok; | |
3066 | n->function = fname; | |
35d4ab18 | 3067 | n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session |
e57b735a GH |
3068 | |
3069 | if (lvalue) | |
3070 | { | |
3071 | // Provide the functioncall to our parent, so that it can be | |
3072 | // used to substitute for the assignment node immediately above | |
3073 | // us. | |
3074 | assert(!target_symbol_setter_functioncalls.empty()); | |
3075 | *(target_symbol_setter_functioncalls.top()) = n; | |
3076 | } | |
3077 | ||
d9b516ca | 3078 | provide <functioncall*> (this, n); |
77de5e9e GH |
3079 | } |
3080 | ||
3081 | ||
dc38c0ae DS |
3082 | void |
3083 | dwarf_derived_probe::register_probe(systemtap_session& s) | |
3084 | { | |
3085 | s.probes.register_probe(this); | |
3086 | } | |
3087 | ||
3088 | ||
2930abc7 FCE |
3089 | void |
3090 | dwarf_derived_probe::add_probe_point(string const & funcname, | |
3091 | char const * filename, | |
3092 | int line, | |
3093 | Dwarf_Addr addr, | |
3094 | dwarf_query & q) | |
bd2b1e68 | 3095 | { |
4cd232e4 | 3096 | string module_name(q.dw.module_name); |
df8fadee | 3097 | |
2930abc7 FCE |
3098 | // "Adding a probe point" means two things: |
3099 | // | |
3100 | // | |
3101 | // 1. Adding an addr to the probe-point vector | |
3102 | ||
3103 | probe_points.push_back(addr); | |
3104 | ||
3105 | // 2. Extending the "locations" vector | |
3106 | ||
a229fcd7 GH |
3107 | vector<probe_point::component*> comps; |
3108 | comps.push_back | |
3109 | (module_name == TOK_KERNEL | |
3110 | ? new probe_point::component(TOK_KERNEL) | |
db520b00 | 3111 | : new probe_point::component(TOK_MODULE, new literal_string(module_name))); |
b5d77020 | 3112 | |
db520b00 FCE |
3113 | string fn_or_stmt; |
3114 | if (q.has_function_str || q.has_function_num) | |
3115 | fn_or_stmt = "function"; | |
2508b230 | 3116 | else if (q.has_inline_str || q.has_inline_num) |
54efe513 | 3117 | fn_or_stmt = "inline"; |
db520b00 FCE |
3118 | else |
3119 | fn_or_stmt = "statement"; | |
a229fcd7 | 3120 | |
54efe513 | 3121 | if (q.has_function_str || q.has_inline_str || q.has_statement_str) |
db520b00 | 3122 | { |
4cd232e4 GH |
3123 | string retro_name = funcname; |
3124 | if (filename && !string (filename).empty()) | |
3125 | retro_name += ("@" + string (filename)); | |
3126 | if (line != -1) | |
3127 | retro_name += (":" + lex_cast<string> (line)); | |
db520b00 FCE |
3128 | comps.push_back |
3129 | (new probe_point::component | |
3130 | (fn_or_stmt, new literal_string (retro_name))); | |
3131 | } | |
54efe513 | 3132 | else if (q.has_function_num || q.has_inline_num || q.has_statement_num) |
db520b00 FCE |
3133 | { |
3134 | Dwarf_Addr retro_addr; | |
3135 | if (q.has_function_num) | |
3136 | retro_addr = q.function_num_val; | |
54efe513 GH |
3137 | else if (q.has_inline_num) |
3138 | retro_addr = q.inline_num_val; | |
db520b00 FCE |
3139 | else |
3140 | retro_addr = q.statement_num_val; | |
3141 | ||
3142 | comps.push_back (new probe_point::component | |
3143 | (fn_or_stmt, | |
3144 | new literal_number(retro_addr))); // XXX: should be hex if possible | |
a229fcd7 GH |
3145 | } |
3146 | ||
db520b00 | 3147 | if (has_return) |
a229fcd7 | 3148 | comps.push_back |
db520b00 | 3149 | (new probe_point::component(TOK_RETURN)); |
d9b516ca | 3150 | |
a229fcd7 GH |
3151 | assert(q.base_probe->locations.size() > 0); |
3152 | locations.push_back(new probe_point(comps, q.base_probe->locations[0]->tok)); | |
2930abc7 FCE |
3153 | } |
3154 | ||
3155 | dwarf_derived_probe::dwarf_derived_probe (Dwarf_Die *scope_die, | |
3156 | Dwarf_Addr addr, | |
3157 | dwarf_query & q) | |
c1d5f3f6 | 3158 | : derived_probe (q.base_probe, 0 /* location-less */), |
2930abc7 FCE |
3159 | has_return (q.has_return) |
3160 | { | |
3161 | string module_name(q.dw.module_name); | |
3162 | ||
3163 | // Lock the kernel module in memory. | |
3164 | if (module_name != TOK_KERNEL) | |
3165 | { | |
3166 | // XXX: There is a race window here, between the time that libdw | |
3167 | // opened up this same file for its relocation duties, and now. | |
3168 | int fd = q.sess.module_fds[module_name]; | |
3169 | if (fd == 0) | |
3170 | { | |
3171 | string sys_module = "/sys/module/" + module_name + "/sections/.text"; | |
3172 | fd = open (sys_module.c_str(), O_RDONLY); | |
3173 | if (fd < 0) | |
3174 | throw semantic_error ("error opening module refcount-bumping file."); | |
3175 | q.sess.module_fds[module_name] = fd; | |
3176 | } | |
3177 | } | |
a229fcd7 GH |
3178 | |
3179 | // Now make a local-variable-expanded copy of the probe body | |
35d4ab18 | 3180 | dwarf_var_expanding_copy_visitor v (q, scope_die, addr); |
77de5e9e GH |
3181 | require <block*> (&v, &(this->body), q.base_probe->body); |
3182 | this->tok = q.base_probe->tok; | |
bd2b1e68 GH |
3183 | } |
3184 | ||
7a053d3b | 3185 | void |
20c6c071 | 3186 | dwarf_derived_probe::register_relative_variants(match_node * root, |
bd2b1e68 GH |
3187 | dwarf_builder * dw) |
3188 | { | |
3189 | // Here we match 2 forms: | |
3190 | // | |
3191 | // . | |
3192 | // .relative(NN) | |
3193 | ||
20c6c071 GH |
3194 | root->bind(dw); |
3195 | root->bind_num(TOK_RELATIVE)->bind(dw); | |
bd2b1e68 GH |
3196 | } |
3197 | ||
7a053d3b | 3198 | void |
20c6c071 | 3199 | dwarf_derived_probe::register_statement_variants(match_node * root, |
bd2b1e68 GH |
3200 | dwarf_builder * dw) |
3201 | { | |
3202 | // Here we match 3 forms: | |
3203 | // | |
3204 | // . | |
3205 | // .return | |
3206 | // .label("foo") | |
7a053d3b | 3207 | |
bd2b1e68 | 3208 | register_relative_variants(root, dw); |
20c6c071 | 3209 | register_relative_variants(root->bind_str(TOK_LABEL), dw); |
bd2b1e68 GH |
3210 | } |
3211 | ||
54efe513 GH |
3212 | void |
3213 | dwarf_derived_probe::register_inline_variants(match_node * root, | |
3214 | dwarf_builder * dw) | |
3215 | { | |
3216 | // Here we match 4 forms: | |
3217 | // | |
3218 | // . | |
3219 | // .callees | |
3220 | // .callees(N) | |
3221 | // | |
3222 | // The last form permits N-level callee resolving without any | |
3223 | // recursive .callees.callees.callees... pattern-matching on our part. | |
3224 | ||
3225 | root->bind(dw); | |
3226 | root->bind(TOK_CALLEES)->bind(dw); | |
3227 | root->bind_num(TOK_CALLEES)->bind(dw); | |
3228 | } | |
3229 | ||
7a053d3b | 3230 | void |
fd6602a0 | 3231 | dwarf_derived_probe::register_function_variants(match_node * root, |
bd2b1e68 GH |
3232 | dwarf_builder * dw) |
3233 | { | |
a229fcd7 | 3234 | // Here we match 4 forms: |
bd2b1e68 GH |
3235 | // |
3236 | // . | |
fd6602a0 | 3237 | // .return |
bd2b1e68 GH |
3238 | // .callees |
3239 | // .callees(N) | |
3240 | // | |
3241 | // The last form permits N-level callee resolving without any | |
3242 | // recursive .callees.callees.callees... pattern-matching on our part. | |
3243 | ||
fd6602a0 FCE |
3244 | root->bind(dw); |
3245 | root->bind(TOK_RETURN)->bind(dw); | |
3246 | root->bind(TOK_CALLEES)->bind(dw); | |
3247 | root->bind_num(TOK_CALLEES)->bind(dw); | |
bd2b1e68 GH |
3248 | } |
3249 | ||
7a053d3b | 3250 | void |
20c6c071 | 3251 | dwarf_derived_probe::register_function_and_statement_variants(match_node * root, |
bd2b1e68 GH |
3252 | dwarf_builder * dw) |
3253 | { | |
3254 | // Here we match 4 forms: | |
3255 | // | |
3256 | // .function("foo") | |
3257 | // .function(0xdeadbeef) | |
54efe513 GH |
3258 | // .inline("foo") |
3259 | // .inline(0xdeadbeef) | |
bd2b1e68 GH |
3260 | // .statement("foo") |
3261 | // .statement(0xdeadbeef) | |
3262 | ||
fd6602a0 FCE |
3263 | register_function_variants(root->bind_str(TOK_FUNCTION), dw); |
3264 | register_function_variants(root->bind_num(TOK_FUNCTION), dw); | |
54efe513 GH |
3265 | register_inline_variants(root->bind_str(TOK_INLINE), dw); |
3266 | register_inline_variants(root->bind_num(TOK_INLINE), dw); | |
20c6c071 GH |
3267 | register_statement_variants(root->bind_str(TOK_STATEMENT), dw); |
3268 | register_statement_variants(root->bind_num(TOK_STATEMENT), dw); | |
bd2b1e68 GH |
3269 | } |
3270 | ||
3271 | void | |
20c6c071 | 3272 | dwarf_derived_probe::register_patterns(match_node * root) |
bd2b1e68 GH |
3273 | { |
3274 | dwarf_builder *dw = new dwarf_builder(); | |
3275 | ||
3276 | // Here we match 3 forms: | |
3277 | // | |
3278 | // .kernel | |
3279 | // .module("foo") | |
3280 | // .process("foo") | |
3281 | ||
20c6c071 GH |
3282 | register_function_and_statement_variants(root->bind(TOK_KERNEL), dw); |
3283 | register_function_and_statement_variants(root->bind_str(TOK_MODULE), dw); | |
ab55a5ae | 3284 | // register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw); |
bd2b1e68 GH |
3285 | } |
3286 | ||
2930abc7 | 3287 | |
7a053d3b | 3288 | void |
46b84a80 DS |
3289 | dwarf_derived_probe::emit_registrations_start (translator_output* o, |
3290 | unsigned index) | |
ec4373ff | 3291 | { |
35d4ab18 | 3292 | string func_name = "enter_" + name; |
46b84a80 DS |
3293 | string index_var = "i_" + lex_cast<string>(index); |
3294 | o->newline(); | |
3295 | o->newline() << "probe_point = dwarf_kprobe_" << name | |
3296 | << "_location_names[0];"; | |
3297 | o->newline() << "for (" << index_var << " = 0; " << index_var << " < " | |
3298 | << probe_points.size() << "; " << index_var << "++) {"; | |
2930abc7 | 3299 | o->indent(1); |
46b84a80 DS |
3300 | string probe_name = string("dwarf_kprobe_") + name + string("[") |
3301 | + index_var + string("]"); | |
2930abc7 | 3302 | |
1472a4e1 FCE |
3303 | #if 0 |
3304 | // XXX: triggers false negatives on RHEL4U2 kernel | |
3305 | // emit address verification code | |
3306 | o->newline() << "void *addr = " << probe_name; | |
3307 | if (has_return) | |
3308 | o->line() << ".kp.addr;"; | |
3309 | else | |
3310 | o->line() << ".addr;"; | |
3311 | o->newline() << "rc = ! virt_addr_valid (addr);"; | |
3312 | #endif | |
3313 | ||
59ff2773 FCE |
3314 | if (has_return) |
3315 | { | |
ff007aa3 | 3316 | o->newline() << "#ifdef ARCH_SUPPORTS_KRETPROBES"; |
2930abc7 | 3317 | o->newline() << probe_name << ".handler = &" << func_name << ";"; |
da4e78db | 3318 | o->newline() << probe_name << ".maxactive = max(10, 4 * NR_CPUS);"; |
2930abc7 FCE |
3319 | // XXX: pending PR 1289 |
3320 | // o->newline() << probe_name << ".kp_fault_handler = &stap_kprobe_fault_handler;"; | |
1472a4e1 | 3321 | o->newline() << "rc = rc || register_kretprobe (&(" << probe_name << "));"; |
ff007aa3 FCE |
3322 | o->newline() << "#else"; |
3323 | o->newline() << "rc = 1;"; | |
3324 | o->newline() << "#endif"; | |
ec4373ff | 3325 | } |
20c6c071 | 3326 | else |
bd2b1e68 | 3327 | { |
2930abc7 FCE |
3328 | o->newline() << probe_name << ".pre_handler = &" << func_name << ";"; |
3329 | // XXX: pending PR 1289 | |
3330 | // o->newline() << probe_name << ".kp_fault_handler = &stap_kprobe_fault_handler;"; | |
1472a4e1 | 3331 | o->newline() << "rc = rc || register_kprobe (&(" << probe_name << "));"; |
bd2b1e68 | 3332 | } |
2930abc7 | 3333 | |
2508b230 | 3334 | o->newline() << "if (unlikely (rc)) {"; |
e38d6504 | 3335 | o->newline(1) << "probe_point = " << string("dwarf_kprobe_") + name |
46b84a80 | 3336 | + string("_location_names[") << index_var << "];"; |
2508b230 FCE |
3337 | o->newline() << "break;"; |
3338 | o->newline(-1) << "}"; | |
2930abc7 FCE |
3339 | o->newline(-1) << "}"; |
3340 | ||
46b84a80 DS |
3341 | // if one failed, must goto code (output by emit_registrations_end) |
3342 | // that will roll back completed registations for this probe | |
3343 | o->newline() << "if (unlikely (rc))"; | |
3344 | o->newline(1) << "goto unwind_dwarf_" << index << ";"; | |
3345 | o->indent(-1); | |
3346 | } | |
3347 | ||
3348 | ||
3349 | void | |
3350 | dwarf_derived_probe::emit_registrations_end (translator_output* o, | |
3351 | unsigned index) | |
3352 | { | |
3353 | string index_var = "i_" + lex_cast<string>(index); | |
3354 | string probe_name = string("dwarf_kprobe_") + name + string("[") | |
3355 | + index_var + string("]"); | |
3356 | ||
2930abc7 | 3357 | // if one failed, must roll back completed registations for this probe |
46b84a80 DS |
3358 | o->newline(-1) << "unwind_dwarf_" << index << ":"; |
3359 | o->newline(1) << "while (--" << index_var << " >= 0)"; | |
2930abc7 FCE |
3360 | o->indent(1); |
3361 | if (has_return) | |
ff007aa3 FCE |
3362 | { |
3363 | o->newline() << "#ifdef ARCH_SUPPORTS_KRETPROBES"; | |
3364 | o->newline() << "unregister_kretprobe (&(" << probe_name << "));"; | |
3365 | o->newline() << "#else"; | |
3366 | o->newline() << ";"; | |
3367 | o->newline() << "#endif"; | |
3368 | } | |
2930abc7 FCE |
3369 | else |
3370 | o->newline() << "unregister_kprobe (&(" << probe_name << "));"; | |
46b84a80 | 3371 | o->indent(-1); |
b55bc428 FCE |
3372 | } |
3373 | ||
2930abc7 | 3374 | |
7a053d3b | 3375 | void |
35d4ab18 | 3376 | dwarf_derived_probe::emit_deregistrations (translator_output* o) |
b55bc428 | 3377 | { |
35d4ab18 | 3378 | string probe_name = string("dwarf_kprobe_") + name + string("[i]"); |
46b84a80 | 3379 | o->newline() << "for (i = 0; i < " << probe_points.size() << "; i++) {"; |
2930abc7 | 3380 | o->indent(1); |
46b84a80 | 3381 | |
fd6602a0 | 3382 | if (has_return) |
ff007aa3 FCE |
3383 | { |
3384 | o->newline() << "#ifdef ARCH_SUPPORTS_KRETPROBES"; | |
9a604fac | 3385 | o->newline() << "atomic_add (" |
46b84a80 DS |
3386 | << probe_name << ".kp.nmissed," |
3387 | << "& skipped_count);"; | |
9a604fac | 3388 | o->newline() << "atomic_add (" |
46b84a80 DS |
3389 | << probe_name << ".nmissed," |
3390 | << "& skipped_count);"; | |
af9ea5ee | 3391 | o->newline() << "unregister_kretprobe (&(" << probe_name << "));"; |
ff007aa3 FCE |
3392 | o->newline() << "#else"; |
3393 | o->newline() << ";"; | |
3394 | o->newline() << "#endif"; | |
3395 | } | |
fd6602a0 | 3396 | else |
9a604fac | 3397 | { |
9a604fac | 3398 | o->newline() << "atomic_add (" |
46b84a80 DS |
3399 | << probe_name << ".nmissed," |
3400 | << "& skipped_count);"; | |
af9ea5ee | 3401 | o->newline() << "unregister_kprobe (&(" << probe_name << "));"; |
9a604fac FCE |
3402 | } |
3403 | ||
af9ea5ee | 3404 | o->newline(-1) << "}"; |
ec4373ff GH |
3405 | } |
3406 | ||
7a053d3b | 3407 | void |
35d4ab18 | 3408 | dwarf_derived_probe::emit_probe_entries (translator_output* o) |
ec4373ff | 3409 | { |
499cf740 FCE |
3410 | static unsigned already_emitted_fault_handler = 0; |
3411 | ||
3412 | if (! already_emitted_fault_handler) | |
3413 | { | |
3414 | o->newline() << "int stap_kprobe_fault_handler (struct kprobe* kp, " | |
3415 | << "struct pt_regs* regs, int trapnr) {"; | |
ded98b33 | 3416 | o->newline(1) << "struct context* c = per_cpu_ptr (contexts, smp_processor_id());"; |
b1f3e72e MH |
3417 | o->newline() << "_stp_warn (\"systemtap probe fault\\n\");"; |
3418 | o->newline() << "_stp_warn (\"cpu %d, probe %s, near %s\\n\", "; | |
499cf740 FCE |
3419 | o->newline(1) << "smp_processor_id(), "; |
3420 | o->newline() << "c->probe_point ? c->probe_point : \"unknown\", "; | |
3421 | o->newline() << "c->last_stmt ? c->last_stmt : \"unknown\");"; | |
3422 | o->newline() << "c->last_error = \"probe faulted\";"; | |
3423 | o->newline(-1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; | |
3424 | ||
3425 | o->newline() << "return 0;"; // defer to kernel fault handler | |
3426 | // NB: We might prefer to use "return 1" instead, to consider | |
3427 | // the fault "handled". But we may get into an infinite loop | |
3428 | // of traps if the faulting instruction is simply restarted. | |
3429 | ||
3430 | o->newline(-1) << "}"; | |
3431 | already_emitted_fault_handler ++; | |
3432 | } | |
3433 | ||
2930abc7 FCE |
3434 | |
3435 | // Emit arrays of probes and location names. | |
3436 | ||
35d4ab18 FCE |
3437 | string probe_array = string("dwarf_kprobe_") + name; |
3438 | string string_array = probe_array + "_location_names"; | |
2930abc7 FCE |
3439 | |
3440 | assert(locations.size() == probe_points.size()); | |
3441 | ||
3442 | if (has_return) | |
ff007aa3 FCE |
3443 | { |
3444 | o->newline() << "#ifdef ARCH_SUPPORTS_KRETPROBES"; | |
2930abc7 FCE |
3445 | o->newline() << "static struct kretprobe " |
3446 | << probe_array | |
3447 | << "[" << probe_points.size() << "]" | |
3448 | << "= {"; | |
ff007aa3 | 3449 | } |
2930abc7 FCE |
3450 | else |
3451 | o->newline() << "static struct kprobe " | |
3452 | << probe_array | |
3453 | << "[" << probe_points.size() << "]" | |
3454 | << "= {"; | |
3455 | ||
3456 | o->indent(1); | |
3457 | for (vector<Dwarf_Addr>::const_iterator i = probe_points.begin(); | |
20e4a32c | 3458 | i != probe_points.end(); |
2930abc7 FCE |
3459 | ++i) |
3460 | { | |
3461 | if (i != probe_points.begin()) | |
3462 | o->line() << ","; | |
3463 | if (has_return) | |
3464 | o->newline() << "{.kp.addr= (void *) 0x" << hex << *i << dec << "}"; | |
3465 | else | |
3466 | o->newline() << "{.addr= (void *) 0x" << hex << *i << dec << "}"; | |
3467 | } | |
3468 | o->newline(-1) << "};"; | |
3469 | ||
ff007aa3 FCE |
3470 | if (has_return) |
3471 | o->newline() << "#endif /* ARCH_SUPPORTS_KRETPROBES */"; | |
3472 | ||
2930abc7 FCE |
3473 | o->newline(); |
3474 | ||
3475 | // This is somewhat gross, but it should work: we allocate a | |
3476 | // *parallel* array of strings containing the location of each | |
3477 | // probe. You can calculate which kprobe or kretprobe you're in by | |
3478 | // taking the difference of the struct kprobe pointer and the base | |
3479 | // of the kprobe array and dividing by the size of the struct kprobe | |
3480 | // (or kretprobe), then you can use this index into the string table | |
20e4a32c | 3481 | // here to work out the *name* of the probe you're in. |
2930abc7 FCE |
3482 | // |
3483 | // Sorry. | |
3484 | ||
3485 | assert(probe_points.size() == locations.size()); | |
3486 | ||
ffd1346f | 3487 | o->newline() << "static char const * " |
2930abc7 FCE |
3488 | << string_array |
3489 | << "[" << locations.size() << "] = {"; | |
3490 | o->indent(1); | |
20e4a32c | 3491 | for (vector<probe_point*>::const_iterator i = locations.begin(); |
2930abc7 FCE |
3492 | i != locations.end(); ++i) |
3493 | { | |
3494 | if (i != locations.begin()) | |
3495 | o->line() << ","; | |
3496 | o->newline() << lex_cast_qstring(*(*i)); | |
3497 | } | |
20e4a32c RM |
3498 | o->newline(-1) << "};"; |
3499 | ||
4b17d6af WC |
3500 | o->newline(); |
3501 | o->newline() << "#ifdef STP_TIMING"; | |
c1d5f3f6 | 3502 | o->newline() << "static __cacheline_aligned Stat " << "time_" << basest()->name << ";"; |
4b17d6af | 3503 | o->newline() << "#endif"; |
2930abc7 | 3504 | |
7a053d3b | 3505 | // Construct a single entry function, and a struct kprobe pointing into |
20c6c071 | 3506 | // the entry function. The entry function will call the probe function. |
20c6c071 | 3507 | o->newline(); |
ff007aa3 FCE |
3508 | if (has_return) |
3509 | o->newline() << "#ifdef ARCH_SUPPORTS_KRETPROBES"; | |
3d49c615 | 3510 | o->newline() << "static int "; |
35d4ab18 | 3511 | o->newline() << "enter_" << name << " ("; |
9e6edd10 | 3512 | if (has_return) |
2930abc7 | 3513 | o->line() << "struct kretprobe_instance *probe_instance"; |
9e6edd10 | 3514 | else |
2930abc7 | 3515 | o->line() << "struct kprobe *probe_instance"; |
9e6edd10 | 3516 | o->line() << ", struct pt_regs *regs) {"; |
9a604fac | 3517 | o->indent(1); |
2930abc7 FCE |
3518 | |
3519 | // Calculate the name of the current probe by finding its index in the probe array. | |
3520 | if (has_return) | |
20e4a32c RM |
3521 | o->newline() << "const char* probe_point = " |
3522 | << string_array | |
2930abc7 FCE |
3523 | << "[ (probe_instance->rp - &(" << probe_array << "[0]))];"; |
3524 | else | |
20e4a32c RM |
3525 | o->newline() << "const char* probe_point = " |
3526 | << string_array | |
2930abc7 | 3527 | << "[ (probe_instance - &(" << probe_array << "[0]))];"; |
9a604fac | 3528 | emit_probe_prologue (o, "STAP_SESSION_RUNNING"); |
3d49c615 | 3529 | o->newline() << "c->regs = regs;"; |
5e309481 | 3530 | |
ec4373ff | 3531 | // NB: locals are initialized by probe function itself |
35d4ab18 | 3532 | o->newline() << name << " (c);"; |
bfb3d2d2 | 3533 | |
9a604fac | 3534 | emit_probe_epilogue (o); |
20e4a32c | 3535 | |
3d49c615 | 3536 | o->newline() << "return 0;"; |
db22e55f | 3537 | o->newline(-1) << "}\n"; |
ff007aa3 FCE |
3538 | if (has_return) |
3539 | o->newline() << "#endif /* ARCH_SUPPORTS_KRETPROBES */"; | |
ec4373ff | 3540 | |
20c6c071 | 3541 | o->newline(); |
20c6c071 | 3542 | } |
ec4373ff | 3543 | |
20c6c071 | 3544 | |
dc38c0ae DS |
3545 | void |
3546 | dwarf_derived_probe_group::emit_probes (translator_output* op, unparser* up) | |
3547 | { | |
3548 | for (unsigned i=0; i < probes.size(); i++) | |
3549 | { | |
3550 | op->newline (); | |
3551 | up->emit_probe (probes[i]); | |
3552 | } | |
3553 | } | |
3554 | ||
3555 | ||
46b84a80 DS |
3556 | void |
3557 | dwarf_derived_probe_group::emit_module_init (translator_output* o) | |
3558 | { | |
3559 | if (probes.size () == 0) | |
3560 | return; | |
3561 | ||
3562 | // Output the dwarf probes create function | |
3563 | o->newline() << "static int register_dwarf_probes (void) {"; | |
3564 | o->indent(1); | |
3565 | o->newline() << "int rc = 0;"; | |
3566 | o->newline() << "const char *probe_point;"; | |
3567 | ||
3568 | for (unsigned i=0; i < probes.size (); i++) | |
3569 | o->newline() << "int i_" << i << ";"; | |
3570 | ||
3571 | for (unsigned i=0; i < probes.size (); i++) | |
3572 | probes[i]->emit_registrations_start (o, i); | |
3573 | ||
3574 | o->newline() << "goto out;"; | |
3575 | o->newline(); | |
3576 | ||
3577 | for (int i=probes.size() - 1; i >= 0; i--) | |
3578 | probes[i]->emit_registrations_end (o, i); | |
3579 | ||
3580 | o->newline(); | |
3581 | ||
3582 | o->newline() << "if (unlikely (rc)) {"; | |
3583 | // In case it's just a lower-layer (kprobes) error that set rc but | |
3584 | // not session_state, do that here to prevent any other BEGIN probe | |
3585 | // from attempting to run. | |
3586 | o->newline(1) << "atomic_set (&session_state, STAP_SESSION_ERROR);"; | |
3587 | o->newline() << "_stp_error (\"dwarf probe %s registration failed, rc=%d\\n\", probe_point, rc);"; | |
3588 | o->newline(-1) << "}\n"; | |
3589 | ||
3590 | o->newline(-1) << "out:"; | |
3591 | o->newline(1) << "return rc;"; | |
3592 | o->newline(-1) << "}\n"; | |
3593 | ||
3594 | // Output the dwarf probes destroy function | |
3595 | o->newline() << "static void unregister_dwarf_probes (void) {"; | |
3596 | o->newline(1) << "int i;"; | |
3597 | ||
3598 | for (unsigned i=0; i < probes.size (); i++) | |
3599 | { | |
3600 | probes[i]->emit_deregistrations (o); | |
3601 | emit_probe_timing(probes[i], o); | |
3602 | } | |
3603 | ||
3604 | o->newline(-1) << "}\n"; | |
3605 | } | |
3606 | ||
3607 | ||
20c6c071 | 3608 | void |
5227f1ea | 3609 | dwarf_builder::build(systemtap_session & sess, |
7a053d3b | 3610 | probe * base, |
20c6c071 GH |
3611 | probe_point * location, |
3612 | std::map<std::string, literal *> const & parameters, | |
20c6c071 GH |
3613 | vector<derived_probe *> & finished_results) |
3614 | { | |
c8959a29 GH |
3615 | dwflpp *dw = NULL; |
3616 | ||
3617 | string dummy; | |
3618 | bool has_kernel = dwarf_query::has_null_param(parameters, TOK_KERNEL); | |
3619 | bool has_module = dwarf_query::get_string_param(parameters, TOK_MODULE, dummy); | |
3620 | ||
3621 | if (has_kernel || has_module) | |
3622 | { | |
3623 | if (!kern_dw) | |
3624 | { | |
3625 | kern_dw = new dwflpp(sess); | |
3626 | assert(kern_dw); | |
3627 | kern_dw->setup(true); | |
3628 | } | |
3629 | dw = kern_dw; | |
3630 | } | |
3631 | else | |
3632 | { | |
3633 | if (!user_dw) | |
3634 | { | |
3635 | user_dw = new dwflpp(sess); | |
3636 | assert(user_dw); | |
3637 | user_dw->setup(false); | |
3638 | } | |
3639 | dw = user_dw; | |
3640 | } | |
3641 | assert(dw); | |
20c6c071 | 3642 | |
c8959a29 | 3643 | dwarf_query q(sess, base, location, *dw, parameters, finished_results); |
20c6c071 | 3644 | |
20c6c071 | 3645 | |
20e4a32c | 3646 | if (q.has_kernel && |
54efe513 | 3647 | (q.has_function_num || q.has_inline_num || q.has_statement_num)) |
20c6c071 | 3648 | { |
50e0d793 GH |
3649 | // If we have kernel.function(0xbeef), or |
3650 | // kernel.statement(0xbeef) the address is global (relative to | |
3651 | // the kernel) and we can seek directly to the module and cudie | |
3652 | // in question. | |
54efe513 GH |
3653 | Dwarf_Addr a; |
3654 | if (q.has_function_num) | |
3655 | a = q.function_num_val; | |
3656 | else if (q.has_inline_num) | |
3657 | a = q.inline_num_val; | |
20e4a32c | 3658 | else |
54efe513 | 3659 | a = q.statement_num_val; |
c8959a29 GH |
3660 | dw->focus_on_module_containing_global_address(a); |
3661 | dw->query_cu_containing_global_address(a, &q); | |
20c6c071 | 3662 | } |
7a053d3b | 3663 | else |
20c6c071 | 3664 | { |
0ce64fb8 | 3665 | // Otherwise we have module("*bar*"), kernel.statement("foo"), or |
20c6c071 GH |
3666 | // kernel.function("foo"); in these cases we need to scan all |
3667 | // the modules. | |
7a053d3b | 3668 | assert((q.has_kernel && q.has_function_str) || |
54efe513 | 3669 | (q.has_kernel && q.has_inline_str) || |
20c6c071 GH |
3670 | (q.has_kernel && q.has_statement_str) || |
3671 | (q.has_module)); | |
0ce64fb8 FCE |
3672 | if (q.has_kernel) |
3673 | { | |
3674 | int flag = 0; | |
c8959a29 | 3675 | dw->iterate_over_modules(&query_kernel_exists, &flag); |
0ce64fb8 FCE |
3676 | if (! flag) |
3677 | throw semantic_error ("cannot find kernel debuginfo"); | |
3678 | } | |
3679 | ||
c8959a29 | 3680 | dw->iterate_over_modules(&query_module, &q); |
20c6c071 | 3681 | } |
b55bc428 FCE |
3682 | } |
3683 | ||
3684 | ||
98afd80e FCE |
3685 | |
3686 | // ------------------------------------------------------------------------ | |
3687 | // timer derived probes | |
3688 | // ------------------------------------------------------------------------ | |
3689 | ||
3690 | ||
3691 | struct timer_derived_probe: public derived_probe | |
3692 | { | |
3693 | int64_t interval, randomize; | |
422d1ceb | 3694 | bool time_is_msecs; |
98afd80e | 3695 | |
422d1ceb | 3696 | timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, bool ms=false); |
98afd80e | 3697 | |
dc38c0ae DS |
3698 | virtual void register_probe (systemtap_session& s); |
3699 | ||
46b84a80 DS |
3700 | virtual void emit_registrations_start (translator_output* o, unsigned index); |
3701 | virtual void emit_registrations_end (translator_output * o, unsigned index); | |
35d4ab18 FCE |
3702 | virtual void emit_deregistrations (translator_output * o); |
3703 | virtual void emit_probe_entries (translator_output * o); | |
98afd80e FCE |
3704 | }; |
3705 | ||
3706 | ||
422d1ceb FCE |
3707 | timer_derived_probe::timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, bool ms): |
3708 | derived_probe (p, l), interval (i), randomize (r), time_is_msecs(ms) | |
98afd80e FCE |
3709 | { |
3710 | if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints | |
3711 | throw semantic_error ("invalid interval for jiffies timer"); | |
3712 | // randomize = 0 means no randomization | |
3713 | if (randomize < 0 || randomize > interval) | |
3714 | throw semantic_error ("invalid randomize for jiffies timer"); | |
3715 | ||
3716 | if (locations.size() != 1) | |
3717 | throw semantic_error ("expect single probe point"); | |
3718 | // so we don't have to loop over them in the other functions | |
3719 | } | |
3720 | ||
3721 | ||
dc38c0ae DS |
3722 | void |
3723 | timer_derived_probe::register_probe(systemtap_session& s) | |
3724 | { | |
3725 | s.probes.register_probe(this); | |
3726 | } | |
3727 | ||
3728 | ||
98afd80e | 3729 | void |
46b84a80 DS |
3730 | timer_derived_probe::emit_registrations_start (translator_output* o, |
3731 | unsigned index) | |
98afd80e | 3732 | { |
46b84a80 DS |
3733 | o->newline(); |
3734 | o->newline() << "probe_point = \"" << *locations[0] << "\";"; | |
35d4ab18 FCE |
3735 | o->newline() << "init_timer (& timer_" << name << ");"; |
3736 | o->newline() << "timer_" << name << ".expires = jiffies + "; | |
422d1ceb FCE |
3737 | if (time_is_msecs) |
3738 | o->line() << "msecs_to_jiffies("; | |
3739 | o->line() << interval; | |
3740 | if (randomize) | |
3741 | o->line() << " + _stp_random_pm(" << randomize << ")"; | |
3742 | if (time_is_msecs) | |
3743 | o->line() << ")"; | |
3744 | o->line() << ";"; | |
35d4ab18 FCE |
3745 | o->newline() << "timer_" << name << ".function = & enter_" << name << ";"; |
3746 | o->newline() << "add_timer (& timer_" << name << ");"; | |
46b84a80 DS |
3747 | |
3748 | // if one failed, must goto code (output by emit_registrations_end) | |
3749 | // that will roll back completed registations for this probe | |
3750 | o->newline() << "if (unlikely (rc))"; | |
3751 | if (index == 0) | |
3752 | o->newline(1) << "goto timer_error;"; | |
3753 | else | |
3754 | o->newline(1) << "goto unwind_timer_" << index - 1 << ";"; | |
3755 | o->indent(-1); | |
3756 | } | |
3757 | ||
3758 | ||
3759 | void | |
3760 | timer_derived_probe::emit_registrations_end (translator_output* o, | |
3761 | unsigned index) | |
3762 | { | |
3763 | // if one failed, must roll back completed registations for this probe | |
3764 | o->newline(-1) << "unwind_timer_" << index << ":"; | |
3765 | o->newline(1) << "del_timer_sync (& timer_" << name << ");"; | |
98afd80e FCE |
3766 | } |
3767 | ||
3768 | ||
3769 | void | |
35d4ab18 | 3770 | timer_derived_probe::emit_deregistrations (translator_output* o) |
98afd80e | 3771 | { |
35d4ab18 | 3772 | o->newline() << "del_timer_sync (& timer_" << name << ");"; |
98afd80e FCE |
3773 | } |
3774 | ||
3775 | ||
3776 | void | |
35d4ab18 | 3777 | timer_derived_probe::emit_probe_entries (translator_output* o) |
98afd80e | 3778 | { |
35d4ab18 | 3779 | o->newline() << "static struct timer_list timer_" << name << ";"; |
98afd80e | 3780 | |
ffd1346f | 3781 | o->newline() << "static void enter_" << name << " (unsigned long val) {"; |
9a604fac | 3782 | o->indent(1); |
cc9ee605 FCE |
3783 | o->newline() << "const char* probe_point = " |
3784 | << lex_cast_qstring(*locations[0]) << ";"; | |
9a604fac | 3785 | emit_probe_prologue (o, "STAP_SESSION_RUNNING"); |
98afd80e | 3786 | |
9a604fac | 3787 | o->newline() << "(void) val;"; |
35d4ab18 | 3788 | o->newline() << "mod_timer (& timer_" << name << ", jiffies + "; |
422d1ceb FCE |
3789 | if (time_is_msecs) |
3790 | o->line() << "msecs_to_jiffies("; | |
3791 | o->line() << interval; | |
98afd80e FCE |
3792 | if (randomize) |
3793 | o->line() << " + _stp_random_pm(" << randomize << ")"; | |
422d1ceb FCE |
3794 | if (time_is_msecs) |
3795 | o->line() << ")"; | |
98afd80e | 3796 | o->line() << ");"; |
20e4a32c | 3797 | |
98afd80e | 3798 | // NB: locals are initialized by probe function itself |
35d4ab18 | 3799 | o->newline() << name << " (c);"; |
20e4a32c | 3800 | |
9a604fac | 3801 | emit_probe_epilogue (o); |
db22e55f | 3802 | o->newline(-1) << "}\n"; |
98afd80e FCE |
3803 | } |
3804 | ||
3805 | ||
dc38c0ae DS |
3806 | struct timer_derived_probe_group: public derived_probe_group |
3807 | { | |
3808 | private: | |
3809 | vector<timer_derived_probe*> probes; | |
3810 | ||
3811 | public: | |
3812 | virtual void register_probe(timer_derived_probe* p) { probes.push_back (p); } | |
3813 | virtual size_t size () { return probes.size (); } | |
3814 | ||
3815 | virtual void emit_probes (translator_output* op, unparser* up); | |
46b84a80 | 3816 | virtual void emit_module_init (translator_output* o); |
dc38c0ae DS |
3817 | }; |
3818 | ||
3819 | ||
3820 | void | |
3821 | timer_derived_probe_group::emit_probes (translator_output* op, unparser* up) | |
3822 | { | |
3823 | for (unsigned i=0; i < probes.size(); i++) | |
3824 | { | |
3825 | op->newline (); | |
3826 | up->emit_probe (probes[i]); | |
3827 | } | |
3828 | } | |
3829 | ||
3830 | ||
46b84a80 DS |
3831 | void |
3832 | timer_derived_probe_group::emit_module_init (translator_output* o) | |
3833 | { | |
3834 | if (probes.size () == 0) | |
3835 | return; | |
3836 | ||
3837 | // Output the timer probes create function | |
3838 | o->newline() << "static int register_timer_probes (void) {"; | |
3839 | o->indent(1); | |
3840 | o->newline() << "int rc = 0;"; | |
3841 | o->newline() << "const char *probe_point;"; | |
3842 | ||
3843 | for (unsigned i=0; i < probes.size (); i++) | |
3844 | o->newline() << "int i_" << i << ";"; | |
3845 | ||
3846 | for (unsigned i=0; i < probes.size (); i++) | |
3847 | probes[i]->emit_registrations_start (o, i); | |
3848 | ||
3849 | o->newline() << "goto out;"; | |
3850 | o->newline(); | |
3851 | ||
3852 | for (int i=probes.size() - 2; i >= 0; i--) | |
3853 | probes[i]->emit_registrations_end (o, i); | |
3854 | ||
3855 | o->newline(); | |
3856 | ||
3857 | o->newline(-1) << "timer_error:"; | |
3858 | o->newline(1) << "if (unlikely (rc)) {"; | |
3859 | // In case it's just a lower-layer (kprobes) error that set rc but | |
3860 | // not session_state, do that here to prevent any other BEGIN probe | |
3861 | // from attempting to run. | |
3862 | o->newline(1) << "atomic_set (&session_state, STAP_SESSION_ERROR);"; | |
3863 | o->newline() << "_stp_error (\"timer probe %s registration failed, rc=%d\\n\", probe_point, rc);"; | |
3864 | o->newline(-1) << "}\n"; | |
3865 | ||
3866 | o->newline(-1) << "out:"; | |
3867 | o->newline(1) << "return rc;"; | |
3868 | o->newline(-1) << "}\n"; | |
3869 | ||
3870 | // Output the timer probes destroy function | |
3871 | o->newline() << "static void unregister_timer_probes (void) {"; | |
3872 | o->indent(1); | |
3873 | ||
3874 | for (unsigned i=0; i < probes.size (); i++) | |
3875 | { | |
3876 | probes[i]->emit_deregistrations (o); | |
3877 | emit_probe_timing(probes[i], o); | |
3878 | } | |
3879 | ||
3880 | o->newline(-1) << "}\n"; | |
3881 | } | |
3882 | ||
3883 | ||
98afd80e FCE |
3884 | struct timer_builder: public derived_probe_builder |
3885 | { | |
422d1ceb FCE |
3886 | bool time_is_msecs; |
3887 | timer_builder(bool ms=false): time_is_msecs(ms) {} | |
98afd80e FCE |
3888 | virtual void build(systemtap_session & sess, |
3889 | probe * base, | |
3890 | probe_point * location, | |
3891 | std::map<std::string, literal *> const & parameters, | |
98afd80e FCE |
3892 | vector<derived_probe *> & finished_results) |
3893 | { | |
3894 | int64_t jn, rn; | |
3895 | bool jn_p, rn_p; | |
3896 | ||
422d1ceb | 3897 | jn_p = get_param (parameters, time_is_msecs ? "ms" : "jiffies", jn); |
98afd80e | 3898 | rn_p = get_param (parameters, "randomize", rn); |
20e4a32c | 3899 | |
98afd80e | 3900 | finished_results.push_back(new timer_derived_probe(base, location, |
422d1ceb FCE |
3901 | jn, rn_p ? rn : 0, |
3902 | time_is_msecs)); | |
98afd80e FCE |
3903 | } |
3904 | }; | |
3905 | ||
3906 | ||
39e57ce0 FCE |
3907 | // ------------------------------------------------------------------------ |
3908 | // profile derived probes | |
3909 | // ------------------------------------------------------------------------ | |
3910 | // On kernels < 2.6.10, this uses the register_profile_notifier API to | |
3911 | // generate the timed events for profiling; on kernels >= 2.6.10 this | |
3912 | // uses the register_timer_hook API. The latter doesn't currently allow | |
3913 | // simultaneous users, so insertion will fail if the profiler is busy. | |
3914 | // (Conflicting users may include OProfile, other SystemTap probes, etc.) | |
3915 | ||
3916 | ||
3917 | struct profile_derived_probe: public derived_probe | |
3918 | { | |
6dce2125 JS |
3919 | // kernels < 2.6.10: use register_profile_notifier API |
3920 | // kernels >= 2.6.10: use register_timer_hook API | |
3921 | bool using_rpn; | |
3922 | ||
3923 | profile_derived_probe (systemtap_session &s, probe* p, probe_point* l); | |
39e57ce0 | 3924 | |
dc38c0ae DS |
3925 | void register_probe (systemtap_session& s); |
3926 | ||
46b84a80 DS |
3927 | virtual void emit_registrations_start (translator_output* o, unsigned index); |
3928 | virtual void emit_registrations_end (translator_output * o, unsigned index); | |
35d4ab18 FCE |
3929 | virtual void emit_deregistrations (translator_output * o); |
3930 | virtual void emit_probe_entries (translator_output * o); | |
39e57ce0 FCE |
3931 | }; |
3932 | ||
3933 | ||
6dce2125 JS |
3934 | profile_derived_probe::profile_derived_probe (systemtap_session &s, probe* p, probe_point* l): |
3935 | derived_probe(p, l) | |
39e57ce0 | 3936 | { |
6dce2125 | 3937 | string target_kernel_v; |
39e57ce0 | 3938 | |
6dce2125 | 3939 | // cut off any release code suffix |
77a5c1f9 JS |
3940 | string::size_type dash_index = s.kernel_release.find ('-'); |
3941 | if (dash_index > 0 && dash_index != string::npos) | |
3942 | target_kernel_v = s.kernel_release.substr (0, dash_index); | |
6dce2125 JS |
3943 | else |
3944 | target_kernel_v = s.kernel_release; | |
39e57ce0 | 3945 | |
6dce2125 | 3946 | using_rpn = (strverscmp(target_kernel_v.c_str(), "2.6.10") < 0); |
39e57ce0 FCE |
3947 | } |
3948 | ||
3949 | ||
dc38c0ae DS |
3950 | void |
3951 | profile_derived_probe::register_probe(systemtap_session& s) | |
3952 | { | |
3953 | s.probes.register_probe(this); | |
3954 | } | |
3955 | ||
3956 | ||
39e57ce0 | 3957 | void |
46b84a80 DS |
3958 | profile_derived_probe::emit_registrations_start (translator_output* o, |
3959 | unsigned index) | |
39e57ce0 | 3960 | { |
46b84a80 DS |
3961 | o->newline(); |
3962 | o->newline() << "probe_point = \"" << *locations[0] << "\";"; | |
6dce2125 | 3963 | if (using_rpn) |
35d4ab18 | 3964 | o->newline() << "rc = register_profile_notifier(& profile_" << name << ");"; |
6dce2125 | 3965 | else |
35d4ab18 | 3966 | o->newline() << "rc = register_timer_hook(enter_" << name << ");"; |
46b84a80 DS |
3967 | |
3968 | // if one failed, must goto code (output by emit_registrations_end) | |
3969 | // that will roll back completed registations for other probes of | |
3970 | // this type. | |
3971 | o->newline() << "if (unlikely (rc))"; | |
3972 | if (index == 0) | |
3973 | o->newline(1) << "goto profile_error;"; | |
3974 | else | |
3975 | o->newline(1) << "goto unwind_profile_" << index - 1 << ";"; | |
3976 | o->indent(-1); | |
3977 | } | |
3978 | ||
3979 | ||
3980 | void | |
3981 | profile_derived_probe::emit_registrations_end (translator_output* o, | |
3982 | unsigned index) | |
3983 | { | |
3984 | // if one failed, must roll back completed registations for this | |
3985 | // type of probe | |
3986 | o->newline(-1) << "unwind_profile_" << index << ":"; | |
3987 | o->indent(1); | |
3988 | emit_deregistrations (o); | |
6dce2125 | 3989 | } |
39e57ce0 | 3990 | |
39e57ce0 | 3991 | |
6dce2125 | 3992 | void |
35d4ab18 | 3993 | profile_derived_probe::emit_deregistrations (translator_output* o) |
6dce2125 JS |
3994 | { |
3995 | if (using_rpn) | |
35d4ab18 | 3996 | o->newline() << "unregister_profile_notifier(& profile_" << name << ");"; |
6dce2125 | 3997 | else |
35d4ab18 | 3998 | o->newline() << "unregister_timer_hook(enter_" << name << ");"; |
39e57ce0 FCE |
3999 | } |
4000 | ||
4001 | ||
4002 | void | |
35d4ab18 | 4003 | profile_derived_probe::emit_probe_entries (translator_output* o) |
39e57ce0 | 4004 | { |
6dce2125 | 4005 | if (using_rpn) { |
35d4ab18 | 4006 | o->newline() << "static int enter_" << name |
6dce2125 | 4007 | << " (struct notifier_block *self, unsigned long val, void *data);"; |
35d4ab18 FCE |
4008 | o->newline() << "static struct notifier_block profile_" << name << " = {"; |
4009 | o->newline(1) << ".notifier_call = enter_" << name << ","; | |
6dce2125 | 4010 | o->newline(-1) << "};"; |
35d4ab18 | 4011 | o->newline() << "int enter_" << name |
6dce2125 JS |
4012 | << " (struct notifier_block *self, unsigned long val, void *data) {"; |
4013 | o->newline(1) << "struct pt_regs *regs = (struct pt_regs *)data;"; | |
4014 | o->indent(-1); | |
4015 | } else { | |
35d4ab18 FCE |
4016 | o->newline() << "static int enter_" << name << " (struct pt_regs *regs);"; |
4017 | o->newline() << "int enter_" << name << " (struct pt_regs *regs) {"; | |
6dce2125 | 4018 | } |
39e57ce0 | 4019 | |
9a604fac | 4020 | o->indent(1); |
39e57ce0 FCE |
4021 | o->newline() << "const char* probe_point = " |
4022 | << lex_cast_qstring(*locations[0]) << ";"; | |
9a604fac | 4023 | emit_probe_prologue (o, "STAP_SESSION_RUNNING"); |
a7978f80 | 4024 | o->newline() << "c->regs = regs;"; |
39e57ce0 | 4025 | |
6dce2125 JS |
4026 | if (using_rpn) { |
4027 | o->newline() << "(void) self;"; | |
4028 | o->newline() << "(void) val;"; | |
4029 | } | |
4030 | ||
35d4ab18 | 4031 | o->newline() << name << " (c);"; |
39e57ce0 | 4032 | |
9a604fac | 4033 | emit_probe_epilogue (o); |
39e57ce0 | 4034 | o->newline() << "return 0;"; |
db22e55f | 4035 | o->newline(-1) << "}\n"; |
39e57ce0 FCE |
4036 | } |
4037 | ||
4038 | ||
dc38c0ae DS |
4039 | struct profile_derived_probe_group: public derived_probe_group |
4040 | { | |
4041 | private: | |
4042 | vector<profile_derived_probe*> probes; | |
4043 | ||
4044 | public: | |
4045 | virtual void register_probe(profile_derived_probe* p) { | |
4046 | probes.push_back (p); } | |
4047 | virtual size_t size () { return probes.size (); } | |
4048 | ||
4049 | virtual void emit_probes (translator_output* op, unparser* up); | |
46b84a80 | 4050 | virtual void emit_module_init (translator_output* o); |
dc38c0ae DS |
4051 | }; |
4052 | ||
4053 | ||
4054 | void | |
4055 | profile_derived_probe_group::emit_probes (translator_output* op, unparser* up) | |
4056 | { | |
4057 | for (unsigned i=0; i < probes.size(); i++) | |
4058 | { | |
4059 | op->newline (); | |
4060 | up->emit_probe (probes[i]); | |
4061 | } | |
4062 | } | |
4063 | ||
4064 | ||
46b84a80 DS |
4065 | void |
4066 | profile_derived_probe_group::emit_module_init (translator_output* o) | |
4067 | { | |
4068 | if (probes.size () == 0) | |
4069 | return; | |
4070 | ||
4071 | // Output the profile probes create function | |
4072 | o->newline() << "static int register_profile_probes (void) {"; | |
4073 | o->indent(1); | |
4074 | o->newline() << "int rc = 0;"; | |
4075 | o->newline() << "const char *probe_point;"; | |
4076 | ||
4077 | for (unsigned i=0; i < probes.size (); i++) | |
4078 | probes[i]->emit_registrations_start (o, i); | |
4079 | ||
4080 | o->newline() << "goto out;"; | |
4081 | o->newline(); | |
4082 | ||
4083 | for (int i=probes.size() - 2; i >= 0; i--) | |
4084 | probes[i]->emit_registrations_end (o, i); | |
4085 | ||
4086 | o->newline(); | |
4087 | ||
4088 | o->newline(-1) << "profile_error:"; | |
4089 | o->newline(1) << "if (unlikely (rc)) {"; | |
4090 | // In case it's just a lower-layer (kprobes) error that set rc but | |
4091 | // not session_state, do that here to prevent any other BEGIN probe | |
4092 | // from attempting to run. | |
4093 | o->newline(1) << "atomic_set (&session_state, STAP_SESSION_ERROR);"; | |
4094 | o->newline() << "_stp_error (\"profile probe %s registration failed, rc=%d\\n\", probe_point, rc);"; | |
4095 | o->newline(-1) << "}\n"; | |
4096 | ||
4097 | o->newline(-1) << "out:"; | |
4098 | o->newline(1) << "return rc;"; | |
4099 | o->newline(-1) << "}\n"; | |
4100 | ||
4101 | // Output the profile probes destroy function | |
4102 | o->newline() << "static void unregister_profile_probes (void) {"; | |
4103 | o->indent(1); | |
4104 | ||
4105 | for (unsigned i=0; i < probes.size (); i++) | |
4106 | { | |
4107 | probes[i]->emit_deregistrations (o); | |
4108 | emit_probe_timing(probes[i], o); | |
4109 | } | |
4110 | ||
4111 | o->newline(-1) << "}\n"; | |
4112 | } | |
4113 | ||
4114 | ||
39e57ce0 FCE |
4115 | struct profile_builder: public derived_probe_builder |
4116 | { | |
4117 | profile_builder() {} | |
4118 | virtual void build(systemtap_session & sess, | |
4119 | probe * base, | |
4120 | probe_point * location, | |
4121 | std::map<std::string, literal *> const & parameters, | |
4122 | vector<derived_probe *> & finished_results) | |
4123 | { | |
6dce2125 | 4124 | finished_results.push_back(new profile_derived_probe(sess, base, location)); |
39e57ce0 FCE |
4125 | } |
4126 | }; | |
4127 | ||
4128 | ||
30a279be FCE |
4129 | // ------------------------------------------------------------------------ |
4130 | // statically inserted macro-based derived probes | |
4131 | // ------------------------------------------------------------------------ | |
4132 | ||
4133 | ||
4134 | struct mark_derived_probe: public derived_probe | |
4135 | { | |
4136 | mark_derived_probe (systemtap_session &s, | |
35d4ab18 FCE |
4137 | const string& probe_name, const string& probe_sig, |
4138 | uintptr_t address, const string& module, | |
4139 | probe* base_probe); | |
30a279be | 4140 | |
35d4ab18 | 4141 | systemtap_session& sess; |
30a279be FCE |
4142 | string probe_name, probe_sig; |
4143 | uintptr_t address; | |
4144 | string module; | |
4145 | string probe_sig_expanded; | |
4146 | ||
dc38c0ae DS |
4147 | void register_probe (systemtap_session& s); |
4148 | ||
46b84a80 DS |
4149 | void emit_registrations_start (translator_output * o, unsigned index); |
4150 | void emit_registrations_end (translator_output * o, unsigned index); | |
35d4ab18 FCE |
4151 | void emit_deregistrations (translator_output * o); |
4152 | void emit_probe_entries (translator_output * o); | |
4153 | void emit_probe_context_vars (translator_output* o); | |
30a279be FCE |
4154 | }; |
4155 | ||
4156 | ||
35d4ab18 FCE |
4157 | struct mark_var_expanding_copy_visitor: public var_expanding_copy_visitor |
4158 | { | |
4159 | mark_var_expanding_copy_visitor(systemtap_session& s, | |
4160 | const string& ms, const string& pn): | |
4161 | sess (s), mark_signature (ms), probe_name (pn) {} | |
4162 | systemtap_session& sess; | |
4163 | string mark_signature; | |
4164 | string probe_name; | |
4165 | ||
4166 | void visit_target_symbol (target_symbol* e); | |
4167 | }; | |
4168 | ||
4169 | ||
4170 | void | |
4171 | mark_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) | |
4172 | { | |
4173 | assert(e->base_name.size() > 0 && e->base_name[0] == '$'); | |
4174 | ||
4175 | if (e->base_name.substr(0,4) != "$arg") | |
4176 | throw semantic_error ("invalid target symbol for marker, $argN expected", e->tok); | |
4177 | string argnum_s = e->base_name.substr(4,e->base_name.length()-4); | |
4178 | int argnum = atoi (argnum_s.c_str()); | |
4179 | if (argnum < 1 || argnum > (int) mark_signature.size()) | |
4180 | throw semantic_error ("invalid marker argument number", e->tok); | |
4181 | ||
4182 | char argtype = mark_signature[argnum-1]; | |
4183 | ||
4184 | // Synthesize a function. | |
4185 | functiondecl *fdecl = new functiondecl; | |
4186 | fdecl->tok = e->tok; | |
4187 | embeddedcode *ec = new embeddedcode; | |
4188 | ec->tok = e->tok; | |
35d4ab18 | 4189 | |
1b07c728 FCE |
4190 | if (is_active_lvalue (e)) |
4191 | throw semantic_error("write to marker parameter not permitted", e->tok); | |
35d4ab18 | 4192 | |
1b07c728 FCE |
4193 | string fname = string("_mark_tvar_get") |
4194 | + "_" + e->base_name.substr(1) | |
4195 | + "_" + lex_cast<string>(tick++); | |
35d4ab18 | 4196 | |
1b07c728 FCE |
4197 | ec->code = string("THIS->__retvalue = CONTEXT->locals[0].") |
4198 | + probe_name + string(".__mark_arg") | |
4199 | + lex_cast<string>(argnum) + string (";"); | |
4200 | ec->code += "/* pure */"; | |
35d4ab18 FCE |
4201 | fdecl->name = fname; |
4202 | fdecl->body = ec; | |
4203 | fdecl->type = (argtype == 'N' ? pe_long : | |
4204 | argtype == 'S' ? pe_string : | |
4205 | pe_unknown); // cannot happen | |
4206 | sess.functions.push_back(fdecl); | |
4207 | ||
4208 | // Synthesize a functioncall. | |
4209 | functioncall* n = new functioncall; | |
4210 | n->tok = e->tok; | |
4211 | n->function = fname; | |
4212 | n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session | |
4213 | provide <functioncall*> (this, n); | |
4214 | } | |
4215 | ||
4216 | ||
4217 | ||
30a279be | 4218 | mark_derived_probe::mark_derived_probe (systemtap_session &s, |
35d4ab18 FCE |
4219 | const string& p_n, |
4220 | const string& p_s, | |
4221 | uintptr_t a, | |
4222 | const string& m, | |
4223 | probe* base): | |
4224 | derived_probe (base, 0), sess (s), probe_name (p_n), probe_sig (p_s), | |
30a279be FCE |
4225 | address (a), module (m) |
4226 | { | |
4227 | // create synthetic probe point | |
4228 | probe_point* pp = new probe_point; | |
4229 | ||
4230 | probe_point::component* c; | |
4231 | if (module == "") c = new probe_point::component ("kernel"); | |
4232 | else c = new probe_point::component ("module", | |
4233 | new literal_string (module)); | |
4234 | pp->components.push_back (c); | |
dc223023 | 4235 | c = new probe_point::component ("mark", |
30a279be FCE |
4236 | new literal_string (probe_name)); |
4237 | pp->components.push_back (c); | |
4238 | this->locations.push_back (pp); | |
4239 | ||
4240 | // expand the signature string | |
4241 | for (unsigned i=0; i<probe_sig.length(); i++) | |
4242 | { | |
4243 | if (i > 0) | |
4244 | probe_sig_expanded += ", "; | |
e38d6504 | 4245 | switch (probe_sig[i]) |
30a279be FCE |
4246 | { |
4247 | case 'N': probe_sig_expanded += "int64_t"; break; | |
4248 | case 'S': probe_sig_expanded += "const char *"; break; | |
e38d6504 | 4249 | default: |
30a279be FCE |
4250 | throw semantic_error ("unsupported probe signature " + probe_sig, |
4251 | this->tok); | |
4252 | } | |
e38d6504 | 4253 | probe_sig_expanded += " arg" + lex_cast<string>(i+1); // arg1 ... |
30a279be | 4254 | } |
35d4ab18 FCE |
4255 | |
4256 | // Now make a local-variable-expanded copy of the probe body | |
4257 | mark_var_expanding_copy_visitor v (sess, probe_sig, name); | |
4258 | require <block*> (&v, &(this->body), base->body); | |
4259 | ||
4260 | if (sess.verbose > 1) | |
4261 | clog << "marker-based " << name << " address=0x" << hex << address << dec | |
4262 | << " signature=" << probe_sig << endl; | |
30a279be FCE |
4263 | } |
4264 | ||
4265 | ||
dc38c0ae DS |
4266 | void |
4267 | mark_derived_probe::register_probe(systemtap_session& s) | |
4268 | { | |
4269 | s.probes.register_probe(this); | |
4270 | } | |
4271 | ||
4272 | ||
30a279be | 4273 | void |
35d4ab18 FCE |
4274 | mark_derived_probe::emit_probe_context_vars (translator_output* o) |
4275 | { | |
4276 | // Save incoming arguments | |
4277 | for (unsigned i=0; i<probe_sig.length(); i++) | |
4278 | { | |
4279 | string localname = "__mark_arg" + lex_cast<string>(i+1); | |
e38d6504 | 4280 | switch (probe_sig[i]) |
35d4ab18 FCE |
4281 | { |
4282 | case 'S': o->newline() << "string_t " << localname << ";"; break; | |
4283 | case 'N': o->newline() << "int64_t " << localname << ";"; break; | |
4284 | } | |
4285 | } | |
4286 | } | |
4287 | ||
4288 | ||
4289 | void | |
4290 | mark_derived_probe::emit_probe_entries (translator_output* o) | |
30a279be FCE |
4291 | { |
4292 | assert (this->locations.size() == 1); | |
4293 | ||
ffd1346f | 4294 | o->newline() << "static void enter_" << name << " (" << probe_sig_expanded << ")"; |
30a279be FCE |
4295 | o->newline() << "{"; |
4296 | o->newline(1) << "const char* probe_point = " | |
4297 | << lex_cast_qstring(* this->locations[0]) << ";"; | |
4298 | emit_probe_prologue (o, "STAP_SESSION_RUNNING"); | |
4299 | ||
35d4ab18 FCE |
4300 | // Save incoming arguments |
4301 | for (unsigned k=0; k<probe_sig.length(); k++) | |
4302 | { | |
4303 | string locals = "c->locals[0]." + name; | |
4304 | string localname = locals + ".__mark_arg" + lex_cast<string>(k+1); | |
4305 | string argname = "arg" + lex_cast<string>(k+1); | |
e38d6504 | 4306 | switch (probe_sig[k]) |
35d4ab18 FCE |
4307 | { |
4308 | case 'S': o->newline() << "strlcpy (" << localname << ", " << argname | |
4309 | << ", MAXSTRINGLEN);"; break; | |
e38d6504 | 4310 | // XXX: dupe with c_unparser::c_strcpy |
35d4ab18 FCE |
4311 | case 'N': o->newline() << localname << " = " << argname << ";"; break; |
4312 | } | |
4313 | } | |
30a279be FCE |
4314 | |
4315 | // NB: locals are initialized by probe function itself | |
35d4ab18 | 4316 | o->newline() << name << " (c);"; |
30a279be FCE |
4317 | |
4318 | emit_probe_epilogue (o); | |
4319 | o->newline(-1) << "}"; | |
4320 | } | |
4321 | ||
4322 | ||
4323 | void | |
46b84a80 DS |
4324 | mark_derived_probe::emit_registrations_start (translator_output* o, |
4325 | unsigned index) | |
30a279be FCE |
4326 | { |
4327 | assert (this->locations.size() == 1); | |
4328 | ||
4329 | o->newline() << "{"; | |
4330 | o->newline(1) << "void (**fn) (" << probe_sig_expanded << ") = (void *)" | |
4331 | << address << "UL;"; | |
4332 | ||
4a5e8a70 FCE |
4333 | o->newline() << "#if __HAVE_ARCH_CMPXCHG"; |
4334 | o->newline() << "unsigned long *fnpp = (unsigned long *) (void *) fn;"; | |
35d4ab18 | 4335 | o->newline() << "unsigned long fnp = (unsigned long) (void *) & enter_" << name << ";"; |
4a5e8a70 FCE |
4336 | o->newline() << "unsigned long oldval = cmpxchg (fnpp, 0, fnp);"; |
4337 | o->newline() << "if (oldval != 0) rc = 1;"; // XXX: could retry a few times | |
4338 | o->newline() << "#else"; | |
dc223023 | 4339 | // XXX: need proper synchronization for concurrent registration attempts |
35d4ab18 | 4340 | o->newline() << "if (*fn == 0) *fn = & enter_" << name << ";"; |
4a5e8a70 | 4341 | o->newline() << "#endif"; |
30a279be | 4342 | o->newline() << "mb ();"; |
35d4ab18 | 4343 | o->newline() << "if (*fn != & enter_" << name << ") rc = 1;"; |
30a279be FCE |
4344 | |
4345 | o->newline(-1) << "}"; | |
e38d6504 | 4346 | |
46b84a80 DS |
4347 | |
4348 | // if one failed, must goto code (output by emit_registrations_end) | |
4349 | // that will roll back completed registations for this probe | |
4350 | o->newline() << "if (unlikely (rc)) {"; | |
4351 | o->newline(1) << "probe_point = " | |
4352 | << lex_cast_qstring (*this->locations[0]) << ";"; | |
4353 | if (index == 0) | |
4354 | o->newline() << "goto mark_error;"; | |
4355 | else | |
4356 | o->newline() << "goto unwind_mark_" << index - 1 << ";"; | |
4357 | o->newline(-1) << "}"; | |
4358 | } | |
4359 | ||
4360 | ||
4361 | void | |
4362 | mark_derived_probe::emit_registrations_end (translator_output* o, | |
4363 | unsigned index) | |
4364 | { | |
4365 | // if one failed, must roll back completed registations for this probe | |
4366 | o->newline(-1) << "unwind_mark_" << index << ":"; | |
4367 | o->indent(1); | |
4368 | emit_deregistrations (o); | |
30a279be FCE |
4369 | } |
4370 | ||
35d4ab18 | 4371 | |
30a279be | 4372 | void |
35d4ab18 | 4373 | mark_derived_probe::emit_deregistrations (translator_output * o) |
30a279be FCE |
4374 | { |
4375 | assert (this->locations.size() == 1); | |
4376 | ||
4377 | o->newline() << "{"; | |
4378 | o->newline(1) << "void (**fn) (" << probe_sig_expanded << ") = (void *)" | |
4379 | << address << "UL;"; | |
4a5e8a70 FCE |
4380 | o->newline() << "#if __HAVE_ARCH_CMPXCHG"; |
4381 | o->newline() << "unsigned long *fnpp = (unsigned long *) (void *) fn;"; | |
35d4ab18 | 4382 | o->newline() << "unsigned long fnp = (unsigned long) (void *) & enter_" << name << ";"; |
4a5e8a70 FCE |
4383 | o->newline() << "unsigned long oldval = cmpxchg (fnpp, fnp, 0);"; |
4384 | o->newline() << "if (oldval != fnp) ;"; // XXX: should not happen | |
4385 | o->newline() << "#else"; | |
30a279be | 4386 | o->newline(0) << "*fn = 0;"; |
4a5e8a70 | 4387 | o->newline() << "#endif"; |
30a279be FCE |
4388 | o->newline(-1) << "}"; |
4389 | } | |
4390 | ||
4391 | ||
dc38c0ae DS |
4392 | struct mark_derived_probe_group: public derived_probe_group |
4393 | { | |
4394 | private: | |
4395 | vector<mark_derived_probe*> probes; | |
4396 | ||
4397 | public: | |
4398 | virtual void register_probe(mark_derived_probe* p) { probes.push_back (p); } | |
4399 | virtual size_t size () { return probes.size (); } | |
4400 | ||
4401 | virtual void emit_probes (translator_output* op, unparser* up); | |
46b84a80 | 4402 | virtual void emit_module_init (translator_output* o); |
dc38c0ae DS |
4403 | }; |
4404 | ||
4405 | ||
4406 | void | |
4407 | mark_derived_probe_group::emit_probes (translator_output* op, unparser* up) | |
4408 | { | |
4409 | for (unsigned i=0; i < probes.size(); i++) | |
4410 | { | |
4411 | op->newline (); | |
4412 | up->emit_probe (probes[i]); | |
4413 | } | |
4414 | } | |
4415 | ||
30a279be | 4416 | |
46b84a80 DS |
4417 | void |
4418 | mark_derived_probe_group::emit_module_init (translator_output* o) | |
4419 | { | |
4420 | if (probes.size () == 0) | |
4421 | return; | |
4422 | ||
4423 | // Output the mark probes create function | |
4424 | o->newline() << "static int register_mark_probes (void) {"; | |
4425 | o->indent(1); | |
4426 | o->newline() << "int rc = 0;"; | |
4427 | o->newline() << "const char *probe_point;"; | |
4428 | ||
4429 | for (unsigned i=0; i < probes.size (); i++) | |
4430 | probes[i]->emit_registrations_start (o, i); | |
4431 | ||
4432 | o->newline() << "goto out;"; | |
4433 | o->newline(); | |
4434 | ||
4435 | for (int i=probes.size() - 2; i >= 0; i--) | |
4436 | probes[i]->emit_registrations_end (o, i); | |
4437 | ||
4438 | o->newline(); | |
4439 | ||
4440 | o->newline(-1) << "mark_error:"; | |
4441 | o->newline(1) << "if (unlikely (rc)) {"; | |
4442 | // In case it's just a lower-layer (kprobes) error that set rc but | |
4443 | // not session_state, do that here to prevent any other BEGIN probe | |
4444 | // from attempting to run. | |
4445 | o->newline(1) << "atomic_set (&session_state, STAP_SESSION_ERROR);"; | |
4446 | o->newline() << "_stp_error (\"mark probe %s registration failed, rc=%d\\n\", probe_point, rc);"; | |
4447 | o->newline(-1) << "}\n"; | |
4448 | ||
4449 | o->newline(-1) << "out:"; | |
4450 | o->newline(1) << "return rc;"; | |
4451 | o->newline(-1) << "}\n"; | |
4452 | ||
4453 | // Output the mark probes destroy function | |
4454 | o->newline() << "static void unregister_mark_probes (void) {"; | |
4455 | o->indent(1); | |
4456 | ||
4457 | for (unsigned i=0; i < probes.size (); i++) | |
4458 | { | |
4459 | probes[i]->emit_deregistrations (o); | |
4460 | emit_probe_timing(probes[i], o); | |
4461 | } | |
4462 | ||
4463 | o->newline(-1) << "}\n"; | |
4464 | } | |
4465 | ||
4466 | ||
30a279be FCE |
4467 | struct symboltable_extract |
4468 | { | |
4469 | uintptr_t address; | |
4470 | string symbol; | |
4471 | string module; | |
4472 | }; | |
4473 | ||
4474 | ||
4475 | #define PROBE_SYMBOL_PREFIX "__systemtap_mark_" | |
4476 | ||
4477 | ||
4478 | struct mark_builder: public derived_probe_builder | |
4479 | { | |
4480 | private: | |
4481 | static const vector<symboltable_extract>* get_symbols (systemtap_session&); | |
4482 | ||
4483 | public: | |
4484 | mark_builder() {} | |
4485 | void build(systemtap_session & sess, | |
4486 | probe * base, | |
4487 | probe_point * location, | |
4488 | std::map<std::string, literal *> const & parameters, | |
4489 | vector<derived_probe *> & finished_results); | |
4490 | }; | |
4491 | ||
4492 | ||
4493 | // Until elfutils makes this straightforward, we kludge. | |
4494 | // See also translate.cxx:emit_symbol_data(). | |
4495 | ||
4496 | const vector<symboltable_extract>* | |
4497 | mark_builder::get_symbols (systemtap_session& sess) | |
4498 | { | |
4499 | static vector<symboltable_extract>* syms = 0; | |
4500 | if (syms) return syms; // already computed | |
4501 | ||
4502 | syms = new vector<symboltable_extract>; | |
4503 | ||
4504 | // Process /proc/kallsyms - contains reliable module symbols | |
4505 | ifstream kallsyms ("/proc/kallsyms"); | |
4506 | while (! kallsyms.eof()) | |
4507 | { | |
4508 | string addr, type, sym, module; | |
4509 | kallsyms >> addr >> type >> sym; | |
4510 | kallsyms >> ws; | |
4511 | if (kallsyms.peek() == '[') | |
4512 | { | |
4513 | string bracketed; | |
4514 | kallsyms >> bracketed; | |
4515 | module = bracketed.substr (1, bracketed.length()-2); | |
4516 | } | |
4517 | else // kernel symbols come from /boot/System.map* | |
4518 | continue; | |
4519 | ||
4520 | if (type == "b" || type == "d") // static data/bss | |
4521 | { | |
4522 | symboltable_extract e; | |
4523 | e.address = strtoul (addr.c_str(), 0, 16); | |
4524 | e.symbol = sym; | |
4525 | e.module = module; | |
4526 | syms->push_back (e); | |
4527 | } | |
4528 | } | |
4529 | kallsyms.close (); | |
4530 | ||
4531 | // grab them kernel symbols | |
4532 | string smname = "/boot/System.map-"; | |
4533 | smname += sess.kernel_release; | |
4534 | ifstream systemmap (smname.c_str()); | |
4535 | while (! systemmap.eof()) | |
4536 | { | |
4537 | string addr, type, sym, module; | |
4538 | systemmap >> addr >> type >> sym; | |
4539 | module = ""; | |
4540 | ||
4541 | if (type == "b" || type == "d") // static data/bss | |
4542 | { | |
4543 | symboltable_extract e; | |
4544 | e.address = strtoul (addr.c_str(), 0, 16); | |
4545 | e.symbol = sym; | |
4546 | e.module = module; | |
4547 | syms->push_back (e); | |
4548 | } | |
4549 | } | |
4550 | systemmap.close (); | |
4551 | ||
4552 | return syms; | |
4553 | } | |
4554 | ||
4555 | ||
4556 | void | |
4557 | mark_builder::build(systemtap_session & sess, | |
4558 | probe * base, | |
4559 | probe_point * location, | |
4560 | std::map<std::string, literal *> const & parameters, | |
4561 | vector<derived_probe *> & finished_results) | |
4562 | { | |
4563 | const vector<symboltable_extract>* syms = get_symbols (sess); | |
4564 | ||
4565 | string param_module; | |
4566 | bool has_module = get_param (parameters, "module", param_module); | |
4567 | bool has_kernel = (parameters.find("kernel") != parameters.end()); | |
4568 | ||
4569 | if (! (has_module ^ has_kernel)) | |
35d4ab18 | 4570 | throw semantic_error ("need kernel or module() component", location->tok); |
30a279be FCE |
4571 | |
4572 | string param_probe; | |
4573 | bool has_probe = get_param (parameters, "mark", param_probe); | |
4574 | if (! has_probe) | |
4575 | throw semantic_error ("need mark() component", location->tok); | |
4576 | ||
4577 | string symbol_regex = PROBE_SYMBOL_PREFIX "([a-zA-Z0-9_]+)_([NS]*)\\.[0-9]+"; | |
4578 | // ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^ ^^^^^^ | |
4579 | // common prefix probe name types suffix | |
4580 | regex_t symbol_regex_t; | |
4581 | int rc = regcomp (& symbol_regex_t, symbol_regex.c_str(), REG_EXTENDED); | |
4582 | if (rc) | |
4583 | throw semantic_error ("regcomp '" + symbol_regex + "' failed"); | |
4584 | ||
4585 | // cout << "searching for " << symbol_regex << endl; | |
4586 | ||
4587 | for (unsigned i=0; i<syms->size(); i++) | |
4588 | { | |
4589 | regmatch_t match[3]; | |
4590 | const symboltable_extract& ext = syms->at(i); | |
4591 | const char* symstr = ext.symbol.c_str(); | |
4592 | ||
4593 | rc = regexec (& symbol_regex_t, symstr, 3, match, 0); | |
4594 | if (! rc) // match | |
4595 | { | |
4596 | #if 0 | |
4597 | cout << "match in " << symstr << ":" | |
4598 | << "[" << match[0].rm_so << "-" << match[0].rm_eo << "]," | |
4599 | << "[" << match[1].rm_so << "-" << match[1].rm_eo << "]," | |
4600 | << "[" << match[2].rm_so << "-" << match[2].rm_eo << "]" | |
4601 | << endl; | |
4602 | #endif | |
4603 | ||
4604 | string probe_name = string (symstr + match[1].rm_so, | |
4605 | (match[1].rm_eo - match[1].rm_so)); | |
4606 | string probe_sig = string (symstr + match[2].rm_so, | |
4607 | (match[2].rm_eo - match[2].rm_so)); | |
4608 | ||
4609 | // Below, "rc" has negative polarity: zero iff matching | |
e38d6504 | 4610 | rc = (has_module |
30a279be FCE |
4611 | ? fnmatch (param_module.c_str(), ext.module.c_str(), 0) |
4612 | : (ext.module != "")); // kernel.* | |
4613 | rc |= fnmatch (param_probe.c_str(), probe_name.c_str(), 0); | |
e38d6504 | 4614 | |
30a279be FCE |
4615 | if (! rc) |
4616 | { | |
4617 | // cout << "match (" << probe_name << "):" << probe_sig << endl; | |
4618 | ||
e38d6504 | 4619 | derived_probe *dp |
30a279be FCE |
4620 | = new mark_derived_probe (sess, |
4621 | probe_name, probe_sig, | |
4622 | ext.address, | |
4623 | ext.module, | |
4624 | base); | |
4625 | finished_results.push_back (dp); | |
4626 | } | |
4627 | } | |
4628 | } | |
4629 | ||
4630 | // cout << "done" << endl; | |
4631 | ||
4632 | // It's not a big deal if this is skipped due to an exception. | |
4633 | regfree (& symbol_regex_t); | |
4634 | } | |
4635 | ||
4636 | ||
56894e91 JS |
4637 | // ------------------------------------------------------------------------ |
4638 | // hrtimer derived probes | |
4639 | // ------------------------------------------------------------------------ | |
4640 | // This is a new timer interface that provides more flexibility in specifying | |
4641 | // intervals, and uses the hrtimer APIs when available for greater precision. | |
4642 | // As of 2.6.16, these APIs don't have the needed EXPORT_SYMBOL_GPL, so we | |
4643 | // can't make use of them yet. | |
4644 | // | |
4645 | // There are two classes defined below: | |
4646 | // * hrtimer_derived_probe: creates a probe point based on the hrtimer APIs. | |
4647 | // * hrtimer_builder: parses the user's time-spec into a 64-bit nanosecond | |
4648 | // value, and calls the appropriate derived_probe. | |
4649 | ||
4650 | ||
4651 | struct hrtimer_derived_probe: public derived_probe | |
4652 | { | |
4653 | // set a (generous) maximum of one day in ns | |
4654 | static const int64_t max_ns_interval = 1000000000LL * 60LL * 60LL * 24LL; | |
4655 | ||
4656 | // 100us seems like a reasonable minimum | |
4657 | static const int64_t min_ns_interval = 100000LL; | |
4658 | ||
4659 | int64_t interval, randomize; | |
4660 | ||
4661 | hrtimer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r): | |
4662 | derived_probe (p, l), interval (i), randomize (r) | |
4663 | { | |
4664 | if ((i < min_ns_interval) || (i > max_ns_interval)) | |
4665 | throw semantic_error("interval value out of range"); | |
4666 | ||
4667 | // randomize = 0 means no randomization | |
4668 | if ((r < 0) || (r > i)) | |
4669 | throw semantic_error("randomization value out of range"); | |
4670 | ||
4671 | if (locations.size() != 1) | |
4672 | throw semantic_error ("expect single probe point"); | |
4673 | // so we don't have to loop over them in the other functions | |
4674 | } | |
4675 | ||
dc38c0ae DS |
4676 | void register_probe (systemtap_session& s); |
4677 | ||
56894e91 JS |
4678 | virtual void emit_interval (translator_output * o); |
4679 | ||
46b84a80 DS |
4680 | virtual void emit_registrations_start (translator_output * o, |
4681 | unsigned index); | |
4682 | virtual void emit_registrations_end (translator_output * o, | |
4683 | unsigned index); | |
35d4ab18 FCE |
4684 | virtual void emit_deregistrations (translator_output * o); |
4685 | virtual void emit_probe_entries (translator_output * o); | |
56894e91 JS |
4686 | }; |
4687 | ||
4688 | ||
dc38c0ae DS |
4689 | void |
4690 | hrtimer_derived_probe::register_probe(systemtap_session& s) | |
4691 | { | |
4692 | s.probes.register_probe(this); | |
4693 | } | |
4694 | ||
4695 | ||
56894e91 JS |
4696 | void |
4697 | hrtimer_derived_probe::emit_interval (translator_output* o) | |
4698 | { | |
4699 | o->line() << "({"; | |
ffb0b3ad | 4700 | o->newline(1) << "unsigned long nsecs;"; |
56894e91 JS |
4701 | o->newline() << "int64_t i = " << interval << "LL;"; |
4702 | if (randomize != 0) | |
e38d6504 | 4703 | { |
56894e91 JS |
4704 | o->newline() << "int64_t r;"; |
4705 | o->newline() << "get_random_bytes(&r, sizeof(r));"; | |
4706 | o->newline() << "r &= ((uint64_t)1 << (8*sizeof(r) - 1)) - 1;"; | |
4707 | o->newline() << "r = _stp_mod64(NULL, r, " << (2*randomize + 1) << "LL);"; | |
4708 | o->newline() << "r -= " << randomize << "LL;"; | |
4709 | o->newline() << "i += r;"; | |
4710 | o->newline() << "if (unlikely(i < " << min_ns_interval << "LL))"; | |
4711 | o->newline(1) << "i = " << min_ns_interval << "LL;"; | |
4712 | o->indent(-1); | |
4713 | } | |
ffb0b3ad JS |
4714 | o->newline() << "nsecs = do_div(i, NSEC_PER_SEC);"; |
4715 | o->newline() << "ktime_set(i, nsecs);"; | |
56894e91 JS |
4716 | o->newline(-1) << "})"; |
4717 | } | |
4718 | ||
4719 | ||
4720 | void | |
46b84a80 DS |
4721 | hrtimer_derived_probe::emit_registrations_start (translator_output* o, |
4722 | unsigned index) | |
56894e91 | 4723 | { |
35d4ab18 | 4724 | o->newline() << "hrtimer_init (& timer_" << name |
56894e91 | 4725 | << ", CLOCK_MONOTONIC, HRTIMER_REL);"; |
35d4ab18 FCE |
4726 | o->newline() << "timer_" << name << ".function = enter_" << name << ";"; |
4727 | o->newline() << "hrtimer_start (& timer_" << name << ", "; | |
56894e91 JS |
4728 | emit_interval(o); |
4729 | o->line() << ", HRTIMER_REL);"; | |
4730 | } | |
4731 | ||
4732 | ||
46b84a80 DS |
4733 | void |
4734 | hrtimer_derived_probe::emit_registrations_end (translator_output* o, | |
4735 | unsigned index) | |
4736 | { | |
4737 | // nothing to do here... | |
4738 | } | |
4739 | ||
4740 | ||
56894e91 | 4741 | void |
35d4ab18 | 4742 | hrtimer_derived_probe::emit_deregistrations (translator_output* o) |
56894e91 | 4743 | { |
35d4ab18 | 4744 | o->newline() << "hrtimer_cancel (& timer_" << name << ");"; |
56894e91 JS |
4745 | } |
4746 | ||
4747 | ||
4748 | void | |
35d4ab18 | 4749 | hrtimer_derived_probe::emit_probe_entries (translator_output* o) |
56894e91 | 4750 | { |
a68f81a2 | 4751 | o->newline() << "static int enter_" << name << " (struct hrtimer *);"; |
35d4ab18 | 4752 | o->newline() << "static struct hrtimer timer_" << name << ";"; |
56894e91 | 4753 | |
a68f81a2 | 4754 | o->newline() << "int enter_" << name << " (struct hrtimer *timer) {"; |
56894e91 JS |
4755 | o->indent(1); |
4756 | o->newline() << "const char* probe_point = " | |
4757 | << lex_cast_qstring(*locations[0]) << ";"; | |
4758 | emit_probe_prologue (o, "STAP_SESSION_RUNNING"); | |
4759 | ||
a68f81a2 | 4760 | o->newline() << "(void) timer;"; |
56894e91 | 4761 | |
ffb0b3ad | 4762 | o->newline() << "hrtimer_start (& timer_" << name << ", "; |
56894e91 | 4763 | emit_interval(o); |
ffb0b3ad | 4764 | o->line() << ", HRTIMER_REL);"; |
56894e91 JS |
4765 | |
4766 | // NB: locals are initialized by probe function itself | |
35d4ab18 | 4767 | o->newline() << name << " (c);"; |
56894e91 JS |
4768 | |
4769 | emit_probe_epilogue (o); | |
a68f81a2 JS |
4770 | |
4771 | // Return NORESTART, because we already requeued the timer above | |
4772 | o->newline() << "return HRTIMER_NORESTART;"; | |
56894e91 JS |
4773 | o->newline(-1) << "}\n"; |
4774 | } | |
4775 | ||
4776 | ||
dc38c0ae DS |
4777 | struct hrtimer_derived_probe_group: public derived_probe_group |
4778 | { | |
4779 | private: | |
4780 | vector<hrtimer_derived_probe*> probes; | |
4781 | ||
4782 | public: | |
4783 | virtual void register_probe(hrtimer_derived_probe* p) { probes.push_back (p); } | |
4784 | virtual size_t size () { return probes.size (); } | |
4785 | ||
4786 | virtual void emit_probes (translator_output* op, unparser* up); | |
46b84a80 | 4787 | virtual void emit_module_init (translator_output* o); |
dc38c0ae DS |
4788 | }; |
4789 | ||
4790 | ||
4791 | void | |
4792 | hrtimer_derived_probe_group::emit_probes (translator_output* op, unparser* up) | |
4793 | { | |
4794 | for (unsigned i=0; i < probes.size(); i++) | |
4795 | { | |
4796 | op->newline (); | |
4797 | up->emit_probe (probes[i]); | |
4798 | } | |
4799 | } | |
4800 | ||
4801 | ||
46b84a80 DS |
4802 | void |
4803 | hrtimer_derived_probe_group::emit_module_init (translator_output* o) | |
4804 | { | |
4805 | if (probes.size () == 0) | |
4806 | return; | |
4807 | ||
4808 | // Output the hrtimer probes create function | |
4809 | o->newline() << "static int register_hrtimer_probes (void) {"; | |
4810 | o->indent(1); | |
4811 | ||
4812 | for (unsigned i=0; i < probes.size (); i++) | |
4813 | { | |
4814 | probes[i]->emit_registrations_start (o, i); | |
4815 | o->newline (); | |
4816 | } | |
4817 | ||
4818 | o->newline() << "return 0;"; | |
4819 | o->newline(-1) << "}\n"; | |
4820 | ||
4821 | // Output the hrtimer probes destroy function | |
4822 | o->newline() << "static void unregister_hrtimer_probes (void) {"; | |
4823 | o->indent(1); | |
4824 | ||
4825 | for (unsigned i=0; i < probes.size (); i++) | |
4826 | { | |
4827 | probes[i]->emit_deregistrations (o); | |
4828 | emit_probe_timing(probes[i], o); | |
4829 | } | |
4830 | ||
4831 | o->newline(-1) << "}\n"; | |
4832 | } | |
4833 | ||
56894e91 JS |
4834 | struct hrtimer_builder: public derived_probe_builder |
4835 | { | |
4836 | hrtimer_builder() {} | |
4837 | static int64_t convert_to_ns(const string &time); | |
4838 | virtual void build(systemtap_session & sess, | |
4839 | probe * base, | |
4840 | probe_point * location, | |
4841 | std::map<std::string, literal *> const & parameters, | |
4842 | vector<derived_probe *> & finished_results) | |
4843 | { | |
4844 | string interval, randomize; | |
4845 | int64_t i_ns, r_ns; | |
4846 | ||
4847 | if (!get_param (parameters, "hrtimer", interval)) | |
4848 | throw semantic_error("timer requires an interval"); | |
4849 | i_ns = convert_to_ns(interval); | |
4850 | if (sess.verbose > 1) | |
4851 | clog << "parsed timer interval '" << interval | |
4852 | << "' to " << i_ns << " ns. "<< endl; | |
4853 | ||
4854 | if (get_param (parameters, "randomize", randomize)) | |
4855 | { | |
4856 | r_ns = convert_to_ns(randomize); | |
4857 | if (sess.verbose > 1) | |
4858 | clog << "parsed timer randomization '" << randomize | |
4859 | << "' to " << r_ns << " ns. "<< endl; | |
4860 | } | |
4861 | else | |
4862 | r_ns = 0; | |
4863 | ||
4864 | string target_kernel_v; | |
4865 | ||
a68f81a2 JS |
4866 | // cut off any release code suffix |
4867 | string::size_type dash_index = sess.kernel_release.find ('-'); | |
4868 | if (dash_index > 0 && dash_index != string::npos) | |
4869 | target_kernel_v = sess.kernel_release.substr (0, dash_index); | |
4870 | else | |
4871 | target_kernel_v = sess.kernel_release; | |
4872 | ||
4873 | // hrtimers are only exported starting in 2.6.17 | |
4874 | if (strverscmp(target_kernel_v.c_str(), "2.6.17") >= 0) | |
56894e91 JS |
4875 | finished_results.push_back( |
4876 | new hrtimer_derived_probe(base, location, i_ns, r_ns)); | |
4877 | else | |
4878 | { | |
4879 | int64_t i_ms = (i_ns + 999999) / 1000000; | |
4880 | int64_t r_ms = (r_ns + 999999) / 1000000; | |
4881 | ||
4882 | if (sess.verbose > 2) | |
4883 | { | |
4884 | clog << "rounded timer interval from " | |
4885 | << i_ns << " ns to " << i_ms <<" ms. "<< endl; | |
4886 | clog << "rounded timer randomization from " | |
4887 | << i_ns << " ns to " << i_ms <<" ms. "<< endl; | |
4888 | } | |
e38d6504 | 4889 | |
56894e91 JS |
4890 | finished_results.push_back( |
4891 | new timer_derived_probe(base, location, i_ms, r_ms, true)); | |
4892 | } | |
4893 | } | |
4894 | }; | |
4895 | ||
4896 | ||
4897 | int64_t | |
4898 | hrtimer_builder::convert_to_ns(const string &time) | |
4899 | { | |
4900 | int64_t ns; | |
4901 | int64_t num; | |
4902 | string unit; | |
4903 | istringstream iss(time); | |
4904 | ||
4905 | iss >> num >> unit; | |
4906 | if (iss.fail() || num==0) goto bad_time; | |
4907 | ||
4908 | if ((unit == "hz") || (unit == "hertz")) | |
4909 | { | |
4910 | ns = 1000000000/num; | |
4911 | iss >> unit; | |
4912 | if (!iss.fail()) goto bad_time; | |
4913 | return ns; | |
4914 | } | |
4915 | ||
4916 | ns = 0; | |
4917 | do | |
4918 | { | |
4919 | if ((unit == "ns") || (unit == "nsec")) | |
4920 | goto unit_parsed; | |
4921 | ||
4922 | num *= 1000; | |
4923 | if ((unit == "us") || (unit == "usec")) | |
4924 | goto unit_parsed; | |
4925 | ||
4926 | num *= 1000; | |
4927 | if ((unit == "ms") || (unit == "msec")) | |
4928 | goto unit_parsed; | |
4929 | ||
4930 | num *= 1000; | |
4931 | if ((unit == "s") || (unit == "sec")) | |
4932 | goto unit_parsed; | |
4933 | ||
4934 | num *= 60; | |
4935 | if ((unit == "m") || (unit == "min")) | |
4936 | goto unit_parsed; | |
4937 | ||
4938 | num *= 60; | |
4939 | if ((unit == "h") || (unit == "hour")) | |
4940 | goto unit_parsed; | |
4941 | ||
4942 | goto bad_time; | |
4943 | ||
4944 | unit_parsed: | |
4945 | ns += num; | |
4946 | ||
4947 | iss >> num; | |
4948 | if (iss.fail()) break; | |
4949 | iss >> unit; | |
4950 | if (iss.fail() || num==0) goto bad_time; | |
4951 | } | |
4952 | while (1); | |
4953 | ||
4954 | return ns; | |
4955 | ||
4956 | bad_time: | |
4957 | throw semantic_error("bad time parameter: '" + time + "'"); | |
4958 | } | |
4959 | ||
4960 | ||
47dd066d WC |
4961 | // ------------------------------------------------------------------------ |
4962 | // perfmon derived probes | |
4963 | // ------------------------------------------------------------------------ | |
4964 | // This is a new interface to the perfmon hw. | |
4965 | // | |
4966 | ||
4967 | ||
4968 | struct perfmon_var_expanding_copy_visitor: public var_expanding_copy_visitor | |
4969 | { | |
4970 | systemtap_session & sess; | |
4971 | unsigned counter_number; | |
4972 | perfmon_var_expanding_copy_visitor(systemtap_session & s, unsigned c): | |
4973 | sess(s), counter_number(c) {} | |
4974 | void visit_target_symbol (target_symbol* e); | |
4975 | }; | |
4976 | ||
4977 | ||
4978 | void | |
4979 | perfmon_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) | |
4980 | { | |
4981 | assert(e->base_name.size() > 0 && e->base_name[0] == '$'); | |
4982 | ||
4983 | // Synthesize a function. | |
4984 | functiondecl *fdecl = new functiondecl; | |
4985 | fdecl->tok = e->tok; | |
4986 | embeddedcode *ec = new embeddedcode; | |
4987 | ec->tok = e->tok; | |
4988 | bool lvalue = is_active_lvalue(e); | |
4989 | ||
4990 | if (lvalue ) | |
4991 | throw semantic_error("writes to $counter not permitted"); | |
4992 | ||
4993 | string fname = string("_perfmon_tvar_get") | |
4994 | + "_" + e->base_name.substr(1) | |
4995 | + "_" + lex_cast<string>(counter_number); | |
4996 | ||
4997 | if (e->base_name != "$counter") | |
4998 | throw semantic_error ("target variables not available to perfmon probes"); | |
4999 | ||
5000 | ec->code = "THIS->__retvalue = _pfm_pmd_x[" + | |
5001 | lex_cast<string>(counter_number) + "].reg_num;"; | |
5002 | ec->code += "/* pure */"; | |
5003 | fdecl->name = fname; | |
5004 | fdecl->body = ec; | |
5005 | fdecl->type = pe_long; | |
5006 | sess.functions.push_back(fdecl); | |
5007 | ||
5008 | // Synthesize a functioncall. | |
5009 | functioncall* n = new functioncall; | |
5010 | n->tok = e->tok; | |
5011 | n->function = fname; | |
5012 | n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session | |
5013 | ||
5014 | provide <functioncall*> (this, n); | |
5015 | } | |
5016 | ||
5017 | ||
5018 | enum perfmon_mode | |
5019 | { | |
5020 | perfmon_count, | |
5021 | perfmon_sample | |
5022 | }; | |
5023 | ||
5024 | ||
5025 | struct perfmon_derived_probe: public derived_probe | |
5026 | { | |
5027 | protected: | |
5028 | static unsigned probes_allocated; | |
5029 | ||
5030 | public: | |
5031 | systemtap_session & sess; | |
5032 | string event; | |
5033 | perfmon_mode mode; | |
5034 | ||
5035 | perfmon_derived_probe (probe* p, probe_point* l, systemtap_session &s, | |
5036 | string e, perfmon_mode m); | |
5037 | virtual void register_probe (systemtap_session& s); | |
5038 | virtual void emit_registrations_start (translator_output* o, unsigned index); | |
5039 | virtual void emit_registrations_end (translator_output * o, unsigned index); | |
5040 | virtual void emit_deregistrations (translator_output * o); | |
5041 | virtual void emit_probe_entries (translator_output * o); | |
5042 | }; | |
5043 | ||
5044 | ||
5045 | struct perfmon_derived_probe_group: public derived_probe_group | |
5046 | { | |
5047 | private: | |
5048 | vector<perfmon_derived_probe*> probes; | |
5049 | ||
5050 | public: | |
5051 | virtual void register_probe(perfmon_derived_probe* p) | |
5052 | { probes.push_back (p); } | |
5053 | virtual size_t size () { return probes.size (); } | |
5054 | virtual void emit_probes (translator_output* op, unparser* up); | |
5055 | virtual void emit_module_init (translator_output* o); | |
5056 | }; | |
5057 | ||
5058 | ||
5059 | struct perfmon_builder: public derived_probe_builder | |
5060 | { | |
5061 | perfmon_builder() {} | |
5062 | virtual void build(systemtap_session & sess, | |
5063 | probe * base, | |
5064 | probe_point * location, | |
5065 | std::map<std::string, literal *> const & parameters, | |
5066 | vector<derived_probe *> & finished_results) | |
5067 | { | |
5068 | string event; | |
5069 | if (!get_param (parameters, "counter", event)) | |
5070 | throw semantic_error("perfmon requires an event"); | |
5071 | ||
5072 | sess.perfmon++; | |
5073 | ||
5074 | // XXX: need to revise when doing sampling | |
5075 | finished_results.push_back(new perfmon_derived_probe(base, location, | |
5076 | sess, event, | |
5077 | perfmon_count)); | |
5078 | } | |
5079 | }; | |
5080 | ||
5081 | unsigned perfmon_derived_probe::probes_allocated; | |
5082 | ||
5083 | perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l, | |
5084 | systemtap_session &s, | |
5085 | string e, perfmon_mode m) | |
5086 | : derived_probe (p, l), sess(s), event(e), mode(m) | |
5087 | { | |
5088 | ++probes_allocated; | |
5089 | ||
5090 | // Now make a local-variable-expanded copy of the probe body | |
5091 | perfmon_var_expanding_copy_visitor v (sess, probes_allocated-1); | |
5092 | require <block*> (&v, &(this->body), base->body); | |
5093 | ||
5094 | if (sess.verbose > 1) | |
5095 | clog << "perfmon-based probe" << endl; | |
5096 | } | |
5097 | ||
5098 | ||
5099 | void | |
5100 | perfmon_derived_probe::register_probe (systemtap_session& s) | |
5101 | { | |
5102 | s.probes.register_probe(this); | |
5103 | } | |
5104 | ||
5105 | ||
5106 | void | |
5107 | perfmon_derived_probe::emit_registrations_start (translator_output* o, | |
5108 | unsigned index) | |
5109 | { | |
5110 | for (unsigned i=0; i<locations.size(); i++) | |
5111 | o->newline() << "enter_" << name << "_" << i << " ();"; | |
5112 | } | |
5113 | ||
5114 | ||
5115 | void | |
5116 | perfmon_derived_probe::emit_registrations_end (translator_output * o, | |
5117 | unsigned index) | |
5118 | { | |
5119 | } | |
5120 | ||
5121 | ||
5122 | void | |
5123 | perfmon_derived_probe::emit_deregistrations (translator_output * o) | |
5124 | { | |
5125 | } | |
5126 | ||
5127 | ||
5128 | void | |
5129 | perfmon_derived_probe::emit_probe_entries (translator_output * o) | |
5130 | { | |
5131 | o->newline() << "#ifdef STP_TIMING"; | |
5132 | o->newline() << "static __cacheline_aligned Stat " << "time_" << basest()->name << ";"; | |
5133 | o->newline() << "#endif"; | |
5134 | ||
5135 | for (unsigned i=0; i<locations.size(); i++) | |
5136 | { | |
5137 | probe_point *l = locations[i]; | |
5138 | o->newline() << "/* location " << i << ": " << *l << " */"; | |
5139 | o->newline() << "static void enter_" << name << "_" << i << " (void) {"; | |
5140 | ||
5141 | o->indent(1); | |
5142 | o->newline() << "const char* probe_point = " | |
5143 | << lex_cast_qstring(*l) << ";"; | |
5144 | emit_probe_prologue (o, | |
5145 | (mode == perfmon_count ? | |
5146 | "STAP_SESSION_STARTING" : | |
5147 | "STAP_SESSION_RUNNING")); | |
5148 | ||
5149 | // NB: locals are initialized by probe function itself | |
5150 | o->newline() << name << " (c);"; | |
5151 | ||
5152 | emit_probe_epilogue (o); | |
5153 | ||
5154 | o->newline(-1) << "}\n"; | |
5155 | } | |
5156 | } | |
5157 | ||
5158 | ||
5159 | #ifdef PERFMON | |
5160 | void no_pfm_event_error (string s) | |
5161 | { | |
5162 | string msg(string("Cannot find event:" + s)); | |
5163 | throw semantic_error(msg); | |
5164 | } | |
5165 | ||
5166 | ||
5167 | void no_pfm_mask_error (string s) | |
5168 | { | |
5169 | string msg(string("Cannot find mask:" + s)); | |
5170 | throw semantic_error(msg); | |
5171 | } | |
5172 | ||
5173 | ||
5174 | void | |
5175 | split(const string& s, vector<string>& v, const string & separator) | |
5176 | { | |
5177 | string::size_type last_pos = s.find_first_not_of(separator, 0); | |
5178 | string::size_type pos = s.find_first_of(separator, last_pos); | |
5179 | ||
5180 | while (string::npos != pos || string::npos != last_pos) { | |
5181 | v.push_back(s.substr(last_pos, pos - last_pos)); | |
5182 | last_pos = s.find_first_not_of(separator, pos); | |
5183 | pos = s.find_first_of(separator, last_pos); | |
5184 | } | |
5185 | } | |
5186 | ||
5187 | ||
5188 | void | |
5189 | perfmon_derived_probe_group::emit_probes (translator_output* op, unparser* up) | |
5190 | { | |
5191 | for (unsigned i=0; i < probes.size(); i++) | |
5192 | { | |
5193 | op->newline (); | |
5194 | up->emit_probe (probes[i]); | |
5195 | } | |
5196 | } | |
5197 | ||
5198 | ||
5199 | void | |
5200 | perfmon_derived_probe_group::emit_module_init (translator_output* o) | |
5201 | { | |
5202 | int ret; | |
5203 | pfmlib_input_param_t inp; | |
5204 | pfmlib_output_param_t outp; | |
5205 | pfarg_pmd_t pd[PFMLIB_MAX_PMDS]; | |
5206 | pfarg_pmc_t pc[PFMLIB_MAX_PMCS]; | |
5207 | pfarg_ctx_t ctx; | |
5208 | pfarg_load_t load_args; | |
5209 | pfmlib_options_t pfmlib_options; | |
5210 | unsigned int max_counters; | |
5211 | ||
5212 | if ( probes.size() == 0) | |
5213 | return; | |
5214 | ret = pfm_initialize(); | |
5215 | if (ret != PFMLIB_SUCCESS) | |
5216 | throw semantic_error("Unable to generate performance monitoring events (no libpfm)"); | |
5217 | ||
5218 | pfm_get_num_counters(&max_counters); | |
5219 | ||
5220 | memset(&pfmlib_options, 0, sizeof(pfmlib_options)); | |
5221 | pfmlib_options.pfm_debug = 0; /* set to 1 for debug */ | |
5222 | pfmlib_options.pfm_verbose = 0; /* set to 1 for debug */ | |
5223 | pfm_set_options(&pfmlib_options); | |
5224 | ||
5225 | memset(pd, 0, sizeof(pd)); | |
5226 | memset(pc, 0, sizeof(pc)); | |
5227 | memset(&ctx, 0, sizeof(ctx)); | |
5228 | memset(&load_args, 0, sizeof(load_args)); | |
5229 | ||
5230 | /* | |
5231 | * prepare parameters to library. | |
5232 | */ | |
5233 | memset(&inp,0, sizeof(inp)); | |
5234 | memset(&outp,0, sizeof(outp)); | |
5235 | ||
5236 | /* figure out the events */ | |
5237 | for (unsigned i=0; i<probes.size(); ++i) | |
5238 | { | |
5239 | if (probes[i]->event == "cycles") { | |
5240 | if (pfm_get_cycle_event( &inp.pfp_events[i].event) != PFMLIB_SUCCESS) | |
5241 | no_pfm_event_error(probes[i]->event); | |
5242 | } else if (probes[i]->event == "instructions") { | |
5243 | if (pfm_get_inst_retired_event( &inp.pfp_events[i].event) != | |
5244 | PFMLIB_SUCCESS) | |
5245 | no_pfm_event_error(probes[i]->event); | |
5246 | } else { | |
5247 | unsigned int event_id = 0; | |
5248 | unsigned int mask_id = 0; | |
5249 | vector<string> event_spec; | |
5250 | split(probes[i]->event, event_spec, ":"); | |
5251 | int num = event_spec.size(); | |
5252 | int masks = num - 1; | |
5253 | ||
5254 | if (num == 0) | |
5255 | throw semantic_error("No events found"); | |
5256 | ||
5257 | /* setup event */ | |
5258 | if (pfm_find_event(event_spec[0].c_str(), &event_id) != PFMLIB_SUCCESS) | |
5259 | no_pfm_event_error(event_spec[0]); | |
5260 | inp.pfp_events[i].event = event_id; | |
5261 | ||
5262 | /* set up masks */ | |
5263 | if (masks > PFMLIB_MAX_MASKS_PER_EVENT) | |
5264 | throw semantic_error("Too many unit masks specified"); | |
5265 | ||
5266 | for (int j=0; j < masks; j++) { | |
5267 | if (pfm_find_event_mask(event_id, event_spec[j+1].c_str(), | |
5268 | &mask_id) != PFMLIB_SUCCESS) | |
5269 | no_pfm_mask_error(string(event_spec[j+1])); | |
5270 | inp.pfp_events[i].unit_masks[j] = mask_id; | |
5271 | } | |
5272 | inp.pfp_events[i].num_masks = masks; | |
5273 | } | |
5274 | } | |
5275 | ||
5276 | /* number of counters in use */ | |
5277 | inp.pfp_event_count = probes.size(); | |
5278 | ||
5279 | // XXX: no elimination of duplicated counters | |
5280 | if (inp.pfp_event_count>max_counters) | |
5281 | throw semantic_error("Too many performance monitoring events."); | |
5282 | ||
5283 | /* count events both in kernel and user-space */ | |
5284 | inp.pfp_dfl_plm = PFM_PLM0 | PFM_PLM3; | |
5285 | ||
5286 | /* XXX: some cases a perfmon register might be used of watch dog | |
5287 | this code doesn't handle that case */ | |
5288 | ||
5289 | /* figure out the pmcs for the events */ | |
5290 | if ((ret=pfm_dispatch_events(&inp, NULL, &outp, NULL)) != PFMLIB_SUCCESS) | |
5291 | throw semantic_error("Cannot configure events"); | |
5292 | ||
5293 | for (unsigned i=0; i < outp.pfp_pmc_count; i++) { | |
5294 | pc[i].reg_num = outp.pfp_pmcs[i].reg_num; | |
5295 | pc[i].reg_value = outp.pfp_pmcs[i].reg_value; | |
5296 | } | |
5297 | ||
5298 | /* | |
5299 | * There could be more pmc settings than pmd. | |
5300 | * Figure out the actual pmds to use. | |
5301 | */ | |
5302 | for (unsigned i=0, j=0; i < inp.pfp_event_count; i++) { | |
5303 | pd[i].reg_num = outp.pfp_pmcs[j].reg_pmd_num; | |
5304 | for(; j < outp.pfp_pmc_count; j++) | |
5305 | if (outp.pfp_pmcs[j].reg_evt_idx != i) break; | |
5306 | } | |
5307 | ||
5308 | // Output the be probes create function | |
5309 | o->newline() << "static int register_perfmon_probes (void) {"; | |
5310 | o->newline(1) << "int rc = 0;"; | |
5311 | ||
5312 | o->newline() << "/* data for perfmon */"; | |
5313 | o->newline() << "static int _pfm_num_pmc = " << outp.pfp_pmc_count << ";"; | |
5314 | o->newline() << "static struct pfarg_pmc _pfm_pmc[" << outp.pfp_pmc_count | |
5315 | << "] = {"; | |
5316 | /* output the needed bits for pmc here */ | |
5317 | for (unsigned i=0; i < outp.pfp_pmc_count; i++) { | |
5318 | o->newline() << "{.reg_num=" << pc[i].reg_num << ", " | |
5319 | << ".reg_value=" << lex_cast_hex<string>(pc[i].reg_value) | |
5320 | << "},"; | |
5321 | } | |
5322 | ||
5323 | o->newline() << "};"; | |
5324 | o->newline() << "static int _pfm_num_pmd = " << inp.pfp_event_count << ";"; | |
5325 | o->newline() << "static struct pfarg_pmd _pfm_pmd[" << inp.pfp_event_count | |
5326 | << "] = {"; | |
5327 | /* output the needed bits for pmd here */ | |
5328 | for (unsigned i=0; i < inp.pfp_event_count; i++) { | |
5329 | o->newline() << "{.reg_num=" << pd[i].reg_num << ", " | |
5330 | << ".reg_value=" << pd[i].reg_value << "},"; | |
5331 | } | |
5332 | o->newline() << "};"; | |
5333 | o->newline(); | |
5334 | ||
5335 | o->newline() << "_pfm_pmc_x=_pfm_pmc;"; | |
5336 | o->newline() << "_pfm_num_pmc_x=_pfm_num_pmc;"; | |
5337 | o->newline() << "_pfm_pmd_x=_pfm_pmd;"; | |
5338 | o->newline() << "_pfm_num_pmd_x=_pfm_num_pmd;"; | |
5339 | ||
5340 | // call all the function bodies associated with perfcounters | |
5341 | for (unsigned i=0; i < probes.size (); i++) | |
5342 | probes[i]->emit_registrations_start (o,i); | |
5343 | ||
5344 | /* generate call to turn on instrumentation */ | |
5345 | o->newline() << "_pfm_context.ctx_flags |= PFM_FL_SYSTEM_WIDE;"; | |
5346 | o->newline() << "rc = rc || _stp_perfmon_setup(&_pfm_desc, &_pfm_context,"; | |
5347 | o->newline(1) << "_pfm_pmc, _pfm_num_pmc,"; | |
5348 | o->newline() << "_pfm_pmd, _pfm_num_pmd);"; | |
5349 | o->newline(-1); | |
5350 | ||
5351 | o->newline() << "return rc;"; | |
5352 | o->newline(-1) << "}\n"; | |
5353 | ||
5354 | // Output the be probes destroy function | |
5355 | o->newline() << "static void unregister_perfmon_probes (void) {"; | |
5356 | o->newline(1) << "_stp_perfmon_shutdown(_pfm_desc);"; | |
5357 | o->newline(-1) << "}\n"; | |
5358 | } | |
5359 | #else | |
5360 | void | |
5361 | perfmon_derived_probe_group::emit_probes (translator_output* op, unparser* up) | |
5362 | { | |
5363 | } | |
5364 | ||
5365 | ||
5366 | void | |
5367 | perfmon_derived_probe_group::emit_module_init (translator_output* o) | |
5368 | { | |
47dd066d WC |
5369 | } |
5370 | #endif /* PERFMON */ | |
5371 | ||
b55bc428 | 5372 | // ------------------------------------------------------------------------ |
bd2b1e68 | 5373 | // Standard tapset registry. |
b55bc428 FCE |
5374 | // ------------------------------------------------------------------------ |
5375 | ||
7a053d3b | 5376 | void |
f8220a7b | 5377 | register_standard_tapsets(systemtap_session & s) |
b55bc428 | 5378 | { |
f8220a7b GH |
5379 | s.pattern_root->bind("begin")->bind(new be_builder(true)); |
5380 | s.pattern_root->bind("end")->bind(new be_builder(false)); | |
30a279be | 5381 | |
6e3347a9 FCE |
5382 | s.pattern_root->bind("never")->bind(new never_builder()); |
5383 | ||
98afd80e FCE |
5384 | s.pattern_root->bind("timer")->bind_num("jiffies")->bind(new timer_builder()); |
5385 | s.pattern_root->bind("timer")->bind_num("jiffies")->bind_num("randomize")->bind(new timer_builder()); | |
422d1ceb FCE |
5386 | s.pattern_root->bind("timer")->bind_num("ms")->bind(new timer_builder(true)); |
5387 | s.pattern_root->bind("timer")->bind_num("ms")->bind_num("randomize")->bind(new timer_builder(true)); | |
39e57ce0 | 5388 | s.pattern_root->bind("timer")->bind("profile")->bind(new profile_builder()); |
56894e91 JS |
5389 | s.pattern_root->bind_str("hrtimer")->bind(new hrtimer_builder()); |
5390 | s.pattern_root->bind_str("hrtimer")->bind_str("randomize")->bind(new hrtimer_builder()); | |
47dd066d | 5391 | s.pattern_root->bind("perfmon")->bind_str("counter")->bind(new perfmon_builder()); |
b98a8d73 | 5392 | |
30a279be | 5393 | // dwarf-based kernel/module parts |
f8220a7b | 5394 | dwarf_derived_probe::register_patterns(s.pattern_root); |
30a279be FCE |
5395 | |
5396 | // marker-based kernel/module parts | |
5397 | s.pattern_root->bind("kernel")->bind_str("mark")->bind(new mark_builder()); | |
5398 | s.pattern_root->bind_str("module")->bind_str("mark")->bind(new mark_builder()); | |
b55bc428 | 5399 | } |
dc38c0ae DS |
5400 | |
5401 | ||
5402 | derived_probe_group_container::derived_probe_group_container (): | |
5403 | be_probe_group(new be_derived_probe_group), | |
5404 | dwarf_probe_group(new dwarf_derived_probe_group), | |
5405 | hrtimer_probe_group(new hrtimer_derived_probe_group), | |
5406 | mark_probe_group(new mark_derived_probe_group), | |
5407 | never_probe_group(new never_derived_probe_group), | |
5408 | profile_probe_group(new profile_derived_probe_group), | |
47dd066d WC |
5409 | timer_probe_group(new timer_derived_probe_group), |
5410 | perfmon_probe_group(new perfmon_derived_probe_group) | |
dc38c0ae DS |
5411 | { |
5412 | } | |
5413 | ||
5414 | ||
5415 | derived_probe_group_container::~derived_probe_group_container () | |
5416 | { | |
5417 | delete be_probe_group; | |
5418 | delete dwarf_probe_group; | |
5419 | delete hrtimer_probe_group; | |
5420 | delete mark_probe_group; | |
5421 | delete never_probe_group; | |
5422 | delete profile_probe_group; | |
5423 | delete timer_probe_group; | |
47dd066d | 5424 | delete perfmon_probe_group; |
dc38c0ae DS |
5425 | } |
5426 | ||
5427 | ||
5428 | void | |
5429 | derived_probe_group_container::register_probe(be_derived_probe* p) | |
5430 | { | |
5431 | probes.push_back (p); | |
5432 | be_probe_group->register_probe(p); | |
5433 | } | |
5434 | ||
5435 | ||
5436 | void | |
5437 | derived_probe_group_container::register_probe(dwarf_derived_probe* p) | |
5438 | { | |
5439 | probes.push_back (p); | |
5440 | dwarf_probe_group->register_probe(p); | |
5441 | } | |
5442 | ||
5443 | ||
5444 | void | |
5445 | derived_probe_group_container::register_probe(hrtimer_derived_probe* p) | |
5446 | { | |
5447 | probes.push_back (p); | |
5448 | hrtimer_probe_group->register_probe(p); | |
5449 | } | |
5450 | ||
5451 | ||
5452 | void | |
5453 | derived_probe_group_container::register_probe(mark_derived_probe* p) | |
5454 | { | |
5455 | probes.push_back (p); | |
5456 | mark_probe_group->register_probe(p); | |
5457 | } | |
5458 | ||
5459 | ||
5460 | void | |
5461 | derived_probe_group_container::register_probe(never_derived_probe* p) | |
5462 | { | |
5463 | probes.push_back (p); | |
5464 | never_probe_group->register_probe(p); | |
5465 | } | |
5466 | ||
5467 | ||
5468 | void | |
5469 | derived_probe_group_container::register_probe(profile_derived_probe* p) | |
5470 | { | |
5471 | probes.push_back (p); | |
5472 | profile_probe_group->register_probe(p); | |
5473 | } | |
5474 | ||
5475 | ||
5476 | void | |
5477 | derived_probe_group_container::register_probe(timer_derived_probe* p) | |
5478 | { | |
5479 | probes.push_back (p); | |
5480 | timer_probe_group->register_probe(p); | |
5481 | } | |
5482 | ||
5483 | ||
47dd066d WC |
5484 | void |
5485 | derived_probe_group_container::register_probe(perfmon_derived_probe* p) | |
5486 | { | |
5487 | probes.push_back (p); | |
5488 | perfmon_probe_group->register_probe(p); | |
5489 | } | |
5490 | ||
5491 | ||
dc38c0ae DS |
5492 | void |
5493 | derived_probe_group_container::emit_probes (translator_output* op, | |
5494 | unparser* up) | |
5495 | { | |
5496 | // Sanity check. | |
5497 | size_t groups_size = be_probe_group->size () | |
5498 | + dwarf_probe_group->size () | |
5499 | + hrtimer_probe_group->size () | |
5500 | + mark_probe_group->size () | |
5501 | + never_probe_group->size () | |
5502 | + profile_probe_group->size () | |
47dd066d WC |
5503 | + timer_probe_group->size () |
5504 | + perfmon_probe_group->size (); | |
dc38c0ae DS |
5505 | if (probes.size () != groups_size) |
5506 | { | |
5507 | cerr << "There are " << probes.size () << " total probes, and " | |
5508 | << groups_size << " grouped probes\n"; | |
5509 | ||
5510 | throw runtime_error("internal probe mismatch"); | |
5511 | } | |
5512 | ||
5513 | // Let each probe group emit its probes. | |
5514 | be_probe_group->emit_probes (op, up); | |
5515 | dwarf_probe_group->emit_probes (op, up); | |
5516 | hrtimer_probe_group->emit_probes (op, up); | |
5517 | mark_probe_group->emit_probes (op, up); | |
5518 | never_probe_group->emit_probes (op, up); | |
5519 | profile_probe_group->emit_probes (op, up); | |
5520 | timer_probe_group->emit_probes (op, up); | |
47dd066d | 5521 | perfmon_probe_group->emit_probes (op, up); |
dc38c0ae | 5522 | } |
46b84a80 DS |
5523 | |
5524 | ||
5525 | void | |
5526 | derived_probe_group_container::emit_module_init (translator_output* o) | |
5527 | { | |
5528 | // Let each probe group emit its module init logic. | |
5529 | be_probe_group->emit_module_init (o); | |
5530 | dwarf_probe_group->emit_module_init (o); | |
5531 | hrtimer_probe_group->emit_module_init (o); | |
5532 | mark_probe_group->emit_module_init (o); | |
5533 | never_probe_group->emit_module_init (o); | |
5534 | profile_probe_group->emit_module_init (o); | |
5535 | timer_probe_group->emit_module_init (o); | |
47dd066d | 5536 | perfmon_probe_group->emit_module_init(o); |
46b84a80 DS |
5537 | } |
5538 | ||
5539 | ||
47dd066d | 5540 | #define PERFMON_ERROR_LABEL "unregister_perfmon" |
46b84a80 DS |
5541 | #define BE_ERROR_LABEL "unregister_be" |
5542 | #define DWARF_ERROR_LABEL "unregister_dwarf" | |
5543 | #define HRTIMER_ERROR_LABEL "unregister_hrtimer" | |
5544 | #define MARK_ERROR_LABEL "unregister_mark" | |
5545 | #define PROFILE_ERROR_LABEL "unregister_profile" | |
5546 | #define TIMER_ERROR_LABEL "unregister_timer" | |
5547 | ||
5548 | void | |
5549 | derived_probe_group_container::emit_module_init_call (translator_output* o) | |
5550 | { | |
5551 | int i = 0; | |
5552 | const char *error_label = ""; | |
5553 | ||
47dd066d WC |
5554 | if (perfmon_probe_group->size () > 0) |
5555 | { | |
5556 | o->newline() << "rc = register_perfmon_probes ();"; | |
5557 | o->newline() << "if (rc)"; | |
5558 | o->indent(1); | |
5559 | // We need to deregister any already probes set up - this is | |
5560 | // essential for kprobes. | |
5561 | o->newline() << "goto out;"; | |
5562 | o->indent(-1); | |
5563 | i++; | |
5564 | error_label = PERFMON_ERROR_LABEL; | |
5565 | } | |
5566 | ||
46b84a80 DS |
5567 | if (be_probe_group->size () > 0) |
5568 | { | |
5569 | o->newline() << "rc = register_be_probes ();"; | |
5570 | o->newline() << "if (rc)"; | |
5571 | o->indent(1); | |
5572 | // We need to deregister any already probes set up - this is | |
5573 | // essential for kprobes. | |
5574 | o->newline() << "goto out;"; | |
5575 | o->indent(-1); | |
5576 | i++; | |
5577 | error_label = BE_ERROR_LABEL; | |
5578 | } | |
5579 | ||
5580 | if (dwarf_probe_group->size () > 0) | |
5581 | { | |
5582 | o->newline() << "rc = register_dwarf_probes ();"; | |
5583 | o->newline() << "if (rc)"; | |
5584 | o->indent(1); | |
5585 | // We need to deregister any already probes set up - this is | |
5586 | // essential for kprobes. | |
5587 | if (i > 0) | |
5588 | o->newline() << "goto " << error_label << ";"; | |
5589 | else | |
5590 | o->newline() << "goto out;"; | |
5591 | o->indent(-1); | |
5592 | i++; | |
5593 | error_label = DWARF_ERROR_LABEL; | |
5594 | } | |
5595 | ||
5596 | if (hrtimer_probe_group->size () > 0) | |
5597 | { | |
5598 | o->newline() << "rc = register_hrtimer_probes ();"; | |
5599 | o->newline() << "if (rc)"; | |
5600 | o->indent(1); | |
5601 | // We need to deregister any already probes set up - this is | |
5602 | // essential for kprobes. | |
5603 | if (i > 0) | |
5604 | o->newline() << "goto " << error_label << ";"; | |
5605 | else | |
5606 | o->newline() << "goto out;"; | |
5607 | o->indent(-1); | |
5608 | i++; | |
5609 | error_label = HRTIMER_ERROR_LABEL; | |
5610 | } | |
5611 | ||
5612 | if (mark_probe_group->size () > 0) | |
5613 | { | |
5614 | o->newline() << "rc = register_mark_probes ();"; | |
5615 | o->newline() << "if (rc)"; | |
5616 | o->indent(1); | |
5617 | // We need to deregister any already probes set up - this is | |
5618 | // essential for kprobes. | |
5619 | if (i > 0) | |
5620 | o->newline() << "goto " << error_label << ";"; | |
5621 | else | |
5622 | o->newline() << "goto out;"; | |
5623 | o->indent(-1); | |
5624 | i++; | |
5625 | error_label = MARK_ERROR_LABEL; | |
5626 | } | |
5627 | ||
5628 | // We don't need to bother with the never_probe_group. | |
5629 | ||
5630 | if (profile_probe_group->size () > 0) | |
5631 | { | |
5632 | o->newline() << "rc = register_profile_probes ();"; | |
5633 | o->newline() << "if (rc)"; | |
5634 | o->indent(1); | |
5635 | // We need to deregister any already probes set up - this is | |
5636 | // essential for kprobes. | |
5637 | if (i > 0) | |
5638 | o->newline() << "goto " << error_label << ";"; | |
5639 | else | |
5640 | o->newline() << "goto out;"; | |
5641 | o->indent(-1); | |
5642 | i++; | |
5643 | error_label = PROFILE_ERROR_LABEL; | |
5644 | } | |
5645 | ||
5646 | if (timer_probe_group->size () > 0) | |
5647 | { | |
5648 | o->newline() << "rc = register_timer_probes ();"; | |
5649 | o->newline() << "if (rc)"; | |
5650 | o->indent(1); | |
5651 | // We need to deregister any already probes set up - this is | |
5652 | // essential for kprobes. | |
5653 | if (i > 0) | |
5654 | o->newline() << "goto " << error_label << ";"; | |
5655 | else | |
5656 | o->newline() << "goto out;"; | |
5657 | o->indent(-1); | |
5658 | i++; | |
5659 | error_label = TIMER_ERROR_LABEL; | |
5660 | } | |
5661 | ||
5662 | // BEGIN probes would have all been run by now. One of them may | |
5663 | // have triggered a STAP_SESSION_ERROR (which would incidentally | |
5664 | // block later BEGIN ones). If so, let that indication stay, and | |
5665 | // otherwise act like probe insertion was a success. | |
5666 | o->newline() << "if (atomic_read (&session_state) == STAP_SESSION_STARTING)"; | |
5667 | o->newline(1) << "atomic_set (&session_state, STAP_SESSION_RUNNING);"; | |
5668 | o->newline(-1) << "goto out;"; | |
5669 | ||
5670 | // Recovery code for partially successful registration (rc != 0) | |
5671 | // XXX: Do we need to delay here to ensure any triggered probes have | |
5672 | // terminated? Probably not much, as they should all test for | |
5673 | // SESSION_STARTING state right at the top and return. ("begin" | |
5674 | // probes don't count, as they return synchronously.) | |
5675 | o->newline(); | |
5676 | ||
5677 | if (i > 0 && timer_probe_group->size () > 0) | |
5678 | { | |
5679 | o->newline(-1) << TIMER_ERROR_LABEL << ":"; | |
5680 | o->newline(1) << "unregister_timer_probes();"; | |
5681 | i--; | |
5682 | } | |
5683 | if (i > 0 && profile_probe_group->size () > 0) | |
5684 | { | |
5685 | o->newline(-1) << PROFILE_ERROR_LABEL << ":"; | |
5686 | o->newline(1) << "unregister_profile_probes();"; | |
5687 | i--; | |
5688 | } | |
5689 | ||
5690 | // We don't need to bother with the never_probe_group. | |
5691 | ||
5692 | if (i > 0 && mark_probe_group->size () > 0) | |
5693 | { | |
5694 | o->newline(-1) << MARK_ERROR_LABEL << ":"; | |
5695 | o->newline(1) << "unregister_mark_probes();"; | |
5696 | i--; | |
5697 | } | |
5698 | if (i > 0 && hrtimer_probe_group->size () > 0) | |
5699 | { | |
5700 | o->newline(-1) << HRTIMER_ERROR_LABEL << ":"; | |
5701 | o->newline(1) << "unregister_hrtimer_probes();"; | |
5702 | i--; | |
5703 | } | |
5704 | if (i > 0 && dwarf_probe_group->size () > 0) | |
5705 | { | |
5706 | o->newline(-1) << DWARF_ERROR_LABEL << ":"; | |
5707 | o->newline(1) << "unregister_dwarf_probes();"; | |
5708 | i--; | |
5709 | } | |
5710 | if (i > 0 && be_probe_group->size () > 0) | |
5711 | { | |
5712 | o->newline(-1) << BE_ERROR_LABEL << ":"; | |
5713 | o->newline(1) << "unregister_be_probes();"; | |
5714 | i--; | |
5715 | } | |
47dd066d WC |
5716 | if (i > 0 && perfmon_probe_group->size () > 0) |
5717 | { | |
5718 | o->newline(-1) << PERFMON_ERROR_LABEL << ":"; | |
5719 | o->newline(1) << "unregister_perfmon_probes();"; | |
5720 | i--; | |
5721 | } | |
46b84a80 DS |
5722 | } |
5723 | ||
5724 | ||
5725 | void | |
5726 | derived_probe_group_container::emit_module_exit (translator_output* o) | |
5727 | { | |
5728 | if (be_probe_group->size () > 0) | |
5729 | o->newline() << "unregister_be_probes ();"; | |
5730 | ||
5731 | if (dwarf_probe_group->size () > 0) | |
5732 | o->newline() << "unregister_dwarf_probes ();"; | |
5733 | ||
5734 | if (hrtimer_probe_group->size () > 0) | |
5735 | o->newline() << "unregister_hrtimer_probes ();"; | |
5736 | ||
5737 | if (mark_probe_group->size () > 0) | |
5738 | o->newline() << "unregister_mark_probes ();"; | |
5739 | ||
5740 | // We don't need to bother with the never_probe_group. | |
5741 | ||
5742 | if (profile_probe_group->size () > 0) | |
5743 | o->newline() << "unregister_profile_probes ();"; | |
5744 | ||
5745 | if (timer_probe_group->size () > 0) | |
5746 | o->newline() << "unregister_timer_probes ();"; | |
47dd066d WC |
5747 | |
5748 | if (perfmon_probe_group->size () > 0) | |
5749 | o->newline() << "unregister_perfmon_probes ();"; | |
46b84a80 | 5750 | } |