]>
Commit | Line | Data |
---|---|---|
f3c26ea5 | 1 | // translation pass |
27cc9ab5 | 2 | // Copyright (C) 2005-2014 Red Hat Inc. |
12363146 | 3 | // Copyright (C) 2005-2008 Intel Corporation. |
77123275 | 4 | // Copyright (C) 2010 Novell Corporation. |
69c68955 FCE |
5 | // |
6 | // This file is part of systemtap, and is free software. You can | |
7 | // redistribute it and/or modify it under the terms of the GNU General | |
8 | // Public License (GPL); either version 2, or (at your option) any | |
9 | // later version. | |
2b066ec1 FCE |
10 | |
11 | #include "config.h" | |
12 | #include "staptree.h" | |
13 | #include "elaborate.h" | |
14 | #include "translate.h" | |
dc38c0ae | 15 | #include "session.h" |
b20febf3 | 16 | #include "tapsets.h" |
72dbc915 | 17 | #include "util.h" |
f5973d67 | 18 | #include "dwarf_wrappers.h" |
3db9c843 | 19 | #include "setupdwfl.h" |
18da5887 | 20 | #include "task_finder.h" |
ea15e536 | 21 | #include "runtime/k_syms.h" |
6bbcd339 | 22 | #include "dwflpp.h" |
60cf5fae | 23 | #include "stapregex.h" |
a3e980f9 | 24 | #include "stringtable.h" |
d2548fe7 | 25 | |
3b579393 | 26 | #include <cstdlib> |
2b066ec1 | 27 | #include <iostream> |
f8220a7b | 28 | #include <set> |
ce10591c | 29 | #include <sstream> |
f8220a7b | 30 | #include <string> |
29e64872 | 31 | #include <cassert> |
1b94bf6d | 32 | #include <cstring> |
ef06c938 | 33 | #include <cerrno> |
2b066ec1 | 34 | |
c4a94c1a | 35 | extern "C" { |
9424498b | 36 | #include <dwarf.h> |
c4a94c1a | 37 | #include <elfutils/libdwfl.h> |
9424498b | 38 | #include <elfutils/libdw.h> |
18da5887 | 39 | #include <ftw.h> |
1e41115c LB |
40 | #define __STDC_FORMAT_MACROS |
41 | #include <inttypes.h> | |
c4a94c1a FCE |
42 | } |
43 | ||
c42e2d2e MW |
44 | // Max unwind table size (debug or eh) per module. Somewhat arbitrary |
45 | // limit (a bit more than twice the .debug_frame size of my local | |
17c0b69c FCE |
46 | // vmlinux for 2.6.31.4-83.fc12.x86_64). |
47 | // A larger value was recently found in a libxul.so build. | |
86058b0f JS |
48 | // ... and yet again in libxul.so, PR15162 |
49 | #define MAX_UNWIND_TABLE_SIZE (16 * 1024 * 1024) | |
c42e2d2e | 50 | |
b5f561be LB |
51 | #define STAP_T_01 _("\"Array overflow, check ") |
52 | #define STAP_T_02 _("\"MAXNESTING exceeded\";") | |
53 | #define STAP_T_03 _("\"division by 0\";") | |
54 | #define STAP_T_04 _("\"MAXACTION exceeded\";") | |
55 | #define STAP_T_05 _("\"aggregation overflow in ") | |
56 | #define STAP_T_06 _("\"empty aggregate\";") | |
57 | #define STAP_T_07 _("\"histogram index out of range\";") | |
a3e980f9 | 58 | |
2b066ec1 FCE |
59 | using namespace std; |
60 | ||
b9aa5bb4 | 61 | class var; |
313b2f74 | 62 | struct tmpvar; |
07c17d67 | 63 | struct aggvar; |
313b2f74 | 64 | struct mapvar; |
b9aa5bb4 | 65 | class itervar; |
ce10591c | 66 | |
d6d4dc4b JS |
67 | // A null-sink output stream, similar to /dev/null |
68 | // (no buffer -> badbit -> quietly suppressed output) | |
69 | static ostream nullstream(NULL); | |
70 | static translator_output null_o(nullstream); | |
71 | ||
4383d78c | 72 | struct c_unparser: public unparser, public visitor |
2b066ec1 FCE |
73 | { |
74 | systemtap_session* session; | |
75 | translator_output* o; | |
76 | ||
77 | derived_probe* current_probe; | |
2b066ec1 | 78 | functiondecl* current_function; |
296c059b JS |
79 | |
80 | const functioncall* assigned_functioncall; | |
81 | const string* assigned_functioncall_retval; | |
82 | ||
4383d78c | 83 | unsigned tmpvar_counter; |
f3c26ea5 | 84 | unsigned label_counter; |
9d0808b4 | 85 | unsigned action_counter; |
ad534e14 | 86 | bool already_checked_action_count; |
2b066ec1 | 87 | |
3be43eac DS |
88 | varuse_collecting_visitor vcv_needs_global_locks; |
89 | ||
1341a03c | 90 | map<string, probe*> probe_contents; |
88bbd60d | 91 | |
5b1fa53b JS |
92 | map<pair<bool, string>, string> compiled_printfs; |
93 | ||
d6d4dc4b JS |
94 | c_unparser (systemtap_session* ss, translator_output* op=NULL): |
95 | session (ss), o (op ?: ss->op), current_probe(0), current_function (0), | |
296c059b | 96 | assigned_functioncall (0), assigned_functioncall_retval (0), |
74fe61bc | 97 | tmpvar_counter (0), label_counter (0), action_counter(0), |
ad534e14 | 98 | already_checked_action_count(false), vcv_needs_global_locks (*ss) {} |
4383d78c | 99 | ~c_unparser () {} |
2b066ec1 | 100 | |
d6d4dc4b JS |
101 | // The main c_unparser doesn't write declarations as it traverses, |
102 | // but the c_tmpcounter subclass will. | |
103 | virtual void var_declare(string const&, var const&) {} | |
104 | ||
105 | // If we've seen a dupe, return it; else remember this and return NULL. | |
106 | probe *get_probe_dupe (derived_probe *dp); | |
107 | ||
313b2f74 | 108 | void emit_map_type_instantiations (); |
2b066ec1 FCE |
109 | void emit_common_header (); |
110 | void emit_global (vardecl* v); | |
4a6d3dfa | 111 | void emit_global_init (vardecl* v); |
bd268288 | 112 | void emit_global_init_type (vardecl *v); |
16c1c808 | 113 | void emit_global_param (vardecl* v); |
bd268288 | 114 | void emit_global_init_setters (); |
2b066ec1 | 115 | void emit_functionsig (functiondecl* v); |
be66b6e1 DS |
116 | void emit_kernel_module_init (); |
117 | void emit_kernel_module_exit (); | |
2b066ec1 | 118 | void emit_module_init (); |
a60923e9 | 119 | void emit_module_refresh (); |
2b066ec1 FCE |
120 | void emit_module_exit (); |
121 | void emit_function (functiondecl* v); | |
29bb0bbc | 122 | void emit_lock_decls (const varuse_collecting_visitor& v); |
3f3f4dd0 | 123 | void emit_locks (); |
c1d5f3f6 | 124 | void emit_probe (derived_probe* v); |
05a072cf | 125 | void emit_probe_condition_update(derived_probe* v); |
3f3f4dd0 | 126 | void emit_unlocks (); |
2b066ec1 | 127 | |
5b1fa53b JS |
128 | void emit_compiled_printfs (); |
129 | void emit_compiled_printf_locals (); | |
130 | void declare_compiled_printf (bool print_to_stream, const string& format); | |
d6d4dc4b JS |
131 | virtual const string& get_compiled_printf (bool print_to_stream, |
132 | const string& format); | |
5b1fa53b | 133 | |
13a9593f FCE |
134 | // for use by stats (pmap) foreach |
135 | set<string> aggregations_active; | |
136 | ||
bdc82277 JS |
137 | // values immediately available in foreach_loop iterations |
138 | map<string, string> foreach_loop_values; | |
d6d4dc4b | 139 | void visit_foreach_loop_value (foreach_loop* s, const string& value=""); |
bdc82277 JS |
140 | bool get_foreach_loop_value (arrayindex* ai, string& value); |
141 | ||
f3c26ea5 FCE |
142 | // for use by looping constructs |
143 | vector<string> loop_break_labels; | |
144 | vector<string> loop_continue_labels; | |
2b066ec1 FCE |
145 | |
146 | string c_typename (exp_type e); | |
49b68a33 | 147 | virtual string c_localname (const string& e, bool mangle_oldstyle = false); |
0386bbcf SM |
148 | virtual string c_globalname (const string &e); |
149 | virtual string c_funcname (const string &e); | |
313b2f74 | 150 | |
0386bbcf SM |
151 | string c_arg_define (const string& e); |
152 | string c_arg_undef (const string& e); | |
153 | ||
0af18f5a FL |
154 | string map_keytypes(vardecl* v); |
155 | void c_global_write_def(vardecl* v); | |
156 | void c_global_read_def(vardecl* v); | |
157 | void c_global_write_undef(vardecl* v); | |
158 | void c_global_read_undef(vardecl* v); | |
159 | ||
54dfabe9 | 160 | void c_assign (var& lvalue, const string& rvalue, const token* tok); |
b2d74f03 JS |
161 | void c_assign (tmpvar& lvalue, expression* rvalue, const char* msg); |
162 | void c_assign (const string& lvalue, expression* rvalue, const char* msg); | |
ce10591c | 163 | void c_assign (const string& lvalue, const string& rvalue, exp_type type, |
b2d74f03 | 164 | const char* msg, const token* tok); |
2b066ec1 | 165 | |
0386bbcf SM |
166 | void c_declare(exp_type ty, const string &ident); |
167 | void c_declare_static(exp_type ty, const string &ident); | |
313b2f74 GH |
168 | |
169 | void c_strcat (const string& lvalue, const string& rvalue); | |
170 | void c_strcat (const string& lvalue, expression* rvalue); | |
171 | ||
172 | void c_strcpy (const string& lvalue, const string& rvalue); | |
173 | void c_strcpy (const string& lvalue, expression* rvalue); | |
174 | ||
54dfabe9 | 175 | bool is_local (vardecl const* r, token const* tok); |
313b2f74 GH |
176 | |
177 | tmpvar gensym(exp_type ty); | |
07c17d67 GH |
178 | aggvar gensym_aggregate(); |
179 | ||
54dfabe9 | 180 | var getvar(vardecl* v, token const* tok = NULL); |
d02548c0 | 181 | itervar getiter(symbol* s); |
54dfabe9 | 182 | mapvar getmap(vardecl* v, token const* tok = NULL); |
313b2f74 | 183 | |
54dfabe9 | 184 | void load_map_indices(arrayindex* e, |
313b2f74 GH |
185 | vector<tmpvar> & idx); |
186 | ||
c4782e01 | 187 | var* load_aggregate (expression *e, aggvar & agg); |
1bbeef03 | 188 | string histogram_index_check(var & vase, tmpvar & idx) const; |
a4636912 | 189 | |
54dfabe9 | 190 | void collect_map_index_types(vector<vardecl* > const & vars, |
d23a2349 | 191 | set< pair<vector<exp_type>, exp_type> > & types); |
313b2f74 | 192 | |
54975cd8 | 193 | void record_actions (unsigned actions, const token* tok, bool update=false); |
5e309481 | 194 | |
54dfabe9 | 195 | void visit_block (block* s); |
f4fe2e93 | 196 | void visit_try_block (try_block* s); |
54dfabe9 FCE |
197 | void visit_embeddedcode (embeddedcode* s); |
198 | void visit_null_statement (null_statement* s); | |
199 | void visit_expr_statement (expr_statement* s); | |
2b066ec1 FCE |
200 | void visit_if_statement (if_statement* s); |
201 | void visit_for_loop (for_loop* s); | |
69c68955 | 202 | void visit_foreach_loop (foreach_loop* s); |
2b066ec1 FCE |
203 | void visit_return_statement (return_statement* s); |
204 | void visit_delete_statement (delete_statement* s); | |
f3c26ea5 FCE |
205 | void visit_next_statement (next_statement* s); |
206 | void visit_break_statement (break_statement* s); | |
207 | void visit_continue_statement (continue_statement* s); | |
2b066ec1 FCE |
208 | void visit_literal_string (literal_string* e); |
209 | void visit_literal_number (literal_number* e); | |
7d902887 | 210 | void visit_embedded_expr (embedded_expr* e); |
2b066ec1 FCE |
211 | void visit_binary_expression (binary_expression* e); |
212 | void visit_unary_expression (unary_expression* e); | |
213 | void visit_pre_crement (pre_crement* e); | |
214 | void visit_post_crement (post_crement* e); | |
215 | void visit_logical_or_expr (logical_or_expr* e); | |
216 | void visit_logical_and_expr (logical_and_expr* e); | |
217 | void visit_array_in (array_in* e); | |
93daaca8 | 218 | void visit_regex_query (regex_query* e); |
2b066ec1 FCE |
219 | void visit_comparison (comparison* e); |
220 | void visit_concatenation (concatenation* e); | |
2b066ec1 FCE |
221 | void visit_ternary_expression (ternary_expression* e); |
222 | void visit_assignment (assignment* e); | |
223 | void visit_symbol (symbol* e); | |
d7f3e0c5 | 224 | void visit_target_symbol (target_symbol* e); |
2b066ec1 FCE |
225 | void visit_arrayindex (arrayindex* e); |
226 | void visit_functioncall (functioncall* e); | |
d02548c0 GH |
227 | void visit_print_format (print_format* e); |
228 | void visit_stat_op (stat_op* e); | |
229 | void visit_hist_op (hist_op* e); | |
9b5af295 | 230 | void visit_cast_op (cast_op* e); |
251707c8 | 231 | void visit_autocast_op (autocast_op* e); |
bd1fcbad | 232 | void visit_atvar_op (atvar_op* e); |
30263a73 | 233 | void visit_defined_op (defined_op* e); |
8cc799a5 | 234 | void visit_entry_op (entry_op* e); |
3689db05 | 235 | void visit_perf_op (perf_op* e); |
7d1e27af JS |
236 | |
237 | // start/close statements with multiple independent child visits | |
238 | virtual void start_compound_statement (const char*, statement*) { } | |
239 | virtual void close_compound_statement (const char*, statement*) { } | |
240 | ||
241 | // wrap one child visit of a compound statement | |
242 | virtual void wrap_compound_visit (expression *e) { if (e) e->visit (this); } | |
243 | virtual void wrap_compound_visit (statement *s) { if (s) s->visit (this); } | |
2b066ec1 FCE |
244 | }; |
245 | ||
313b2f74 | 246 | // A shadow visitor, meant to generate temporary variable declarations |
d6d4dc4b JS |
247 | // for function or probe bodies. The output is discarded, but we now do |
248 | // real work in var_declare(). | |
29d86764 | 249 | struct c_tmpcounter cxx_final: public c_unparser |
313b2f74 GH |
250 | { |
251 | c_unparser* parent; | |
d6d4dc4b JS |
252 | set<string> declared_vars; |
253 | ||
dff50e09 | 254 | c_tmpcounter (c_unparser* p): |
d6d4dc4b JS |
255 | c_unparser(p->session, &null_o), parent (p) |
256 | { } | |
313b2f74 | 257 | |
d6d4dc4b JS |
258 | // When vars are created *and used* (i.e. not overridden tmpvars) they call |
259 | // var_declare(), which will forward to the parent c_unparser for output; | |
260 | void var_declare(string const&, var const& v) cxx_override; | |
11b52b73 | 261 | |
d6d4dc4b JS |
262 | void emit_function (functiondecl* fd); |
263 | void emit_probe (derived_probe* dp); | |
264 | ||
265 | const string& get_compiled_printf (bool print_to_stream, | |
266 | const string& format) cxx_override; | |
11b52b73 | 267 | |
7d1e27af JS |
268 | void start_compound_statement (const char*, statement*) cxx_override; |
269 | void close_compound_statement (const char*, statement*) cxx_override; | |
395146b5 | 270 | |
7d1e27af JS |
271 | void wrap_compound_visit (expression *e) cxx_override; |
272 | void wrap_compound_visit (statement *s) cxx_override; | |
395146b5 | 273 | |
395146b5 AJ |
274 | void start_struct_def (std::ostream::pos_type &before, |
275 | std::ostream::pos_type &after, const token* tok); | |
276 | void close_struct_def (std::ostream::pos_type before, | |
277 | std::ostream::pos_type after); | |
313b2f74 GH |
278 | }; |
279 | ||
dff50e09 | 280 | struct c_unparser_assignment: |
313b2f74 GH |
281 | public throwing_visitor |
282 | { | |
283 | c_unparser* parent; | |
47d349b1 | 284 | interned_string op; |
313b2f74 | 285 | expression* rvalue; |
78110925 | 286 | bool post; // true == value saved before modify operator |
47d349b1 | 287 | c_unparser_assignment (c_unparser* p, interned_string o, expression* e): |
313b2f74 | 288 | throwing_visitor ("invalid lvalue type"), |
78110925 | 289 | parent (p), op (o), rvalue (e), post (false) {} |
47d349b1 | 290 | c_unparser_assignment (c_unparser* p, interned_string o, bool pp): |
313b2f74 | 291 | throwing_visitor ("invalid lvalue type"), |
78110925 | 292 | parent (p), op (o), rvalue (0), post (pp) {} |
313b2f74 | 293 | |
47d349b1 | 294 | void prepare_rvalue (interned_string op, |
11b52b73 | 295 | tmpvar & rval, |
54dfabe9 | 296 | token const* tok); |
313b2f74 | 297 | |
dff50e09 FCE |
298 | void c_assignop(tmpvar & res, |
299 | var const & lvar, | |
313b2f74 | 300 | tmpvar const & tmp, |
54dfabe9 | 301 | token const* tok); |
313b2f74 GH |
302 | |
303 | // only symbols and arrayindex nodes are possible lvalues | |
54dfabe9 FCE |
304 | void visit_symbol (symbol* e); |
305 | void visit_arrayindex (arrayindex* e); | |
313b2f74 GH |
306 | }; |
307 | ||
308 | ||
313b2f74 GH |
309 | ostream & operator<<(ostream & o, var const & v); |
310 | ||
07c17d67 GH |
311 | |
312 | /* | |
313 | Some clarification on the runtime structures involved in statistics: | |
dff50e09 | 314 | |
07c17d67 GH |
315 | The basic type for collecting statistics in the runtime is struct |
316 | stat_data. This contains the count, min, max, sum, and possibly | |
317 | histogram fields. | |
dff50e09 | 318 | |
07c17d67 | 319 | There are two places struct stat_data shows up. |
dff50e09 | 320 | |
07c17d67 GH |
321 | 1. If you declare a statistic variable of any sort, you want to make |
322 | a struct _Stat. A struct _Stat* is also called a Stat. Struct _Stat | |
323 | contains a per-CPU array of struct stat_data values, as well as a | |
324 | struct stat_data which it aggregates into. Writes into a Struct | |
325 | _Stat go into the per-CPU struct stat. Reads involve write-locking | |
326 | the struct _Stat, aggregating into its aggregate struct stat_data, | |
327 | unlocking, read-locking the struct _Stat, then reading values out of | |
328 | the aggregate and unlocking. | |
329 | ||
330 | 2. If you declare a statistic-valued map, you want to make a | |
331 | pmap. This is a per-CPU array of maps, each of which holds struct | |
332 | stat_data values, as well as an aggregate *map*. Writes into a pmap | |
333 | go into the per-CPU map. Reads involve write-locking the pmap, | |
334 | aggregating into its aggregate map, unlocking, read-locking the | |
335 | pmap, then reading values out of its aggregate (which is a normal | |
336 | map) and unlocking. | |
337 | ||
338 | Because, at the moment, the runtime does not support the concept of | |
339 | a statistic which collects multiple histogram types, we may need to | |
340 | instantiate one pmap or struct _Stat for each histogram variation | |
dff50e09 | 341 | the user wants to track. |
07c17d67 GH |
342 | */ |
343 | ||
313b2f74 GH |
344 | class var |
345 | { | |
07c17d67 GH |
346 | |
347 | protected: | |
0386bbcf SM |
348 | // Required for accurate mangling: |
349 | c_unparser *u; | |
350 | ||
313b2f74 GH |
351 | bool local; |
352 | exp_type ty; | |
57b73400 | 353 | statistic_decl sd; |
313b2f74 | 354 | string name; |
0386bbcf | 355 | bool do_mangle; |
313b2f74 | 356 | |
d6d4dc4b JS |
357 | private: |
358 | mutable bool declaration_needed; | |
359 | ||
313b2f74 GH |
360 | public: |
361 | ||
0386bbcf SM |
362 | var(c_unparser *u, bool local, exp_type ty, |
363 | statistic_decl const & sd, string const & name) | |
d6d4dc4b JS |
364 | : u(u), local(local), ty(ty), sd(sd), name(name), |
365 | do_mangle(true), declaration_needed(false) | |
57b73400 GH |
366 | {} |
367 | ||
0386bbcf | 368 | var(c_unparser *u, bool local, exp_type ty, string const & name) |
d6d4dc4b JS |
369 | : u(u), local(local), ty(ty), name(name), |
370 | do_mangle(true), declaration_needed(false) | |
0386bbcf SM |
371 | {} |
372 | ||
373 | var(c_unparser *u, bool local, exp_type ty, | |
374 | string const & name, bool do_mangle) | |
d6d4dc4b JS |
375 | : u(u), local(local), ty(ty), name(name), |
376 | do_mangle(do_mangle), declaration_needed(false) | |
377 | {} | |
378 | ||
379 | var(c_unparser *u, bool local, exp_type ty, unsigned & counter) | |
380 | : u(u), local(local), ty(ty), name("__tmp" + lex_cast(counter++)), | |
381 | do_mangle(false), declaration_needed(true) | |
313b2f74 GH |
382 | {} |
383 | ||
1820694f JS |
384 | virtual ~var() {} |
385 | ||
313b2f74 GH |
386 | bool is_local() const |
387 | { | |
388 | return local; | |
389 | } | |
390 | ||
57b73400 GH |
391 | statistic_decl const & sdecl() const |
392 | { | |
393 | return sd; | |
394 | } | |
395 | ||
a4636912 GH |
396 | void assert_hist_compatible(hist_op const & hop) |
397 | { | |
398 | // Semantic checks in elaborate should have caught this if it was | |
399 | // false. This is just a double-check. | |
400 | switch (sd.type) | |
401 | { | |
402 | case statistic_decl::linear: | |
403 | assert(hop.htype == hist_linear); | |
404 | assert(hop.params.size() == 3); | |
405 | assert(hop.params[0] == sd.linear_low); | |
406 | assert(hop.params[1] == sd.linear_high); | |
407 | assert(hop.params[2] == sd.linear_step); | |
408 | break; | |
409 | case statistic_decl::logarithmic: | |
410 | assert(hop.htype == hist_log); | |
e38723d2 | 411 | assert(hop.params.size() == 0); |
a4636912 GH |
412 | break; |
413 | case statistic_decl::none: | |
414 | assert(false); | |
415 | } | |
416 | } | |
417 | ||
313b2f74 GH |
418 | exp_type type() const |
419 | { | |
420 | return ty; | |
421 | } | |
422 | ||
0386bbcf SM |
423 | string c_name() const |
424 | { | |
425 | if (!do_mangle) | |
426 | return name; | |
427 | else if (local) | |
428 | return u->c_localname(name); | |
429 | else | |
430 | return u->c_globalname(name); | |
431 | } | |
432 | ||
11b52b73 | 433 | string value() const |
313b2f74 | 434 | { |
d6d4dc4b JS |
435 | if (declaration_needed) |
436 | { | |
437 | u->var_declare (name, *this); | |
438 | declaration_needed = false; | |
439 | } | |
440 | ||
313b2f74 | 441 | if (local) |
0386bbcf | 442 | return "l->" + c_name(); |
313b2f74 | 443 | else |
63438a79 | 444 | return "global(" + c_name() + ")"; |
313b2f74 GH |
445 | } |
446 | ||
1820694f | 447 | virtual string hist() const |
a4636912 GH |
448 | { |
449 | assert (ty == pe_stats); | |
1bbeef03 | 450 | assert (sd.type != statistic_decl::none); |
11b52b73 | 451 | return "(&(" + value() + "->hist))"; |
1bbeef03 GH |
452 | } |
453 | ||
1820694f | 454 | virtual string buckets() const |
1bbeef03 GH |
455 | { |
456 | assert (ty == pe_stats); | |
457 | assert (sd.type != statistic_decl::none); | |
11b52b73 | 458 | return "(" + value() + "->hist.buckets)"; |
a4636912 GH |
459 | } |
460 | ||
67c0a579 | 461 | string init() const |
313b2f74 GH |
462 | { |
463 | switch (type()) | |
464 | { | |
465 | case pe_string: | |
16c1c808 FCE |
466 | if (! local) |
467 | return ""; // module_param | |
468 | else | |
63438a79 | 469 | return value() + "[0] = '\\0';"; |
313b2f74 | 470 | case pe_long: |
213bee8f | 471 | if (! local) |
9ba8c134 | 472 | return ""; // module_param |
213bee8f | 473 | else |
11b52b73 | 474 | return value() + " = 0;"; |
57b73400 | 475 | case pe_stats: |
133467ef FCE |
476 | { |
477 | // See also mapvar::init(). | |
dff50e09 | 478 | |
63438a79 | 479 | if (local) |
dc09353a | 480 | throw SEMANTIC_ERROR(_F("unsupported local stats init for %s", value().c_str())); |
63438a79 JS |
481 | |
482 | string prefix = "global_set(" + c_name() + ", _stp_stat_init ("; | |
133467ef | 483 | // Check for errors during allocation. |
11b52b73 | 484 | string suffix = "if (" + value () + " == NULL) rc = -ENOMEM;"; |
dff50e09 | 485 | |
133467ef FCE |
486 | switch (sd.type) |
487 | { | |
488 | case statistic_decl::none: | |
489 | prefix += "HIST_NONE"; | |
490 | break; | |
dff50e09 | 491 | |
133467ef FCE |
492 | case statistic_decl::linear: |
493 | prefix += string("HIST_LINEAR") | |
aca66a36 JS |
494 | + ", " + lex_cast(sd.linear_low) |
495 | + ", " + lex_cast(sd.linear_high) | |
496 | + ", " + lex_cast(sd.linear_step); | |
133467ef | 497 | break; |
dff50e09 | 498 | |
133467ef | 499 | case statistic_decl::logarithmic: |
e38723d2 | 500 | prefix += string("HIST_LOG"); |
133467ef | 501 | break; |
dff50e09 | 502 | |
133467ef | 503 | default: |
dc09353a | 504 | throw SEMANTIC_ERROR(_F("unsupported stats type for %s", value().c_str())); |
133467ef | 505 | } |
dff50e09 | 506 | |
63438a79 | 507 | prefix = prefix + ")); "; |
133467ef FCE |
508 | return string (prefix + suffix); |
509 | } | |
dff50e09 | 510 | |
313b2f74 | 511 | default: |
dc09353a | 512 | throw SEMANTIC_ERROR(_F("unsupported initializer for %s", value().c_str())); |
313b2f74 GH |
513 | } |
514 | } | |
515 | ||
85278e66 DB |
516 | string fini () const |
517 | { | |
518 | switch (type()) | |
519 | { | |
520 | case pe_string: | |
521 | case pe_long: | |
522 | return ""; // no action required | |
523 | case pe_stats: | |
524 | return "_stp_stat_del (" + value () + ");"; | |
525 | default: | |
dc09353a | 526 | throw SEMANTIC_ERROR(_F("unsupported deallocator for %s", value().c_str())); |
85278e66 DB |
527 | } |
528 | } | |
529 | ||
d6d4dc4b | 530 | virtual void declare(c_unparser &c) const |
313b2f74 | 531 | { |
0386bbcf | 532 | c.c_declare(ty, c_name()); |
313b2f74 GH |
533 | } |
534 | }; | |
535 | ||
536 | ostream & operator<<(ostream & o, var const & v) | |
537 | { | |
11b52b73 | 538 | return o << v.value(); |
313b2f74 GH |
539 | } |
540 | ||
d6d4dc4b JS |
541 | void |
542 | c_tmpcounter::var_declare (string const& name, var const& v) | |
543 | { | |
544 | if (declared_vars.insert(name).second) | |
545 | v.declare (*parent); | |
546 | } | |
547 | ||
313b2f74 GH |
548 | struct stmt_expr |
549 | { | |
550 | c_unparser & c; | |
dff50e09 | 551 | stmt_expr(c_unparser & c) : c(c) |
313b2f74 | 552 | { |
1bbeef03 | 553 | c.o->newline() << "({"; |
313b2f74 GH |
554 | c.o->indent(1); |
555 | } | |
556 | ~stmt_expr() | |
557 | { | |
bb788f9f | 558 | c.o->newline(-1) << "})"; |
313b2f74 GH |
559 | } |
560 | }; | |
561 | ||
bb788f9f | 562 | |
313b2f74 GH |
563 | struct tmpvar |
564 | : public var | |
565 | { | |
11b52b73 DS |
566 | protected: |
567 | bool overridden; | |
568 | string override_value; | |
569 | ||
570 | public: | |
0386bbcf | 571 | tmpvar(c_unparser *u, exp_type ty, unsigned & counter) |
d6d4dc4b | 572 | : var(u, true, ty, counter), |
0386bbcf | 573 | overridden(false) |
11b52b73 DS |
574 | {} |
575 | ||
576 | tmpvar(const var& source) | |
577 | : var(source), overridden(false) | |
313b2f74 | 578 | {} |
11b52b73 DS |
579 | |
580 | void override(const string &value) | |
581 | { | |
582 | overridden = true; | |
583 | override_value = value; | |
584 | } | |
585 | ||
b2d74f03 JS |
586 | bool is_overridden() |
587 | { | |
588 | return overridden; | |
589 | } | |
590 | ||
11b52b73 DS |
591 | string value() const |
592 | { | |
593 | if (overridden) | |
594 | return override_value; | |
595 | else | |
596 | return var::value(); | |
dff50e09 | 597 | } |
313b2f74 GH |
598 | }; |
599 | ||
11b52b73 DS |
600 | ostream & operator<<(ostream & o, tmpvar const & v) |
601 | { | |
602 | return o << v.value(); | |
603 | } | |
604 | ||
07c17d67 GH |
605 | struct aggvar |
606 | : public var | |
607 | { | |
0386bbcf | 608 | aggvar(c_unparser *u, unsigned & counter) |
d6d4dc4b | 609 | : var(u, true, pe_stats, counter) |
07c17d67 GH |
610 | {} |
611 | ||
612 | string init() const | |
613 | { | |
614 | assert (type() == pe_stats); | |
11b52b73 | 615 | return value() + " = NULL;"; |
07c17d67 GH |
616 | } |
617 | ||
d6d4dc4b | 618 | void declare(c_unparser &c) const cxx_override |
07c17d67 GH |
619 | { |
620 | assert (type() == pe_stats); | |
621 | c.o->newline() << "struct stat_data *" << name << ";"; | |
622 | } | |
bdc82277 JS |
623 | |
624 | string get_hist (var& index) const | |
625 | { | |
626 | return "(" + value() + "->histogram[" + index.value() + "])"; | |
627 | } | |
07c17d67 GH |
628 | }; |
629 | ||
313b2f74 GH |
630 | struct mapvar |
631 | : public var | |
632 | { | |
633 | vector<exp_type> index_types; | |
ef474d24 | 634 | int maxsize; |
74e6cc92 | 635 | bool wrap; |
0386bbcf SM |
636 | mapvar (c_unparser *u, |
637 | bool local, exp_type ty, | |
57b73400 | 638 | statistic_decl const & sd, |
dff50e09 | 639 | string const & name, |
ef474d24 | 640 | vector<exp_type> const & index_types, |
74e6cc92 | 641 | int maxsize, bool wrap) |
0386bbcf | 642 | : var (u, local, ty, sd, name), |
ef474d24 | 643 | index_types (index_types), |
74e6cc92 | 644 | maxsize (maxsize), wrap(wrap) |
313b2f74 | 645 | {} |
dff50e09 | 646 | |
313b2f74 GH |
647 | static string shortname(exp_type e); |
648 | static string key_typename(exp_type e); | |
649 | static string value_typename(exp_type e); | |
650 | ||
d23a2349 | 651 | string keysym () const |
d98d459c | 652 | { |
d23a2349 GH |
653 | string result; |
654 | vector<exp_type> tmp = index_types; | |
655 | tmp.push_back (type ()); | |
656 | for (unsigned i = 0; i < tmp.size(); ++i) | |
657 | { | |
658 | switch (tmp[i]) | |
659 | { | |
660 | case pe_long: | |
661 | result += 'i'; | |
662 | break; | |
663 | case pe_string: | |
664 | result += 's'; | |
665 | break; | |
666 | case pe_stats: | |
667 | result += 'x'; | |
668 | break; | |
669 | default: | |
dc09353a | 670 | throw SEMANTIC_ERROR(_("unknown type of map")); |
d23a2349 GH |
671 | break; |
672 | } | |
673 | } | |
674 | return result; | |
51bf37c3 GH |
675 | } |
676 | ||
2473ac1b | 677 | string function_keysym(string const & fname, bool pre_agg=false) const |
313b2f74 | 678 | { |
57eedf94 | 679 | string mtype = (is_parallel() && !pre_agg) ? "pmap" : "map"; |
2473ac1b JS |
680 | string result = "_stp_" + mtype + "_" + fname + "_" + keysym(); |
681 | return result; | |
682 | } | |
683 | ||
684 | string call_prefix (string const & fname, vector<tmpvar> const & indices, bool pre_agg=false) const | |
685 | { | |
686 | string result = function_keysym(fname, pre_agg) + " ("; | |
11b52b73 | 687 | result += pre_agg? fetch_existing_aggregate() : value(); |
313b2f74 GH |
688 | for (unsigned i = 0; i < indices.size(); ++i) |
689 | { | |
690 | if (indices[i].type() != index_types[i]) | |
dc09353a | 691 | throw SEMANTIC_ERROR(_("index type mismatch")); |
313b2f74 | 692 | result += ", "; |
11b52b73 | 693 | result += indices[i].value(); |
313b2f74 | 694 | } |
d23a2349 | 695 | |
313b2f74 GH |
696 | return result; |
697 | } | |
698 | ||
07c17d67 GH |
699 | bool is_parallel() const |
700 | { | |
701 | return type() == pe_stats; | |
702 | } | |
703 | ||
704 | string calculate_aggregate() const | |
705 | { | |
706 | if (!is_parallel()) | |
dc09353a | 707 | throw SEMANTIC_ERROR(_("aggregating non-parallel map type")); |
dff50e09 | 708 | |
2473ac1b | 709 | return function_keysym("agg") + " (" + value() + ")"; |
07c17d67 GH |
710 | } |
711 | ||
712 | string fetch_existing_aggregate() const | |
713 | { | |
714 | if (!is_parallel()) | |
dc09353a | 715 | throw SEMANTIC_ERROR(_("fetching aggregate of non-parallel map type")); |
dff50e09 | 716 | |
11b52b73 | 717 | return "_stp_pmap_get_agg(" + value() + ")"; |
07c17d67 | 718 | } |
d23a2349 GH |
719 | |
720 | string del (vector<tmpvar> const & indices) const | |
e7ae4442 MH |
721 | { |
722 | return (call_prefix("del", indices) + ")"); | |
d23a2349 GH |
723 | } |
724 | ||
725 | string exists (vector<tmpvar> const & indices) const | |
726 | { | |
77d3caaf MH |
727 | if (type() == pe_long || type() == pe_string) |
728 | return (call_prefix("exists", indices) + ")"); | |
729 | else if (type() == pe_stats) | |
4c82f679 DS |
730 | return ("((uintptr_t)" + call_prefix("get", indices) |
731 | + ") != (uintptr_t) 0)"); | |
732 | else | |
dc09353a | 733 | throw SEMANTIC_ERROR(_("checking existence of an unsupported map type")); |
d23a2349 GH |
734 | } |
735 | ||
57eedf94 | 736 | string get (vector<tmpvar> const & indices, bool pre_agg=false) const |
313b2f74 | 737 | { |
aab2b35f FCE |
738 | // see also itervar::get_key |
739 | if (type() == pe_string) | |
740 | // impedance matching: NULL -> empty strings | |
57eedf94 | 741 | return ("({ char *v = " + call_prefix("get", indices, pre_agg) + ");" |
d23a2349 | 742 | + "if (!v) v = \"\"; v; })"); |
07c17d67 | 743 | else if (type() == pe_long || type() == pe_stats) |
57eedf94 | 744 | return call_prefix("get", indices, pre_agg) + ")"; |
57b73400 | 745 | else |
dc09353a | 746 | throw SEMANTIC_ERROR(_("getting a value from an unsupported map type")); |
313b2f74 GH |
747 | } |
748 | ||
d23a2349 | 749 | string add (vector<tmpvar> const & indices, tmpvar const & val) const |
313b2f74 | 750 | { |
ef474d24 JS |
751 | string res = "{ int rc = "; |
752 | ||
aab2b35f | 753 | // impedance matching: empty strings -> NULL |
d23a2349 | 754 | if (type() == pe_stats) |
11b52b73 | 755 | res += (call_prefix("add", indices) + ", " + val.value() + ")"); |
57b73400 | 756 | else |
dc09353a | 757 | throw SEMANTIC_ERROR(_("adding a value of an unsupported map type")); |
ef474d24 | 758 | |
b5f561be LB |
759 | res += "; if (unlikely(rc)) { c->last_error = "; |
760 | res += STAP_T_01 + | |
aca66a36 JS |
761 | lex_cast(maxsize > 0 ? |
762 | "size limit (" + lex_cast(maxsize) + ")" : "MAXMAPENTRIES") | |
12363146 | 763 | + "\"; goto out; }}"; |
ef474d24 JS |
764 | |
765 | return res; | |
313b2f74 GH |
766 | } |
767 | ||
d23a2349 | 768 | string set (vector<tmpvar> const & indices, tmpvar const & val) const |
313b2f74 | 769 | { |
2288c6bb ET |
770 | string res = "{ int rc = "; |
771 | ||
d23a2349 GH |
772 | // impedance matching: empty strings -> NULL |
773 | if (type() == pe_string) | |
dff50e09 | 774 | res += (call_prefix("set", indices) |
11b52b73 | 775 | + ", (" + val.value() + "[0] ? " + val.value() + " : NULL))"); |
d23a2349 | 776 | else if (type() == pe_long) |
11b52b73 | 777 | res += (call_prefix("set", indices) + ", " + val.value() + ")"); |
d23a2349 | 778 | else |
dc09353a | 779 | throw SEMANTIC_ERROR(_("setting a value of an unsupported map type")); |
2288c6bb | 780 | |
b5f561be LB |
781 | res += "; if (unlikely(rc)) { c->last_error = "; |
782 | res += STAP_T_01 + | |
aca66a36 JS |
783 | lex_cast(maxsize > 0 ? |
784 | "size limit (" + lex_cast(maxsize) + ")" : "MAXMAPENTRIES") | |
12363146 | 785 | + "\"; goto out; }}"; |
2288c6bb ET |
786 | |
787 | return res; | |
313b2f74 | 788 | } |
1820694f JS |
789 | |
790 | string hist() const | |
791 | { | |
792 | assert (ty == pe_stats); | |
793 | assert (sd.type != statistic_decl::none); | |
794 | return "(&(" + fetch_existing_aggregate() + "->hist))"; | |
795 | } | |
796 | ||
797 | string buckets() const | |
798 | { | |
799 | assert (ty == pe_stats); | |
800 | assert (sd.type != statistic_decl::none); | |
801 | return "(" + fetch_existing_aggregate() + "->hist.buckets)"; | |
802 | } | |
dff50e09 | 803 | |
313b2f74 GH |
804 | string init () const |
805 | { | |
63438a79 | 806 | if (local) |
dc09353a | 807 | throw SEMANTIC_ERROR(_F("unsupported local map init for %s", value().c_str())); |
63438a79 JS |
808 | |
809 | string prefix = "global_set(" + c_name() + ", "; | |
810 | prefix += function_keysym("new") + " (" | |
db0a4028 DS |
811 | + (maxsize > 0 ? lex_cast(maxsize) : "MAXMAPENTRIES") |
812 | + ((wrap == true) ? ", 1" : ", 0"); | |
d23a2349 | 813 | |
133467ef FCE |
814 | // See also var::init(). |
815 | ||
3a02f9bf | 816 | // Check for errors during allocation. |
11b52b73 | 817 | string suffix = "if (" + value () + " == NULL) rc = -ENOMEM;"; |
3a02f9bf | 818 | |
57b73400 GH |
819 | if (type() == pe_stats) |
820 | { | |
821 | switch (sdecl().type) | |
822 | { | |
823 | case statistic_decl::none: | |
3a02f9bf | 824 | prefix = prefix + ", HIST_NONE"; |
57b73400 GH |
825 | break; |
826 | ||
827 | case statistic_decl::linear: | |
828 | // FIXME: check for "reasonable" values in linear stats | |
dff50e09 | 829 | prefix = prefix + ", HIST_LINEAR" |
aca66a36 JS |
830 | + ", " + lex_cast(sdecl().linear_low) |
831 | + ", " + lex_cast(sdecl().linear_high) | |
832 | + ", " + lex_cast(sdecl().linear_step); | |
57b73400 GH |
833 | break; |
834 | ||
835 | case statistic_decl::logarithmic: | |
e38723d2 | 836 | prefix = prefix + ", HIST_LOG"; |
57b73400 GH |
837 | break; |
838 | } | |
839 | } | |
840 | ||
63438a79 | 841 | prefix = prefix + ")); "; |
b20febf3 | 842 | return (prefix + suffix); |
313b2f74 GH |
843 | } |
844 | ||
845 | string fini () const | |
846 | { | |
b20febf3 FCE |
847 | // NB: fini() is safe to call even for globals that have not |
848 | // successfully initialized (that is to say, on NULL pointers), | |
849 | // because the runtime specifically tolerates that in its _del | |
850 | // functions. | |
851 | ||
b68e0c9e | 852 | if (is_parallel()) |
11b52b73 | 853 | return "_stp_pmap_del (" + value() + ");"; |
b68e0c9e | 854 | else |
11b52b73 | 855 | return "_stp_map_del (" + value() + ");"; |
b68e0c9e | 856 | } |
313b2f74 GH |
857 | }; |
858 | ||
07c17d67 | 859 | |
67c0a579 | 860 | class itervar |
d6d4dc4b | 861 | : public var |
67c0a579 | 862 | { |
67c0a579 GH |
863 | public: |
864 | ||
d6d4dc4b JS |
865 | itervar (c_unparser *u, symbol* e, unsigned & counter) |
866 | : var(u, true, e->referent->type, counter) | |
67c0a579 | 867 | { |
d6d4dc4b | 868 | if (type() == pe_unknown) |
dc09353a | 869 | throw SEMANTIC_ERROR(_("iterating over unknown reference type"), e->tok); |
67c0a579 | 870 | } |
dff50e09 | 871 | |
d6d4dc4b | 872 | void declare(c_unparser &c) const cxx_override |
67c0a579 | 873 | { |
d6d4dc4b | 874 | c.o->newline() << "struct map_node *" << name << ";"; |
67c0a579 | 875 | } |
dff50e09 | 876 | |
67c0a579 GH |
877 | string start (mapvar const & mv) const |
878 | { | |
07c17d67 GH |
879 | string res; |
880 | ||
d6d4dc4b | 881 | if (mv.type() != type()) |
dc09353a | 882 | throw SEMANTIC_ERROR(_("inconsistent iterator type in itervar::start()")); |
dff50e09 | 883 | |
07c17d67 GH |
884 | if (mv.is_parallel()) |
885 | return "_stp_map_start (" + mv.fetch_existing_aggregate() + ")"; | |
886 | else | |
11b52b73 | 887 | return "_stp_map_start (" + mv.value() + ")"; |
67c0a579 GH |
888 | } |
889 | ||
890 | string next (mapvar const & mv) const | |
891 | { | |
d6d4dc4b | 892 | if (mv.type() != type()) |
dc09353a | 893 | throw SEMANTIC_ERROR(_("inconsistent iterator type in itervar::next()")); |
67c0a579 | 894 | |
40687c55 | 895 | if (mv.is_parallel()) |
11b52b73 | 896 | return "_stp_map_iter (" + mv.fetch_existing_aggregate() + ", " + value() + ")"; |
40687c55 | 897 | else |
11b52b73 | 898 | return "_stp_map_iter (" + mv.value() + ", " + value() + ")"; |
67c0a579 GH |
899 | } |
900 | ||
3a7fec94 AJ |
901 | // Cannot handle deleting and iterating on pmaps |
902 | string del_next (mapvar const & mv) const | |
a98c930b | 903 | { |
d6d4dc4b | 904 | if (mv.type() != type()) |
a98c930b AJ |
905 | throw SEMANTIC_ERROR(_("inconsistent iterator type in itervar::next()")); |
906 | ||
907 | if (mv.is_parallel()) | |
3a7fec94 | 908 | throw SEMANTIC_ERROR(_("deleting a value of an unsupported map type")); |
a98c930b AJ |
909 | else |
910 | return "_stp_map_iterdel (" + mv.value() + ", " + value() + ")"; | |
911 | } | |
912 | ||
2473ac1b | 913 | string get_key (mapvar const& mv, exp_type ty, unsigned i) const |
67c0a579 | 914 | { |
aab2b35f FCE |
915 | // bug translator/1175: runtime uses base index 1 for the first dimension |
916 | // see also mapval::get | |
67c0a579 GH |
917 | switch (ty) |
918 | { | |
919 | case pe_long: | |
3cb9c91e | 920 | return mv.function_keysym("key_get_int64", true) |
2473ac1b | 921 | + " (" + value() + ", " + lex_cast(i+1) + ")"; |
67c0a579 | 922 | case pe_string: |
aab2b35f | 923 | // impedance matching: NULL -> empty strings |
3cb9c91e | 924 | return "(" + mv.function_keysym("key_get_str", true) |
2473ac1b | 925 | + " (" + value() + ", " + lex_cast(i+1) + ") ?: \"\")"; |
67c0a579 | 926 | default: |
dc09353a | 927 | throw SEMANTIC_ERROR(_("illegal key type")); |
67c0a579 GH |
928 | } |
929 | } | |
bdc82277 | 930 | |
1841d2dd | 931 | string get_value (mapvar const& mv, exp_type ty) const |
bdc82277 | 932 | { |
d6d4dc4b | 933 | if (ty != type()) |
dc09353a | 934 | throw SEMANTIC_ERROR(_("inconsistent iterator value in itervar::get_value()")); |
bdc82277 JS |
935 | |
936 | switch (ty) | |
937 | { | |
938 | case pe_long: | |
1841d2dd | 939 | return mv.function_keysym("get_int64", true) + " ("+ value() + ")"; |
bdc82277 JS |
940 | case pe_string: |
941 | // impedance matching: NULL -> empty strings | |
1841d2dd | 942 | return "(" + mv.function_keysym("get_str", true) + " ("+ value() + ") ?: \"\")"; |
bdc82277 | 943 | case pe_stats: |
1841d2dd | 944 | return mv.function_keysym("get_stat_data", true) + " ("+ value() + ")"; |
bdc82277 | 945 | default: |
dc09353a | 946 | throw SEMANTIC_ERROR(_("illegal value type")); |
bdc82277 JS |
947 | } |
948 | } | |
67c0a579 GH |
949 | }; |
950 | ||
951 | ostream & operator<<(ostream & o, itervar const & v) | |
952 | { | |
11b52b73 | 953 | return o << v.value(); |
67c0a579 | 954 | } |
2b066ec1 | 955 | |
2b066ec1 FCE |
956 | // ------------------------------------------------------------------------ |
957 | ||
60cf5fae | 958 | // translator_output moved to translator-output.cxx |
f8220a7b | 959 | |
313b2f74 | 960 | // ------------------------------------------------------------------------ |
4383d78c | 961 | |
b9086437 | 962 | struct unmodified_fnargs_checker : public embedded_tags_visitor |
befa891f AJ |
963 | { |
964 | bool embedded_seen; // excludes code with pure and unmodified-args | |
b9086437 | 965 | unmodified_fnargs_checker (): embedded_tags_visitor(true), embedded_seen(false) {} |
befa891f | 966 | |
befa891f AJ |
967 | void visit_embeddedcode (embeddedcode *e) |
968 | { | |
b9086437 | 969 | embedded_tags_visitor::visit_embeddedcode(e); |
da1bd8fa | 970 | // set embedded_seen to true if it does not contain /* unmodified-fnargs */ |
2451f2f1 | 971 | embedded_seen = (embedded_seen || !tagged_p("/* unmodified-fnargs */")); |
befa891f AJ |
972 | } |
973 | }; | |
974 | ||
975 | bool | |
976 | is_unmodified_string_fnarg (systemtap_session* sess, functiondecl* fd, vardecl* v) | |
977 | { | |
b9086437 AJ |
978 | if (sess->unoptimized || v->type != pe_string) |
979 | return false; | |
980 | ||
981 | // check that there is no embedded code that might modify the fn args | |
982 | unmodified_fnargs_checker ecv; | |
983 | fd->body->visit(& ecv); | |
984 | if (ecv.embedded_seen) | |
985 | return false; | |
986 | ||
987 | varuse_collecting_visitor vut (*sess); | |
988 | vut.current_function = fd; | |
989 | fd->body->visit(& vut); | |
990 | return (find(vut.written.begin(), vut.written.end(), v) == vut.written.end()); | |
befa891f AJ |
991 | } |
992 | ||
d6d4dc4b JS |
993 | // If we've seen a dupe, return it; else remember this and return NULL. |
994 | probe * | |
995 | c_unparser::get_probe_dupe (derived_probe *dp) | |
996 | { | |
997 | if (session->unoptimized) | |
998 | return NULL; | |
999 | ||
1000 | // Notice we're using the probe body itself instead of the emitted C | |
1001 | // probe body to compare probes. We need to do this because the | |
1002 | // emitted C probe body has stuff in it like: | |
1003 | // c->last_stmt = "identifier 'printf' at foo.stp:<line>:<column>"; | |
1004 | // | |
1005 | // which would make comparisons impossible. | |
1006 | ||
1007 | ostringstream oss; | |
1008 | ||
1009 | dp->print_dupe_stamp (oss); | |
1010 | dp->body->print(oss); | |
1011 | ||
1012 | // Since the generated C changes based on whether or not the probe | |
1013 | // needs locks around global variables, this needs to be reflected | |
1014 | // here. We don't want to treat as duplicate the handlers of | |
1015 | // begin/end and normal probes that differ only in need_global_locks. | |
1016 | oss << "# needs_global_locks: " << dp->needs_global_locks () << endl; | |
1017 | ||
1018 | // NB: dependent probe conditions *could* be listed here, but don't need to | |
1019 | // be. That's because they're only dependent on the probe body, which is | |
1020 | // already "hashed" in above. | |
1021 | ||
1022 | pair<map<string, probe*>::iterator, bool> const& inserted = | |
1023 | probe_contents.insert(make_pair(oss.str(), dp)); | |
1024 | ||
1025 | if (inserted.second) | |
1026 | return NULL; // it's new! | |
1027 | ||
1028 | // Already seen it; here's the old one: | |
1029 | return inserted.first->second; | |
1030 | } | |
1031 | ||
2b066ec1 | 1032 | void |
4383d78c | 1033 | c_unparser::emit_common_header () |
2b066ec1 | 1034 | { |
d6d4dc4b JS |
1035 | c_tmpcounter ct (this); |
1036 | ||
342d3f96 | 1037 | o->newline(); |
97cd9334 | 1038 | |
a34a9fe0 MW |
1039 | // Per CPU context for probes. Includes common shared state held for |
1040 | // all probes (defined in common_probe_context), the probe locals (union) | |
1041 | // and the function locals (union). | |
2b066ec1 | 1042 | o->newline() << "struct context {"; |
18e5ffd4 | 1043 | |
a34a9fe0 MW |
1044 | // Common state held shared by probes. |
1045 | o->newline(1) << "#include \"common_probe_context.h\""; | |
18e5ffd4 FCE |
1046 | |
1047 | // PR10516: probe locals | |
2b066ec1 FCE |
1048 | o->newline() << "union {"; |
1049 | o->indent(1); | |
2b066ec1 FCE |
1050 | |
1051 | for (unsigned i=0; i<session->probes.size(); i++) | |
d6d4dc4b | 1052 | ct.emit_probe (session->probes[i]); |
57478609 | 1053 | |
18e5ffd4 FCE |
1054 | o->newline(-1) << "} probe_locals;"; |
1055 | ||
1056 | // PR10516: function locals | |
1057 | o->newline() << "union {"; | |
1058 | o->indent(1); | |
2b066ec1 | 1059 | |
d6d4dc4b JS |
1060 | for (map<string,functiondecl*>::iterator it = session->functions.begin(); |
1061 | it != session->functions.end(); it++) | |
1062 | ct.emit_function (it->second); | |
9b1b0d7e | 1063 | |
a7ed0d3e FCE |
1064 | o->newline(-1) << "} locals [MAXNESTING+1];"; |
1065 | ||
1066 | // NB: The +1 above for extra room for outgoing arguments of next nested function. | |
1067 | // If MAXNESTING is set too small, the args will be written, but the MAXNESTING | |
1068 | // check done at c_unparser::emit_function will reject. | |
1069 | // | |
1070 | // This policy wastes memory (one row of locals[] that cannot really | |
1071 | // be used), but trades that for smaller code (not having to check | |
1072 | // c->nesting against MAXNESTING at every call site). | |
1073 | ||
1074 | // Try to catch a crazy user dude passing in -DMAXNESTING=-1, leading to a [0]-sized | |
1075 | // locals[] array. | |
1076 | o->newline() << "#if MAXNESTING < 0"; | |
1077 | o->newline() << "#error \"MAXNESTING must be positive\""; | |
1078 | o->newline() << "#endif"; | |
1079 | ||
5b1fa53b JS |
1080 | // Use a separate union for compiled-printf locals, no nesting required. |
1081 | emit_compiled_printf_locals (); | |
1082 | ||
c08bf9de JS |
1083 | o->newline(-1) << "};\n"; // end of struct context |
1084 | ||
1085 | o->newline() << "#include \"runtime_context.h\""; | |
1086 | ||
313b2f74 | 1087 | emit_map_type_instantiations (); |
57b73400 | 1088 | |
5b1fa53b JS |
1089 | emit_compiled_printfs(); |
1090 | ||
4bf3d59d JL |
1091 | if (!session->runtime_usermode_p()) |
1092 | { | |
1093 | // Updated in probe handlers to signal that a module refresh is needed. | |
1094 | // Checked and cleared by common epilogue after scheduling refresh work. | |
6092ee9e | 1095 | o->newline( 0) << "static atomic_t need_module_refresh = ATOMIC_INIT(0);"; |
4bf3d59d JL |
1096 | |
1097 | // We will use a workqueue to schedule module_refresh work when we need | |
1098 | // to enable/disable probes. | |
1099 | o->newline( 0) << "#include <linux/workqueue.h>"; | |
1100 | o->newline( 0) << "static struct work_struct module_refresher_work;"; | |
1101 | o->newline( 0) << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)"; | |
1102 | o->newline( 0) << "static void module_refresher(void *data) {"; | |
1103 | o->newline( 0) << "#else"; | |
1104 | o->newline( 0) << "static void module_refresher(struct work_struct *work) {"; | |
1105 | o->newline( 0) << "#endif"; | |
1106 | o->newline( 1) << "systemtap_module_refresh(NULL);"; | |
1107 | o->newline(-1) << "}"; | |
0d10ad2d | 1108 | |
4619bb71 | 1109 | o->newline( 0) << "#ifdef STP_ON_THE_FLY_TIMER_ENABLE"; |
566b515c | 1110 | o->newline( 0) << "#include \"timer.h\""; |
0d10ad2d JL |
1111 | o->newline( 0) << "static struct hrtimer module_refresh_timer;"; |
1112 | ||
406ca289 JL |
1113 | o->newline( 0) << "#ifndef STP_ON_THE_FLY_INTERVAL"; |
1114 | o->newline( 0) << "#define STP_ON_THE_FLY_INTERVAL (100*1000*1000)"; // default to 100 ms | |
1115 | o->newline( 0) << "#endif"; | |
1116 | ||
566b515c | 1117 | o->newline( 0) << "hrtimer_return_t module_refresh_timer_cb(struct hrtimer *timer) {"; |
0d10ad2d | 1118 | o->newline(+1) << "if (atomic_cmpxchg(&need_module_refresh, 1, 0) == 1)"; |
df6c01e7 FCE |
1119 | // NB: one might like to invoke systemtap_module_refresh(NULL) directly from |
1120 | // here ... however hrtimers are called from an unsleepable context, so no can do. | |
0d10ad2d JL |
1121 | o->newline(+1) << "schedule_work(&module_refresher_work);"; |
1122 | o->newline(-1) << "hrtimer_set_expires(timer,"; | |
1123 | o->newline( 0) << " ktime_add(hrtimer_get_expires(timer),"; | |
406ca289 | 1124 | o->newline( 0) << " ktime_set(0, STP_ON_THE_FLY_INTERVAL))); "; |
0d10ad2d JL |
1125 | o->newline( 0) << "return HRTIMER_RESTART;"; |
1126 | o->newline(-1) << "}"; | |
f161bd74 | 1127 | o->newline( 0) << "#endif /* STP_ON_THE_FLY_TIMER_ENABLE */"; |
4bf3d59d | 1128 | } |
fc422d2b | 1129 | |
8cef7c70 | 1130 | o->newline(0) << "#include \"namespaces.h\""; |
ba7276fa JL |
1131 | |
1132 | o->newline(); | |
2b066ec1 FCE |
1133 | } |
1134 | ||
1135 | ||
5b1fa53b JS |
1136 | void |
1137 | c_unparser::declare_compiled_printf (bool print_to_stream, const string& format) | |
1138 | { | |
1139 | pair<bool, string> index (print_to_stream, format); | |
1140 | map<pair<bool, string>, string>::iterator it = compiled_printfs.find(index); | |
1141 | if (it == compiled_printfs.end()) | |
1142 | compiled_printfs[index] = (print_to_stream ? "stp_printf_" : "stp_sprintf_") | |
1143 | + lex_cast(compiled_printfs.size() + 1); | |
1144 | } | |
1145 | ||
1146 | const string& | |
1147 | c_unparser::get_compiled_printf (bool print_to_stream, const string& format) | |
1148 | { | |
1149 | map<pair<bool, string>, string>::iterator it = | |
1150 | compiled_printfs.find(make_pair(print_to_stream, format)); | |
1151 | if (it == compiled_printfs.end()) | |
dc09353a | 1152 | throw SEMANTIC_ERROR (_("internal error translating printf")); |
5b1fa53b JS |
1153 | return it->second; |
1154 | } | |
1155 | ||
d6d4dc4b JS |
1156 | const string& |
1157 | c_tmpcounter::get_compiled_printf (bool print_to_stream, const string& format) | |
1158 | { | |
1159 | parent->declare_compiled_printf (print_to_stream, format); | |
1160 | return parent->get_compiled_printf (print_to_stream, format); | |
1161 | } | |
1162 | ||
5b1fa53b JS |
1163 | void |
1164 | c_unparser::emit_compiled_printf_locals () | |
1165 | { | |
0da35eae | 1166 | o->newline() << "#ifndef STP_LEGACY_PRINT"; |
5b1fa53b JS |
1167 | o->newline() << "union {"; |
1168 | o->indent(1); | |
1169 | map<pair<bool, string>, string>::iterator it; | |
1170 | for (it = compiled_printfs.begin(); it != compiled_printfs.end(); ++it) | |
1171 | { | |
1172 | bool print_to_stream = it->first.first; | |
1173 | const string& format_string = it->first.second; | |
1174 | const string& name = it->second; | |
1175 | vector<print_format::format_component> components = | |
1176 | print_format::string_to_components(format_string); | |
1177 | ||
1178 | o->newline() << "struct " << name << "_locals {"; | |
1179 | o->indent(1); | |
1180 | ||
1181 | size_t arg_ix = 0; | |
1182 | vector<print_format::format_component>::const_iterator c; | |
1183 | for (c = components.begin(); c != components.end(); ++c) | |
1184 | { | |
1185 | if (c->type == print_format::conv_literal) | |
1186 | continue; | |
1187 | ||
1188 | // Take note of the width and precision arguments, if any. | |
1189 | if (c->widthtype == print_format::width_dynamic) | |
1190 | o->newline() << "int64_t arg" << arg_ix++ << ";"; | |
1191 | if (c->prectype == print_format::prec_dynamic) | |
1192 | o->newline() << "int64_t arg" << arg_ix++ << ";"; | |
1193 | ||
1194 | // Output the actual argument. | |
1195 | switch (c->type) | |
1196 | { | |
1197 | case print_format::conv_pointer: | |
1198 | case print_format::conv_number: | |
1199 | case print_format::conv_char: | |
1200 | case print_format::conv_memory: | |
1201 | case print_format::conv_memory_hex: | |
1202 | case print_format::conv_binary: | |
1203 | o->newline() << "int64_t arg" << arg_ix++ << ";"; | |
1204 | break; | |
1205 | ||
1206 | case print_format::conv_string: | |
1207 | // NB: Since we know incoming strings are immutable, we can use | |
1208 | // const char* rather than a private char[] copy. This is a | |
1209 | // special case of the sort of optimizations desired in PR11528. | |
1210 | o->newline() << "const char* arg" << arg_ix++ << ";"; | |
1211 | break; | |
1212 | ||
1213 | default: | |
1214 | assert(false); // XXX | |
1215 | break; | |
1216 | } | |
1217 | } | |
1218 | ||
1219 | ||
1220 | if (!print_to_stream) | |
1221 | o->newline() << "char * __retvalue;"; | |
1222 | ||
1223 | o->newline(-1) << "} " << name << ";"; | |
1224 | } | |
1225 | o->newline(-1) << "} printf_locals;"; | |
0da35eae | 1226 | o->newline() << "#endif // STP_LEGACY_PRINT"; |
5b1fa53b JS |
1227 | } |
1228 | ||
1229 | void | |
1230 | c_unparser::emit_compiled_printfs () | |
1231 | { | |
0da35eae | 1232 | o->newline() << "#ifndef STP_LEGACY_PRINT"; |
5b1fa53b JS |
1233 | map<pair<bool, string>, string>::iterator it; |
1234 | for (it = compiled_printfs.begin(); it != compiled_printfs.end(); ++it) | |
1235 | { | |
1236 | bool print_to_stream = it->first.first; | |
1237 | const string& format_string = it->first.second; | |
1238 | const string& name = it->second; | |
1239 | vector<print_format::format_component> components = | |
1240 | print_format::string_to_components(format_string); | |
1241 | ||
1242 | o->newline(); | |
1243 | ||
1244 | // Might be nice to output the format string in a comment, but we'd have | |
1245 | // to be extra careful about format strings not escaping the comment... | |
8f122660 | 1246 | o->newline() << "static void " << name |
5b1fa53b JS |
1247 | << " (struct context* __restrict__ c) {"; |
1248 | o->newline(1) << "struct " << name << "_locals * __restrict__ l = " | |
1249 | << "& c->printf_locals." << name << ";"; | |
1250 | o->newline() << "char *str = NULL, *end = NULL;"; | |
8f122660 FCE |
1251 | o->newline() << "const char *src;"; |
1252 | o->newline() << "int width;"; | |
1253 | o->newline() << "int precision;"; | |
1254 | o->newline() << "unsigned long ptr_value;"; | |
1255 | o->newline() << "int num_bytes;"; | |
1256 | ||
1257 | o->newline() << "(void) width;"; | |
1258 | o->newline() << "(void) precision;"; | |
1259 | o->newline() << "(void) ptr_value;"; | |
1260 | o->newline() << "(void) num_bytes;"; | |
5b1fa53b JS |
1261 | |
1262 | if (print_to_stream) | |
1263 | { | |
1264 | // Compute the buffer size needed for these arguments. | |
1265 | size_t arg_ix = 0; | |
8f122660 | 1266 | o->newline() << "num_bytes = 0;"; |
5b1fa53b JS |
1267 | vector<print_format::format_component>::const_iterator c; |
1268 | for (c = components.begin(); c != components.end(); ++c) | |
1269 | { | |
1270 | if (c->type == print_format::conv_literal) | |
1271 | { | |
1272 | literal_string ls(c->literal_string); | |
1273 | o->newline() << "num_bytes += sizeof("; | |
1274 | visit_literal_string(&ls); | |
1275 | o->line() << ") - 1;"; // don't count the '\0' | |
1276 | continue; | |
1277 | } | |
1278 | ||
8f122660 | 1279 | o->newline() << "width = "; |
5b1fa53b JS |
1280 | if (c->widthtype == print_format::width_dynamic) |
1281 | o->line() << "clamp_t(int, l->arg" << arg_ix++ | |
1282 | << ", 0, STP_BUFFER_SIZE);"; | |
1283 | else if (c->widthtype == print_format::width_static) | |
1284 | o->line() << "clamp_t(int, " << c->width | |
1285 | << ", 0, STP_BUFFER_SIZE);"; | |
1286 | else | |
1287 | o->line() << "-1;"; | |
1288 | ||
8f122660 | 1289 | o->newline() << "precision = "; |
5b1fa53b JS |
1290 | if (c->prectype == print_format::prec_dynamic) |
1291 | o->line() << "clamp_t(int, l->arg" << arg_ix++ | |
1292 | << ", 0, STP_BUFFER_SIZE);"; | |
1293 | else if (c->prectype == print_format::prec_static) | |
1294 | o->line() << "clamp_t(int, " << c->precision | |
1295 | << ", 0, STP_BUFFER_SIZE);"; | |
1296 | else | |
1297 | o->line() << "-1;"; | |
1298 | ||
1299 | string value = "l->arg" + lex_cast(arg_ix++); | |
1300 | switch (c->type) | |
1301 | { | |
1302 | case print_format::conv_pointer: | |
1303 | // NB: stap < 1.3 had odd %p behavior... see _stp_vsnprintf | |
1304 | if (strverscmp(session->compatible.c_str(), "1.3") < 0) | |
1305 | { | |
8f122660 | 1306 | o->newline() << "ptr_value = " << value << ";"; |
5b1fa53b JS |
1307 | o->newline() << "if (width == -1)"; |
1308 | o->newline(1) << "width = 2 + 2 * sizeof(void*);"; | |
1309 | o->newline(-1) << "precision = width - 2;"; | |
1310 | if (!c->test_flag(print_format::fmt_flag_left)) | |
1311 | o->newline() << "precision = min_t(int, precision, 2 * sizeof(void*));"; | |
1312 | o->newline() << "num_bytes += number_size(ptr_value, " | |
1313 | << c->base << ", width, precision, " << c->flags << ");"; | |
1314 | break; | |
1315 | } | |
1316 | // else fall-through to conv_number | |
1317 | case print_format::conv_number: | |
1318 | o->newline() << "num_bytes += number_size(" << value << ", " | |
1319 | << c->base << ", width, precision, " << c->flags << ");"; | |
1320 | break; | |
1321 | ||
1322 | case print_format::conv_char: | |
5650ca76 JS |
1323 | o->newline() << "num_bytes += _stp_vsprint_char_size(" |
1324 | << value << ", width, " << c->flags << ");"; | |
5b1fa53b JS |
1325 | break; |
1326 | ||
1327 | case print_format::conv_string: | |
1328 | o->newline() << "num_bytes += _stp_vsprint_memory_size(" | |
1329 | << value << ", width, precision, 's', " | |
1330 | << c->flags << ");"; | |
1331 | break; | |
1332 | ||
1333 | case print_format::conv_memory: | |
1334 | case print_format::conv_memory_hex: | |
1335 | o->newline() << "num_bytes += _stp_vsprint_memory_size(" | |
1336 | << "(const char*)(intptr_t)" << value | |
1337 | << ", width, precision, '" | |
1338 | << ((c->type == print_format::conv_memory) ? "m" : "M") | |
1339 | << "', " << c->flags << ");"; | |
1340 | break; | |
1341 | ||
1342 | case print_format::conv_binary: | |
1343 | o->newline() << "num_bytes += _stp_vsprint_binary_size(" | |
1344 | << value << ", width, precision);"; | |
1345 | break; | |
1346 | ||
1347 | default: | |
1348 | assert(false); // XXX | |
1349 | break; | |
1350 | } | |
5b1fa53b JS |
1351 | } |
1352 | ||
1353 | o->newline() << "num_bytes = clamp(num_bytes, 0, STP_BUFFER_SIZE);"; | |
1354 | o->newline() << "str = (char*)_stp_reserve_bytes(num_bytes);"; | |
1355 | o->newline() << "end = str ? str + num_bytes - 1 : 0;"; | |
5b1fa53b JS |
1356 | } |
1357 | else // !print_to_stream | |
1358 | { | |
1359 | // String results are a known buffer and size; | |
1360 | o->newline() << "str = l->__retvalue;"; | |
1361 | o->newline() << "end = str + MAXSTRINGLEN - 1;"; | |
1362 | } | |
1363 | ||
1364 | o->newline() << "if (str && str <= end) {"; | |
1365 | o->indent(1); | |
1366 | ||
1367 | // Generate code to print the actual arguments. | |
1368 | size_t arg_ix = 0; | |
1369 | vector<print_format::format_component>::const_iterator c; | |
1370 | for (c = components.begin(); c != components.end(); ++c) | |
1371 | { | |
1372 | if (c->type == print_format::conv_literal) | |
1373 | { | |
1374 | literal_string ls(c->literal_string); | |
8f122660 | 1375 | o->newline() << "src = "; |
5b1fa53b JS |
1376 | visit_literal_string(&ls); |
1377 | o->line() << ";"; | |
1378 | o->newline() << "while (*src && str <= end)"; | |
1379 | o->newline(1) << "*str++ = *src++;"; | |
8f122660 | 1380 | o->indent(-1); |
5b1fa53b JS |
1381 | continue; |
1382 | } | |
1383 | ||
8f122660 | 1384 | o->newline() << "width = "; |
5b1fa53b JS |
1385 | if (c->widthtype == print_format::width_dynamic) |
1386 | o->line() << "clamp_t(int, l->arg" << arg_ix++ | |
1387 | << ", 0, end - str + 1);"; | |
1388 | else if (c->widthtype == print_format::width_static) | |
1389 | o->line() << "clamp_t(int, " << c->width | |
1390 | << ", 0, end - str + 1);"; | |
1391 | else | |
1392 | o->line() << "-1;"; | |
1393 | ||
8f122660 | 1394 | o->newline() << "precision = "; |
5b1fa53b JS |
1395 | if (c->prectype == print_format::prec_dynamic) |
1396 | o->line() << "clamp_t(int, l->arg" << arg_ix++ | |
1397 | << ", 0, end - str + 1);"; | |
1398 | else if (c->prectype == print_format::prec_static) | |
1399 | o->line() << "clamp_t(int, " << c->precision | |
1400 | << ", 0, end - str + 1);"; | |
1401 | else | |
1402 | o->line() << "-1;"; | |
1403 | ||
1404 | string value = "l->arg" + lex_cast(arg_ix++); | |
1405 | switch (c->type) | |
1406 | { | |
1407 | case print_format::conv_pointer: | |
1408 | // NB: stap < 1.3 had odd %p behavior... see _stp_vsnprintf | |
1409 | if (strverscmp(session->compatible.c_str(), "1.3") < 0) | |
1410 | { | |
8f122660 | 1411 | o->newline() << "ptr_value = " << value << ";"; |
5b1fa53b JS |
1412 | o->newline() << "if (width == -1)"; |
1413 | o->newline(1) << "width = 2 + 2 * sizeof(void*);"; | |
1414 | o->newline(-1) << "precision = width - 2;"; | |
1415 | if (!c->test_flag(print_format::fmt_flag_left)) | |
1416 | o->newline() << "precision = min_t(int, precision, 2 * sizeof(void*));"; | |
1417 | o->newline() << "str = number(str, end, ptr_value, " | |
1418 | << c->base << ", width, precision, " << c->flags << ");"; | |
1419 | break; | |
1420 | } | |
1421 | // else fall-through to conv_number | |
1422 | case print_format::conv_number: | |
1423 | o->newline() << "str = number(str, end, " << value << ", " | |
1424 | << c->base << ", width, precision, " << c->flags << ");"; | |
1425 | break; | |
1426 | ||
1427 | case print_format::conv_char: | |
5650ca76 JS |
1428 | o->newline() << "str = _stp_vsprint_char(str, end, " |
1429 | << value << ", width, " << c->flags << ");"; | |
5b1fa53b JS |
1430 | break; |
1431 | ||
1432 | case print_format::conv_string: | |
1433 | o->newline() << "str = _stp_vsprint_memory(str, end, " | |
1434 | << value << ", width, precision, 's', " | |
1435 | << c->flags << ");"; | |
1436 | break; | |
1437 | ||
1438 | case print_format::conv_memory: | |
1439 | case print_format::conv_memory_hex: | |
1440 | o->newline() << "str = _stp_vsprint_memory(str, end, " | |
1441 | << "(const char*)(intptr_t)" << value | |
1442 | << ", width, precision, '" | |
1443 | << ((c->type == print_format::conv_memory) ? "m" : "M") | |
1444 | << "', " << c->flags << ");"; | |
2ec6b38c DS |
1445 | o->newline() << "if (unlikely(str == NULL)) {"; |
1446 | o->indent(1); | |
1447 | if (print_to_stream) | |
1448 | o->newline() << "_stp_unreserve_bytes(num_bytes);"; | |
1449 | o->newline() << "return;"; | |
1450 | o->newline(-1) << "}"; | |
5b1fa53b JS |
1451 | break; |
1452 | ||
1453 | case print_format::conv_binary: | |
1454 | o->newline() << "str = _stp_vsprint_binary(str, end, " | |
1455 | << value << ", width, precision, " | |
1456 | << c->flags << ");"; | |
1457 | break; | |
1458 | ||
1459 | default: | |
1460 | assert(false); // XXX | |
1461 | break; | |
1462 | } | |
5b1fa53b JS |
1463 | } |
1464 | ||
1465 | if (!print_to_stream) | |
1466 | { | |
1467 | o->newline() << "if (str <= end)"; | |
1468 | o->newline(1) << "*str = '\\0';"; | |
1469 | o->newline(-1) << "else"; | |
1470 | o->newline(1) << "*end = '\\0';"; | |
1471 | o->indent(-1); | |
1472 | } | |
1473 | ||
1474 | o->newline(-1) << "}"; | |
1475 | ||
1476 | o->newline(-1) << "}"; | |
1477 | } | |
0da35eae | 1478 | o->newline() << "#endif // STP_LEGACY_PRINT"; |
5b1fa53b JS |
1479 | } |
1480 | ||
1481 | ||
16c1c808 FCE |
1482 | void |
1483 | c_unparser::emit_global_param (vardecl *v) | |
1484 | { | |
6b15a04a JS |
1485 | // Only true globals can be params, not private variables. |
1486 | if (!v->name.starts_with("__global_")) return; | |
1487 | ||
1488 | string global = c_globalname (v->name); | |
1489 | interned_string param = v->name.substr(sizeof("__global_") - 1); | |
16c1c808 | 1490 | |
bd268288 SM |
1491 | // For dyninst, use the emit_global_init_* functionality instead. |
1492 | assert (!session->runtime_usermode_p()); | |
71db462b | 1493 | |
16c1c808 FCE |
1494 | // NB: systemtap globals can collide with linux macros, |
1495 | // e.g. VM_FAULT_MAJOR. We want the parameter name anyway. This | |
1496 | // #undef is spit out at the end of the C file, so that removing the | |
1497 | // definition won't affect any other embedded-C or generated code. | |
1498 | // XXX: better not have a global variable named module_param_named etc.! | |
eba95df1 | 1499 | o->newline() << "#undef " << param; // avoid colliding with non-mangled name |
16c1c808 FCE |
1500 | |
1501 | // Emit module_params for this global, if its type is convenient. | |
1502 | if (v->arity == 0 && v->type == pe_long) | |
1503 | { | |
6b15a04a JS |
1504 | o->newline() << "module_param_named (" << param << ", " |
1505 | << "global(" << global << "), int64_t, 0);"; | |
16c1c808 FCE |
1506 | } |
1507 | else if (v->arity == 0 && v->type == pe_string) | |
1508 | { | |
1509 | // NB: no special copying is needed. | |
6b15a04a JS |
1510 | o->newline() << "module_param_string (" << param << ", " |
1511 | << "global(" << global << "), MAXSTRINGLEN, 0);"; | |
16c1c808 FCE |
1512 | } |
1513 | } | |
1514 | ||
1515 | ||
bd268288 SM |
1516 | void |
1517 | c_unparser::emit_global_init_setters () | |
1518 | { | |
1519 | // Hack for dyninst module params: setter function forms a little | |
1520 | // linear lookup table ditty to find a global variable by name. | |
1521 | o->newline() << "int stp_global_setter (const char *name, const char *value) {"; | |
1522 | o->newline(1); | |
1523 | for (unsigned i=0; i<session->globals.size(); i++) | |
1524 | { | |
1525 | vardecl* v = session->globals[i]; | |
1526 | if (v->arity > 0) continue; | |
1527 | if (v->type != pe_string && v->type != pe_long) continue; | |
1528 | ||
6b15a04a JS |
1529 | // Only true globals can be params, not private variables. |
1530 | if (!v->name.starts_with("__global_")) continue; | |
1531 | ||
1532 | string global = c_globalname (v->name); | |
1533 | interned_string param = v->name.substr(sizeof("__global_") - 1); | |
1534 | ||
bd268288 | 1535 | // Do not mangle v->name for the comparison! |
6b15a04a | 1536 | o->line() << "if (0 == strcmp(name,\"" << param << "\"))" << " {"; |
bd268288 SM |
1537 | |
1538 | o->indent(1); | |
1539 | if (v->type == pe_string) | |
1540 | { | |
6b15a04a | 1541 | c_assign("stp_global_init." + global, "value", pe_string, "BUG: global module param", v->tok); |
bd268288 SM |
1542 | o->newline() << "return 0;"; |
1543 | } | |
1544 | else | |
1545 | { | |
6b15a04a | 1546 | o->newline() << "return set_int64_t(value, &stp_global_init." << global << ");"; |
bd268288 SM |
1547 | } |
1548 | ||
1549 | o->newline(-1) << "} else "; | |
1550 | } | |
ac033e87 DS |
1551 | |
1552 | // Call the runtime function that handles session attributes, like | |
1553 | // log_level, etc. | |
1554 | o->line() << "return stp_session_attribute_setter(name, value);"; | |
bd268288 SM |
1555 | o->newline(-1) << "}"; |
1556 | o->newline(); | |
1557 | } | |
1558 | ||
1559 | ||
2b066ec1 | 1560 | void |
4383d78c | 1561 | c_unparser::emit_global (vardecl *v) |
2b066ec1 | 1562 | { |
0386bbcf | 1563 | string vn = c_globalname (v->name); |
213bee8f | 1564 | |
63438a79 JS |
1565 | string type; |
1566 | if (v->arity > 0) | |
1567 | type = (v->type == pe_stats) ? "PMAP" : "MAP"; | |
4a6d3dfa | 1568 | else |
63438a79 JS |
1569 | type = c_typename (v->type); |
1570 | ||
1571 | if (session->runtime_usermode_p()) | |
1572 | { | |
1573 | // In stapdyn mode, the stat/map/pmap pointers are stored as offptr_t in | |
1574 | // shared memory. However, we can keep a little type safety by emitting | |
1575 | // FOO_typed and using typeof(FOO_typed) in the global() macros. | |
1576 | bool offptr_p = (v->type == pe_stats) || (v->arity > 0); | |
1577 | string stored_type = offptr_p ? "offptr_t" : type; | |
1578 | ||
1579 | // NB: The casted_type is in the unused side of a __builtin_choose_expr | |
1580 | // for non-offptr types, so it doesn't matter what we put for them, as | |
1581 | // long as it passes syntax long enough for gcc to choose the other expr. | |
1582 | string casted_type = offptr_p ? type : "void*"; | |
1583 | ||
1584 | o->newline() << "union {"; | |
1585 | o->newline(1) << casted_type << " " << vn << "_typed;"; | |
1586 | o->newline() << stored_type << " " << vn << ";"; | |
1587 | o->newline(-1) << "};"; | |
1588 | } | |
1589 | else | |
1590 | o->newline() << type << " " << vn << ";"; | |
1591 | ||
0386bbcf | 1592 | o->newline() << "rwlock_t " << vn << "_lock;"; |
d9582a60 | 1593 | o->newline() << "#ifdef STP_TIMING"; |
0386bbcf | 1594 | o->newline() << "atomic_t " << vn << "_lock_skip_count;"; |
1751e667 | 1595 | o->newline() << "#endif\n"; |
4a6d3dfa FCE |
1596 | } |
1597 | ||
1598 | ||
1599 | void | |
1600 | c_unparser::emit_global_init (vardecl *v) | |
1601 | { | |
63438a79 JS |
1602 | // We can only statically initialize some scalars. |
1603 | if (v->arity == 0 && v->init) | |
9ba8c134 | 1604 | { |
63438a79 JS |
1605 | o->newline() << "." << c_globalname (v->name) << " = "; |
1606 | v->init->visit(this); | |
1607 | o->line() << ","; | |
b68e0c9e | 1608 | } |
bd268288 SM |
1609 | else if (v->arity == 0 && session->runtime_usermode_p()) |
1610 | { | |
1611 | // For dyninst: always try to put a default value into the initial | |
1612 | // static structure, so we don't have to guess if it was customized. | |
1613 | if (v->type == pe_long) | |
1614 | o->newline() << "." << c_globalname (v->name) << " = 0,"; | |
1615 | else if (v->type == pe_string) | |
1616 | o->newline() << "." << c_globalname (v->name) << " = { '\\0' },"; // XXX: "" | |
1617 | } | |
63438a79 | 1618 | // The lock and lock_skip_count are handled in emit_module_init. |
2b066ec1 FCE |
1619 | } |
1620 | ||
1621 | ||
bd268288 SM |
1622 | void |
1623 | c_unparser::emit_global_init_type (vardecl *v) | |
1624 | { | |
1625 | // We can only statically initialize some scalars. | |
1626 | if (v->arity == 0) // ... although we still allow !v->init here. | |
1627 | { | |
1628 | o->newline() << c_typename(v->type) << " " << c_globalname(v->name) << ";"; | |
1629 | } | |
1630 | } | |
1631 | ||
1632 | ||
2b066ec1 | 1633 | void |
4383d78c | 1634 | c_unparser::emit_functionsig (functiondecl* v) |
2b066ec1 | 1635 | { |
acb811fc | 1636 | o->newline() << "static void " << c_funcname(v->name) |
9a604fac | 1637 | << " (struct context * __restrict__ c);"; |
2b066ec1 FCE |
1638 | } |
1639 | ||
1640 | ||
be66b6e1 DS |
1641 | void |
1642 | c_unparser::emit_kernel_module_init () | |
1643 | { | |
1644 | if (session->runtime_usermode_p()) | |
1645 | return; | |
1646 | ||
1647 | o->newline(); | |
1648 | o->newline() << "static int systemtap_kernel_module_init (void) {"; | |
1649 | o->newline(1) << "int rc = 0;"; | |
1650 | o->newline() << "int i=0, j=0;"; // for derived_probe_group use | |
1651 | ||
1652 | vector<derived_probe_group*> g = all_session_groups (*session); | |
1653 | for (unsigned i=0; i<g.size(); i++) | |
1654 | { | |
1655 | g[i]->emit_kernel_module_init (*session); | |
1656 | ||
1657 | o->newline() << "if (rc) {"; | |
1658 | o->indent(1); | |
1659 | if (i>0) | |
1660 | { | |
1661 | for (int j=i-1; j>=0; j--) | |
1662 | g[j]->emit_kernel_module_exit (*session); | |
1663 | } | |
1664 | o->newline() << "goto out;"; | |
1665 | o->newline(-1) << "}"; | |
1666 | } | |
1667 | o->newline(-1) << "out:"; | |
1668 | o->indent(1); | |
1669 | o->newline() << "return rc;"; | |
1670 | o->newline(-1) << "}\n"; | |
1671 | o->assert_0_indent(); | |
1672 | } | |
1673 | ||
1674 | ||
1675 | void | |
1676 | c_unparser::emit_kernel_module_exit () | |
1677 | { | |
1678 | if (session->runtime_usermode_p()) | |
1679 | return; | |
1680 | ||
1681 | o->newline(); | |
1682 | o->newline() << "static void systemtap_kernel_module_exit (void) {"; | |
1683 | o->newline(1) << "int i=0, j=0;"; // for derived_probe_group use | |
1684 | ||
1685 | // We're processing the derived_probe_group list in reverse order. | |
1686 | // This ensures that probe groups get unregistered in reverse order | |
1687 | // of the way they were registered. | |
1688 | vector<derived_probe_group*> g = all_session_groups (*session); | |
1689 | for (vector<derived_probe_group*>::reverse_iterator i = g.rbegin(); | |
1690 | i != g.rend(); i++) | |
1691 | { | |
1692 | (*i)->emit_kernel_module_exit (*session); | |
1693 | } | |
1694 | o->newline(-1) << "}\n"; | |
1695 | o->assert_0_indent(); | |
1696 | } | |
1697 | ||
1698 | ||
2b066ec1 | 1699 | void |
4383d78c | 1700 | c_unparser::emit_module_init () |
2b066ec1 | 1701 | { |
b20febf3 FCE |
1702 | vector<derived_probe_group*> g = all_session_groups (*session); |
1703 | for (unsigned i=0; i<g.size(); i++) | |
dac77b80 FCE |
1704 | { |
1705 | g[i]->emit_module_decls (*session); | |
1706 | o->assert_0_indent(); | |
1707 | } | |
dff50e09 | 1708 | |
3ef9830a JS |
1709 | o->newline() << "#ifdef STAP_NEED_TRACEPOINTS"; |
1710 | o->newline() << "#include \"linux/stp_tracepoint.c\""; | |
1711 | o->newline() << "#endif"; | |
1712 | ||
db22e55f | 1713 | o->newline(); |
4c2732a1 | 1714 | o->newline() << "static int systemtap_module_init (void) {"; |
bfb3d2d2 | 1715 | o->newline(1) << "int rc = 0;"; |
4a0ae64c | 1716 | o->newline() << "int cpu;"; |
b20febf3 | 1717 | o->newline() << "int i=0, j=0;"; // for derived_probe_group use |
2508b230 | 1718 | o->newline() << "const char *probe_point = \"\";"; |
bfb3d2d2 | 1719 | |
4441e344 | 1720 | // NB: This block of initialization only makes sense in kernel |
ac3af990 | 1721 | if (! session->runtime_usermode_p()) |
71db462b DS |
1722 | { |
1723 | // XXX Plus, most of this code is completely static, so it probably should | |
1724 | // move into the runtime, where kernel/dyninst is more easily separated. | |
1725 | ||
1726 | // Compare actual and targeted kernel releases/machines. Sometimes | |
1727 | // one may install the incorrect debuginfo or -devel RPM, and try to | |
1728 | // run a probe compiled for a different version. Catch this early, | |
1729 | // just in case modversions didn't. | |
1730 | o->newline() << "{"; | |
2c867c94 | 1731 | o->newline() << "#ifndef STP_NO_VERREL_CHECK"; |
71db462b DS |
1732 | o->newline(1) << "const char* release = UTS_RELEASE;"; |
1733 | o->newline() << "#ifdef STAPCONF_GENERATED_COMPILE"; | |
1734 | o->newline() << "const char* version = UTS_VERSION;"; | |
1735 | o->newline() << "#endif"; | |
1736 | ||
1737 | // NB: This UTS_RELEASE compile-time macro directly checks only that | |
1738 | // the compile-time kbuild tree matches the compile-time debuginfo/etc. | |
1739 | // It does not check the run time kernel value. However, this is | |
1740 | // probably OK since the kbuild modversions system aims to prevent | |
1741 | // mismatches between kbuild and runtime versions at module-loading time. | |
1742 | ||
1743 | // o->newline() << "const char* machine = UTS_MACHINE;"; | |
1744 | // NB: We could compare UTS_MACHINE too, but on x86 it lies | |
1745 | // (UTS_MACHINE=i386, but uname -m is i686). Sheesh. | |
1746 | ||
1747 | o->newline() << "if (strcmp (release, " | |
1748 | << lex_cast_qstring (session->kernel_release) << ")) {"; | |
1749 | o->newline(1) << "_stp_error (\"module release mismatch (%s vs %s)\", " | |
1750 | << "release, " | |
1751 | << lex_cast_qstring (session->kernel_release) | |
1752 | << ");"; | |
1753 | o->newline() << "rc = -EINVAL;"; | |
1754 | o->newline(-1) << "}"; | |
f2013cc9 | 1755 | |
71db462b DS |
1756 | o->newline() << "#ifdef STAPCONF_GENERATED_COMPILE"; |
1757 | o->newline() << "if (strcmp (utsname()->version, version)) {"; | |
1758 | o->newline(1) << "_stp_error (\"module version mismatch (%s vs %s), release %s\", " | |
1759 | << "version, " | |
1760 | << "utsname()->version, " | |
1761 | << "release" | |
1762 | << ");"; | |
1763 | o->newline() << "rc = -EINVAL;"; | |
1764 | o->newline(-1) << "}"; | |
1765 | o->newline() << "#endif"; | |
2c867c94 | 1766 | o->newline() << "#endif"; |
71db462b DS |
1767 | |
1768 | // perform buildid-based checking if able | |
1769 | o->newline() << "if (_stp_module_check()) rc = -EINVAL;"; | |
1770 | ||
1771 | // Perform checking on the user's credentials vs those required to load/run this module. | |
1772 | o->newline() << "if (_stp_privilege_credentials == 0) {"; | |
1773 | o->newline(1) << "if (STP_PRIVILEGE_CONTAINS(STP_PRIVILEGE, STP_PR_STAPDEV) ||"; | |
1774 | o->newline() << " STP_PRIVILEGE_CONTAINS(STP_PRIVILEGE, STP_PR_STAPUSR)) {"; | |
1775 | o->newline(1) << "_stp_privilege_credentials = STP_PRIVILEGE;"; | |
1776 | o->newline() << "#ifdef DEBUG_PRIVILEGE"; | |
1777 | o->newline(1) << "_dbug(\"User's privilege credentials default to %s\\n\","; | |
1778 | o->newline() << " privilege_to_text(_stp_privilege_credentials));"; | |
1779 | o->newline(-1) << "#endif"; | |
1780 | o->newline(-1) << "}"; | |
1781 | o->newline() << "else {"; | |
1782 | o->newline(1) << "_stp_error (\"Unable to verify that you have the required privilege credentials to run this module (%s required). You must use staprun version 1.7 or higher.\","; | |
1783 | o->newline() << " privilege_to_text(STP_PRIVILEGE));"; | |
1784 | o->newline() << "rc = -EINVAL;"; | |
1785 | o->newline(-1) << "}"; | |
1786 | o->newline(-1) << "}"; | |
1787 | o->newline() << "else {"; | |
1788 | o->newline(1) << "#ifdef DEBUG_PRIVILEGE"; | |
1789 | o->newline(1) << "_dbug(\"User's privilege credentials provided as %s\\n\","; | |
1790 | o->newline() << " privilege_to_text(_stp_privilege_credentials));"; | |
1791 | o->newline(-1) << "#endif"; | |
1792 | o->newline() << "if (! STP_PRIVILEGE_CONTAINS(_stp_privilege_credentials, STP_PRIVILEGE)) {"; | |
1793 | o->newline(1) << "_stp_error (\"Your privilege credentials (%s) are insufficient to run this module (%s required).\","; | |
1794 | o->newline () << " privilege_to_text(_stp_privilege_credentials), privilege_to_text(STP_PRIVILEGE));"; | |
1795 | o->newline() << "rc = -EINVAL;"; | |
1796 | o->newline(-1) << "}"; | |
1797 | o->newline(-1) << "}"; | |
faf38cd9 | 1798 | |
71db462b | 1799 | o->newline(-1) << "}"; |
4441e344 | 1800 | |
71db462b DS |
1801 | o->newline() << "if (rc) goto out;"; |
1802 | } | |
90ce056f | 1803 | |
065d5567 JS |
1804 | // Now that kernel version and permissions are correct, |
1805 | // initialize the global session states before anything else. | |
1806 | o->newline() << "rc = stp_session_init();"; | |
1807 | o->newline() << "if (rc) {"; | |
1808 | o->newline(1) << "_stp_error (\"couldn't initialize the main session (rc %d)\", rc);"; | |
1809 | o->newline() << "goto out;"; | |
1810 | o->newline(-1) << "}"; | |
1811 | ||
29e2616a JS |
1812 | // initialize gettimeofday (if needed) |
1813 | o->newline() << "#ifdef STAP_NEED_GETTIMEOFDAY"; | |
1814 | o->newline() << "rc = _stp_init_time();"; // Kick off the Big Bang. | |
1815 | o->newline() << "if (rc) {"; | |
1816 | o->newline(1) << "_stp_error (\"couldn't initialize gettimeofday\");"; | |
1817 | o->newline() << "goto out;"; | |
1818 | o->newline(-1) << "}"; | |
1819 | o->newline() << "#endif"; | |
1820 | ||
3ef9830a JS |
1821 | // initialize tracepoints (if needed) |
1822 | o->newline() << "#ifdef STAP_NEED_TRACEPOINTS"; | |
1823 | o->newline() << "rc = stp_tracepoint_init();"; | |
1824 | o->newline() << "if (rc) {"; | |
1825 | o->newline(1) << "_stp_error (\"couldn't initialize tracepoints\");"; | |
1826 | o->newline() << "goto out;"; | |
1827 | o->newline(-1) << "}"; | |
1828 | o->newline() << "#endif"; | |
1829 | ||
89ba3085 | 1830 | // NB: we don't need per-_stp_module task_finders, since a single common one |
a057c85c | 1831 | // set up in runtime/sym.c's _stp_sym_init() will scan through all _stp_modules. XXX - check this! |
438cd7ed | 1832 | o->newline() << "(void) probe_point;"; |
b20febf3 FCE |
1833 | o->newline() << "(void) i;"; |
1834 | o->newline() << "(void) j;"; | |
065d5567 | 1835 | o->newline() << "atomic_set (session_state(), STAP_SESSION_STARTING);"; |
bfb3d2d2 FCE |
1836 | // This signals any other probes that may be invoked in the next little |
1837 | // while to abort right away. Currently running probes are allowed to | |
1838 | // terminate. These may set STAP_SESSION_ERROR! | |
bb2e3076 | 1839 | |
1d0e697d DS |
1840 | // Allocate context structures. |
1841 | o->newline() << "rc = _stp_runtime_contexts_alloc();"; | |
1842 | o->newline() << "if (rc != 0)"; | |
1843 | o->newline(1) << "goto out;"; | |
1844 | o->indent(-1); | |
dff50e09 | 1845 | |
bb2e3076 FCE |
1846 | for (unsigned i=0; i<session->globals.size(); i++) |
1847 | { | |
dff50e09 | 1848 | vardecl* v = session->globals[i]; |
313b2f74 GH |
1849 | if (v->index_types.size() > 0) |
1850 | o->newline() << getmap (v).init(); | |
bd268288 SM |
1851 | else if (session->runtime_usermode_p() && v->arity == 0 |
1852 | && (v->type == pe_long || v->type == pe_string)) | |
1853 | c_assign(getvar (v).value(), "stp_global_init." + c_globalname(v->name), v->type, "BUG: global initialization", v->tok); | |
bb2e3076 | 1854 | else |
313b2f74 | 1855 | o->newline() << getvar (v).init(); |
b20febf3 FCE |
1856 | // NB: in case of failure of allocation, "rc" will be set to non-zero. |
1857 | // Allocation can in general continue. | |
1858 | ||
1859 | o->newline() << "if (rc) {"; | |
ae87121a | 1860 | o->newline(1) << "_stp_error (\"global variable '" << v->name << "' allocation failed\");"; |
b20febf3 FCE |
1861 | o->newline() << "goto out;"; |
1862 | o->newline(-1) << "}"; | |
1863 | ||
63438a79 JS |
1864 | o->newline() << "global_lock_init(" << c_globalname (v->name) << ");"; |
1865 | o->newline() << "#ifdef STP_TIMING"; | |
1866 | o->newline() << "atomic_set(global_skipped(" << c_globalname (v->name) << "), 0);"; | |
1867 | o->newline() << "#endif"; | |
bb2e3076 FCE |
1868 | } |
1869 | ||
cbc32000 MH |
1870 | // Print a message to the kernel log about this module. This is |
1871 | // intended to help debug problems with systemtap modules. | |
1d0e697d DS |
1872 | if (! session->runtime_usermode_p()) |
1873 | o->newline() << "_stp_print_kernel_info(" | |
1874 | << "\"" << VERSION | |
1875 | << "/" << dwfl_version (NULL) << "\"" | |
1876 | << ", (num_online_cpus() * sizeof(struct context))" | |
1877 | << ", " << session->probes.size() | |
1878 | << ");"; | |
8ca891c4 DS |
1879 | // In dyninst mode, we need to know when all the globals have been |
1880 | // allocated and we're ready to run probe registration. | |
1881 | else | |
1882 | { | |
1883 | o->newline() << "rc = stp_session_init_finished();"; | |
1884 | o->newline() << "if (rc) goto out;"; | |
1885 | } | |
cbc32000 | 1886 | |
4bf3d59d JL |
1887 | if (!session->runtime_usermode_p()) |
1888 | { | |
1889 | // Initialize workqueue needed for on-the-fly arming/disarming | |
1890 | o->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)"; | |
1891 | o->newline() << "INIT_WORK(&module_refresher_work, module_refresher, NULL);"; | |
1892 | o->newline() << "#else"; | |
1893 | o->newline() << "INIT_WORK(&module_refresher_work, module_refresher);"; | |
1894 | o->newline() << "#endif"; | |
1895 | } | |
ba7276fa | 1896 | |
65aeaea0 FCE |
1897 | // Run all probe registrations. This actually runs begin probes. |
1898 | ||
1899 | for (unsigned i=0; i<g.size(); i++) | |
1900 | { | |
1901 | g[i]->emit_module_init (*session); | |
1902 | // NB: this gives O(N**2) amount of code, but luckily there | |
1903 | // are only seven or eight derived_probe_groups, so it's ok. | |
1904 | o->newline() << "if (rc) {"; | |
b0f614a0 DS |
1905 | // If a probe types's emit_module_init() wants to handle error |
1906 | // messages itself, it should set probe_point to NULL, | |
1907 | o->newline(1) << "if (probe_point)"; | |
65aeaea0 | 1908 | o->newline(1) << "_stp_error (\"probe %s registration error (rc %d)\", probe_point, rc);"; |
b0f614a0 | 1909 | o->indent(-1); |
65aeaea0 FCE |
1910 | // NB: we need to be in the error state so timers can shutdown cleanly, |
1911 | // and so end probes don't run. OTOH, error probes can run. | |
065d5567 | 1912 | o->newline() << "atomic_set (session_state(), STAP_SESSION_ERROR);"; |
65aeaea0 FCE |
1913 | if (i>0) |
1914 | for (int j=i-1; j>=0; j--) | |
1915 | g[j]->emit_module_exit (*session); | |
1916 | o->newline() << "goto out;"; | |
1917 | o->newline(-1) << "}"; | |
1918 | } | |
1919 | ||
b20febf3 | 1920 | // All registrations were successful. Consider the system started. |
065d5567 | 1921 | o->newline() << "if (atomic_read (session_state()) == STAP_SESSION_STARTING)"; |
dff50e09 | 1922 | // NB: only other valid state value is ERROR, in which case we don't |
065d5567 | 1923 | o->newline(1) << "atomic_set (session_state(), STAP_SESSION_RUNNING);"; |
0d10ad2d | 1924 | o->newline(-1); |
f346b8b3 DS |
1925 | |
1926 | // Run all post-session starting code. | |
1927 | for (unsigned i=0; i<g.size(); i++) | |
1928 | { | |
1929 | g[i]->emit_module_post_init (*session); | |
1930 | } | |
0d10ad2d JL |
1931 | |
1932 | if (!session->runtime_usermode_p()) | |
1933 | { | |
4619bb71 JL |
1934 | o->newline() << "#ifdef STP_ON_THE_FLY_TIMER_ENABLE"; |
1935 | ||
0d10ad2d JL |
1936 | // Initialize hrtimer needed for on-the-fly arming/disarming |
1937 | o->newline() << "hrtimer_init(&module_refresh_timer, CLOCK_MONOTONIC,"; | |
1938 | o->newline() << " HRTIMER_MODE_REL);"; | |
1939 | o->newline() << "module_refresh_timer.function = &module_refresh_timer_cb;"; | |
32fb33bd JL |
1940 | |
1941 | // We check here if it's worth it to start the timer at all. We only need | |
1942 | // the background timer if there is a probe which doesn't support directy | |
1943 | // scheduling work (otf_safe_context() == false), but yet does affect the | |
1944 | // condition of at least one probe which supports on-the-fly operations. | |
1945 | { | |
1946 | // for each derived probe... | |
1947 | bool start_timer = false; | |
1948 | for (unsigned i=0; i<session->probes.size() && !start_timer; i++) | |
1949 | { | |
1950 | // if it isn't safe in this probe type to directly schedule work, | |
1951 | // and this probe could affect other probes... | |
1952 | if (session->probes[i]->group | |
1953 | && !session->probes[i]->group->otf_safe_context(*session) | |
1954 | && !session->probes[i]->probes_with_affected_conditions.empty()) | |
1955 | { | |
1956 | // and if any of those possible probes support on-the-fly operations, | |
1957 | // then we'll need the timer | |
1958 | for (set<derived_probe*>::const_iterator | |
1959 | it = session->probes[i]->probes_with_affected_conditions.begin(); | |
1960 | it != session->probes[i]->probes_with_affected_conditions.end() | |
1961 | && !start_timer; ++it) | |
1962 | { | |
1963 | if ((*it)->group->otf_supported(*session)) | |
1964 | start_timer = true; | |
1965 | } | |
1966 | } | |
1967 | } | |
1968 | ||
1969 | if (start_timer) | |
1970 | { | |
1971 | o->newline() << "hrtimer_start(&module_refresh_timer,"; | |
1972 | o->newline() << " ktime_set(0, STP_ON_THE_FLY_INTERVAL),"; | |
1973 | o->newline() << " HRTIMER_MODE_REL);"; | |
1974 | } | |
1975 | } | |
4619bb71 JL |
1976 | |
1977 | o->newline() << "#endif /* STP_ON_THE_FLY_TIMER_ENABLE */"; | |
0d10ad2d JL |
1978 | } |
1979 | ||
1980 | o->newline() << "return 0;"; | |
b20febf3 FCE |
1981 | |
1982 | // Error handling path; by now all partially registered probe groups | |
1983 | // have been unregistered. | |
1984 | o->newline(-1) << "out:"; | |
1985 | o->indent(1); | |
fe3d01fa | 1986 | |
ff007aa3 FCE |
1987 | // If any registrations failed, we will need to deregister the globals, |
1988 | // as this is our only chance. | |
1989 | for (unsigned i=0; i<session->globals.size(); i++) | |
1990 | { | |
dff50e09 | 1991 | vardecl* v = session->globals[i]; |
ff007aa3 FCE |
1992 | if (v->index_types.size() > 0) |
1993 | o->newline() << getmap (v).fini(); | |
85278e66 DB |
1994 | else |
1995 | o->newline() << getvar (v).fini(); | |
ff007aa3 FCE |
1996 | } |
1997 | ||
bc9a523d | 1998 | // For any partially registered/unregistered kernel facilities. |
065d5567 | 1999 | o->newline() << "atomic_set (session_state(), STAP_SESSION_STOPPED);"; |
b9197b0f | 2000 | o->newline() << "stp_synchronize_sched();"; |
bc9a523d | 2001 | |
3ef9830a JS |
2002 | // In case tracepoints were started, they need to be cleaned up |
2003 | o->newline() << "#ifdef STAP_NEED_TRACEPOINTS"; | |
2004 | o->newline() << " stp_tracepoint_exit();"; | |
2005 | o->newline() << "#endif"; | |
2006 | ||
cc76db23 JS |
2007 | // In case gettimeofday was started, it needs to be stopped |
2008 | o->newline() << "#ifdef STAP_NEED_GETTIMEOFDAY"; | |
2009 | o->newline() << " _stp_kill_time();"; // An error is no cause to hurry... | |
2010 | o->newline() << "#endif"; | |
2011 | ||
2012 | // Free up the context memory after an error too | |
1d0e697d | 2013 | o->newline() << "_stp_runtime_contexts_free();"; |
cc76db23 | 2014 | |
b20febf3 | 2015 | o->newline() << "return rc;"; |
db22e55f | 2016 | o->newline(-1) << "}\n"; |
2b066ec1 FCE |
2017 | } |
2018 | ||
2019 | ||
a60923e9 FCE |
2020 | void |
2021 | c_unparser::emit_module_refresh () | |
2022 | { | |
19d62b5b | 2023 | o->newline() << "static void systemtap_module_refresh (const char *modname) {"; |
9c91d9d5 JL |
2024 | o->newline(1) << "int state;"; |
2025 | o->newline() << "int i=0, j=0;"; // for derived_probe_group use | |
2026 | ||
35878a75 JL |
2027 | if (!session->runtime_usermode_p()) |
2028 | { | |
4bf3d59d | 2029 | o->newline() << "#if defined(STP_TIMING)"; |
35878a75 JL |
2030 | o->newline() << "cycles_t cycles_atstart = get_cycles();"; |
2031 | o->newline() << "#endif"; | |
2032 | } | |
2033 | ||
9c91d9d5 JL |
2034 | // Ensure we're only doing the refreshing one at a time. NB: it's important |
2035 | // that we get the lock prior to checking the session_state, in case whoever | |
2036 | // is holding the lock (e.g. systemtap_module_exit()) changes it. | |
4bf3d59d JL |
2037 | if (!session->runtime_usermode_p()) |
2038 | o->newline() << "mutex_lock(&module_refresh_mutex);"; | |
ae91e3d5 FCE |
2039 | |
2040 | /* If we're not in STARTING/RUNNING state, don't try doing any work. | |
2041 | PR16766 */ | |
9c91d9d5 | 2042 | o->newline() << "state = atomic_read (session_state());"; |
7caa63eb | 2043 | o->newline() << "if (state != STAP_SESSION_RUNNING && state != STAP_SESSION_STARTING && state != STAP_SESSION_ERROR) {"; |
ae91e3d5 | 2044 | // cannot _stp_warn etc. since we're not in probe context |
53d72bca | 2045 | o->newline(1) << "#if defined(__KERNEL__)"; |
e6f437ad DS |
2046 | o->newline() << "if (state != STAP_SESSION_STOPPING)"; |
2047 | o->newline(1) << "printk (KERN_ERR \"stap module notifier triggered in unexpected state %d\\n\", state);"; | |
2048 | o->indent(-1); | |
53d72bca | 2049 | o->newline() << "#endif"; |
9c91d9d5 | 2050 | |
4bf3d59d JL |
2051 | if (!session->runtime_usermode_p()) |
2052 | o->newline() << "mutex_unlock(&module_refresh_mutex);"; | |
9c91d9d5 | 2053 | |
ae91e3d5 FCE |
2054 | o->newline() << "return;"; |
2055 | o->newline(-1) << "}"; | |
2056 | ||
a60923e9 FCE |
2057 | o->newline() << "(void) i;"; |
2058 | o->newline() << "(void) j;"; | |
ae91e3d5 | 2059 | |
a60923e9 FCE |
2060 | vector<derived_probe_group*> g = all_session_groups (*session); |
2061 | for (unsigned i=0; i<g.size(); i++) | |
2062 | { | |
2063 | g[i]->emit_module_refresh (*session); | |
2064 | } | |
9c91d9d5 | 2065 | |
35878a75 JL |
2066 | if (!session->runtime_usermode_p()) |
2067 | { | |
2068 | // see also common_probe_entryfn_epilogue() | |
4bf3d59d | 2069 | o->newline() << "#if defined(STP_TIMING)"; |
35878a75 JL |
2070 | o->newline() << "if (likely(g_refresh_timing)) {"; |
2071 | o->newline(1) << "cycles_t cycles_atend = get_cycles ();"; | |
2072 | o->newline() << "int32_t cycles_elapsed = ((int32_t)cycles_atend > (int32_t)cycles_atstart)"; | |
2073 | o->newline(1) << "? ((int32_t)cycles_atend - (int32_t)cycles_atstart)"; | |
2074 | o->newline() << ": (~(int32_t)0) - (int32_t)cycles_atstart + (int32_t)cycles_atend + 1;"; | |
2075 | o->indent(-1); | |
2076 | o->newline() << "_stp_stat_add(g_refresh_timing, cycles_elapsed);"; | |
2077 | o->newline(-1) << "}"; | |
2078 | o->newline() << "#endif"; | |
2079 | } | |
2080 | ||
4bf3d59d JL |
2081 | if (!session->runtime_usermode_p()) |
2082 | o->newline() << "mutex_unlock(&module_refresh_mutex);"; | |
9c91d9d5 | 2083 | |
a60923e9 FCE |
2084 | o->newline(-1) << "}\n"; |
2085 | } | |
2086 | ||
2087 | ||
2b066ec1 | 2088 | void |
4383d78c | 2089 | c_unparser::emit_module_exit () |
2b066ec1 | 2090 | { |
4c2732a1 | 2091 | o->newline() << "static void systemtap_module_exit (void) {"; |
bfb3d2d2 | 2092 | // rc? |
71db462b | 2093 | o->newline(1) << "int i=0, j=0;"; // for derived_probe_group use |
b20febf3 FCE |
2094 | o->newline() << "(void) i;"; |
2095 | o->newline() << "(void) j;"; | |
ff007aa3 FCE |
2096 | // If we aborted startup, then everything has been cleaned up already, and |
2097 | // module_exit shouldn't even have been called. But since it might be, let's | |
2098 | // beat a hasty retreat to avoid double uninitialization. | |
065d5567 | 2099 | o->newline() << "if (atomic_read (session_state()) == STAP_SESSION_STARTING)"; |
ff007aa3 FCE |
2100 | o->newline(1) << "return;"; |
2101 | o->indent(-1); | |
dff50e09 | 2102 | |
065d5567 | 2103 | o->newline() << "if (atomic_read (session_state()) == STAP_SESSION_RUNNING)"; |
dff50e09 | 2104 | // NB: only other valid state value is ERROR, in which case we don't |
065d5567 | 2105 | o->newline(1) << "atomic_set (session_state(), STAP_SESSION_STOPPING);"; |
bfb3d2d2 FCE |
2106 | o->indent(-1); |
2107 | // This signals any other probes that may be invoked in the next little | |
2108 | // while to abort right away. Currently running probes are allowed to | |
2109 | // terminate. These may set STAP_SESSION_ERROR! | |
2110 | ||
0d10ad2d | 2111 | if (!session->runtime_usermode_p()) |
4619bb71 JL |
2112 | { |
2113 | o->newline() << "#ifdef STP_ON_THE_FLY_TIMER_ENABLE"; | |
2114 | o->newline() << "hrtimer_cancel(&module_refresh_timer);"; | |
2115 | o->newline() << "#endif"; | |
2116 | } | |
0d10ad2d | 2117 | |
df6c01e7 FCE |
2118 | // cargo cult prologue ... hope to flush any pending workqueue items too |
2119 | o->newline() << "stp_synchronize_sched();"; | |
2120 | ||
9c91d9d5 | 2121 | // Get the lock before exiting to ensure there's no one in module_refresh |
df6c01e7 FCE |
2122 | // NB: this should't be able to happen, because both the module_refresh_timer |
2123 | // and the workqueue ought to have been shut down by now. | |
4bf3d59d JL |
2124 | if (!session->runtime_usermode_p()) |
2125 | o->newline() << "mutex_lock(&module_refresh_mutex);"; | |
ba7276fa | 2126 | |
ce5cddc5 FCE |
2127 | // We're processing the derived_probe_group list in reverse |
2128 | // order. This ensures that probes get unregistered in reverse | |
2129 | // order of the way they were registered. | |
2130 | vector<derived_probe_group*> g = all_session_groups (*session); | |
2131 | for (vector<derived_probe_group*>::reverse_iterator i = g.rbegin(); | |
2132 | i != g.rend(); i++) | |
2133 | (*i)->emit_module_exit (*session); // NB: runs "end" probes | |
2134 | ||
4bf3d59d JL |
2135 | if (!session->runtime_usermode_p()) |
2136 | o->newline() << "mutex_unlock(&module_refresh_mutex);"; | |
9c91d9d5 | 2137 | |
ce5cddc5 FCE |
2138 | // But some other probes may have launched too during unregistration. |
2139 | // Let's wait a while to make sure they're all done, done, done. | |
2140 | ||
224e23be | 2141 | // cargo cult prologue |
b9197b0f | 2142 | o->newline() << "stp_synchronize_sched();"; |
224e23be | 2143 | |
bfb3d2d2 FCE |
2144 | // NB: systemtap_module_exit is assumed to be called from ordinary |
2145 | // user context, say during module unload. Among other things, this | |
2146 | // means we can sleep a while. | |
1d0e697d | 2147 | o->newline() << "_stp_runtime_context_wait();"; |
a36378d7 | 2148 | |
224e23be | 2149 | // cargo cult epilogue |
065d5567 | 2150 | o->newline() << "atomic_set (session_state(), STAP_SESSION_STOPPED);"; |
b9197b0f | 2151 | o->newline() << "stp_synchronize_sched();"; |
8d59b39f | 2152 | |
bfb3d2d2 | 2153 | // XXX: might like to have an escape hatch, in case some probe is |
cc9ee605 | 2154 | // genuinely stuck somehow |
bfb3d2d2 | 2155 | |
313b2f74 GH |
2156 | for (unsigned i=0; i<session->globals.size(); i++) |
2157 | { | |
dff50e09 | 2158 | vardecl* v = session->globals[i]; |
313b2f74 GH |
2159 | if (v->index_types.size() > 0) |
2160 | o->newline() << getmap (v).fini(); | |
85278e66 DB |
2161 | else |
2162 | o->newline() << getvar (v).fini(); | |
313b2f74 | 2163 | } |
ded98b33 | 2164 | |
8ca891c4 DS |
2165 | // We're finished with the contexts if we're not in dyninst |
2166 | // mode. The dyninst mode needs the contexts, since print buffers | |
2167 | // are stored there. | |
2168 | if (!session->runtime_usermode_p()) | |
2169 | { | |
2170 | o->newline() << "_stp_runtime_contexts_free();"; | |
2171 | } | |
2172 | else | |
2173 | { | |
2174 | o->newline() << "struct context* __restrict__ c;"; | |
2175 | o->newline() << "c = _stp_runtime_entryfn_get_context();"; | |
2176 | } | |
ded98b33 | 2177 | |
3ef9830a JS |
2178 | // teardown tracepoints (if needed) |
2179 | o->newline() << "#ifdef STAP_NEED_TRACEPOINTS"; | |
2180 | o->newline() << " stp_tracepoint_exit();"; | |
2181 | o->newline() << "#endif"; | |
2182 | ||
b9527ce5 FCE |
2183 | // teardown gettimeofday (if needed) |
2184 | o->newline() << "#ifdef STAP_NEED_GETTIMEOFDAY"; | |
2185 | o->newline() << " _stp_kill_time();"; // Go to a beach. Drink a beer. | |
2186 | o->newline() << "#endif"; | |
2187 | ||
c114ce7f FCE |
2188 | // NB: PR13386 points out that _stp_printf may be called from contexts |
2189 | // without already active preempt disabling, which breaks various uses | |
2190 | // of smp_processor_id(). So we temporary block preemption around this | |
2191 | // whole printing block. XXX: get_cpu() / put_cpu() may work just as well. | |
2192 | o->newline() << "preempt_disable();"; | |
2193 | ||
653e6a9a JS |
2194 | // print per probe point timing/alibi statistics |
2195 | o->newline() << "#if defined(STP_TIMING) || defined(STP_ALIBI)"; | |
26e63673 JS |
2196 | o->newline() << "_stp_printf(\"----- probe hit report: \\n\");"; |
2197 | o->newline() << "for (i = 0; i < ARRAY_SIZE(stap_probes); ++i) {"; | |
7c3e97f4 | 2198 | o->newline(1) << "const struct stap_probe *const p = &stap_probes[i];"; |
653e6a9a | 2199 | o->newline() << "#ifdef STP_ALIBI"; |
7c3e97f4 | 2200 | o->newline() << "int alibi = atomic_read(probe_alibi(i));"; |
653e6a9a | 2201 | o->newline() << "if (alibi)"; |
ea260cbc FCE |
2202 | o->newline(1) << "_stp_printf (\"%s, (%s), hits: %d,%s, index: %d\\n\","; |
2203 | o->newline(2) << "p->pp, p->location, alibi, p->derivation, i);"; | |
653e6a9a JS |
2204 | o->newline(-3) << "#endif"; // STP_ALIBI |
2205 | o->newline() << "#ifdef STP_TIMING"; | |
7c3e97f4 JS |
2206 | o->newline() << "if (likely (probe_timing(i))) {"; // NB: check for null stat object |
2207 | o->newline(1) << "struct stat_data *stats = _stp_stat_get (probe_timing(i), 0);"; | |
26e63673 JS |
2208 | o->newline() << "if (stats->count) {"; |
2209 | o->newline(1) << "int64_t avg = _stp_div64 (NULL, stats->sum, stats->count);"; | |
f887a8c9 DS |
2210 | o->newline() << "_stp_printf (\"%s, (%s), hits: %lld, " |
2211 | << (!session->runtime_usermode_p() ? "cycles" : "nsecs") | |
ea260cbc | 2212 | << ": %lldmin/%lldavg/%lldmax,%s, index: %d\\n\","; |
26e63673 JS |
2213 | o->newline(2) << "p->pp, p->location, (long long) stats->count,"; |
2214 | o->newline() << "(long long) stats->min, (long long) avg, (long long) stats->max,"; | |
ea260cbc | 2215 | o->newline() << "p->derivation, i);"; |
26e63673 | 2216 | o->newline(-3) << "}"; |
7c3e97f4 | 2217 | o->newline() << "_stp_stat_del (probe_timing(i));"; |
26e63673 | 2218 | o->newline(-1) << "}"; |
653e6a9a | 2219 | o->newline() << "#endif"; // STP_TIMING |
26e63673 | 2220 | o->newline(-1) << "}"; |
35878a75 JL |
2221 | |
2222 | if (!session->runtime_usermode_p()) | |
2223 | { | |
4bf3d59d | 2224 | o->newline() << "#if defined(STP_TIMING)"; |
35878a75 JL |
2225 | o->newline() << "_stp_printf(\"----- refresh report:\\n\");"; |
2226 | o->newline() << "if (likely (g_refresh_timing)) {"; | |
2227 | o->newline(1) << "struct stat_data *stats = _stp_stat_get (g_refresh_timing, 0);"; | |
2228 | o->newline() << "if (stats->count) {"; | |
2229 | o->newline(1) << "int64_t avg = _stp_div64 (NULL, stats->sum, stats->count);"; | |
2230 | o->newline() << "_stp_printf (\"hits: %lld, cycles: %lldmin/%lldavg/%lldmax\\n\","; | |
2231 | o->newline(2) << "(long long) stats->count, (long long) stats->min, "; | |
2232 | o->newline() << "(long long) avg, (long long) stats->max);"; | |
2233 | o->newline(-3) << "}"; | |
2234 | o->newline() << "_stp_stat_del (g_refresh_timing);"; | |
2235 | o->newline(-1) << "}"; | |
4bf3d59d | 2236 | o->newline() << "#endif"; // STP_TIMING |
35878a75 JL |
2237 | } |
2238 | ||
26e63673 JS |
2239 | o->newline() << "_stp_print_flush();"; |
2240 | o->newline() << "#endif"; | |
dbb68664 | 2241 | |
9c736061 | 2242 | // print final error/skipped counts if non-zero |
065d5567 JS |
2243 | o->newline() << "if (atomic_read (skipped_count()) || " |
2244 | << "atomic_read (error_count()) || " | |
2245 | << "atomic_read (skipped_count_reentrant())) {"; // PR9967 | |
802e6327 | 2246 | o->newline(1) << "_stp_warn (\"Number of errors: %d, " |
9a604fac | 2247 | << "skipped probes: %d\\n\", " |
065d5567 JS |
2248 | << "(int) atomic_read (error_count()), " |
2249 | << "(int) atomic_read (skipped_count()));"; | |
d9582a60 FCE |
2250 | o->newline() << "#ifdef STP_TIMING"; |
2251 | o->newline() << "{"; | |
2252 | o->newline(1) << "int ctr;"; | |
2253 | for (unsigned i=0; i<session->globals.size(); i++) | |
2254 | { | |
0386bbcf SM |
2255 | string orig_vn = session->globals[i]->name; |
2256 | string vn = c_globalname (orig_vn); | |
63438a79 | 2257 | o->newline() << "ctr = atomic_read (global_skipped(" << vn << "));"; |
b3c3ca7c | 2258 | o->newline() << "if (ctr) _stp_warn (\"Skipped due to global '%s' lock timeout: %d\\n\", " |
0386bbcf | 2259 | << lex_cast_qstring(orig_vn) << ", ctr);"; |
d9582a60 | 2260 | } |
065d5567 | 2261 | o->newline() << "ctr = atomic_read (skipped_count_lowstack());"; |
b3c3ca7c | 2262 | o->newline() << "if (ctr) _stp_warn (\"Skipped due to low stack: %d\\n\", ctr);"; |
065d5567 | 2263 | o->newline() << "ctr = atomic_read (skipped_count_reentrant());"; |
b3c3ca7c | 2264 | o->newline() << "if (ctr) _stp_warn (\"Skipped due to reentrancy: %d\\n\", ctr);"; |
065d5567 | 2265 | o->newline() << "ctr = atomic_read (skipped_count_uprobe_reg());"; |
73209876 | 2266 | o->newline() << "if (ctr) _stp_warn (\"Skipped due to uprobe register failure: %d\\n\", ctr);"; |
065d5567 | 2267 | o->newline() << "ctr = atomic_read (skipped_count_uprobe_unreg());"; |
73209876 | 2268 | o->newline() << "if (ctr) _stp_warn (\"Skipped due to uprobe unregister failure: %d\\n\", ctr);"; |
d9582a60 FCE |
2269 | o->newline(-1) << "}"; |
2270 | o->newline () << "#endif"; | |
e65b03c1 MH |
2271 | o->newline() << "_stp_print_flush();"; |
2272 | o->newline(-1) << "}"; | |
c114ce7f FCE |
2273 | |
2274 | // NB: PR13386 needs to restore preemption-blocking counts | |
2275 | o->newline() << "preempt_enable_no_resched();"; | |
2276 | ||
fee09ad5 | 2277 | // In dyninst mode, now we're done with the contexts, transport, everything! |
8ca891c4 DS |
2278 | if (session->runtime_usermode_p()) |
2279 | { | |
e481ab2e | 2280 | o->newline() << "_stp_runtime_entryfn_put_context(c);"; |
fee09ad5 | 2281 | o->newline() << "_stp_dyninst_transport_shutdown();"; |
8ca891c4 DS |
2282 | o->newline() << "_stp_runtime_contexts_free();"; |
2283 | } | |
2284 | ||
db22e55f | 2285 | o->newline(-1) << "}\n"; |
2b066ec1 FCE |
2286 | } |
2287 | ||
1bf6fd2c AJ |
2288 | struct max_action_info: public functioncall_traversing_visitor |
2289 | { | |
2290 | max_action_info(systemtap_session& s): sess(s), statement_count(0) {} | |
2291 | ||
2292 | systemtap_session& sess; | |
2293 | unsigned statement_count; | |
2294 | static const unsigned max_statement_count = ~0; | |
2295 | ||
2296 | void add_stmt_count (unsigned val) | |
2297 | { | |
2298 | statement_count = (statement_count > max_statement_count - val) ? max_statement_count : statement_count + val; | |
2299 | } | |
2300 | void add_max_stmt_count () { statement_count = max_statement_count; } | |
765e6976 | 2301 | bool statement_count_finite() { return statement_count < max_statement_count; } |
1bf6fd2c | 2302 | |
dabd71bb MW |
2303 | void visit_for_loop (for_loop*) { add_max_stmt_count(); } |
2304 | void visit_foreach_loop (foreach_loop*) { add_max_stmt_count(); } | |
1bf6fd2c AJ |
2305 | void visit_expr_statement (expr_statement *stmt) |
2306 | { | |
2307 | add_stmt_count(1); | |
2308 | traversing_visitor::visit_expr_statement(stmt); // which will trigger visit_functioncall, if applicable | |
2309 | } | |
2310 | void visit_if_statement (if_statement *stmt) | |
2311 | { | |
2312 | add_stmt_count(1); | |
2313 | stmt->condition->visit(this); | |
2314 | ||
13133f2c | 2315 | // Create new visitors for the two forks. Copy the nested[] set |
1bf6fd2c AJ |
2316 | // to prevent infinite recursion for a function f () { if (a) f() } |
2317 | max_action_info tmp_visitor_then (*this); | |
2318 | max_action_info tmp_visitor_else (*this); | |
2319 | stmt->thenblock->visit(& tmp_visitor_then); | |
2320 | if (stmt->elseblock) | |
2321 | { | |
2322 | stmt->elseblock->visit(& tmp_visitor_else); | |
2323 | } | |
2324 | ||
2325 | // Simply overwrite our copy of statement_count, since these | |
2326 | // visitor copies already included our starting count. | |
2327 | statement_count = max(tmp_visitor_then.statement_count, tmp_visitor_else.statement_count); | |
2328 | } | |
2329 | ||
dabd71bb | 2330 | void note_recursive_functioncall (functioncall *) { add_max_stmt_count(); } |
1bf6fd2c | 2331 | |
dabd71bb MW |
2332 | void visit_null_statement (null_statement *) { add_stmt_count(1); } |
2333 | void visit_return_statement (return_statement *) { add_stmt_count(1); } | |
2334 | void visit_delete_statement (delete_statement *) { add_stmt_count(1); } | |
2335 | void visit_next_statement (next_statement *) { add_stmt_count(1); } | |
2336 | void visit_break_statement (break_statement *) { add_stmt_count(1); } | |
2337 | void visit_continue_statement (continue_statement *) { add_stmt_count(1); } | |
1bf6fd2c | 2338 | }; |
2b066ec1 FCE |
2339 | |
2340 | void | |
d6d4dc4b | 2341 | c_tmpcounter::emit_function (functiondecl* fd) |
2b066ec1 | 2342 | { |
d6d4dc4b JS |
2343 | this->current_probe = 0; |
2344 | this->current_function = fd; | |
2345 | this->tmpvar_counter = 0; | |
2346 | this->action_counter = 0; | |
2347 | this->already_checked_action_count = false; | |
2348 | declared_vars.clear(); | |
2349 | ||
2350 | translator_output *o = parent->o; | |
2351 | ||
2352 | // indent the dummy output as if we were already in a block | |
2353 | this->o->indent (1); | |
2354 | ||
2355 | o->newline() << "struct " << c_funcname (fd->name) << "_locals {"; | |
2b066ec1 | 2356 | o->indent(1); |
d6d4dc4b JS |
2357 | |
2358 | for (unsigned j=0; j<fd->locals.size(); j++) | |
2359 | { | |
2360 | vardecl* v = fd->locals[j]; | |
2361 | try | |
2362 | { | |
2363 | if (fd->mangle_oldstyle) | |
2364 | { | |
2365 | // PR14524: retain old way of referring to the locals | |
2366 | o->newline() << "union { " | |
2367 | << c_typename (v->type) << " " | |
2368 | << c_localname (v->name) << "; " | |
2369 | << c_typename (v->type) << " " | |
2370 | << c_localname (v->name, true) << "; };"; | |
2371 | } | |
2372 | else | |
2373 | { | |
2374 | o->newline() << c_typename (v->type) << " " | |
2375 | << c_localname (v->name) << ";"; | |
2376 | } | |
2377 | } catch (const semantic_error& e) { | |
2378 | semantic_error e2 (e); | |
2379 | if (e2.tok1 == 0) e2.tok1 = v->tok; | |
2380 | throw e2; | |
2381 | } | |
2382 | } | |
2383 | ||
2384 | for (unsigned j=0; j<fd->formal_args.size(); j++) | |
2385 | { | |
2386 | vardecl* v = fd->formal_args[j]; | |
2387 | try | |
2388 | { | |
2389 | v->char_ptr_arg = (is_unmodified_string_fnarg (session, fd, v)); | |
2390 | ||
2391 | if (v->char_ptr_arg && session->verbose > 2) | |
2392 | clog << _F("variable %s for function %s will be passed by reference (char *)", | |
5eb6ecb1 DS |
2393 | v->name.to_string().c_str(), |
2394 | fd->unmangled_name.to_string().c_str()) << endl; | |
d6d4dc4b JS |
2395 | |
2396 | if (fd->mangle_oldstyle) | |
2397 | { | |
2398 | // PR14524: retain old way of referring to the locals | |
2399 | o->newline() << "union { " | |
2400 | << (v->char_ptr_arg ? "const char *" : c_typename (v->type)) | |
2401 | << " " << c_localname (v->name) << "; " | |
2402 | << (v->char_ptr_arg ? "const char *" : c_typename (v->type)) | |
2403 | << " " << c_localname (v->name, true) << "; };"; | |
2404 | } | |
2405 | else | |
2406 | { | |
2407 | o->newline() << (v->char_ptr_arg ? "const char *" : c_typename (v->type)) | |
2408 | << " " << c_localname (v->name) << ";"; | |
2409 | } | |
2410 | } catch (const semantic_error& e) { | |
2411 | semantic_error e2 (e); | |
2412 | if (e2.tok1 == 0) e2.tok1 = v->tok; | |
2413 | throw e2; | |
2414 | } | |
2415 | } | |
2416 | ||
2417 | fd->body->visit (this); | |
2418 | ||
2419 | if (fd->type == pe_unknown) | |
2420 | o->newline() << "/* no return value */"; | |
2421 | else | |
2422 | { | |
2423 | bool as_charp = !session->unoptimized && fd->type == pe_string; | |
2424 | if (as_charp && session->verbose > 2) | |
2425 | clog << _F("return value for function %s will be passed by reference (char *)", | |
5eb6ecb1 | 2426 | fd->unmangled_name.to_string().c_str()) << endl; |
d6d4dc4b JS |
2427 | o->newline() << (as_charp ? "char *" : c_typename (fd->type)) |
2428 | << " __retvalue;"; | |
2429 | } | |
2430 | o->newline(-1) << "} " << c_funcname (fd->name) << ";"; | |
2431 | ||
2432 | // finish dummy indentation | |
2433 | this->o->indent (-1); | |
2434 | this->o->assert_0_indent (); | |
2435 | ||
2436 | declared_vars.clear(); | |
2437 | this->current_function = 0; | |
2438 | this->already_checked_action_count = false; | |
2439 | } | |
2440 | ||
2441 | void | |
2442 | c_unparser::emit_function (functiondecl* v) | |
2443 | { | |
2b066ec1 | 2444 | this->current_probe = 0; |
2b066ec1 | 2445 | this->current_function = v; |
ce10591c | 2446 | this->tmpvar_counter = 0; |
9d0808b4 | 2447 | this->action_counter = 0; |
ad534e14 | 2448 | this->already_checked_action_count = false; |
4383d78c | 2449 | |
d6d4dc4b JS |
2450 | o->newline() << "static void " << c_funcname (v->name) |
2451 | << " (struct context* __restrict__ c) {"; | |
2452 | o->indent(1); | |
2453 | ||
f4fe2e93 | 2454 | o->newline() << "__label__ out;"; |
4383d78c | 2455 | o->newline() |
0386bbcf | 2456 | << "struct " << c_funcname (v->name) << "_locals * " |
f4fe2e93 | 2457 | << " __restrict__ l = " |
0386bbcf | 2458 | << "& c->locals[c->nesting+1]." << c_funcname (v->name) // NB: nesting+1 |
3d3887df | 2459 | << ";"; |
f4fe2e93 | 2460 | o->newline() << "(void) l;"; // make sure "l" is marked used |
3a20432b | 2461 | o->newline() << "#define CONTEXT c"; |
54dfabe9 | 2462 | o->newline() << "#define THIS l"; |
0386bbcf SM |
2463 | for (unsigned i = 0; i < v->formal_args.size(); i++) { |
2464 | o->newline() << c_arg_define(v->formal_args[i]->name); // #define STAP_ARG_foo ... | |
2465 | } | |
2466 | for (unsigned i = 0; i < v->locals.size(); i++) { | |
2467 | o->newline() << c_arg_define(v->locals[i]->name); // #define STAP_ARG_foo ... | |
2468 | } | |
a9bbc498 SM |
2469 | // define STAP_RETVALUE only if the function is non-void |
2470 | if (v->type != pe_unknown) | |
2471 | o->newline() << "#define STAP_RETVALUE THIS->__retvalue"; | |
4383d78c | 2472 | |
dff50e09 | 2473 | // set this, in case embedded-c code sets last_error but doesn't otherwise identify itself |
6120441d FL |
2474 | if (v->tok) |
2475 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*v->tok) << ";"; | |
0301cfe7 | 2476 | |
60ba482c | 2477 | // check/increment nesting level |
a7ed0d3e FCE |
2478 | // NB: incoming c->nesting level will be -1 (if we're called directly from a probe), |
2479 | // or 0...N (if we're called from another function). Incoming parameters are already | |
2480 | // stored in c->locals[c->nesting+1]. See also ::emit_common_header() for more. | |
2481 | ||
101a2bb8 | 2482 | o->newline() << "if (unlikely (c->nesting+1 >= MAXNESTING)) {"; |
b5f561be LB |
2483 | o->newline(1) << "c->last_error = "; |
2484 | o->line() << STAP_T_02; | |
60ba482c FCE |
2485 | o->newline() << "return;"; |
2486 | o->newline(-1) << "} else {"; | |
2487 | o->newline(1) << "c->nesting ++;"; | |
2488 | o->newline(-1) << "}"; | |
2489 | ||
4383d78c | 2490 | // initialize locals |
3a20432b | 2491 | // XXX: optimization: use memset instead |
4383d78c FCE |
2492 | for (unsigned i=0; i<v->locals.size(); i++) |
2493 | { | |
2494 | if (v->locals[i]->index_types.size() > 0) // array? | |
dc09353a | 2495 | throw SEMANTIC_ERROR (_("array locals not supported, missing global declaration?"), |
9f36b77f | 2496 | v->locals[i]->tok); |
313b2f74 GH |
2497 | |
2498 | o->newline() << getvar (v->locals[i]).init(); | |
4383d78c FCE |
2499 | } |
2500 | ||
2501 | // initialize return value, if any | |
31966088 FCE |
2502 | if (v->type != pe_unknown) |
2503 | { | |
0386bbcf | 2504 | var retvalue = var(this, true, v->type, "__retvalue", false); // not mangled |
31966088 FCE |
2505 | o->newline() << retvalue.init(); |
2506 | } | |
4383d78c | 2507 | |
27cc9ab5 FCE |
2508 | switch (v->type) |
2509 | { | |
2510 | case pe_long: | |
2511 | o->newline() << "#define STAP_RETURN(v) do { STAP_RETVALUE = (int64_t) (v); " | |
2512 | "goto out; } while(0)"; | |
2513 | break; | |
2514 | ||
2515 | case pe_string: | |
2516 | o->newline() << | |
66b920f0 | 2517 | "#define STAP_RETURN(v) do { strlcpy(STAP_RETVALUE, (v), MAXSTRINGLEN); " |
27cc9ab5 FCE |
2518 | "goto out; } while(0)"; |
2519 | break; | |
2520 | ||
2521 | default: | |
2522 | o->newline() << "#define STAP_RETURN() do { goto out; } while(0)"; | |
2523 | break; | |
2524 | } | |
2525 | ||
68cdd41e | 2526 | o->newline() << "#define STAP_PRINTF(fmt, ...) do { _stp_printf(fmt, ##__VA_ARGS__); } while (0)"; |
bbbf5f8c | 2527 | o->newline() << "#define STAP_ERROR(...) do { snprintf(CONTEXT->error_buffer, MAXSTRINGLEN, __VA_ARGS__); CONTEXT->last_error = CONTEXT->error_buffer; goto out; } while (0)"; |
60ba482c | 2528 | o->newline() << "#define return goto out"; // redirect embedded-C return |
1bf6fd2c AJ |
2529 | |
2530 | max_action_info mai (*session); | |
2531 | v->body->visit (&mai); | |
2532 | ||
3021c2e8 | 2533 | if (mai.statement_count_finite() && !session->suppress_time_limits |
1497f0cc | 2534 | && !session->unoptimized) // this is a finite-statement-count function |
1bf6fd2c AJ |
2535 | { |
2536 | o->newline() << "if (c->actionremaining < " << mai.statement_count | |
7650d3de | 2537 | << ") { c->last_error = " << STAP_T_04 << "goto out; }"; |
1bf6fd2c AJ |
2538 | this->already_checked_action_count = true; |
2539 | } | |
2540 | ||
2b066ec1 | 2541 | v->body->visit (this); |
60ba482c | 2542 | o->newline() << "#undef return"; |
68cdd41e | 2543 | o->newline() << "#undef STAP_PRINTF"; |
27cc9ab5 FCE |
2544 | o->newline() << "#undef STAP_ERROR"; |
2545 | o->newline() << "#undef STAP_RETURN"; | |
0d155048 | 2546 | |
2b066ec1 FCE |
2547 | this->current_function = 0; |
2548 | ||
54975cd8 | 2549 | record_actions(0, v->body->tok, true); |
9d0808b4 | 2550 | |
2b066ec1 | 2551 | o->newline(-1) << "out:"; |
f4fe2e93 | 2552 | o->newline(1) << "if (0) goto out;"; // make sure out: is marked used |
2b066ec1 | 2553 | |
60ba482c FCE |
2554 | // Function prologue: this is why we redirect the "return" above. |
2555 | // Decrement nesting level. | |
2556 | o->newline() << "c->nesting --;"; | |
ec03bd4b | 2557 | |
3a20432b | 2558 | o->newline() << "#undef CONTEXT"; |
54dfabe9 | 2559 | o->newline() << "#undef THIS"; |
0386bbcf SM |
2560 | for (unsigned i = 0; i < v->formal_args.size(); i++) { |
2561 | o->newline() << c_arg_undef(v->formal_args[i]->name); // #undef STAP_ARG_foo | |
2562 | } | |
2563 | for (unsigned i = 0; i < v->locals.size(); i++) { | |
2564 | o->newline() << c_arg_undef(v->locals[i]->name); // #undef STAP_ARG_foo | |
2565 | } | |
2566 | o->newline() << "#undef STAP_RETVALUE"; | |
db22e55f | 2567 | o->newline(-1) << "}\n"; |
2b066ec1 | 2568 | |
d6d4dc4b JS |
2569 | this->current_function = 0; |
2570 | this->already_checked_action_count = false; | |
2571 | } | |
2572 | ||
2573 | void | |
2574 | c_tmpcounter::emit_probe (derived_probe* dp) | |
2575 | { | |
2576 | this->current_function = 0; | |
2577 | this->current_probe = dp; | |
2578 | this->tmpvar_counter = 0; | |
2579 | this->action_counter = 0; | |
2580 | this->already_checked_action_count = false; | |
2581 | declared_vars.clear(); | |
2582 | ||
2583 | if (get_probe_dupe (dp) == NULL) | |
2584 | { | |
2585 | translator_output *o = parent->o; | |
2586 | ||
2587 | // indent the dummy output as if we were already in a block | |
2588 | this->o->indent (1); | |
2589 | ||
2590 | o->newline() << "struct " << dp->name() << "_locals {"; | |
2591 | o->indent(1); | |
2592 | for (unsigned j=0; j<dp->locals.size(); j++) | |
2593 | { | |
2594 | vardecl* v = dp->locals[j]; | |
2595 | try | |
2596 | { | |
2597 | o->newline() << c_typename (v->type) << " " | |
2598 | << c_localname (v->name) << ";"; | |
2599 | } catch (const semantic_error& e) { | |
2600 | semantic_error e2 (e); | |
2601 | if (e2.tok1 == 0) e2.tok1 = v->tok; | |
2602 | throw e2; | |
2603 | } | |
2604 | } | |
2605 | ||
2606 | dp->body->visit (this); | |
2607 | ||
2608 | // finish by visiting conditions of affected probes to match | |
2609 | // c_unparser::emit_probe() | |
2610 | if (!dp->probes_with_affected_conditions.empty()) | |
2611 | { | |
2612 | for (set<derived_probe*>::const_iterator | |
2613 | it = dp->probes_with_affected_conditions.begin(); | |
2614 | it != dp->probes_with_affected_conditions.end(); ++it) | |
2615 | (*it)->sole_location()->condition->visit(this); | |
2616 | } | |
2617 | ||
2618 | o->newline(-1) << "} " << dp->name() << ";"; | |
2619 | ||
2620 | // finish dummy indentation | |
2621 | this->o->indent (-1); | |
2622 | this->o->assert_0_indent (); | |
2623 | } | |
2624 | ||
2625 | declared_vars.clear(); | |
2626 | this->current_probe = 0; | |
1bf6fd2c AJ |
2627 | this->already_checked_action_count = false; |
2628 | } | |
2b066ec1 | 2629 | |
b20febf3 FCE |
2630 | #define DUPMETHOD_CALL 0 |
2631 | #define DUPMETHOD_ALIAS 0 | |
2632 | #define DUPMETHOD_RENAME 1 | |
2633 | ||
d6d4dc4b | 2634 | |
2b066ec1 | 2635 | void |
c1d5f3f6 | 2636 | c_unparser::emit_probe (derived_probe* v) |
2b066ec1 | 2637 | { |
3066c15c FCE |
2638 | this->current_function = 0; |
2639 | this->current_probe = v; | |
3066c15c | 2640 | this->tmpvar_counter = 0; |
9d0808b4 | 2641 | this->action_counter = 0; |
ad534e14 | 2642 | this->already_checked_action_count = false; |
3066c15c | 2643 | |
88bbd60d DS |
2644 | // If we about to emit a probe that is exactly the same as another |
2645 | // probe previously emitted, make the second probe just call the | |
2646 | // first one. | |
d6d4dc4b JS |
2647 | probe *dupe = get_probe_dupe (v); |
2648 | if (dupe != NULL) | |
2b066ec1 | 2649 | { |
b20febf3 FCE |
2650 | // NB: Elision of context variable structs is a separate |
2651 | // operation which has already taken place by now. | |
2652 | if (session->verbose > 1) | |
7371cd19 | 2653 | clog << _F("%s elided, duplicates %s\n", |
1341a03c | 2654 | v->name().c_str(), dupe->name().c_str()); |
b20febf3 FCE |
2655 | |
2656 | #if DUPMETHOD_CALL | |
2657 | // This one emits a direct call to the first copy. | |
2658 | o->newline(); | |
1341a03c | 2659 | o->newline() << "static void " << v->name() << " (struct context * __restrict__ c) "; |
d6d4dc4b | 2660 | o->newline() << "{ " << dupe->name() << " (c); }"; |
b20febf3 FCE |
2661 | #elif DUPMETHOD_ALIAS |
2662 | // This one defines a function alias, arranging gcc to emit | |
2663 | // several equivalent symbols for the same function body. | |
2664 | // For some reason, on gcc 4.1, this is twice as slow as | |
2665 | // the CALL option. | |
2666 | o->newline(); | |
1341a03c | 2667 | o->newline() << "static void " << v->name() << " (struct context * __restrict__ c) "; |
d6d4dc4b | 2668 | o->line() << "__attribute__ ((alias (\"" << dupe->name() << "\")));"; |
b20febf3 FCE |
2669 | #elif DUPMETHOD_RENAME |
2670 | // This one is sneaky. It emits nothing for duplicate probe | |
2671 | // handlers. It instead redirects subsequent references to the | |
2672 | // probe handler function to the first copy, *by name*. | |
1341a03c | 2673 | v->id = dupe->id; |
b20febf3 | 2674 | #else |
3866fc1d | 2675 | #error "Unknown duplicate elimination method" |
b20febf3 | 2676 | #endif |
2b066ec1 | 2677 | } |
b20febf3 | 2678 | else // This probe is unique. Remember it and output it. |
88bbd60d | 2679 | { |
b20febf3 | 2680 | o->newline(); |
1341a03c | 2681 | o->newline() << "static void " << v->name() << " (struct context * __restrict__ c) "; |
b20febf3 FCE |
2682 | o->line () << "{"; |
2683 | o->indent (1); | |
2684 | ||
f4fe2e93 FCE |
2685 | o->newline() << "__label__ out;"; |
2686 | ||
29bb0bbc | 2687 | // emit static read/write lock decls for global variables |
29bb0bbc JS |
2688 | if (v->needs_global_locks ()) |
2689 | { | |
3f3f4dd0 JS |
2690 | varuse_collecting_visitor vut(*session); |
2691 | v->body->visit (& vut); | |
be855773 JL |
2692 | |
2693 | // also visit any probe conditions which this current probe might | |
2694 | // evaluate so that read locks are emitted as necessary: e.g. suppose | |
2695 | // probe X if (a || b) {...} probe Y {a = ...} probe Z {b = ...} | |
2696 | // then Y and Z will already write-lock a and b respectively, but they | |
2697 | // also need a read-lock on b and a respectively, since they will read | |
2698 | // them when evaluating the new cond_enabled field (see c_unparser:: | |
2699 | // emit_probe_condition_update()). | |
2700 | for (set<derived_probe*>::const_iterator | |
2701 | it = v->probes_with_affected_conditions.begin(); | |
2702 | it != v->probes_with_affected_conditions.end(); ++it) | |
2703 | { | |
2704 | assert((*it)->sole_location()->condition != NULL); | |
2705 | (*it)->sole_location()->condition->visit (& vut); | |
2706 | } | |
2707 | ||
3f3f4dd0 JS |
2708 | emit_lock_decls (vut); |
2709 | } | |
29bb0bbc | 2710 | |
88bbd60d | 2711 | // initialize frame pointer |
1341a03c JS |
2712 | o->newline() << "struct " << v->name() << "_locals * __restrict__ l = " |
2713 | << "& c->probe_locals." << v->name() << ";"; | |
f4fe2e93 | 2714 | o->newline() << "(void) l;"; // make sure "l" is marked used |
dff50e09 | 2715 | |
2865d17a | 2716 | // Emit runtime safety net for unprivileged mode. |
4441e344 | 2717 | // NB: In usermode, the system restricts our privilege for us. |
ac3af990 | 2718 | if (!session->runtime_usermode_p()) |
4441e344 | 2719 | v->emit_privilege_assertion (o); |
2865d17a | 2720 | |
9020300d | 2721 | // emit probe local initialization block |
3689db05 SC |
2722 | |
2723 | v->emit_probe_local_init(*this->session, o); | |
9020300d | 2724 | |
88bbd60d | 2725 | // emit all read/write locks for global variables |
90f98cc3 | 2726 | if (v->needs_global_locks ()) |
3f3f4dd0 | 2727 | emit_locks (); |
88bbd60d DS |
2728 | |
2729 | // initialize locals | |
2730 | for (unsigned j=0; j<v->locals.size(); j++) | |
2731 | { | |
69aa668e | 2732 | if (v->locals[j]->synthetic) |
a45664f4 | 2733 | continue; |
88bbd60d | 2734 | if (v->locals[j]->index_types.size() > 0) // array? |
dc09353a | 2735 | throw SEMANTIC_ERROR (_("array locals not supported, missing global declaration?"), |
9f36b77f | 2736 | v->locals[j]->tok); |
88bbd60d | 2737 | else if (v->locals[j]->type == pe_long) |
0386bbcf | 2738 | o->newline() << "l->" << c_localname (v->locals[j]->name) |
88bbd60d DS |
2739 | << " = 0;"; |
2740 | else if (v->locals[j]->type == pe_string) | |
0386bbcf | 2741 | o->newline() << "l->" << c_localname (v->locals[j]->name) |
88bbd60d DS |
2742 | << "[0] = '\\0';"; |
2743 | else | |
dc09353a | 2744 | throw SEMANTIC_ERROR (_("unsupported local variable type"), |
88bbd60d DS |
2745 | v->locals[j]->tok); |
2746 | } | |
2c384610 DS |
2747 | |
2748 | v->initialize_probe_context_vars (o); | |
5d23847d | 2749 | |
ad534e14 AJ |
2750 | max_action_info mai (*session); |
2751 | v->body->visit (&mai); | |
2752 | if (session->verbose > 1) | |
7371cd19 | 2753 | clog << _F("%d statements for probe %s", mai.statement_count, |
1341a03c | 2754 | v->name().c_str()) << endl; |
ad534e14 | 2755 | |
3021c2e8 | 2756 | if (mai.statement_count_finite() && !session->suppress_time_limits |
1497f0cc | 2757 | && !session->unoptimized) // this is a finite-statement-count probe |
ad534e14 | 2758 | { |
2e19a3c1 | 2759 | o->newline() << "if (c->actionremaining < " << mai.statement_count |
7650d3de | 2760 | << ") { c->last_error = " << STAP_T_04 << " goto out; }"; |
ad534e14 AJ |
2761 | this->already_checked_action_count = true; |
2762 | } | |
2763 | ||
1bf6fd2c | 2764 | |
88bbd60d | 2765 | v->body->visit (this); |
2b066ec1 | 2766 | |
54975cd8 | 2767 | record_actions(0, v->body->tok, true); |
9d0808b4 | 2768 | |
88bbd60d | 2769 | o->newline(-1) << "out:"; |
5d23847d | 2770 | // NB: no need to uninitialize locals, except if arrays/stats can |
dff50e09 | 2771 | // someday be local |
4a6d3dfa | 2772 | |
c1969f1b | 2773 | o->indent(1); |
05a072cf JL |
2774 | |
2775 | if (!v->probes_with_affected_conditions.empty()) | |
2776 | { | |
05a072cf JL |
2777 | for (set<derived_probe*>::const_iterator |
2778 | it = v->probes_with_affected_conditions.begin(); | |
2779 | it != v->probes_with_affected_conditions.end(); ++it) | |
2780 | emit_probe_condition_update(*it); | |
05a072cf JL |
2781 | } |
2782 | ||
90f98cc3 | 2783 | if (v->needs_global_locks ()) |
3f3f4dd0 | 2784 | emit_unlocks (); |
b20febf3 | 2785 | |
c1969f1b DS |
2786 | // XXX: do this flush only if the body included a |
2787 | // print/printf/etc. routine! | |
2788 | o->newline() << "_stp_print_flush();"; | |
b20febf3 | 2789 | o->newline(-1) << "}\n"; |
88bbd60d | 2790 | } |
3066c15c | 2791 | |
3066c15c | 2792 | this->current_probe = 0; |
8f8d261a | 2793 | this->already_checked_action_count = false; |
2b066ec1 FCE |
2794 | } |
2795 | ||
05a072cf JL |
2796 | // Updates the cond_enabled field and sets need_module_refresh if it was |
2797 | // changed. | |
2798 | void | |
2799 | c_unparser::emit_probe_condition_update(derived_probe* v) | |
2800 | { | |
2801 | unsigned i = v->session_index; | |
2802 | assert(i < session->probes.size()); | |
2803 | ||
2804 | expression *cond = v->sole_location()->condition; | |
2805 | assert(cond); | |
2806 | ||
2807 | string cond_enabled = "stap_probes[" + lex_cast(i) + "].cond_enabled"; | |
2808 | ||
be855773 JL |
2809 | // Concurrency note: we're safe modifying cond_enabled here since we emit |
2810 | // locks not only for globals we write to, but also for globals read in other | |
2811 | // probes' whose conditions we visit below (see in c_unparser::emit_probe). So | |
2812 | // we can be assured we're the only ones modifying cond_enabled. | |
d02d9b1c | 2813 | |
05a072cf | 2814 | o->newline() << "if (" << cond_enabled << " != "; |
d02d9b1c | 2815 | o->line() << "!!"; // NB: turn general integer into boolean 1 or 0 |
05a072cf JL |
2816 | v->sole_location()->condition->visit(this); |
2817 | o->line() << ") {"; | |
d02d9b1c | 2818 | o->newline(1) << cond_enabled << " ^= 1;"; // toggle it |
ca6d3b0f | 2819 | |
4bf3d59d JL |
2820 | // don't bother refreshing if on-the-fly not supported |
2821 | if (!session->runtime_usermode_p() | |
ca6d3b0f | 2822 | && v->group && v->group->otf_supported(*session)) |
6092ee9e | 2823 | o->newline() << "atomic_set(&need_module_refresh, 1);"; |
ca6d3b0f | 2824 | |
05a072cf JL |
2825 | o->newline(-1) << "}"; |
2826 | } | |
2b066ec1 | 2827 | |
dff50e09 | 2828 | void |
29bb0bbc | 2829 | c_unparser::emit_lock_decls(const varuse_collecting_visitor& vut) |
3066c15c | 2830 | { |
29bb0bbc JS |
2831 | unsigned numvars = 0; |
2832 | ||
2833 | if (session->verbose > 1) | |
a8f84c45 JL |
2834 | clog << "probe " << current_probe->session_index << " " |
2835 | "('" << *current_probe->sole_location() << "') locks"; | |
29bb0bbc | 2836 | |
63438a79 JS |
2837 | // We can only make this static in kernel mode. In stapdyn mode, |
2838 | // the globals and their locks are in shared memory. | |
2839 | o->newline(); | |
2840 | if (!session->runtime_usermode_p()) | |
2841 | o->line() << "static "; | |
2842 | o->line() << "const struct stp_probe_lock locks[] = {"; | |
29bb0bbc | 2843 | o->indent(1); |
3066c15c | 2844 | |
3066c15c FCE |
2845 | for (unsigned i = 0; i < session->globals.size(); i++) |
2846 | { | |
2847 | vardecl* v = session->globals[i]; | |
3f3f4dd0 JS |
2848 | bool read_p = vut.read.count(v) > 0; |
2849 | bool write_p = vut.written.count(v) > 0; | |
3066c15c FCE |
2850 | if (!read_p && !write_p) continue; |
2851 | ||
3f3f4dd0 | 2852 | bool written_p; |
3066c15c FCE |
2853 | if (v->type == pe_stats) // read and write locks are flipped |
2854 | // Specifically, a "<<<" to a stats object is considered a | |
2855 | // "shared-lock" operation, since it's implicitly done | |
2856 | // per-cpu. But a "@op(x)" extraction is an "exclusive-lock" | |
2857 | // one, as is a (sorted or unsorted) foreach, so those cases | |
2858 | // are excluded by the w & !r condition below. | |
2859 | { | |
2860 | if (write_p && !read_p) { read_p = true; write_p = false; } | |
2861 | else if (read_p && !write_p) { read_p = false; write_p = true; } | |
3f3f4dd0 | 2862 | written_p = vcv_needs_global_locks.read.count(v) > 0; |
3066c15c | 2863 | } |
3f3f4dd0 JS |
2864 | else |
2865 | written_p = vcv_needs_global_locks.written.count(v) > 0; | |
3066c15c | 2866 | |
3be43eac DS |
2867 | // We don't need to read lock "read-mostly" global variables. A |
2868 | // "read-mostly" global variable is only written to within | |
2869 | // probes that don't need global variable locking (such as | |
2870 | // begin/end probes). If vcv_needs_global_locks doesn't mark | |
2871 | // the global as written to, then we don't have to lock it | |
2872 | // here to read it safely. | |
3f3f4dd0 JS |
2873 | if (!written_p && read_p && !write_p) |
2874 | continue; | |
3be43eac | 2875 | |
29bb0bbc | 2876 | o->newline() << "{"; |
63438a79 | 2877 | o->newline(1) << ".lock = global_lock(" + c_globalname(v->name) + "),"; |
29bb0bbc | 2878 | o->newline() << ".write_p = " << (write_p ? 1 : 0) << ","; |
d9582a60 | 2879 | o->newline() << "#ifdef STP_TIMING"; |
63438a79 | 2880 | o->newline() << ".skipped = global_skipped(" << c_globalname (v->name) << "),"; |
d9582a60 | 2881 | o->newline() << "#endif"; |
29bb0bbc | 2882 | o->newline(-1) << "},"; |
3066c15c | 2883 | |
29bb0bbc JS |
2884 | numvars ++; |
2885 | if (session->verbose > 1) | |
a8f84c45 JL |
2886 | clog << " " << v->name << "[" << (read_p ? "r" : "") |
2887 | << (write_p ? "w" : "") << "]"; | |
3066c15c FCE |
2888 | } |
2889 | ||
29bb0bbc | 2890 | o->newline(-1) << "};"; |
438cd7ed | 2891 | |
29bb0bbc JS |
2892 | if (session->verbose > 1) |
2893 | { | |
2894 | if (!numvars) | |
a8f84c45 | 2895 | clog << _(" nothing"); |
29bb0bbc JS |
2896 | clog << endl; |
2897 | } | |
3066c15c FCE |
2898 | } |
2899 | ||
2900 | ||
dff50e09 | 2901 | void |
3f3f4dd0 | 2902 | c_unparser::emit_locks() |
3066c15c | 2903 | { |
29bb0bbc JS |
2904 | o->newline() << "if (!stp_lock_probe(locks, ARRAY_SIZE(locks)))"; |
2905 | o->newline(1) << "return;"; | |
2906 | o->indent(-1); | |
2907 | } | |
dff50e09 | 2908 | |
3066c15c | 2909 | |
29bb0bbc | 2910 | void |
3f3f4dd0 | 2911 | c_unparser::emit_unlocks() |
29bb0bbc JS |
2912 | { |
2913 | o->newline() << "stp_unlock_probe(locks, ARRAY_SIZE(locks));"; | |
3066c15c FCE |
2914 | } |
2915 | ||
2916 | ||
dff50e09 | 2917 | void |
313b2f74 | 2918 | c_unparser::collect_map_index_types(vector<vardecl *> const & vars, |
d23a2349 | 2919 | set< pair<vector<exp_type>, exp_type> > & types) |
313b2f74 GH |
2920 | { |
2921 | for (unsigned i = 0; i < vars.size(); ++i) | |
2922 | { | |
2923 | vardecl *v = vars[i]; | |
2924 | if (v->arity > 0) | |
2925 | { | |
d23a2349 | 2926 | types.insert(make_pair(v->index_types, v->type)); |
313b2f74 GH |
2927 | } |
2928 | } | |
2929 | } | |
2930 | ||
2931 | string | |
2932 | mapvar::value_typename(exp_type e) | |
2933 | { | |
2934 | switch (e) | |
2935 | { | |
2936 | case pe_long: | |
2937 | return "INT64"; | |
313b2f74 GH |
2938 | case pe_string: |
2939 | return "STRING"; | |
313b2f74 GH |
2940 | case pe_stats: |
2941 | return "STAT"; | |
313b2f74 | 2942 | default: |
dc09353a | 2943 | throw SEMANTIC_ERROR(_("array type is neither string nor long")); |
03ad4de1 | 2944 | } |
313b2f74 GH |
2945 | } |
2946 | ||
2947 | string | |
2948 | mapvar::key_typename(exp_type e) | |
2949 | { | |
2950 | switch (e) | |
2951 | { | |
2952 | case pe_long: | |
2953 | return "INT64"; | |
313b2f74 GH |
2954 | case pe_string: |
2955 | return "STRING"; | |
313b2f74 | 2956 | default: |
dc09353a | 2957 | throw SEMANTIC_ERROR(_("array key is neither string nor long")); |
dff50e09 | 2958 | } |
313b2f74 GH |
2959 | } |
2960 | ||
2961 | string | |
2962 | mapvar::shortname(exp_type e) | |
2963 | { | |
2964 | switch (e) | |
2965 | { | |
2966 | case pe_long: | |
d23a2349 | 2967 | return "i"; |
313b2f74 | 2968 | case pe_string: |
d23a2349 | 2969 | return "s"; |
313b2f74 | 2970 | default: |
dc09353a | 2971 | throw SEMANTIC_ERROR(_("array type is neither string nor long")); |
dff50e09 | 2972 | } |
313b2f74 GH |
2973 | } |
2974 | ||
0af18f5a FL |
2975 | string |
2976 | c_unparser::map_keytypes(vardecl* v) | |
2977 | { | |
2978 | string result; | |
2979 | vector<exp_type> types = v->index_types; | |
2980 | types.push_back (v->type); | |
2981 | for (unsigned i = 0; i < types.size(); ++i) | |
2982 | { | |
2983 | switch (types[i]) | |
2984 | { | |
2985 | case pe_long: | |
2986 | result += 'i'; | |
2987 | break; | |
2988 | case pe_string: | |
2989 | result += 's'; | |
2990 | break; | |
2991 | case pe_stats: | |
2992 | result += 'x'; | |
2993 | break; | |
2994 | default: | |
2995 | throw SEMANTIC_ERROR(_("unknown type of map")); | |
2996 | break; | |
2997 | } | |
2998 | } | |
2999 | return result; | |
3000 | } | |
313b2f74 GH |
3001 | |
3002 | void | |
3003 | c_unparser::emit_map_type_instantiations () | |
3004 | { | |
d23a2349 | 3005 | set< pair<vector<exp_type>, exp_type> > types; |
dff50e09 | 3006 | |
d23a2349 | 3007 | collect_map_index_types(session->globals, types); |
313b2f74 GH |
3008 | |
3009 | for (unsigned i = 0; i < session->probes.size(); ++i) | |
d23a2349 | 3010 | collect_map_index_types(session->probes[i]->locals, types); |
313b2f74 | 3011 | |
f76427a2 FCE |
3012 | for (map<string,functiondecl*>::iterator it = session->functions.begin(); it != session->functions.end(); it++) |
3013 | collect_map_index_types(it->second->locals, types); | |
313b2f74 | 3014 | |
07c17d67 GH |
3015 | if (!types.empty()) |
3016 | o->newline() << "#include \"alloc.c\""; | |
3017 | ||
d23a2349 GH |
3018 | for (set< pair<vector<exp_type>, exp_type> >::const_iterator i = types.begin(); |
3019 | i != types.end(); ++i) | |
313b2f74 | 3020 | { |
d23a2349 GH |
3021 | o->newline() << "#define VALUE_TYPE " << mapvar::value_typename(i->second); |
3022 | for (unsigned j = 0; j < i->first.size(); ++j) | |
313b2f74 | 3023 | { |
d23a2349 | 3024 | string ktype = mapvar::key_typename(i->first.at(j)); |
313b2f74 GH |
3025 | o->newline() << "#define KEY" << (j+1) << "_TYPE " << ktype; |
3026 | } | |
3cb9c91e | 3027 | /* For statistics, flag map-gen to pull in nested pmap-gen too. */ |
07c17d67 | 3028 | if (i->second == pe_stats) |
3cb9c91e JS |
3029 | o->newline() << "#define MAP_DO_PMAP 1"; |
3030 | o->newline() << "#include \"map-gen.c\""; | |
3031 | o->newline() << "#undef MAP_DO_PMAP"; | |
d23a2349 GH |
3032 | o->newline() << "#undef VALUE_TYPE"; |
3033 | for (unsigned j = 0; j < i->first.size(); ++j) | |
313b2f74 GH |
3034 | { |
3035 | o->newline() << "#undef KEY" << (j+1) << "_TYPE"; | |
dff50e09 | 3036 | } |
313b2f74 GH |
3037 | } |
3038 | ||
d23a2349 | 3039 | if (!types.empty()) |
313b2f74 | 3040 | o->newline() << "#include \"map.c\""; |
07c17d67 | 3041 | |
313b2f74 GH |
3042 | }; |
3043 | ||
3044 | ||
2b066ec1 | 3045 | string |
4383d78c | 3046 | c_unparser::c_typename (exp_type e) |
2b066ec1 FCE |
3047 | { |
3048 | switch (e) | |
3049 | { | |
3a20432b | 3050 | case pe_long: return string("int64_t"); |
dff50e09 | 3051 | case pe_string: return string("string_t"); |
57b73400 | 3052 | case pe_stats: return string("Stat"); |
dff50e09 | 3053 | case pe_unknown: |
2b066ec1 | 3054 | default: |
dc09353a | 3055 | throw SEMANTIC_ERROR (_("cannot expand unknown type")); |
2b066ec1 FCE |
3056 | } |
3057 | } | |
3058 | ||
3059 | ||
05e1f292 SM |
3060 | // XXX: the below is just for the sake of example; it's possibly |
3061 | // better to expose the hash function in hash.cxx | |
3062 | ||
3063 | // unsigned int | |
3064 | // do_hash (const char *e) | |
3065 | // { | |
3066 | // unsigned int foo = 0; | |
3067 | // while (*e) { | |
3068 | // foo *= 101; foo += *e; e++; | |
3069 | // } | |
3070 | // return foo; | |
3071 | // } | |
0386bbcf SM |
3072 | |
3073 | ||
3074 | string | |
49b68a33 | 3075 | c_unparser::c_localname (const string& e, bool mangle_oldstyle) |
0386bbcf | 3076 | { |
49b68a33 | 3077 | if (strverscmp(session->compatible.c_str(), "1.8") < 0 || mangle_oldstyle) |
0386bbcf SM |
3078 | return e; // old mangling behaviour |
3079 | else | |
05e1f292 SM |
3080 | // XXX: we may wish to invent and/or test other mangling schemes, e.g.: |
3081 | // return "l_" + e + "_" + lex_cast(do_hash(e.c_str())); | |
0386bbcf SM |
3082 | return "l_" + e; |
3083 | } | |
3084 | ||
3085 | ||
3086 | string | |
3087 | c_unparser::c_globalname (const string& e) | |
3088 | { | |
acb811fc SM |
3089 | // XXX uncomment to test custom mangling: |
3090 | // return "s_" + e + "_" + lex_cast(do_hash(e.c_str())); | |
0386bbcf SM |
3091 | return "s_" + e; |
3092 | } | |
3093 | ||
3094 | ||
3095 | string | |
3096 | c_unparser::c_funcname (const string& e) | |
3097 | { | |
acb811fc SM |
3098 | // XXX uncomment to test custom mangling: |
3099 | // return "function_" + e + "_" + lex_cast(do_hash(e.c_str())); | |
0386bbcf SM |
3100 | return "function_" + e; |
3101 | } | |
3102 | ||
3103 | ||
3104 | string | |
3105 | c_unparser::c_arg_define (const string& e) | |
3106 | { | |
9e1830b9 | 3107 | return "#define STAP_ARG_" + e + " THIS->" + c_localname(e); |
0386bbcf SM |
3108 | } |
3109 | ||
3110 | ||
313b2f74 | 3111 | string |
0386bbcf | 3112 | c_unparser::c_arg_undef (const string& e) |
313b2f74 | 3113 | { |
0386bbcf | 3114 | return "#undef STAP_ARG_" + e; |
313b2f74 GH |
3115 | } |
3116 | ||
0af18f5a FL |
3117 | void |
3118 | c_unparser::c_global_write_def(vardecl* v) | |
3119 | { | |
3120 | if (v->arity > 0) | |
3121 | { | |
8e95959e | 3122 | o->newline() << "#define STAP_GLOBAL_SET_" << v->unmangled_name << "(...) " |
0af18f5a FL |
3123 | << "({int rc = _stp_map_set_" << map_keytypes(v) |
3124 | << "(global(" << c_globalname(v->name) << "), __VA_ARGS__); " | |
3125 | << "if (unlikely(rc)) { c->last_error = " << STAP_T_01 | |
3126 | << lex_cast(v->maxsize > 0 ? "size limit (" + lex_cast(v->maxsize) | |
3127 | + ")" : "MAXMAPENTRIES") + "\"; goto out; } rc;})"; | |
3128 | } | |
3129 | else | |
3130 | { | |
8e95959e | 3131 | o->newline() << "#define STAP_GLOBAL_SET_" << v->unmangled_name << "(val) "; |
0af18f5a FL |
3132 | if (v->type == pe_string) |
3133 | o->line() << "strlcpy(global(" << c_globalname(v->name) << "), val, MAXSTRINGLEN)"; | |
3134 | else if (v->type == pe_long) | |
3135 | o->line() << "global_set(" << c_globalname(v->name) << ", val)"; | |
3136 | } | |
3137 | } | |
3138 | ||
3139 | void | |
3140 | c_unparser::c_global_read_def(vardecl* v) | |
3141 | { | |
3142 | if (v->arity > 0) | |
3143 | { | |
8e95959e | 3144 | o->newline() << "#define STAP_GLOBAL_GET_" << v->unmangled_name << "(...) " |
0af18f5a FL |
3145 | << "_stp_map_get_" << map_keytypes(v) |
3146 | << "(global(" << c_globalname(v->name) << "), __VA_ARGS__)"; | |
3147 | } | |
3148 | else | |
3149 | { | |
8e95959e | 3150 | o->newline() << "#define STAP_GLOBAL_GET_" << v->unmangled_name << "() " |
0af18f5a FL |
3151 | << "global(" << c_globalname(v->name) << ")"; |
3152 | } | |
3153 | } | |
3154 | ||
3155 | void | |
3156 | c_unparser::c_global_write_undef(vardecl* v) | |
3157 | { | |
8e95959e | 3158 | o->newline() << "#undef STAP_GLOBAL_SET_" << v->unmangled_name; |
0af18f5a FL |
3159 | } |
3160 | ||
3161 | void | |
3162 | c_unparser::c_global_read_undef(vardecl* v) | |
3163 | { | |
8e95959e | 3164 | o->newline() << "#undef STAP_GLOBAL_GET_" << v->unmangled_name; |
0af18f5a | 3165 | } |
11b52b73 | 3166 | |
dff50e09 | 3167 | void |
67c0a579 | 3168 | c_unparser::c_assign (var& lvalue, const string& rvalue, const token *tok) |
dff50e09 | 3169 | { |
67c0a579 GH |
3170 | switch (lvalue.type()) |
3171 | { | |
3172 | case pe_string: | |
11b52b73 | 3173 | c_strcpy(lvalue.value(), rvalue); |
67c0a579 GH |
3174 | break; |
3175 | case pe_long: | |
3176 | o->newline() << lvalue << " = " << rvalue << ";"; | |
3177 | break; | |
3178 | default: | |
dc09353a | 3179 | throw SEMANTIC_ERROR (_("unknown lvalue type in assignment"), tok); |
67c0a579 GH |
3180 | } |
3181 | } | |
313b2f74 | 3182 | |
412c6fe4 | 3183 | |
b2d74f03 JS |
3184 | void |
3185 | c_unparser::c_assign(tmpvar& t, expression *e, const char* msg) | |
3186 | { | |
3187 | // We don't really need a tmpvar if the expression is a literal. | |
3188 | // (NB: determined by the expression itself, not tok->type!) | |
3189 | ||
3190 | if (dynamic_cast<literal*>(e)) | |
3191 | { | |
3192 | // We need to use the visitors to get proper C values, like | |
3193 | // "((int64_t)5LL)" for numbers and escaped characters in strings. | |
3194 | ||
3195 | // Create a fake output stream so we can grab the string output. | |
3196 | ostringstream oss; | |
3197 | translator_output tmp_o(oss); | |
3198 | ||
3199 | // Temporarily swap out the real translator_output stream with our | |
3200 | // fake one. | |
3201 | translator_output *saved_o = o; | |
3202 | o = &tmp_o; | |
3203 | ||
3204 | // Visit the expression then restore the original output stream | |
3205 | e->visit (this); | |
3206 | o = saved_o; | |
3207 | ||
3208 | // All instances of this tmpvar will use the literal value. | |
3209 | t.override (oss.str()); | |
3210 | } | |
3211 | else | |
3212 | c_assign (t.value(), e, msg); | |
3213 | } | |
3214 | ||
f281029c | 3215 | struct expression_is_functioncall : public nop_visitor |
412c6fe4 | 3216 | { |
412c6fe4 | 3217 | functioncall* fncall; |
f281029c JS |
3218 | expression_is_functioncall () |
3219 | : fncall(NULL) {} | |
412c6fe4 | 3220 | |
412c6fe4 AJ |
3221 | void visit_functioncall (functioncall* e) |
3222 | { | |
3223 | fncall = e; | |
3224 | } | |
3225 | }; | |
3226 | ||
313b2f74 GH |
3227 | void |
3228 | c_unparser::c_assign (const string& lvalue, expression* rvalue, | |
b2d74f03 | 3229 | const char* msg) |
313b2f74 GH |
3230 | { |
3231 | if (rvalue->type == pe_long) | |
3232 | { | |
3233 | o->newline() << lvalue << " = "; | |
3234 | rvalue->visit (this); | |
3235 | o->line() << ";"; | |
3236 | } | |
3237 | else if (rvalue->type == pe_string) | |
3238 | { | |
f281029c | 3239 | expression_is_functioncall eif; |
412c6fe4 AJ |
3240 | rvalue->visit(& eif); |
3241 | if (!session->unoptimized && eif.fncall) | |
cfaa0635 | 3242 | { |
296c059b JS |
3243 | const functioncall* saved_fncall = assigned_functioncall; |
3244 | const string* saved_retval = assigned_functioncall_retval; | |
3245 | ||
cfaa0635 | 3246 | // let the functioncall know that the return value is being saved/used |
6c22bc26 AJ |
3247 | // and keep track of the lvalue, so that the retval assignment can |
3248 | // happen in ::visit_functioncall, to avoid complications with nesting. | |
296c059b JS |
3249 | assigned_functioncall = eif.fncall; |
3250 | assigned_functioncall_retval = &lvalue; | |
412c6fe4 | 3251 | eif.fncall->visit (this); |
cfaa0635 | 3252 | o->line() << ";"; |
296c059b JS |
3253 | |
3254 | assigned_functioncall = saved_fncall; | |
3255 | assigned_functioncall_retval = saved_retval; | |
cfaa0635 AJ |
3256 | } |
3257 | else | |
3258 | { | |
3259 | // will call rvalue->visit() | |
3260 | c_strcpy (lvalue, rvalue); | |
3261 | } | |
313b2f74 GH |
3262 | } |
3263 | else | |
3264 | { | |
b2d74f03 | 3265 | string fullmsg = string(msg) + _(" type unsupported"); |
dc09353a | 3266 | throw SEMANTIC_ERROR (fullmsg, rvalue->tok); |
313b2f74 GH |
3267 | } |
3268 | } | |
3269 | ||
3270 | ||
3271 | void | |
3272 | c_unparser::c_assign (const string& lvalue, const string& rvalue, | |
b2d74f03 | 3273 | exp_type type, const char* msg, const token* tok) |
313b2f74 GH |
3274 | { |
3275 | if (type == pe_long) | |
3276 | { | |
3277 | o->newline() << lvalue << " = " << rvalue << ";"; | |
3278 | } | |
3279 | else if (type == pe_string) | |
3280 | { | |
3281 | c_strcpy (lvalue, rvalue); | |
3282 | } | |
3283 | else | |
3284 | { | |
b2d74f03 | 3285 | string fullmsg = string(msg) + _(" type unsupported"); |
dc09353a | 3286 | throw SEMANTIC_ERROR (fullmsg, tok); |
313b2f74 GH |
3287 | } |
3288 | } | |
3289 | ||
3290 | ||
dff50e09 FCE |
3291 | void |
3292 | c_unparser_assignment::c_assignop(tmpvar & res, | |
3293 | var const & lval, | |
313b2f74 GH |
3294 | tmpvar const & rval, |
3295 | token const * tok) | |
3296 | { | |
3297 | // This is common code used by scalar and array-element assignments. | |
3298 | // It assumes an operator-and-assignment (defined by the 'pre' and | |
3299 | // 'op' fields of c_unparser_assignment) is taking place between the | |
3300 | // following set of variables: | |
3301 | // | |
11b52b73 | 3302 | // res: the result of evaluating the expression, a temporary |
313b2f74 | 3303 | // lval: the lvalue of the expression, which may be damaged |
11b52b73 | 3304 | // rval: the rvalue of the expression, which is a temporary or constant |
313b2f74 | 3305 | |
dff50e09 | 3306 | // we'd like to work with a local tmpvar so we can overwrite it in |
313b2f74 | 3307 | // some optimized cases |
67c0a579 | 3308 | |
313b2f74 GH |
3309 | translator_output* o = parent->o; |
3310 | ||
3311 | if (res.type() == pe_string) | |
3312 | { | |
78110925 | 3313 | if (post) |
dc09353a | 3314 | throw SEMANTIC_ERROR (_("post assignment on strings not supported"), |
313b2f74 GH |
3315 | tok); |
3316 | if (op == "=") | |
3317 | { | |
11b52b73 | 3318 | parent->c_strcpy (lval.value(), rval.value()); |
313b2f74 GH |
3319 | // no need for second copy |
3320 | res = rval; | |
b5f561be | 3321 | } |
313b2f74 GH |
3322 | else if (op == ".=") |
3323 | { | |
11b52b73 DS |
3324 | parent->c_strcat (lval.value(), rval.value()); |
3325 | res = lval; | |
313b2f74 GH |
3326 | } |
3327 | else | |
7371cd19 JS |
3328 | throw SEMANTIC_ERROR (_F("string assignment operator %s unsupported", |
3329 | op.to_string().c_str()), tok); | |
313b2f74 | 3330 | } |
57b73400 GH |
3331 | else if (op == "<<<") |
3332 | { | |
3333 | assert(lval.type() == pe_stats); | |
3334 | assert(rval.type() == pe_long); | |
3335 | assert(res.type() == pe_long); | |
0f1a1dda FCE |
3336 | o->newline() << "_stp_stat_add (" << lval << ", " << rval << ");"; |
3337 | res = rval; | |
57b73400 | 3338 | } |
313b2f74 GH |
3339 | else if (res.type() == pe_long) |
3340 | { | |
3341 | // a lot of operators come through this "gate": | |
3342 | // - vanilla assignment "=" | |
3343 | // - stats aggregation "<<<" | |
3344 | // - modify-accumulate "+=" and many friends | |
3345 | // - pre/post-crement "++"/"--" | |
3a20432b | 3346 | // - "/" and "%" operators, but these need special handling in kernel |
313b2f74 GH |
3347 | |
3348 | // compute the modify portion of a modify-accumulate | |
3349 | string macop; | |
3350 | unsigned oplen = op.size(); | |
3351 | if (op == "=") | |
3a20432b | 3352 | macop = "*error*"; // special shortcuts below |
11b52b73 | 3353 | else if (op == "++" || op == "+=") |
53362f0e | 3354 | macop = "+="; |
11b52b73 DS |
3355 | else if (op == "--" || op == "-=") |
3356 | macop = "-="; | |
53362f0e | 3357 | else if (oplen > 1 && op[oplen-1] == '=') // for *=, <<=, etc... |
47d349b1 | 3358 | macop = op; |
313b2f74 GH |
3359 | else |
3360 | // internal error | |
dc09353a | 3361 | throw SEMANTIC_ERROR (_("unknown macop for assignment"), tok); |
3a20432b | 3362 | |
78110925 | 3363 | if (post) |
313b2f74 | 3364 | { |
3a20432b | 3365 | if (macop == "/" || macop == "%" || op == "=") |
dc09353a | 3366 | throw SEMANTIC_ERROR (_("invalid post-mode operator"), tok); |
3a20432b | 3367 | |
313b2f74 | 3368 | o->newline() << res << " = " << lval << ";"; |
11b52b73 DS |
3369 | |
3370 | if (macop == "+=" || macop == "-=") | |
3371 | o->newline() << lval << " " << macop << " " << rval << ";"; | |
3372 | else | |
3373 | o->newline() << lval << " = " << res << " " << macop << " " << rval << ";"; | |
313b2f74 GH |
3374 | } |
3375 | else | |
3376 | { | |
3a20432b | 3377 | if (op == "=") // shortcut simple assignment |
11b52b73 | 3378 | { |
53362f0e DS |
3379 | o->newline() << lval << " = " << rval << ";"; |
3380 | res = rval; | |
11b52b73 | 3381 | } |
12363146 JS |
3382 | else |
3383 | { | |
3384 | if (macop == "/=" || macop == "%=") | |
3385 | { | |
3386 | o->newline() << "if (unlikely(!" << rval << ")) {"; | |
b5f561be LB |
3387 | o->newline(1) << "c->last_error = "; |
3388 | o->line() << STAP_T_03; | |
54975cd8 | 3389 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*rvalue->tok) << ";"; |
12363146 JS |
3390 | o->newline() << "goto out;"; |
3391 | o->newline(-1) << "}"; | |
3392 | o->newline() << lval << " = " | |
3393 | << ((macop == "/=") ? "_stp_div64" : "_stp_mod64") | |
3394 | << " (NULL, " << lval << ", " << rval << ");"; | |
3395 | } | |
53362f0e DS |
3396 | else |
3397 | o->newline() << lval << " " << macop << " " << rval << ";"; | |
3398 | res = lval; | |
12363146 | 3399 | } |
313b2f74 GH |
3400 | } |
3401 | } | |
3402 | else | |
dc09353a | 3403 | throw SEMANTIC_ERROR (_("assignment type not yet implemented"), tok); |
313b2f74 GH |
3404 | } |
3405 | ||
3406 | ||
dff50e09 | 3407 | void |
0386bbcf | 3408 | c_unparser::c_declare(exp_type ty, const string &ident) |
313b2f74 | 3409 | { |
0386bbcf | 3410 | o->newline() << c_typename (ty) << " " << ident << ";"; |
313b2f74 GH |
3411 | } |
3412 | ||
3413 | ||
dff50e09 | 3414 | void |
0386bbcf | 3415 | c_unparser::c_declare_static(exp_type ty, const string &ident) |
313b2f74 | 3416 | { |
0386bbcf | 3417 | o->newline() << "static " << c_typename (ty) << " " << ident << ";"; |
313b2f74 GH |
3418 | } |
3419 | ||
3420 | ||
dff50e09 FCE |
3421 | void |
3422 | c_unparser::c_strcpy (const string& lvalue, const string& rvalue) | |
313b2f74 | 3423 | { |
dff50e09 FCE |
3424 | o->newline() << "strlcpy (" |
3425 | << lvalue << ", " | |
313b2f74 GH |
3426 | << rvalue << ", MAXSTRINGLEN);"; |
3427 | } | |
3428 | ||
3429 | ||
dff50e09 FCE |
3430 | void |
3431 | c_unparser::c_strcpy (const string& lvalue, expression* rvalue) | |
2b066ec1 | 3432 | { |
7d46afb8 | 3433 | o->newline() << "strlcpy (" << lvalue << ", "; |
313b2f74 GH |
3434 | rvalue->visit (this); |
3435 | o->line() << ", MAXSTRINGLEN);"; | |
2b066ec1 FCE |
3436 | } |
3437 | ||
3438 | ||
dff50e09 FCE |
3439 | void |
3440 | c_unparser::c_strcat (const string& lvalue, const string& rvalue) | |
ce10591c | 3441 | { |
dff50e09 FCE |
3442 | o->newline() << "strlcat (" |
3443 | << lvalue << ", " | |
7d46afb8 | 3444 | << rvalue << ", MAXSTRINGLEN);"; |
ce10591c FCE |
3445 | } |
3446 | ||
3447 | ||
dff50e09 FCE |
3448 | void |
3449 | c_unparser::c_strcat (const string& lvalue, expression* rvalue) | |
ce10591c | 3450 | { |
7d46afb8 | 3451 | o->newline() << "strlcat (" << lvalue << ", "; |
313b2f74 GH |
3452 | rvalue->visit (this); |
3453 | o->line() << ", MAXSTRINGLEN);"; | |
3454 | } | |
3455 | ||
3456 | ||
3457 | bool | |
3458 | c_unparser::is_local(vardecl const *r, token const *tok) | |
dff50e09 | 3459 | { |
313b2f74 | 3460 | if (current_probe) |
ce10591c | 3461 | { |
313b2f74 GH |
3462 | for (unsigned i=0; i<current_probe->locals.size(); i++) |
3463 | { | |
3464 | if (current_probe->locals[i] == r) | |
3465 | return true; | |
3466 | } | |
ce10591c | 3467 | } |
313b2f74 | 3468 | else if (current_function) |
ce10591c | 3469 | { |
313b2f74 GH |
3470 | for (unsigned i=0; i<current_function->locals.size(); i++) |
3471 | { | |
3472 | if (current_function->locals[i] == r) | |
3473 | return true; | |
3474 | } | |
3475 | ||
3476 | for (unsigned i=0; i<current_function->formal_args.size(); i++) | |
3477 | { | |
3478 | if (current_function->formal_args[i] == r) | |
3479 | return true; | |
3480 | } | |
ce10591c | 3481 | } |
313b2f74 GH |
3482 | |
3483 | for (unsigned i=0; i<session->globals.size(); i++) | |
ce10591c | 3484 | { |
313b2f74 GH |
3485 | if (session->globals[i] == r) |
3486 | return false; | |
ce10591c | 3487 | } |
dff50e09 | 3488 | |
313b2f74 | 3489 | if (tok) |
dc09353a | 3490 | throw SEMANTIC_ERROR (_("unresolved symbol"), tok); |
313b2f74 | 3491 | else |
47d349b1 | 3492 | throw SEMANTIC_ERROR (_("unresolved symbol: ") + (string)r->name); |
313b2f74 GH |
3493 | } |
3494 | ||
3495 | ||
dff50e09 FCE |
3496 | tmpvar |
3497 | c_unparser::gensym(exp_type ty) | |
3498 | { | |
0386bbcf | 3499 | return tmpvar (this, ty, tmpvar_counter); |
ce10591c FCE |
3500 | } |
3501 | ||
dff50e09 FCE |
3502 | aggvar |
3503 | c_unparser::gensym_aggregate() | |
3504 | { | |
0386bbcf | 3505 | return aggvar (this, tmpvar_counter); |
07c17d67 GH |
3506 | } |
3507 | ||
ce10591c | 3508 | |
dff50e09 FCE |
3509 | var |
3510 | c_unparser::getvar(vardecl *v, token const *tok) | |
3511 | { | |
57b73400 | 3512 | bool loc = is_local (v, tok); |
dff50e09 | 3513 | if (loc) |
0386bbcf | 3514 | return var (this, loc, v->type, v->name); |
57b73400 GH |
3515 | else |
3516 | { | |
3517 | statistic_decl sd; | |
47d349b1 | 3518 | std::map<interned_string, statistic_decl>::const_iterator i; |
57b73400 GH |
3519 | i = session->stat_decls.find(v->name); |
3520 | if (i != session->stat_decls.end()) | |
3521 | sd = i->second; | |
0386bbcf | 3522 | return var (this, loc, v->type, sd, v->name); |
57b73400 | 3523 | } |
313b2f74 GH |
3524 | } |
3525 | ||
3526 | ||
dff50e09 FCE |
3527 | mapvar |
3528 | c_unparser::getmap(vardecl *v, token const *tok) | |
3529 | { | |
d98d459c | 3530 | if (v->arity < 1) |
dc09353a | 3531 | throw SEMANTIC_ERROR(_("attempt to use scalar where map expected"), tok); |
57b73400 | 3532 | statistic_decl sd; |
47d349b1 | 3533 | std::map<interned_string, statistic_decl>::const_iterator i; |
57b73400 GH |
3534 | i = session->stat_decls.find(v->name); |
3535 | if (i != session->stat_decls.end()) | |
3536 | sd = i->second; | |
0386bbcf | 3537 | return mapvar (this, is_local (v, tok), v->type, sd, |
74e6cc92 | 3538 | v->name, v->index_types, v->maxsize, v->wrap); |
313b2f74 GH |
3539 | } |
3540 | ||
4383d78c | 3541 | |
dff50e09 | 3542 | itervar |
d02548c0 | 3543 | c_unparser::getiter(symbol *s) |
dff50e09 | 3544 | { |
d6d4dc4b | 3545 | return itervar (this, s, tmpvar_counter); |
67c0a579 GH |
3546 | } |
3547 | ||
3548 | ||
9d0808b4 JS |
3549 | // Queue up some actions to remove from actionremaining. Set update=true at |
3550 | // the end of basic blocks to actually update actionremaining and check it | |
3551 | // against MAXACTION. | |
5e309481 | 3552 | void |
54975cd8 | 3553 | c_unparser::record_actions (unsigned actions, const token* tok, bool update) |
5e309481 | 3554 | { |
9d0808b4 | 3555 | action_counter += actions; |
a7c9924b | 3556 | |
9d0808b4 JS |
3557 | // Update if needed, or after queueing up a few actions, in case of very |
3558 | // large code sequences. | |
ad534e14 AJ |
3559 | if (((update && action_counter > 0) || action_counter >= 10/*<-arbitrary*/) |
3560 | && !session->suppress_time_limits && !already_checked_action_count) | |
5e309481 | 3561 | { |
ad534e14 | 3562 | |
9d0808b4 | 3563 | o->newline() << "c->actionremaining -= " << action_counter << ";"; |
29fdb4e4 | 3564 | o->newline() << "if (unlikely (c->actionremaining <= 0)) {"; |
b5f561be LB |
3565 | o->newline(1) << "c->last_error = "; |
3566 | o->line() << STAP_T_04; | |
63ea4244 JS |
3567 | |
3568 | // XXX it really ought to be illegal for anything to be missing a token, | |
3569 | // but until we're sure of that, we need to defend against NULL. | |
3570 | if (tok) | |
3571 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*tok) << ";"; | |
3572 | ||
12363146 | 3573 | o->newline() << "goto out;"; |
5e309481 | 3574 | o->newline(-1) << "}"; |
9d0808b4 | 3575 | action_counter = 0; |
5e309481 FCE |
3576 | } |
3577 | } | |
3578 | ||
3579 | ||
2b066ec1 | 3580 | void |
4383d78c | 3581 | c_unparser::visit_block (block *s) |
2b066ec1 | 3582 | { |
d6d4dc4b JS |
3583 | // Key insight: individual statements of a block can reuse |
3584 | // temporary variable slots, since temporaries don't survive | |
3585 | // statement boundaries. So we use gcc's anonymous union/struct | |
3586 | // facility to explicitly overlay the temporaries. | |
7d1e27af | 3587 | start_compound_statement ("block_statement", s); |
d6d4dc4b | 3588 | |
2b066ec1 FCE |
3589 | o->newline() << "{"; |
3590 | o->indent (1); | |
a7c9924b | 3591 | |
2b066ec1 FCE |
3592 | for (unsigned i=0; i<s->statements.size(); i++) |
3593 | { | |
3594 | try | |
3595 | { | |
7d1e27af | 3596 | wrap_compound_visit (s->statements[i]); |
2b066ec1 FCE |
3597 | o->newline(); |
3598 | } | |
3599 | catch (const semantic_error& e) | |
3600 | { | |
3601 | session->print_error (e); | |
3602 | } | |
3603 | } | |
3604 | o->newline(-1) << "}"; | |
2b066ec1 | 3605 | |
7d1e27af JS |
3606 | close_compound_statement ("block_statement", s); |
3607 | } | |
2b066ec1 | 3608 | |
d74a7874 | 3609 | |
f4fe2e93 FCE |
3610 | void c_unparser::visit_try_block (try_block *s) |
3611 | { | |
0940fad9 JS |
3612 | record_actions(0, s->tok, true); // flush prior actions |
3613 | ||
7d1e27af JS |
3614 | start_compound_statement ("try_block", s); |
3615 | ||
f4fe2e93 | 3616 | o->newline() << "{"; |
0940fad9 | 3617 | o->newline(1) << "__label__ normal_fallthrough;"; |
f4fe2e93 FCE |
3618 | o->newline(1) << "{"; |
3619 | o->newline() << "__label__ out;"; | |
3620 | ||
3621 | assert (!session->unoptimized || s->try_block); // dead_stmtexpr_remover would zap it | |
3622 | if (s->try_block) | |
54975cd8 | 3623 | { |
7d1e27af | 3624 | wrap_compound_visit (s->try_block); |
54975cd8 JS |
3625 | record_actions(0, s->try_block->tok, true); // flush accumulated actions |
3626 | } | |
0940fad9 | 3627 | o->newline() << "goto normal_fallthrough;"; |
54975cd8 | 3628 | |
f4fe2e93 FCE |
3629 | o->newline() << "if (0) goto out;"; // to prevent 'unused label' warnings |
3630 | o->newline() << "out:"; | |
0940fad9 JS |
3631 | o->newline() << ";"; // to have _some_ statement |
3632 | ||
3633 | // Close the scope of the above nested 'out' label, to make sure | |
3634 | // that the catch block, should it encounter errors, does not resolve | |
3635 | // a 'goto out;' to the above label, causing infinite looping. | |
3636 | o->newline(-1) << "}"; | |
3637 | ||
3638 | o->newline() << "if (likely(c->last_error == NULL)) goto out;"; | |
3639 | ||
f4fe2e93 FCE |
3640 | if (s->catch_error_var) |
3641 | { | |
3642 | var cev(getvar(s->catch_error_var->referent, s->catch_error_var->tok)); | |
3643 | c_strcpy (cev.value(), "c->last_error"); | |
3644 | } | |
3645 | o->newline() << "c->last_error = NULL;"; | |
3646 | ||
f4fe2e93 | 3647 | // Prevent the catch{} handler from even starting if MAXACTIONS have |
54975cd8 JS |
3648 | // already been used up. Add one for the act of catching too. |
3649 | record_actions(1, s->tok, true); | |
3650 | ||
f4fe2e93 | 3651 | if (s->catch_block) |
54975cd8 | 3652 | { |
7d1e27af | 3653 | wrap_compound_visit (s->catch_block); |
54975cd8 JS |
3654 | record_actions(0, s->catch_block->tok, true); // flush accumulated actions |
3655 | } | |
3656 | ||
0940fad9 | 3657 | o->newline() << "normal_fallthrough:"; |
f4fe2e93 FCE |
3658 | o->newline() << ";"; // to have _some_ statement |
3659 | o->newline(-1) << "}"; | |
7d1e27af JS |
3660 | |
3661 | close_compound_statement ("try_block", s); | |
f4fe2e93 FCE |
3662 | } |
3663 | ||
3664 | ||
54dfabe9 FCE |
3665 | void |
3666 | c_unparser::visit_embeddedcode (embeddedcode *s) | |
3667 | { | |
2363d2a5 DB |
3668 | // Automatically add a call to assert_is_myproc to any code tagged with |
3669 | // /* myproc-unprivileged */ | |
3670 | if (s->code.find ("/* myproc-unprivileged */") != string::npos) | |
3671 | o->newline() << "assert_is_myproc();"; | |
5e309481 | 3672 | o->newline() << "{"; |
0af18f5a FL |
3673 | |
3674 | vector<vardecl*> read_defs; | |
3675 | vector<vardecl*> write_defs; | |
3676 | for (unsigned i = 0; i < session->globals.size(); i++) | |
3677 | { | |
3678 | vardecl* v = session->globals[i]; | |
8e95959e | 3679 | string name = v->unmangled_name; |
0af18f5a FL |
3680 | if (s->code.find("/* pragma:read:" + name + " */") != string::npos) |
3681 | { | |
3682 | c_global_read_def(v); | |
3683 | read_defs.push_back(v); | |
3684 | } | |
3685 | if (s->code.find("/* pragma:write:" + name + " */") != string::npos) | |
3686 | { | |
3687 | c_global_write_def(v); | |
3688 | write_defs.push_back(v); | |
3689 | } | |
3690 | } | |
3691 | ||
5e309481 | 3692 | o->newline(1) << s->code; |
0af18f5a FL |
3693 | o->indent(-1); |
3694 | ||
3695 | for (vector<vardecl*>::const_iterator it = read_defs.begin(); it != read_defs.end(); ++it) | |
3696 | c_global_read_undef(*it); | |
3697 | for (vector<vardecl*>::const_iterator it = write_defs.begin(); it != write_defs.end(); ++it) | |
3698 | c_global_write_undef(*it); | |
3699 | ||
3700 | o->newline() << "}"; | |
54dfabe9 FCE |
3701 | } |
3702 | ||
3703 | ||
2b066ec1 | 3704 | void |
78f6bba6 | 3705 | c_unparser::visit_null_statement (null_statement *) |
2b066ec1 | 3706 | { |
2b066ec1 FCE |
3707 | o->newline() << "/* null */;"; |
3708 | } | |
3709 | ||
3710 | ||
3711 | void | |
4383d78c | 3712 | c_unparser::visit_expr_statement (expr_statement *s) |
2b066ec1 | 3713 | { |
2b066ec1 FCE |
3714 | o->newline() << "(void) "; |
3715 | s->value->visit (this); | |
3716 | o->line() << ";"; | |
54975cd8 | 3717 | record_actions(1, s->tok); |
2b066ec1 FCE |
3718 | } |
3719 | ||
3720 | ||
395146b5 | 3721 | void |
7d1e27af | 3722 | c_tmpcounter::wrap_compound_visit (statement *s) |
395146b5 | 3723 | { |
d6d4dc4b JS |
3724 | if (!s) return; |
3725 | ||
395146b5 AJ |
3726 | std::ostream::pos_type before_struct_pos; |
3727 | std::ostream::pos_type after_struct_pos; | |
3728 | ||
3729 | start_struct_def(before_struct_pos, after_struct_pos, s->tok); | |
7d1e27af | 3730 | c_unparser::wrap_compound_visit (s); |
395146b5 AJ |
3731 | close_struct_def(before_struct_pos, after_struct_pos); |
3732 | } | |
3733 | ||
3734 | void | |
7d1e27af | 3735 | c_tmpcounter::wrap_compound_visit (expression *e) |
395146b5 | 3736 | { |
d6d4dc4b JS |
3737 | if (!e) return; |
3738 | ||
395146b5 AJ |
3739 | std::ostream::pos_type before_struct_pos; |
3740 | std::ostream::pos_type after_struct_pos; | |
3741 | ||
3742 | start_struct_def(before_struct_pos, after_struct_pos, e->tok); | |
7d1e27af | 3743 | c_unparser::wrap_compound_visit (e); |
395146b5 AJ |
3744 | close_struct_def(before_struct_pos, after_struct_pos); |
3745 | } | |
3746 | ||
3747 | void | |
3748 | c_tmpcounter::start_struct_def (std::ostream::pos_type &before, | |
3749 | std::ostream::pos_type &after, const token* tok) | |
3750 | { | |
3751 | // To avoid lots of empty structs, remember where we are now. Then, | |
3752 | // output the struct start and remember that positon. If when we get | |
3753 | // done with the statement we haven't moved, then we don't really need | |
3754 | // the struct. To get rid of the struct start we output, we'll seek back | |
3755 | // to where we were before we output the struct (done in ::close_struct_def). | |
d6d4dc4b JS |
3756 | translator_output *o = parent->o; |
3757 | before = o->tellp(); | |
3758 | o->newline() << "struct { /* source: " << tok->location.file->name | |
3759 | << ":" << lex_cast(tok->location.line) << " */"; | |
3760 | o->indent(1); | |
3761 | after = o->tellp(); | |
395146b5 AJ |
3762 | } |
3763 | ||
3764 | void | |
3765 | c_tmpcounter::close_struct_def (std::ostream::pos_type before, | |
3766 | std::ostream::pos_type after) | |
3767 | { | |
3768 | // meant to be used with ::start_struct_def. remove the struct if empty. | |
d6d4dc4b JS |
3769 | translator_output *o = parent->o; |
3770 | o->indent(-1); | |
3771 | if (after == o->tellp()) | |
3772 | o->seekp(before); | |
395146b5 | 3773 | else |
d6d4dc4b | 3774 | o->newline() << "};"; |
395146b5 AJ |
3775 | } |
3776 | ||
d74a7874 | 3777 | void |
7d1e27af | 3778 | c_tmpcounter::start_compound_statement (const char* tag, statement *s) |
d74a7874 | 3779 | { |
7d1e27af | 3780 | const source_loc& loc = s->tok->location; |
d6d4dc4b JS |
3781 | translator_output *o = parent->o; |
3782 | o->newline() << "union { /* " << tag << ": " | |
7d1e27af JS |
3783 | << loc.file->name << ":" |
3784 | << lex_cast(loc.line) << " */"; | |
d6d4dc4b JS |
3785 | o->indent(1); |
3786 | } | |
d74a7874 | 3787 | |
d6d4dc4b | 3788 | void |
7d1e27af | 3789 | c_tmpcounter::close_compound_statement (const char*, statement *) |
d6d4dc4b JS |
3790 | { |
3791 | translator_output *o = parent->o; | |
3792 | o->newline(-1) << "};"; | |
d74a7874 AJ |
3793 | } |
3794 | ||
d74a7874 | 3795 | |
2b066ec1 | 3796 | void |
4383d78c | 3797 | c_unparser::visit_if_statement (if_statement *s) |
2b066ec1 | 3798 | { |
54975cd8 | 3799 | record_actions(1, s->tok, true); |
7d1e27af JS |
3800 | |
3801 | start_compound_statement ("if_statement", s); | |
3802 | ||
2b066ec1 FCE |
3803 | o->newline() << "if ("; |
3804 | o->indent (1); | |
7d1e27af | 3805 | wrap_compound_visit (s->condition); |
2b066ec1 FCE |
3806 | o->indent (-1); |
3807 | o->line() << ") {"; | |
3808 | o->indent (1); | |
7d1e27af | 3809 | wrap_compound_visit (s->thenblock); |
54975cd8 | 3810 | record_actions(0, s->thenblock->tok, true); |
2b066ec1 FCE |
3811 | o->newline(-1) << "}"; |
3812 | if (s->elseblock) | |
3813 | { | |
3814 | o->newline() << "else {"; | |
3815 | o->indent (1); | |
7d1e27af | 3816 | wrap_compound_visit (s->elseblock); |
54975cd8 | 3817 | record_actions(0, s->elseblock->tok, true); |
2b066ec1 FCE |
3818 | o->newline(-1) << "}"; |
3819 | } | |
2b066ec1 | 3820 | |
7d1e27af | 3821 | close_compound_statement ("if_statement", s); |
bb788f9f FCE |
3822 | } |
3823 | ||
3824 | ||
2b066ec1 | 3825 | void |
4383d78c | 3826 | c_unparser::visit_for_loop (for_loop *s) |
2b066ec1 | 3827 | { |
aca66a36 | 3828 | string ctr = lex_cast (label_counter++); |
bb788f9f | 3829 | string toplabel = "top_" + ctr; |
f3c26ea5 FCE |
3830 | string contlabel = "continue_" + ctr; |
3831 | string breaklabel = "break_" + ctr; | |
3832 | ||
7d1e27af JS |
3833 | start_compound_statement ("for_loop", s); |
3834 | ||
bb788f9f | 3835 | // initialization |
7d1e27af | 3836 | wrap_compound_visit (s->init); |
54975cd8 | 3837 | record_actions(1, s->tok, true); |
f3c26ea5 | 3838 | |
bb788f9f FCE |
3839 | // condition |
3840 | o->newline(-1) << toplabel << ":"; | |
a7c9924b | 3841 | |
29fdb4e4 DS |
3842 | // Emit an explicit action here to cover the act of iteration. |
3843 | // Equivalently, it can stand for the evaluation of the condition | |
3844 | // expression. | |
a7c9924b | 3845 | o->indent(1); |
54975cd8 | 3846 | record_actions(1, s->tok); |
a7c9924b FCE |
3847 | |
3848 | o->newline() << "if (! ("; | |
f3c26ea5 | 3849 | if (s->cond->type != pe_long) |
dc09353a | 3850 | throw SEMANTIC_ERROR (_("expected numeric type"), s->cond->tok); |
7d1e27af | 3851 | wrap_compound_visit (s->cond); |
f3c26ea5 FCE |
3852 | o->line() << ")) goto " << breaklabel << ";"; |
3853 | ||
bb788f9f | 3854 | // body |
f3c26ea5 FCE |
3855 | loop_break_labels.push_back (breaklabel); |
3856 | loop_continue_labels.push_back (contlabel); | |
7d1e27af | 3857 | wrap_compound_visit (s->block); |
54975cd8 | 3858 | record_actions(0, s->block->tok, true); |
f3c26ea5 FCE |
3859 | loop_break_labels.pop_back (); |
3860 | loop_continue_labels.pop_back (); | |
3861 | ||
bb788f9f FCE |
3862 | // iteration |
3863 | o->newline(-1) << contlabel << ":"; | |
3864 | o->indent(1); | |
7d1e27af | 3865 | wrap_compound_visit (s->incr); |
bb788f9f | 3866 | o->newline() << "goto " << toplabel << ";"; |
f3c26ea5 | 3867 | |
bb788f9f FCE |
3868 | // exit |
3869 | o->newline(-1) << breaklabel << ":"; | |
3870 | o->newline(1) << "; /* dummy statement */"; | |
7d1e27af JS |
3871 | |
3872 | close_compound_statement ("for_loop", s); | |
2b066ec1 FCE |
3873 | } |
3874 | ||
3875 | ||
71572ba8 GH |
3876 | struct arrayindex_downcaster |
3877 | : public traversing_visitor | |
3878 | { | |
3879 | arrayindex *& arr; | |
dff50e09 | 3880 | |
71572ba8 | 3881 | arrayindex_downcaster (arrayindex *& arr) |
dff50e09 | 3882 | : arr(arr) |
71572ba8 GH |
3883 | {} |
3884 | ||
3885 | void visit_arrayindex (arrayindex* e) | |
3886 | { | |
3887 | arr = e; | |
3888 | } | |
3889 | }; | |
3890 | ||
3891 | ||
3892 | static bool | |
dff50e09 | 3893 | expression_is_arrayindex (expression *e, |
71572ba8 GH |
3894 | arrayindex *& hist) |
3895 | { | |
3896 | arrayindex *h = NULL; | |
3897 | arrayindex_downcaster d(h); | |
3898 | e->visit (&d); | |
3899 | if (static_cast<void*>(h) == static_cast<void*>(e)) | |
3900 | { | |
3901 | hist = h; | |
3902 | return true; | |
3903 | } | |
3904 | return false; | |
3905 | } | |
3906 | ||
3907 | ||
bdc82277 JS |
3908 | // Look for opportunities to used a saved value at the beginning of the loop |
3909 | void | |
d6d4dc4b | 3910 | c_unparser::visit_foreach_loop_value (foreach_loop* s, const string& value) |
bdc82277 JS |
3911 | { |
3912 | bool stable_value = false; | |
3913 | ||
3914 | // There are three possible cases that we might easily retrieve the value: | |
3915 | // 1. foreach ([keys] in any_array_type) | |
3916 | // 2. foreach (idx in @hist_*(stat)) | |
3917 | // 3. foreach (idx in @hist_*(stat[keys])) | |
3918 | // | |
3919 | // For 1 and 2, we just need to check that the keys/idx are const throughout | |
3920 | // the loop. For 3, we'd have to check also that the arbitrary keys | |
3921 | // expressions indexing the stat are const -- much harder, so I'm punting | |
3922 | // that case for now. | |
3923 | ||
3924 | symbol *array; | |
3925 | hist_op *hist; | |
3926 | classify_indexable (s->base, array, hist); | |
3927 | ||
3928 | if (!(hist && get_symbol_within_expression(hist->stat)->referent->arity > 0)) | |
3929 | { | |
3930 | set<vardecl*> indexes; | |
3931 | for (unsigned i=0; i < s->indexes.size(); ++i) | |
3932 | indexes.insert(s->indexes[i]->referent); | |
3933 | ||
3934 | varuse_collecting_visitor v(*session); | |
3935 | s->block->visit (&v); | |
3936 | v.embedded_seen = false; // reset because we only care about the indexes | |
3937 | if (v.side_effect_free_wrt(indexes)) | |
3938 | stable_value = true; | |
3939 | } | |
3940 | ||
3941 | if (stable_value) | |
3942 | { | |
3943 | // Rather than trying to compare arrayindexes to this foreach_loop | |
3944 | // manually, we just create a fake arrayindex that would match the | |
3945 | // foreach_loop, render it as a string, and later render encountered | |
3946 | // arrayindexes as strings and compare. | |
3947 | arrayindex ai; | |
3948 | ai.base = s->base; | |
3949 | for (unsigned i=0; i < s->indexes.size(); ++i) | |
3950 | ai.indexes.push_back(s->indexes[i]); | |
3951 | string loopai = lex_cast(ai); | |
3952 | foreach_loop_values[loopai] = value; | |
d6d4dc4b | 3953 | s->block->visit (this); |
bdc82277 JS |
3954 | foreach_loop_values.erase(loopai); |
3955 | } | |
3956 | else | |
d6d4dc4b | 3957 | s->block->visit (this); |
bdc82277 JS |
3958 | } |
3959 | ||
3960 | ||
3961 | bool | |
3962 | c_unparser::get_foreach_loop_value (arrayindex* ai, string& value) | |
3963 | { | |
3964 | if (!ai) | |
3965 | return false; | |
3966 | map<string,string>::iterator it = foreach_loop_values.find(lex_cast(*ai)); | |
3967 | if (it == foreach_loop_values.end()) | |
3968 | return false; | |
3969 | value = it->second; | |
3970 | return true; | |
3971 | } | |
3972 | ||
3973 | ||
69c68955 FCE |
3974 | void |
3975 | c_unparser::visit_foreach_loop (foreach_loop *s) | |
3976 | { | |
dff50e09 | 3977 | symbol *array; |
d02548c0 GH |
3978 | hist_op *hist; |
3979 | classify_indexable (s->base, array, hist); | |
5e309481 | 3980 | |
8e00730c JS |
3981 | string ctr = lex_cast (label_counter++); |
3982 | string toplabel = "top_" + ctr; | |
3983 | string contlabel = "continue_" + ctr; | |
3984 | string breaklabel = "break_" + ctr; | |
3985 | ||
d02548c0 | 3986 | if (array) |
1a0e4851 | 3987 | { |
d02548c0 | 3988 | mapvar mv = getmap (array->referent, s->tok); |
d02548c0 | 3989 | vector<var> keys; |
dff50e09 | 3990 | |
d02548c0 | 3991 | // NB: structure parallels for_loop |
dff50e09 | 3992 | |
d02548c0 | 3993 | // initialization |
07c17d67 | 3994 | |
27f21e8c DS |
3995 | tmpvar *res_limit = NULL; |
3996 | if (s->limit) | |
3997 | { | |
3998 | // Evaluate the limit expression once. | |
3999 | res_limit = new tmpvar(gensym(pe_long)); | |
43ff5962 | 4000 | c_assign (*res_limit, s->limit, "foreach limit"); |
27f21e8c | 4001 | } |
dff50e09 | 4002 | |
07c17d67 GH |
4003 | // aggregate array if required |
4004 | if (mv.is_parallel()) | |
d02548c0 | 4005 | { |
12363146 | 4006 | o->newline() << "if (unlikely(NULL == " << mv.calculate_aggregate() << ")) {"; |
b5f561be LB |
4007 | o->newline(1) << "c->last_error = "; |
4008 | o->line() << STAP_T_05 << mv << "\";"; | |
54975cd8 | 4009 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*s->tok) << ";"; |
12363146 JS |
4010 | o->newline() << "goto out;"; |
4011 | o->newline(-1) << "}"; | |
ea7f4e8d | 4012 | |
07c17d67 | 4013 | // sort array if desired |
27f21e8c DS |
4014 | if (s->sort_direction) |
4015 | { | |
fd5689dc | 4016 | string sort_column; |
6a59236b DS |
4017 | |
4018 | // If the user wanted us to sort by value, we'll sort by | |
fd5689dc FCE |
4019 | // @count or selected function instead for aggregates. |
4020 | // See runtime/map.c | |
6a59236b | 4021 | if (s->sort_column == 0) |
fd5689dc FCE |
4022 | switch (s->sort_aggr) { |
4023 | default: case sc_none: case sc_count: sort_column = "SORT_COUNT"; break; | |
4024 | case sc_sum: sort_column = "SORT_SUM"; break; | |
4025 | case sc_min: sort_column = "SORT_MIN"; break; | |
4026 | case sc_max: sort_column = "SORT_MAX"; break; | |
4027 | case sc_average: sort_column = "SORT_AVG"; break; | |
4028 | } | |
6a59236b | 4029 | else |
fd5689dc | 4030 | sort_column = lex_cast(s->sort_column); |
6a59236b | 4031 | |
27f21e8c DS |
4032 | o->newline() << "else"; // only sort if aggregation was ok |
4033 | if (s->limit) | |
4034 | { | |
3cb9c91e | 4035 | o->newline(1) << mv.function_keysym("sortn", true) <<" (" |
27f21e8c | 4036 | << mv.fetch_existing_aggregate() << ", " |
6a59236b | 4037 | << *res_limit << ", " << sort_column << ", " |
27f21e8c DS |
4038 | << - s->sort_direction << ");"; |
4039 | } | |
4040 | else | |
4041 | { | |
3cb9c91e | 4042 | o->newline(1) << mv.function_keysym("sort", true) <<" (" |
27f21e8c | 4043 | << mv.fetch_existing_aggregate() << ", " |
6a59236b | 4044 | << sort_column << ", " |
27f21e8c DS |
4045 | << - s->sort_direction << ");"; |
4046 | } | |
4047 | o->indent(-1); | |
4048 | } | |
4049 | } | |
07c17d67 | 4050 | else |
dff50e09 | 4051 | { |
07c17d67 GH |
4052 | // sort array if desired |
4053 | if (s->sort_direction) | |
4054 | { | |
27f21e8c DS |
4055 | if (s->limit) |
4056 | { | |
2473ac1b JS |
4057 | o->newline() << mv.function_keysym("sortn") <<" (" |
4058 | << mv.value() << ", " | |
27f21e8c DS |
4059 | << *res_limit << ", " << s->sort_column << ", " |
4060 | << - s->sort_direction << ");"; | |
4061 | } | |
4062 | else | |
4063 | { | |
2473ac1b JS |
4064 | o->newline() << mv.function_keysym("sort") <<" (" |
4065 | << mv.value() << ", " | |
27f21e8c DS |
4066 | << s->sort_column << ", " |
4067 | << - s->sort_direction << ");"; | |
4068 | } | |
07c17d67 | 4069 | } |
d02548c0 | 4070 | } |
07c17d67 | 4071 | |
d02548c0 | 4072 | // NB: sort direction sense is opposite in runtime, thus the negation |
dff50e09 | 4073 | |
27f21e8c DS |
4074 | tmpvar *limitv = NULL; |
4075 | if (s->limit) | |
4076 | { | |
4077 | // Create the loop limit variable here and initialize it. | |
4078 | limitv = new tmpvar(gensym (pe_long)); | |
4079 | o->newline() << *limitv << " = 0LL;"; | |
4080 | } | |
4081 | ||
c56fc632 JL |
4082 | if (mv.is_parallel()) |
4083 | aggregations_active.insert(mv.value()); | |
4084 | ||
4085 | itervar iv = getiter (array); | |
4086 | o->newline() << iv << " = " << iv.start (mv) << ";"; | |
4087 | ||
05f0fc64 AJ |
4088 | vector<tmpvar *> array_slice_vars; |
4089 | // store the the variables corresponding to the index of the array slice | |
4090 | // as temporary variables | |
4091 | if (!s->array_slice.empty()) | |
4092 | for (unsigned i = 0; i < s->array_slice.size(); ++i) | |
4093 | { | |
45af9d1b | 4094 | if (s->array_slice[i]) |
05f0fc64 AJ |
4095 | { |
4096 | tmpvar *asvar = new tmpvar(gensym(s->array_slice[i]->type)); | |
43ff5962 | 4097 | c_assign(*asvar, s->array_slice[i], "array slice index"); |
05f0fc64 AJ |
4098 | array_slice_vars.push_back(asvar); |
4099 | } | |
45af9d1b AJ |
4100 | else |
4101 | array_slice_vars.push_back(NULL); | |
05f0fc64 AJ |
4102 | } |
4103 | ||
54975cd8 | 4104 | record_actions(1, s->tok, true); |
9d0808b4 | 4105 | |
d02548c0 GH |
4106 | // condition |
4107 | o->newline(-1) << toplabel << ":"; | |
a7c9924b | 4108 | |
29fdb4e4 DS |
4109 | // Emit an explicit action here to cover the act of iteration. |
4110 | // Equivalently, it can stand for the evaluation of the | |
a7c9924b FCE |
4111 | // condition expression. |
4112 | o->indent(1); | |
54975cd8 | 4113 | record_actions(1, s->tok); |
a7c9924b FCE |
4114 | |
4115 | o->newline() << "if (! (" << iv << ")) goto " << breaklabel << ";"; | |
dff50e09 | 4116 | |
d02548c0 GH |
4117 | // body |
4118 | loop_break_labels.push_back (breaklabel); | |
4119 | loop_continue_labels.push_back (contlabel); | |
4120 | o->newline() << "{"; | |
4121 | o->indent (1); | |
27f21e8c DS |
4122 | |
4123 | if (s->limit) | |
4124 | { | |
4125 | // If we've been through LIMIT loop iterations, quit. | |
4126 | o->newline() << "if (" << *limitv << "++ >= " << *res_limit | |
4127 | << ") goto " << breaklabel << ";"; | |
4128 | ||
4129 | // We're done with limitv and res_limit. | |
4130 | delete limitv; | |
4131 | delete res_limit; | |
4132 | } | |
4133 | ||
d02548c0 GH |
4134 | for (unsigned i = 0; i < s->indexes.size(); ++i) |
4135 | { | |
4136 | // copy the iter values into the specified locals | |
4137 | var v = getvar (s->indexes[i]->referent); | |
2473ac1b | 4138 | c_assign (v, iv.get_key (mv, v.type(), i), s->tok); |
d02548c0 | 4139 | } |
c261711d | 4140 | |
3040bf3a AJ |
4141 | // in the case that the user specified something like |
4142 | // foreach ([a,b] in foo[*, 123]), need to check that it iterates over | |
4143 | // the specified values, ie b is alwasy going to be 123 | |
4144 | if (!s->array_slice.empty()) | |
4145 | { | |
4146 | //add in the beginning portion of the if statement | |
ad02fd4f | 4147 | o->newline() << "if (0"; // in case all are wildcards |
3040bf3a | 4148 | for (unsigned i = 0; i < s->array_slice.size(); ++i) |
05f0fc64 | 4149 | |
3040bf3a | 4150 | // only output a comparsion if the expression is not "*". |
45af9d1b | 4151 | if (s->array_slice[i]) |
3040bf3a AJ |
4152 | { |
4153 | o->line() << " || "; | |
4154 | if (s->indexes[i]->type == pe_string) | |
4155 | { | |
4156 | if (s->array_slice[i]->type != pe_string) | |
4157 | throw SEMANTIC_ERROR (_("expected string types"), s->tok); | |
05f0fc64 AJ |
4158 | o->line() << "strncmp(" << getvar (s->indexes[i]->referent) |
4159 | << ", " << *array_slice_vars[i]; | |
3040bf3a AJ |
4160 | o->line() << ", MAXSTRINGLEN) !=0"; |
4161 | } | |
4162 | else if (s->indexes[i]->type == pe_long) | |
4163 | { | |
4164 | if (s->array_slice[i]->type != pe_long) | |
4165 | throw SEMANTIC_ERROR (_("expected numeric types"), s->tok); | |
05f0fc64 AJ |
4166 | o->line() << getvar (s->indexes[i]->referent) << " != " |
4167 | << *array_slice_vars[i]; | |
3040bf3a AJ |
4168 | } |
4169 | else | |
4170 | { | |
05f0fc64 | 4171 | throw SEMANTIC_ERROR (_("unexpected type"), s->tok); |
3040bf3a AJ |
4172 | } |
4173 | } | |
4174 | o->line() << ") goto " << contlabel << ";"; // end of the if statment | |
4175 | } | |
4176 | ||
c261711d JS |
4177 | if (s->value) |
4178 | { | |
4179 | var v = getvar (s->value->referent); | |
1841d2dd | 4180 | c_assign (v, iv.get_value (mv, v.type()), s->tok); |
c261711d JS |
4181 | } |
4182 | ||
d6d4dc4b | 4183 | visit_foreach_loop_value(s, iv.get_value(mv, array->type)); |
54975cd8 | 4184 | record_actions(0, s->block->tok, true); |
d02548c0 GH |
4185 | o->newline(-1) << "}"; |
4186 | loop_break_labels.pop_back (); | |
4187 | loop_continue_labels.pop_back (); | |
dff50e09 | 4188 | |
d02548c0 GH |
4189 | // iteration |
4190 | o->newline(-1) << contlabel << ":"; | |
4191 | o->newline(1) << iv << " = " << iv.next (mv) << ";"; | |
4192 | o->newline() << "goto " << toplabel << ";"; | |
dff50e09 | 4193 | |
d02548c0 GH |
4194 | // exit |
4195 | o->newline(-1) << breaklabel << ":"; | |
4196 | o->newline(1) << "; /* dummy statement */"; | |
57eedf94 JS |
4197 | |
4198 | if (mv.is_parallel()) | |
11b52b73 | 4199 | aggregations_active.erase(mv.value()); |
1a0e4851 | 4200 | } |
d02548c0 | 4201 | else |
67c0a579 | 4202 | { |
71572ba8 | 4203 | // Iterating over buckets in a histogram. |
d6d4dc4b JS |
4204 | |
4205 | // First make sure we have exactly one pe_long variable to use as | |
4206 | // our bucket index. | |
4207 | if (s->indexes.size() != 1 || s->indexes[0]->referent->type != pe_long) | |
4208 | throw SEMANTIC_ERROR(_("Invalid indexing of histogram"), s->tok); | |
e76c6d65 | 4209 | |
27f21e8c DS |
4210 | tmpvar *res_limit = NULL; |
4211 | tmpvar *limitv = NULL; | |
4212 | if (s->limit) | |
4213 | { | |
4214 | // Evaluate the limit expression once. | |
4215 | res_limit = new tmpvar(gensym(pe_long)); | |
43ff5962 | 4216 | c_assign (*res_limit, s->limit, "foreach limit"); |
27f21e8c DS |
4217 | |
4218 | // Create the loop limit variable here and initialize it. | |
4219 | limitv = new tmpvar(gensym (pe_long)); | |
4220 | o->newline() << *limitv << " = 0LL;"; | |
4221 | } | |
dff50e09 | 4222 | |
c56fc632 JL |
4223 | var bucketvar = getvar (s->indexes[0]->referent); |
4224 | ||
4225 | aggvar agg = gensym_aggregate (); | |
4226 | ||
4227 | var *v = load_aggregate(hist->stat, agg); | |
4228 | v->assert_hist_compatible(*hist); | |
4229 | ||
54975cd8 | 4230 | record_actions(1, s->tok, true); |
dff50e09 | 4231 | o->newline() << "for (" << bucketvar << " = 0; " |
e76c6d65 | 4232 | << bucketvar << " < " << v->buckets() << "; " |
71572ba8 GH |
4233 | << bucketvar << "++) { "; |
4234 | o->newline(1); | |
8e00730c JS |
4235 | loop_break_labels.push_back (breaklabel); |
4236 | loop_continue_labels.push_back (contlabel); | |
27f21e8c DS |
4237 | |
4238 | if (s->limit) | |
4239 | { | |
4240 | // If we've been through LIMIT loop iterations, quit. | |
4241 | o->newline() << "if (" << *limitv << "++ >= " << *res_limit | |
4242 | << ") break;"; | |
4243 | ||
4244 | // We're done with limitv and res_limit. | |
4245 | delete limitv; | |
4246 | delete res_limit; | |
4247 | } | |
4248 | ||
c261711d JS |
4249 | if (s->value) |
4250 | { | |
4251 | var v = getvar (s->value->referent); | |
4252 | c_assign (v, agg.get_hist (bucketvar), s->tok); | |
4253 | } | |
4254 | ||
d6d4dc4b | 4255 | visit_foreach_loop_value(s, agg.get_hist(bucketvar)); |
54975cd8 | 4256 | record_actions(1, s->block->tok, true); |
8e00730c JS |
4257 | |
4258 | o->newline(-1) << contlabel << ":"; | |
4259 | o->newline(1) << "continue;"; | |
4260 | o->newline(-1) << breaklabel << ":"; | |
4261 | o->newline(1) << "break;"; | |
71572ba8 | 4262 | o->newline(-1) << "}"; |
8e00730c JS |
4263 | loop_break_labels.pop_back (); |
4264 | loop_continue_labels.pop_back (); | |
e76c6d65 JS |
4265 | |
4266 | delete v; | |
67c0a579 | 4267 | } |
69c68955 FCE |
4268 | } |
4269 | ||
4270 | ||
2b066ec1 | 4271 | void |
4383d78c | 4272 | c_unparser::visit_return_statement (return_statement* s) |
2b066ec1 | 4273 | { |
2b066ec1 | 4274 | if (current_function == 0) |
dc09353a | 4275 | throw SEMANTIC_ERROR (_("cannot 'return' from probe"), s->tok); |
2b066ec1 FCE |
4276 | |
4277 | if (s->value->type != current_function->type) | |
dc09353a | 4278 | throw SEMANTIC_ERROR (_("return type mismatch"), current_function->tok, |
e26c2f83 | 4279 | s->tok); |
2b066ec1 | 4280 | |
ce10591c | 4281 | c_assign ("l->__retvalue", s->value, "return value"); |
54975cd8 | 4282 | record_actions(1, s->tok, true); |
12363146 | 4283 | o->newline() << "goto out;"; |
2b066ec1 FCE |
4284 | } |
4285 | ||
4286 | ||
f3c26ea5 FCE |
4287 | void |
4288 | c_unparser::visit_next_statement (next_statement* s) | |
4289 | { | |
4290 | if (current_probe == 0) | |
dc09353a | 4291 | throw SEMANTIC_ERROR (_("cannot 'next' from function"), s->tok); |
f3c26ea5 | 4292 | |
54975cd8 | 4293 | record_actions(1, s->tok, true); |
12363146 | 4294 | o->newline() << "goto out;"; |
f3c26ea5 FCE |
4295 | } |
4296 | ||
4297 | ||
d98d459c GH |
4298 | struct delete_statement_operand_visitor: |
4299 | public throwing_visitor | |
4300 | { | |
4301 | c_unparser *parent; | |
4302 | delete_statement_operand_visitor (c_unparser *p): | |
1e41115c | 4303 | throwing_visitor (_("invalid operand of delete expression")), |
d98d459c GH |
4304 | parent (p) |
4305 | {} | |
4306 | void visit_symbol (symbol* e); | |
4307 | void visit_arrayindex (arrayindex* e); | |
4308 | }; | |
4309 | ||
dff50e09 | 4310 | void |
d98d459c GH |
4311 | delete_statement_operand_visitor::visit_symbol (symbol* e) |
4312 | { | |
d6d4dc4b | 4313 | translator_output* o = parent->o; |
ed238a16 | 4314 | assert (e->referent != 0); |
45c2b487 JS |
4315 | if (e->referent->arity > 0) |
4316 | { | |
dff50e09 | 4317 | mapvar mvar = parent->getmap(e->referent, e->tok); |
13a9593f FCE |
4318 | /* NB: Memory deallocation/allocation operations |
4319 | are not generally safe. | |
d6d4dc4b JS |
4320 | o->newline() << mvar.fini (); |
4321 | o->newline() << mvar.init (); | |
45c2b487 JS |
4322 | */ |
4323 | if (mvar.is_parallel()) | |
d6d4dc4b | 4324 | o->newline() << "_stp_pmap_clear (" << mvar.value() << ");"; |
45c2b487 | 4325 | else |
d6d4dc4b | 4326 | o->newline() << "_stp_map_clear (" << mvar.value() << ");"; |
45c2b487 JS |
4327 | } |
4328 | else | |
4329 | { | |
dff50e09 | 4330 | var v = parent->getvar(e->referent, e->tok); |
45c2b487 JS |
4331 | switch (e->type) |
4332 | { | |
4333 | case pe_stats: | |
d6d4dc4b | 4334 | o->newline() << "_stp_stat_clear (" << v.value() << ");"; |
45c2b487 JS |
4335 | break; |
4336 | case pe_long: | |
d6d4dc4b | 4337 | o->newline() << v.value() << " = 0;"; |
45c2b487 JS |
4338 | break; |
4339 | case pe_string: | |
d6d4dc4b | 4340 | o->newline() << v.value() << "[0] = '\\0';"; |
45c2b487 JS |
4341 | break; |
4342 | case pe_unknown: | |
4343 | default: | |
dc09353a | 4344 | throw SEMANTIC_ERROR(_("Cannot delete unknown expression type"), e->tok); |
45c2b487 JS |
4345 | } |
4346 | } | |
4347 | } | |
4348 | ||
dff50e09 | 4349 | void |
d98d459c GH |
4350 | delete_statement_operand_visitor::visit_arrayindex (arrayindex* e) |
4351 | { | |
dff50e09 | 4352 | symbol *array; |
d02548c0 GH |
4353 | hist_op *hist; |
4354 | classify_indexable (e->base, array, hist); | |
d6d4dc4b | 4355 | translator_output* o = parent->o; |
bb788f9f | 4356 | |
d02548c0 GH |
4357 | if (array) |
4358 | { | |
a98c930b AJ |
4359 | bool array_slice = false; |
4360 | for (unsigned i = 0; i < e->indexes.size(); i ++) | |
45af9d1b | 4361 | if (e->indexes[i] == NULL) |
a98c930b AJ |
4362 | { |
4363 | array_slice = true; | |
4364 | break; | |
4365 | } | |
dff50e09 | 4366 | |
a98c930b AJ |
4367 | if (!array_slice) // delete a single element |
4368 | { | |
4369 | vector<tmpvar> idx; | |
4370 | parent->load_map_indices (e, idx); | |
4371 | mapvar mvar = parent->getmap (array->referent, e->tok); | |
d6d4dc4b | 4372 | o->newline() << mvar.del (idx) << ";"; |
a98c930b AJ |
4373 | } |
4374 | else // delete elements if they match the array slice. | |
4375 | { | |
3a7fec94 AJ |
4376 | vardecl* r = array->referent; |
4377 | mapvar mvar = parent->getmap (r, e->tok); | |
4378 | itervar iv = parent->getiter(array); | |
4379 | ||
a98c930b AJ |
4380 | // create tmpvars for the array indexes, storing NULL where there is |
4381 | // no specific value that the index should be | |
4382 | vector<tmpvar *> array_slice_vars; | |
3a7fec94 | 4383 | vector<tmpvar> idx; // for the indexes if the variable is a pmap |
a98c930b AJ |
4384 | for (unsigned i=0; i<e->indexes.size(); i++) |
4385 | { | |
45af9d1b | 4386 | if (e->indexes[i]) |
a98c930b | 4387 | { |
45af9d1b | 4388 | tmpvar *asvar = new tmpvar(parent->gensym(e->indexes[i]->type)); |
43ff5962 | 4389 | parent->c_assign (*asvar, e->indexes[i], "tmp var"); |
a98c930b | 4390 | array_slice_vars.push_back(asvar); |
3a7fec94 AJ |
4391 | if (mvar.is_parallel()) |
4392 | idx.push_back(*asvar); | |
a98c930b | 4393 | } |
45af9d1b | 4394 | else |
3a7fec94 AJ |
4395 | { |
4396 | array_slice_vars.push_back(NULL); | |
4397 | if (mvar.is_parallel()) | |
4398 | { | |
4399 | tmpvar *asvar = new tmpvar(parent->gensym(r->index_types[i])); | |
4400 | idx.push_back(*asvar); | |
4401 | } | |
4402 | } | |
a98c930b AJ |
4403 | } |
4404 | ||
3a7fec94 AJ |
4405 | if (mvar.is_parallel()) |
4406 | { | |
d6d4dc4b JS |
4407 | o->newline() << "if (unlikely(NULL == " |
4408 | << mvar.calculate_aggregate() << ")) {"; | |
4409 | o->newline(1) << "c->last_error = "; | |
4410 | o->line() << STAP_T_05 << mvar << "\";"; | |
4411 | o->newline() << "c->last_stmt = " | |
4412 | << lex_cast_qstring(*e->tok) << ";"; | |
4413 | o->newline() << "goto out;"; | |
4414 | o->newline(-1) << "}"; | |
3a7fec94 | 4415 | } |
a98c930b AJ |
4416 | |
4417 | // iterate through the map, deleting elements that match the array slice | |
4418 | string ctr = lex_cast (parent->label_counter++); | |
4419 | string toplabel = "top_" + ctr; | |
4420 | string breaklabel = "break_" + ctr; | |
4421 | ||
d6d4dc4b JS |
4422 | o->newline() << iv << " = " << iv.start(mvar) << ";"; |
4423 | o->newline() << toplabel << ":"; | |
a98c930b | 4424 | |
d6d4dc4b JS |
4425 | o->newline(1) << "if (!(" << iv << ")){"; |
4426 | o->newline(1) << "goto " << breaklabel << ";}"; | |
a98c930b AJ |
4427 | |
4428 | // insert the comparison for keys that aren't wildcards | |
d6d4dc4b | 4429 | o->newline(-1) << "if (1"; // in case all are wildcards |
a98c930b AJ |
4430 | for (unsigned i=0; i<array_slice_vars.size(); i++) |
4431 | if (array_slice_vars[i] != NULL) | |
4432 | { | |
4433 | if (array_slice_vars[i]->type() == pe_long) | |
d6d4dc4b JS |
4434 | o->line() << " && " << *array_slice_vars[i] << " == " |
4435 | << iv.get_key(mvar, array_slice_vars[i]->type(), i); | |
a98c930b | 4436 | else if (array_slice_vars[i]->type() == pe_string) |
d6d4dc4b JS |
4437 | o->line() << " && strncmp(" << *array_slice_vars[i] << ", " |
4438 | << iv.get_key(mvar, array_slice_vars[i]->type(), i) | |
4439 | << ", MAXSTRINGLEN) == 0"; | |
a98c930b AJ |
4440 | else |
4441 | throw SEMANTIC_ERROR (_("unexpected type"), e->tok); | |
4442 | } | |
3a7fec94 | 4443 | |
d6d4dc4b | 4444 | o->line() << ") {"; |
3a7fec94 | 4445 | |
a98c930b | 4446 | // conditional is true, so delete item and go to the next item |
3a7fec94 AJ |
4447 | if (mvar.is_parallel()) |
4448 | { | |
d6d4dc4b | 4449 | o->indent(1); |
3a7fec94 AJ |
4450 | // fills in the wildcards with the current iteration's (map) indexes |
4451 | for (unsigned i = 0; i<array_slice_vars.size(); i++) | |
4452 | if (array_slice_vars[i] == NULL) | |
4453 | parent->c_assign (idx[i].value(), | |
4454 | iv.get_key(mvar, r->index_types[i], i), | |
4455 | r->index_types[i], "tmpvar", e->tok); | |
d6d4dc4b JS |
4456 | o->newline() << iv << " = " << iv.next(mvar) << ";"; |
4457 | o->newline() << mvar.del(idx) << ";"; | |
3a7fec94 AJ |
4458 | } |
4459 | else | |
d6d4dc4b | 4460 | o->newline(1) << iv << " = " << iv.del_next(mvar) << ";"; |
a98c930b | 4461 | |
d6d4dc4b JS |
4462 | o->newline(-1) << "} else"; |
4463 | o->newline(1) << iv << " = " << iv.next(mvar) << ";"; | |
a98c930b | 4464 | |
d6d4dc4b | 4465 | o->newline(-1) << "goto " << toplabel << ";"; |
a98c930b | 4466 | |
d6d4dc4b JS |
4467 | o->newline(-1) << breaklabel<< ":"; |
4468 | o->newline(1) << "; /* dummy statement */"; | |
4469 | o->indent(-1); | |
a98c930b | 4470 | } |
d02548c0 GH |
4471 | } |
4472 | else | |
4473 | { | |
dc09353a | 4474 | throw SEMANTIC_ERROR(_("cannot delete histogram bucket entries\n"), e->tok); |
d02548c0 | 4475 | } |
d98d459c GH |
4476 | } |
4477 | ||
4478 | ||
2b066ec1 | 4479 | void |
4383d78c | 4480 | c_unparser::visit_delete_statement (delete_statement* s) |
2b066ec1 | 4481 | { |
d98d459c GH |
4482 | delete_statement_operand_visitor dv (this); |
4483 | s->value->visit (&dv); | |
54975cd8 | 4484 | record_actions(1, s->tok); |
2b066ec1 FCE |
4485 | } |
4486 | ||
f3c26ea5 FCE |
4487 | |
4488 | void | |
4489 | c_unparser::visit_break_statement (break_statement* s) | |
4490 | { | |
f6abaa09 | 4491 | if (loop_break_labels.empty()) |
dc09353a | 4492 | throw SEMANTIC_ERROR (_("cannot 'break' outside loop"), s->tok); |
f3c26ea5 | 4493 | |
54975cd8 | 4494 | record_actions(1, s->tok, true); |
f6abaa09 | 4495 | o->newline() << "goto " << loop_break_labels.back() << ";"; |
f3c26ea5 FCE |
4496 | } |
4497 | ||
4498 | ||
4499 | void | |
4500 | c_unparser::visit_continue_statement (continue_statement* s) | |
4501 | { | |
f6abaa09 | 4502 | if (loop_continue_labels.empty()) |
dc09353a | 4503 | throw SEMANTIC_ERROR (_("cannot 'continue' outside loop"), s->tok); |
f3c26ea5 | 4504 | |
54975cd8 | 4505 | record_actions(1, s->tok, true); |
f6abaa09 | 4506 | o->newline() << "goto " << loop_continue_labels.back() << ";"; |
f3c26ea5 FCE |
4507 | } |
4508 | ||
4509 | ||
4510 | ||
2b066ec1 | 4511 | void |
4383d78c | 4512 | c_unparser::visit_literal_string (literal_string* e) |
2b066ec1 | 4513 | { |
47d349b1 | 4514 | interned_string v = e->value; |
f86db5a7 FCE |
4515 | o->line() << '"'; |
4516 | for (unsigned i=0; i<v.size(); i++) | |
72dbc915 FCE |
4517 | // NB: The backslash character is specifically passed through as is. |
4518 | // This is because our parser treats "\" as an ordinary character, not | |
4519 | // an escape sequence, leaving it to the C compiler (and this function) | |
4520 | // to treat it as such. If we were to escape it, there would be no way | |
4521 | // of generating C-level escapes from script code. | |
c4bb5be2 | 4522 | // See also print_format::components_to_string and lex_cast_qstring |
f86db5a7 FCE |
4523 | if (v[i] == '"') // or other escapeworthy characters? |
4524 | o->line() << '\\' << '"'; | |
4525 | else | |
4526 | o->line() << v[i]; | |
4527 | o->line() << '"'; | |
2b066ec1 FCE |
4528 | } |
4529 | ||
f3c26ea5 | 4530 | |
2b066ec1 | 4531 | void |
4383d78c | 4532 | c_unparser::visit_literal_number (literal_number* e) |
2b066ec1 | 4533 | { |
3a20432b FCE |
4534 | // This looks ugly, but tries to be warning-free on 32- and 64-bit |
4535 | // hosts. | |
ba4a90fd | 4536 | // NB: this needs to be signed! |
0a08ca99 FCE |
4537 | if (e->value == -9223372036854775807LL-1) // PR 5023 |
4538 | o->line() << "((int64_t)" << (unsigned long long) e->value << "ULL)"; | |
4539 | else | |
4540 | o->line() << "((int64_t)" << e->value << "LL)"; | |
2b066ec1 FCE |
4541 | } |
4542 | ||
3d3887df | 4543 | |
7d902887 FCE |
4544 | void |
4545 | c_unparser::visit_embedded_expr (embedded_expr* e) | |
4546 | { | |
0af18f5a FL |
4547 | bool has_defines = false; |
4548 | vector<vardecl*> read_defs; | |
4549 | vector<vardecl*> write_defs; | |
4550 | for (unsigned i = 0; i < session->globals.size(); i++) | |
4551 | { | |
4552 | vardecl* v = session->globals[i]; | |
8e95959e | 4553 | string name = v->unmangled_name; |
0af18f5a FL |
4554 | if (e->code.find("/* pragma:read:" + name + " */") != string::npos) |
4555 | { | |
4556 | has_defines = true; | |
4557 | c_global_read_def(v); | |
4558 | read_defs.push_back(v); | |
4559 | } | |
4560 | if (e->code.find("/* pragma:write:" + name + " */") != string::npos) | |
4561 | { | |
4562 | has_defines = true; | |
4563 | c_global_write_def(v); | |
4564 | write_defs.push_back(v); | |
4565 | } | |
4566 | } | |
4567 | ||
4568 | if (has_defines) | |
4569 | o->newline(); | |
4570 | ||
2363d2a5 DB |
4571 | o->line() << "("; |
4572 | ||
4573 | // Automatically add a call to assert_is_myproc to any code tagged with | |
4574 | // /* myproc-unprivileged */ | |
4575 | if (e->code.find ("/* myproc-unprivileged */") != string::npos) | |
58b666e3 | 4576 | o->line() << "({ assert_is_myproc(); }), "; |
2363d2a5 | 4577 | |
7d902887 FCE |
4578 | if (e->type == pe_long) |
4579 | o->line() << "((int64_t) (" << e->code << "))"; | |
4580 | else if (e->type == pe_string) | |
4581 | o->line() << "((const char *) (" << e->code << "))"; | |
4582 | else | |
dc09353a | 4583 | throw SEMANTIC_ERROR (_("expected numeric or string type"), e->tok); |
2363d2a5 DB |
4584 | |
4585 | o->line() << ")"; | |
0af18f5a FL |
4586 | |
4587 | for (vector<vardecl*>::const_iterator it = read_defs.begin(); it != read_defs.end(); ++it) | |
4588 | c_global_read_undef(*it); | |
4589 | for (vector<vardecl*>::const_iterator it = write_defs.begin(); it != write_defs.end(); ++it) | |
4590 | c_global_write_undef(*it); | |
4591 | ||
4592 | if (has_defines) | |
4593 | o->newline(); | |
7d902887 FCE |
4594 | } |
4595 | ||
4596 | ||
2b066ec1 | 4597 | void |
4383d78c | 4598 | c_unparser::visit_binary_expression (binary_expression* e) |
2b066ec1 | 4599 | { |
bb2e3076 FCE |
4600 | if (e->type != pe_long || |
4601 | e->left->type != pe_long || | |
4602 | e->right->type != pe_long) | |
dc09353a | 4603 | throw SEMANTIC_ERROR (_("expected numeric types"), e->tok); |
dff50e09 | 4604 | |
3d3887df FCE |
4605 | if (e->op == "+" || |
4606 | e->op == "-" || | |
4607 | e->op == "*" || | |
bb2e3076 FCE |
4608 | e->op == "&" || |
4609 | e->op == "|" || | |
79cd1b27 | 4610 | e->op == "^") |
3d3887df | 4611 | { |
bb2e3076 FCE |
4612 | o->line() << "(("; |
4613 | e->left->visit (this); | |
4614 | o->line() << ") " << e->op << " ("; | |
4615 | e->right->visit (this); | |
4616 | o->line() << "))"; | |
4617 | } | |
79cd1b27 ET |
4618 | else if (e->op == ">>" || |
4619 | e->op == "<<") | |
4620 | { | |
4621 | o->line() << "(("; | |
4622 | e->left->visit (this); | |
4623 | o->line() << ") " << e->op << "max(min("; | |
4624 | e->right->visit (this); | |
4625 | o->line() << ", (int64_t)64LL), (int64_t)0LL))"; // between 0 and 64 | |
4626 | } | |
bb2e3076 FCE |
4627 | else if (e->op == "/" || |
4628 | e->op == "%") | |
4629 | { | |
4630 | // % and / need a division-by-zero check; and thus two temporaries | |
4631 | // for proper evaluation order | |
313b2f74 GH |
4632 | tmpvar left = gensym (pe_long); |
4633 | tmpvar right = gensym (pe_long); | |
4634 | ||
bb2e3076 | 4635 | o->line() << "({"; |
99613db7 | 4636 | o->indent(1); |
bb2e3076 | 4637 | |
b2d74f03 JS |
4638 | c_assign (left, e->left, "division"); |
4639 | c_assign (right, e->right, "division"); | |
bb2e3076 | 4640 | |
12363146 | 4641 | o->newline() << "if (unlikely(!" << right << ")) {"; |
b5f561be LB |
4642 | o->newline(1) << "c->last_error = "; |
4643 | o->line() << STAP_T_03; | |
12363146 JS |
4644 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; |
4645 | o->newline() << "goto out;"; | |
4646 | o->newline(-1) << "}"; | |
3a20432b | 4647 | o->newline() << ((e->op == "/") ? "_stp_div64" : "_stp_mod64") |
12363146 | 4648 | << " (NULL, " << left << ", " << right << ");"; |
bb2e3076 | 4649 | |
bb2e3076 | 4650 | o->newline(-1) << "})"; |
3d3887df | 4651 | } |
3d3887df | 4652 | else |
dc09353a | 4653 | throw SEMANTIC_ERROR (_("operator not yet implemented"), e->tok); |
2b066ec1 FCE |
4654 | } |
4655 | ||
553d27a5 | 4656 | |
2b066ec1 | 4657 | void |
4383d78c | 4658 | c_unparser::visit_unary_expression (unary_expression* e) |
2b066ec1 | 4659 | { |
553d27a5 FCE |
4660 | if (e->type != pe_long || |
4661 | e->operand->type != pe_long) | |
dc09353a | 4662 | throw SEMANTIC_ERROR (_("expected numeric types"), e->tok); |
553d27a5 | 4663 | |
0a08ca99 FCE |
4664 | if (e->op == "-") |
4665 | { | |
4666 | // NB: Subtraction is special, since negative literals in the | |
4667 | // script language show up as unary negations over positive | |
4668 | // literals here. This makes it "exciting" for emitting pure | |
4669 | // C since: - 0x8000_0000_0000_0000 ==> - (- 9223372036854775808) | |
4670 | // This would constitute a signed overflow, which gcc warns on | |
4671 | // unless -ftrapv/-J are in CFLAGS - which they're not. | |
4672 | ||
4673 | o->line() << "(int64_t)(0 " << e->op << " (uint64_t)("; | |
4674 | e->operand->visit (this); | |
4675 | o->line() << "))"; | |
4676 | } | |
4677 | else | |
4678 | { | |
4679 | o->line() << "(" << e->op << " ("; | |
4680 | e->operand->visit (this); | |
4681 | o->line() << "))"; | |
4682 | } | |
2b066ec1 FCE |
4683 | } |
4684 | ||
4685 | void | |
4383d78c | 4686 | c_unparser::visit_logical_or_expr (logical_or_expr* e) |
2b066ec1 | 4687 | { |
553d27a5 FCE |
4688 | if (e->type != pe_long || |
4689 | e->left->type != pe_long || | |
4690 | e->right->type != pe_long) | |
dc09353a | 4691 | throw SEMANTIC_ERROR (_("expected numeric types"), e->tok); |
553d27a5 | 4692 | |
bb2e3076 | 4693 | o->line() << "(("; |
553d27a5 FCE |
4694 | e->left->visit (this); |
4695 | o->line() << ") " << e->op << " ("; | |
4696 | e->right->visit (this); | |
bb2e3076 | 4697 | o->line() << "))"; |
2b066ec1 FCE |
4698 | } |
4699 | ||
553d27a5 | 4700 | |
2b066ec1 | 4701 | void |
4383d78c | 4702 | c_unparser::visit_logical_and_expr (logical_and_expr* e) |
2b066ec1 | 4703 | { |
553d27a5 FCE |
4704 | if (e->type != pe_long || |
4705 | e->left->type != pe_long || | |
4706 | e->right->type != pe_long) | |
dc09353a | 4707 | throw SEMANTIC_ERROR (_("expected numeric types"), e->tok); |
553d27a5 | 4708 | |
bb2e3076 | 4709 | o->line() << "(("; |
553d27a5 FCE |
4710 | e->left->visit (this); |
4711 | o->line() << ") " << e->op << " ("; | |
4712 | e->right->visit (this); | |
bb2e3076 | 4713 | o->line() << "))"; |
2b066ec1 FCE |
4714 | } |
4715 | ||
553d27a5 | 4716 | |
2b066ec1 | 4717 | void |
4383d78c | 4718 | c_unparser::visit_array_in (array_in* e) |
2b066ec1 | 4719 | { |
dff50e09 | 4720 | symbol *array; |
d02548c0 GH |
4721 | hist_op *hist; |
4722 | classify_indexable (e->operand->base, array, hist); | |
dff50e09 | 4723 | |
d02548c0 GH |
4724 | if (array) |
4725 | { | |
dff50e09 FCE |
4726 | stmt_expr block(*this); |
4727 | ||
e225e273 | 4728 | tmpvar res = gensym (pe_long); |
d02548c0 | 4729 | vector<tmpvar> idx; |
dff50e09 | 4730 | |
e225e273 AJ |
4731 | // determine if the array index contains an asterisk |
4732 | bool array_slice = false; | |
4733 | for (unsigned i = 0; i < e->operand->indexes.size(); i ++) | |
45af9d1b | 4734 | if (e->operand->indexes[i] == NULL) |
e225e273 AJ |
4735 | { |
4736 | array_slice = true; | |
4737 | break; | |
4738 | } | |
4739 | ||
4740 | if (!array_slice) // checking for membership of a specific element | |
4741 | { | |
4742 | load_map_indices (e->operand, idx); | |
4743 | // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; | |
4744 | ||
4745 | mapvar mvar = getmap (array->referent, e->tok); | |
4746 | c_assign (res, mvar.exists(idx), e->tok); | |
4747 | ||
4748 | o->newline() << res << ";"; | |
4749 | } | |
4750 | else | |
4751 | { | |
4752 | // create tmpvars for the array indexes, storing NULL where there is | |
4753 | // no specific value that the index should be | |
4754 | vector<tmpvar *> array_slice_vars; | |
4755 | for (unsigned i=0; i<e->operand->indexes.size(); i++) | |
4756 | { | |
45af9d1b | 4757 | if (e->operand->indexes[i]) |
e225e273 | 4758 | { |
45af9d1b | 4759 | tmpvar *asvar = new tmpvar(gensym(e->operand->indexes[i]->type)); |
43ff5962 | 4760 | c_assign (*asvar, e->operand->indexes[i], "tmp var"); |
e225e273 AJ |
4761 | array_slice_vars.push_back(asvar); |
4762 | } | |
45af9d1b AJ |
4763 | else |
4764 | array_slice_vars.push_back(NULL); | |
e225e273 AJ |
4765 | } |
4766 | ||
4767 | mapvar mvar = getmap (array->referent, e->operand->tok); | |
4768 | itervar iv = getiter(array); | |
4769 | vector<tmpvar> idx; | |
4770 | ||
5306eb13 JS |
4771 | // we may not need to aggregate if we're already in a foreach |
4772 | bool pre_agg = (aggregations_active.count(mvar.value()) > 0); | |
4773 | if (mvar.is_parallel() && !pre_agg) | |
4774 | { | |
4775 | o->newline() << "if (unlikely(NULL == " | |
4776 | << mvar.calculate_aggregate() << ")) {"; | |
4777 | o->newline(1) << "c->last_error = "; | |
4778 | o->line() << STAP_T_05 << mvar << "\";"; | |
4779 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; | |
4780 | o->newline() << "goto out;"; | |
4781 | o->newline(-1) << "}"; | |
4782 | } | |
4783 | ||
e225e273 AJ |
4784 | string ctr = lex_cast (label_counter++); |
4785 | string toplabel = "top_" + ctr; | |
4786 | string contlabel = "continue_" + ctr; | |
4787 | string breaklabel = "break_" + ctr; | |
4788 | ||
4789 | o->newline() << iv << " = " << iv.start(mvar) << ";"; | |
4790 | c_assign (res, "0", e->tok); // set the default to 0 | |
4791 | ||
4792 | o->newline() << toplabel << ":"; | |
4793 | ||
4794 | o->newline(1) << "if (!(" << iv << "))"; | |
4795 | o->newline(1) << "goto " << breaklabel << ";"; | |
4796 | ||
4797 | // generate code for comparing the keys to the index slice | |
ad02fd4f | 4798 | o->newline(-1) << "if (1"; // in case all are wildcards |
e225e273 AJ |
4799 | for (unsigned i=0; i<array_slice_vars.size(); i++) |
4800 | { | |
4801 | if (array_slice_vars[i] != NULL) | |
4802 | { | |
4803 | if (array_slice_vars[i]->type() == pe_long) | |
4804 | o->line() << " && " << *array_slice_vars[i] << " == " | |
4805 | << iv.get_key(mvar, array_slice_vars[i]->type(), i); | |
4806 | else if (array_slice_vars[i]->type() == pe_string) | |
4807 | o->line() << " && strncmp(" << *array_slice_vars[i] << ", " | |
4808 | << iv.get_key(mvar, array_slice_vars[i]->type(), i) | |
4809 | << ", MAXSTRINGLEN) == 0"; | |
4810 | else | |
4811 | throw SEMANTIC_ERROR (_("unexpected type"), e->tok); | |
4812 | } | |
4813 | } | |
4814 | o->line() << "){"; | |
4815 | o->indent(1); | |
4816 | // conditional is true, so set res and go to break | |
4817 | c_assign (res, "1", e->tok); | |
4818 | o->newline() << "goto " << breaklabel << ";"; | |
4819 | o->newline(-1) << "}"; | |
4820 | ||
4821 | // else, keep iterating | |
4822 | o->newline() << iv << " = " << iv.next(mvar) << ";"; | |
4823 | o->newline() << "goto " << toplabel << ";"; | |
4824 | ||
4825 | o->newline(-1) << breaklabel<< ":"; | |
4826 | o->newline(1) << "; /* dummy statement */"; | |
4827 | o->newline(-1) << res << ";"; | |
4828 | } | |
51bf37c3 | 4829 | |
d02548c0 GH |
4830 | } |
4831 | else | |
4832 | { | |
460b2038 GH |
4833 | // By definition: |
4834 | // | |
4835 | // 'foo in @hist_op(...)' is true iff | |
4836 | // '@hist_op(...)[foo]' is nonzero | |
4837 | // | |
4838 | // so we just delegate to the latter call, since int64_t is also | |
4839 | // our boolean type. | |
4840 | e->operand->visit(this); | |
d02548c0 | 4841 | } |
2b066ec1 FCE |
4842 | } |
4843 | ||
93daaca8 SM |
4844 | void |
4845 | c_unparser::visit_regex_query (regex_query* e) | |
4846 | { | |
d2548fe7 | 4847 | o->line() << "("; |
93daaca8 | 4848 | o->indent(1); |
d2548fe7 SM |
4849 | o->newline(); |
4850 | if (e->op == "!~") o->line() << "!"; | |
47d349b1 | 4851 | stapdfa *dfa = session->dfas[e->right->value]; |
d2548fe7 | 4852 | dfa->emit_matchop_start (o); |
93daaca8 | 4853 | e->left->visit(this); |
d2548fe7 SM |
4854 | dfa->emit_matchop_end (o); |
4855 | o->newline(-1) << ")"; | |
93daaca8 | 4856 | } |
4383d78c | 4857 | |
2b066ec1 | 4858 | void |
4383d78c | 4859 | c_unparser::visit_comparison (comparison* e) |
2b066ec1 | 4860 | { |
553d27a5 FCE |
4861 | o->line() << "("; |
4862 | ||
4863 | if (e->left->type == pe_string) | |
4864 | { | |
26de79f7 | 4865 | if (e->right->type != pe_string) |
dc09353a | 4866 | throw SEMANTIC_ERROR (_("expected string types"), e->tok); |
553d27a5 | 4867 | |
c12bdeab JS |
4868 | o->line() << "({"; |
4869 | o->indent(1); | |
4870 | ||
4871 | tmpvar left = gensym (pe_string); | |
b2d74f03 | 4872 | c_assign (left, e->left, "assignment"); |
c12bdeab JS |
4873 | |
4874 | o->newline() << "strncmp (" << left << ", "; | |
553d27a5 | 4875 | e->right->visit (this); |
c12bdeab JS |
4876 | o->line() << ", MAXSTRINGLEN) " << e->op << " 0;"; |
4877 | o->newline(-1) << "})"; | |
553d27a5 FCE |
4878 | } |
4879 | else if (e->left->type == pe_long) | |
4880 | { | |
26de79f7 | 4881 | if (e->right->type != pe_long) |
dc09353a | 4882 | throw SEMANTIC_ERROR (_("expected numeric types"), e->tok); |
553d27a5 | 4883 | |
bb2e3076 | 4884 | o->line() << "(("; |
553d27a5 FCE |
4885 | e->left->visit (this); |
4886 | o->line() << ") " << e->op << " ("; | |
4887 | e->right->visit (this); | |
bb2e3076 | 4888 | o->line() << "))"; |
553d27a5 FCE |
4889 | } |
4890 | else | |
dc09353a | 4891 | throw SEMANTIC_ERROR (_("unexpected type"), e->left->tok); |
553d27a5 FCE |
4892 | |
4893 | o->line() << ")"; | |
2b066ec1 FCE |
4894 | } |
4895 | ||
4383d78c | 4896 | |
2b066ec1 | 4897 | void |
4383d78c | 4898 | c_unparser::visit_concatenation (concatenation* e) |
2b066ec1 | 4899 | { |
3d3887df | 4900 | if (e->op != ".") |
dc09353a | 4901 | throw SEMANTIC_ERROR (_("unexpected concatenation operator"), e->tok); |
3d3887df FCE |
4902 | |
4903 | if (e->type != pe_string || | |
4904 | e->left->type != pe_string || | |
4905 | e->right->type != pe_string) | |
dc09353a | 4906 | throw SEMANTIC_ERROR (_("expected string types"), e->tok); |
3d3887df | 4907 | |
313b2f74 | 4908 | tmpvar t = gensym (e->type); |
dff50e09 | 4909 | |
3d3887df FCE |
4910 | o->line() << "({ "; |
4911 | o->indent(1); | |
99613db7 | 4912 | // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; |
11b52b73 DS |
4913 | c_assign (t.value(), e->left, "assignment"); |
4914 | c_strcat (t.value(), e->right); | |
313b2f74 | 4915 | o->newline() << t << ";"; |
3d3887df | 4916 | o->newline(-1) << "})"; |
2b066ec1 FCE |
4917 | } |
4918 | ||
4383d78c | 4919 | |
2b066ec1 | 4920 | void |
4383d78c | 4921 | c_unparser::visit_ternary_expression (ternary_expression* e) |
2b066ec1 | 4922 | { |
553d27a5 | 4923 | if (e->cond->type != pe_long) |
dc09353a | 4924 | throw SEMANTIC_ERROR (_("expected numeric condition"), e->cond->tok); |
553d27a5 FCE |
4925 | |
4926 | if (e->truevalue->type != e->falsevalue->type || | |
4927 | e->type != e->truevalue->type || | |
4928 | (e->truevalue->type != pe_long && e->truevalue->type != pe_string)) | |
dc09353a | 4929 | throw SEMANTIC_ERROR (_("expected matching types"), e->tok); |
553d27a5 FCE |
4930 | |
4931 | o->line() << "(("; | |
4932 | e->cond->visit (this); | |
4933 | o->line() << ") ? ("; | |
4934 | e->truevalue->visit (this); | |
4935 | o->line() << ") : ("; | |
4936 | e->falsevalue->visit (this); | |
4937 | o->line() << "))"; | |
2b066ec1 FCE |
4938 | } |
4939 | ||
4940 | ||
2b066ec1 | 4941 | void |
4383d78c | 4942 | c_unparser::visit_assignment (assignment* e) |
2b066ec1 | 4943 | { |
57b73400 GH |
4944 | if (e->op == "<<<") |
4945 | { | |
4946 | if (e->type != pe_long) | |
dc09353a | 4947 | throw SEMANTIC_ERROR (_("non-number <<< expression"), e->tok); |
57b73400 GH |
4948 | |
4949 | if (e->left->type != pe_stats) | |
dc09353a | 4950 | throw SEMANTIC_ERROR (_("non-stats left operand to <<< expression"), e->left->tok); |
57b73400 GH |
4951 | |
4952 | if (e->right->type != pe_long) | |
dc09353a | 4953 | throw SEMANTIC_ERROR (_("non-number right operand to <<< expression"), e->right->tok); |
dff50e09 | 4954 | |
57b73400 GH |
4955 | } |
4956 | else | |
4957 | { | |
4958 | if (e->type != e->left->type) | |
dc09353a | 4959 | throw SEMANTIC_ERROR (_("type mismatch"), e->tok, e->left->tok); |
57b73400 | 4960 | if (e->right->type != e->left->type) |
dc09353a | 4961 | throw SEMANTIC_ERROR (_("type mismatch"), e->right->tok, e->left->tok); |
57b73400 | 4962 | } |
2b066ec1 | 4963 | |
bb2e3076 FCE |
4964 | c_unparser_assignment tav (this, e->op, e->right); |
4965 | e->left->visit (& tav); | |
4966 | } | |
4967 | ||
4968 | ||
bb2e3076 FCE |
4969 | void |
4970 | c_unparser::visit_pre_crement (pre_crement* e) | |
4971 | { | |
4972 | if (e->type != pe_long || | |
4973 | e->type != e->operand->type) | |
dc09353a | 4974 | throw SEMANTIC_ERROR (_("expected numeric type"), e->tok); |
bb2e3076 | 4975 | |
78110925 | 4976 | c_unparser_assignment tav (this, e->op, false); |
bb2e3076 FCE |
4977 | e->operand->visit (& tav); |
4978 | } | |
4979 | ||
4980 | ||
bb2e3076 FCE |
4981 | void |
4982 | c_unparser::visit_post_crement (post_crement* e) | |
4983 | { | |
4984 | if (e->type != pe_long || | |
4985 | e->type != e->operand->type) | |
dc09353a | 4986 | throw SEMANTIC_ERROR (_("expected numeric type"), e->tok); |
bb2e3076 | 4987 | |
78110925 | 4988 | c_unparser_assignment tav (this, e->op, true); |
bb2e3076 | 4989 | e->operand->visit (& tav); |
2b066ec1 FCE |
4990 | } |
4991 | ||
4992 | ||
4993 | void | |
4383d78c | 4994 | c_unparser::visit_symbol (symbol* e) |
2b066ec1 | 4995 | { |
ed238a16 | 4996 | assert (e->referent != 0); |
2b066ec1 FCE |
4997 | vardecl* r = e->referent; |
4998 | ||
4999 | if (r->index_types.size() != 0) | |
dc09353a | 5000 | throw SEMANTIC_ERROR (_("invalid reference to array"), e->tok); |
2b066ec1 | 5001 | |
313b2f74 GH |
5002 | var v = getvar(r, e->tok); |
5003 | o->line() << v; | |
2b066ec1 FCE |
5004 | } |
5005 | ||
5006 | ||
bb2e3076 FCE |
5007 | // Assignment expansion is tricky. |
5008 | // | |
5009 | // Because assignments are nestable expressions, we have | |
5010 | // to emit C constructs that are nestable expressions too. | |
5011 | // We have to evaluate the given expressions the proper number of times, | |
5012 | // including array indices. | |
5013 | // We have to lock the lvalue (if global) against concurrent modification, | |
5014 | // especially with modify-assignment operations (+=, ++). | |
5015 | // We have to check the rvalue (for division-by-zero checks). | |
5016 | ||
5017 | // In the normal "pre=false" case, for (A op B) emit: | |
5018 | // ({ tmp = B; check(B); lock(A); res = A op tmp; A = res; unlock(A); res; }) | |
5019 | // In the "pre=true" case, emit instead: | |
5020 | // ({ tmp = B; check(B); lock(A); res = A; A = res op tmp; unlock(A); res; }) | |
5021 | // | |
5022 | // (op is the plain operator portion of a combined calculate/assignment: | |
5023 | // "+" for "+=", and so on. It is in the "macop" variable below.) | |
5024 | // | |
5025 | // For array assignments, additional temporaries are used for each | |
5026 | // index, which are expanded before the "tmp=B" expression, in order | |
5027 | // to consistently order evaluation of lhs before rhs. | |
5028 | // | |
5029 | ||
4383d78c | 5030 | void |
47d349b1 | 5031 | c_unparser_assignment::prepare_rvalue (interned_string op, |
11b52b73 | 5032 | tmpvar & rval, |
313b2f74 | 5033 | token const * tok) |
2b066ec1 | 5034 | { |
bb2e3076 | 5035 | if (rvalue) |
b2d74f03 | 5036 | parent->c_assign (rval, rvalue, "assignment"); |
bb2e3076 FCE |
5037 | else |
5038 | { | |
5039 | if (op == "++" || op == "--") | |
11b52b73 DS |
5040 | // Here is part of the conversion proccess of turning "x++" to |
5041 | // "x += 1". | |
5042 | rval.override("1"); | |
bb2e3076 | 5043 | else |
dc09353a | 5044 | throw SEMANTIC_ERROR (_("need rvalue for assignment"), tok); |
bb2e3076 | 5045 | } |
313b2f74 | 5046 | } |
ce10591c | 5047 | |
313b2f74 GH |
5048 | void |
5049 | c_unparser_assignment::visit_symbol (symbol *e) | |
5050 | { | |
5051 | stmt_expr block(*parent); | |
d6d4dc4b | 5052 | translator_output* o = parent->o; |
bb2e3076 | 5053 | |
ed238a16 | 5054 | assert (e->referent != 0); |
313b2f74 | 5055 | if (e->referent->index_types.size() != 0) |
dc09353a | 5056 | throw SEMANTIC_ERROR (_("unexpected reference to array"), e->tok); |
bb2e3076 | 5057 | |
d6d4dc4b | 5058 | // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; |
57b73400 GH |
5059 | exp_type ty = rvalue ? rvalue->type : e->type; |
5060 | tmpvar rval = parent->gensym (ty); | |
5061 | tmpvar res = parent->gensym (ty); | |
bb2e3076 | 5062 | |
313b2f74 | 5063 | prepare_rvalue (op, rval, e->tok); |
2b066ec1 | 5064 | |
13a9593f | 5065 | var lvar = parent->getvar (e->referent, e->tok); |
dff50e09 | 5066 | c_assignop (res, lvar, rval, e->tok); |
bb2e3076 | 5067 | |
d6d4dc4b | 5068 | o->newline() << res << ";"; |
2b066ec1 FCE |
5069 | } |
5070 | ||
5071 | ||
dff50e09 | 5072 | void |
d7f3e0c5 GH |
5073 | c_unparser::visit_target_symbol (target_symbol* e) |
5074 | { | |
dc09353a | 5075 | throw SEMANTIC_ERROR(_("cannot translate general target-symbol expression"), e->tok); |
d7f3e0c5 GH |
5076 | } |
5077 | ||
5078 | ||
bd1fcbad YZ |
5079 | void |
5080 | c_unparser::visit_atvar_op (atvar_op* e) | |
5081 | { | |
dc09353a | 5082 | throw SEMANTIC_ERROR(_("cannot translate general @var expression"), e->tok); |
bd1fcbad YZ |
5083 | } |
5084 | ||
5085 | ||
9b5af295 JS |
5086 | void |
5087 | c_unparser::visit_cast_op (cast_op* e) | |
5088 | { | |
dc09353a | 5089 | throw SEMANTIC_ERROR(_("cannot translate general @cast expression"), e->tok); |
30263a73 FCE |
5090 | } |
5091 | ||
5092 | ||
251707c8 JS |
5093 | void |
5094 | c_unparser::visit_autocast_op (autocast_op* e) | |
5095 | { | |
5096 | throw SEMANTIC_ERROR(_("cannot translate general dereference expression"), e->tok); | |
5097 | } | |
5098 | ||
5099 | ||
30263a73 FCE |
5100 | void |
5101 | c_unparser::visit_defined_op (defined_op* e) | |
5102 | { | |
dc09353a | 5103 | throw SEMANTIC_ERROR(_("cannot translate general @defined expression"), e->tok); |
9b5af295 JS |
5104 | } |
5105 | ||
5106 | ||
8cc799a5 JS |
5107 | void |
5108 | c_unparser::visit_entry_op (entry_op* e) | |
5109 | { | |
dc09353a | 5110 | throw SEMANTIC_ERROR(_("cannot translate general @entry expression"), e->tok); |
8cc799a5 JS |
5111 | } |
5112 | ||
5113 | ||
3689db05 SC |
5114 | void |
5115 | c_unparser::visit_perf_op (perf_op* e) | |
5116 | { | |
dc09353a | 5117 | throw SEMANTIC_ERROR(_("cannot translate general @perf expression"), e->tok); |
3689db05 SC |
5118 | } |
5119 | ||
5120 | ||
4383d78c | 5121 | void |
313b2f74 GH |
5122 | c_unparser::load_map_indices(arrayindex *e, |
5123 | vector<tmpvar> & idx) | |
2b066ec1 | 5124 | { |
dff50e09 | 5125 | symbol *array; |
d02548c0 GH |
5126 | hist_op *hist; |
5127 | classify_indexable (e->base, array, hist); | |
313b2f74 | 5128 | |
d02548c0 | 5129 | if (array) |
313b2f74 | 5130 | { |
d02548c0 | 5131 | idx.clear(); |
dff50e09 | 5132 | |
ed238a16 | 5133 | assert (array->referent != 0); |
d02548c0 | 5134 | vardecl* r = array->referent; |
dff50e09 | 5135 | |
d02548c0 GH |
5136 | if (r->index_types.size() == 0 || |
5137 | r->index_types.size() != e->indexes.size()) | |
dc09353a | 5138 | throw SEMANTIC_ERROR (_("invalid array reference"), e->tok); |
dff50e09 | 5139 | |
d02548c0 GH |
5140 | for (unsigned i=0; i<r->index_types.size(); i++) |
5141 | { | |
5142 | if (r->index_types[i] != e->indexes[i]->type) | |
dc09353a | 5143 | throw SEMANTIC_ERROR (_("array index type mismatch"), e->indexes[i]->tok); |
dff50e09 | 5144 | |
d02548c0 | 5145 | tmpvar ix = gensym (r->index_types[i]); |
b2d74f03 | 5146 | c_assign (ix, e->indexes[i], "array index copy"); |
d02548c0 GH |
5147 | idx.push_back (ix); |
5148 | } | |
313b2f74 | 5149 | } |
d02548c0 GH |
5150 | else |
5151 | { | |
1bbeef03 GH |
5152 | assert (e->indexes.size() == 1); |
5153 | assert (e->indexes[0]->type == pe_long); | |
5154 | tmpvar ix = gensym (pe_long); | |
b2d74f03 | 5155 | c_assign (ix, e->indexes[0], "array index copy"); |
1bbeef03 | 5156 | idx.push_back(ix); |
dff50e09 | 5157 | } |
313b2f74 | 5158 | } |
bb2e3076 | 5159 | |
2b066ec1 | 5160 | |
c4782e01 JS |
5161 | var* |
5162 | c_unparser::load_aggregate (expression *e, aggvar & agg) | |
a4636912 GH |
5163 | { |
5164 | symbol *sym = get_symbol_within_expression (e); | |
dff50e09 | 5165 | |
a4636912 | 5166 | if (sym->referent->type != pe_stats) |
dc09353a | 5167 | throw SEMANTIC_ERROR (_("unexpected aggregate of non-statistic"), sym->tok); |
dff50e09 | 5168 | |
c4782e01 | 5169 | var *v; |
a4636912 GH |
5170 | if (sym->referent->arity == 0) |
5171 | { | |
c4782e01 | 5172 | v = new var(getvar(sym->referent, sym->tok)); |
99613db7 | 5173 | // o->newline() << "c->last_stmt = " << lex_cast_qstring(*sym->tok) << ";"; |
c4782e01 | 5174 | o->newline() << agg << " = _stp_stat_get (" << *v << ", 0);"; |
a4636912 GH |
5175 | } |
5176 | else | |
5177 | { | |
c4782e01 JS |
5178 | mapvar *mv = new mapvar(getmap(sym->referent, sym->tok)); |
5179 | v = mv; | |
5180 | ||
a4636912 GH |
5181 | arrayindex *arr = NULL; |
5182 | if (!expression_is_arrayindex (e, arr)) | |
dc09353a | 5183 | throw SEMANTIC_ERROR(_("unexpected aggregate of non-arrayindex"), e->tok); |
dff50e09 | 5184 | |
bdc82277 JS |
5185 | // If we have a foreach_loop value, we don't need to index the map |
5186 | string agg_value; | |
5187 | if (get_foreach_loop_value(arr, agg_value)) | |
5188 | o->newline() << agg << " = " << agg_value << ";"; | |
5189 | else | |
5190 | { | |
5191 | vector<tmpvar> idx; | |
5192 | load_map_indices (arr, idx); | |
bdc82277 | 5193 | // o->newline() << "c->last_stmt = " << lex_cast_qstring(*sym->tok) << ";"; |
c4782e01 JS |
5194 | bool pre_agg = (aggregations_active.count(mv->value()) > 0); |
5195 | o->newline() << agg << " = " << mv->get(idx, pre_agg) << ";"; | |
bdc82277 | 5196 | } |
a4636912 | 5197 | } |
c4782e01 JS |
5198 | |
5199 | return v; | |
a4636912 GH |
5200 | } |
5201 | ||
1bbeef03 | 5202 | |
dff50e09 | 5203 | string |
1bbeef03 GH |
5204 | c_unparser::histogram_index_check(var & base, tmpvar & idx) const |
5205 | { | |
11b52b73 | 5206 | return "((" + idx.value() + " >= 0)" |
dff50e09 | 5207 | + " && (" + idx.value() + " < " + base.buckets() + "))"; |
1bbeef03 GH |
5208 | } |
5209 | ||
5210 | ||
313b2f74 | 5211 | void |
d6d4dc4b | 5212 | c_unparser::visit_arrayindex (arrayindex* e) |
313b2f74 | 5213 | { |
d6d4dc4b | 5214 | // If we have a foreach_loop value, use it and call it a day! |
bdc82277 | 5215 | string ai_value; |
d6d4dc4b JS |
5216 | if (get_foreach_loop_value(e, ai_value)) |
5217 | { | |
5218 | o->line() << ai_value; | |
5219 | return; | |
5220 | } | |
bdc82277 | 5221 | |
dff50e09 | 5222 | symbol *array; |
d02548c0 GH |
5223 | hist_op *hist; |
5224 | classify_indexable (e->base, array, hist); | |
5225 | ||
5226 | if (array) | |
5227 | { | |
d6d4dc4b JS |
5228 | // Visiting an statistic-valued array in a non-lvalue context is prohibited. |
5229 | if (array->referent->type == pe_stats) | |
5230 | throw SEMANTIC_ERROR (_("statistic-valued array in rvalue context"), e->tok); | |
dff50e09 | 5231 | |
d6d4dc4b | 5232 | stmt_expr block(*this); |
dff50e09 | 5233 | |
d6d4dc4b JS |
5234 | vector<tmpvar> idx; |
5235 | load_map_indices (e, idx); | |
5236 | tmpvar res = gensym (e->type); | |
5237 | ||
5238 | mapvar mvar = getmap (array->referent, e->tok); | |
5239 | // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; | |
5240 | c_assign (res, mvar.get(idx), e->tok); | |
5241 | ||
5242 | o->newline() << res << ";"; | |
1bbeef03 GH |
5243 | } |
5244 | else | |
5245 | { | |
1bbeef03 GH |
5246 | // Note: this is a slightly tricker-than-it-looks allocation of |
5247 | // temporaries. The reason is that we're in the branch handling | |
5248 | // histogram-indexing, and the histogram might be build over an | |
5249 | // indexable entity itself. For example if we have: | |
dff50e09 | 5250 | // |
1bbeef03 GH |
5251 | // global foo |
5252 | // ... | |
5253 | // foo[getpid(), geteuid()] <<< 1 | |
5254 | // ... | |
5255 | // print @log_hist(foo[pid, euid])[bucket] | |
dff50e09 | 5256 | // |
1bbeef03 GH |
5257 | // We are looking at the @log_hist(...)[bucket] expression, so |
5258 | // allocating one tmpvar for calculating bucket (the "index" of | |
5259 | // this arrayindex expression), and one tmpvar for storing the | |
5260 | // result in, just as normal. | |
dff50e09 | 5261 | // |
1bbeef03 GH |
5262 | // But we are *also* going to call load_aggregate on foo, which |
5263 | // will itself require tmpvars for each of its indices. Since | |
5264 | // this is not handled by delving into the subexpression (it | |
5265 | // would be if hist were first-class in the type system, but | |
5266 | // it's not) we we allocate all the tmpvars used in such a | |
5267 | // subexpression up here: first our own aggvar, then our index | |
5268 | // (bucket) tmpvar, then all the index tmpvars of our | |
5269 | // pe_stat-valued subexpression, then our result. | |
5270 | ||
1bbeef03 | 5271 | assert(hist); |
dff50e09 | 5272 | stmt_expr block(*this); |
1bbeef03 | 5273 | |
d6d4dc4b | 5274 | aggvar agg = gensym_aggregate (); |
dff50e09 | 5275 | |
1bbeef03 GH |
5276 | vector<tmpvar> idx; |
5277 | load_map_indices (e, idx); | |
5278 | tmpvar res = gensym (e->type); | |
dff50e09 | 5279 | |
1bbeef03 | 5280 | // These should have faulted during elaboration if not true. |
d6d4dc4b JS |
5281 | if (idx.size() != 1 || idx[0].type() != pe_long) |
5282 | throw SEMANTIC_ERROR(_("Invalid indexing of histogram"), e->tok); | |
1bbeef03 | 5283 | |
c4782e01 | 5284 | var *v = load_aggregate(hist->stat, agg); |
1820694f | 5285 | v->assert_hist_compatible(*hist); |
1bbeef03 | 5286 | |
5db2fa89 | 5287 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; |
1bbeef03 | 5288 | |
35ba8b83 | 5289 | // PR 2142+2610: empty aggregates |
11b52b73 | 5290 | o->newline() << "if (unlikely (" << agg.value() << " == NULL)" |
12363146 | 5291 | << " || " << agg.value() << "->count == 0) {"; |
b5f561be LB |
5292 | o->newline(1) << "c->last_error = "; |
5293 | o->line() << STAP_T_06; | |
12363146 JS |
5294 | o->newline() << "goto out;"; |
5295 | o->newline(-1) << "} else {"; | |
35ba8b83 | 5296 | o->newline(1) << "if (" << histogram_index_check(*v, idx[0]) << ")"; |
5db2fa89 | 5297 | o->newline(1) << res << " = " << agg << "->histogram[" << idx[0] << "];"; |
12363146 | 5298 | o->newline(-1) << "else {"; |
b5f561be LB |
5299 | o->newline(1) << "c->last_error = "; |
5300 | o->line() << STAP_T_07; | |
12363146 JS |
5301 | o->newline() << "goto out;"; |
5302 | o->newline(-1) << "}"; | |
1820694f | 5303 | |
5db2fa89 | 5304 | o->newline(-1) << "}"; |
12363146 | 5305 | o->newline() << res << ";"; |
dff50e09 | 5306 | |
35ba8b83 | 5307 | delete v; |
d02548c0 | 5308 | } |
313b2f74 | 5309 | } |
4383d78c | 5310 | |
bb2e3076 | 5311 | |
4383d78c FCE |
5312 | void |
5313 | c_unparser_assignment::visit_arrayindex (arrayindex *e) | |
2b066ec1 | 5314 | { |
dff50e09 | 5315 | symbol *array; |
d02548c0 GH |
5316 | hist_op *hist; |
5317 | classify_indexable (e->base, array, hist); | |
313b2f74 | 5318 | |
d02548c0 GH |
5319 | if (array) |
5320 | { | |
313b2f74 | 5321 | |
dff50e09 | 5322 | stmt_expr block(*parent); |
313b2f74 | 5323 | |
d02548c0 | 5324 | translator_output *o = parent->o; |
57b73400 | 5325 | |
d02548c0 | 5326 | if (array->referent->index_types.size() == 0) |
dc09353a | 5327 | throw SEMANTIC_ERROR (_("unexpected reference to scalar"), e->tok); |
57b73400 | 5328 | |
d02548c0 GH |
5329 | vector<tmpvar> idx; |
5330 | parent->load_map_indices (e, idx); | |
5331 | exp_type ty = rvalue ? rvalue->type : e->type; | |
5332 | tmpvar rvar = parent->gensym (ty); | |
5333 | tmpvar lvar = parent->gensym (ty); | |
5334 | tmpvar res = parent->gensym (ty); | |
dff50e09 | 5335 | |
d02548c0 GH |
5336 | // NB: because these expressions are nestable, emit this construct |
5337 | // thusly: | |
5338 | // ({ tmp0=(idx0); ... tmpN=(idxN); rvar=(rhs); lvar; res; | |
5339 | // lock (array); | |
5340 | // lvar = get (array,idx0...N); // if necessary | |
5341 | // assignop (res, lvar, rvar); | |
5342 | // set (array, idx0...N, lvar); | |
5343 | // unlock (array); | |
5344 | // res; }) | |
5345 | // | |
5346 | // we store all indices in temporary variables to avoid nasty | |
5347 | // reentrancy issues that pop up with nested expressions: | |
5348 | // e.g. ++a[a[c]=5] could deadlock | |
5349 | // | |
5350 | // | |
dff50e09 | 5351 | // There is an exception to the above form: if we're doign a <<< assigment to |
d02548c0 GH |
5352 | // a statistic-valued map, there's a special form we follow: |
5353 | // | |
c01d3d3d | 5354 | // ({ tmp0=(idx0); ... tmpN=(idxN); rvar=(rhs); |
8616e84e | 5355 | // *no need to* lock (array); |
d02548c0 | 5356 | // _stp_map_add_stat (array, idx0...N, rvar); |
8616e84e | 5357 | // *no need to* unlock (array); |
d02548c0 GH |
5358 | // rvar; }) |
5359 | // | |
5360 | // To simplify variable-allocation rules, we assign rvar to lvar and | |
5361 | // res in this block as well, even though they are technically | |
5362 | // superfluous. | |
5363 | ||
5364 | prepare_rvalue (op, rvar, e->tok); | |
5365 | ||
5366 | if (op == "<<<") | |
5367 | { | |
5368 | assert (e->type == pe_stats); | |
5369 | assert (rvalue->type == pe_long); | |
5370 | ||
5371 | mapvar mvar = parent->getmap (array->referent, e->tok); | |
cd1db1dd | 5372 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; |
d02548c0 | 5373 | o->newline() << mvar.add (idx, rvar) << ";"; |
c01d3d3d FCE |
5374 | res = rvar; |
5375 | // no need for these dummy assignments | |
5376 | // o->newline() << lvar << " = " << rvar << ";"; | |
5377 | // o->newline() << res << " = " << rvar << ";"; | |
d02548c0 GH |
5378 | } |
5379 | else | |
13a9593f | 5380 | { |
d02548c0 | 5381 | mapvar mvar = parent->getmap (array->referent, e->tok); |
cd1db1dd | 5382 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; |
d02548c0 GH |
5383 | if (op != "=") // don't bother fetch slot if we will just overwrite it |
5384 | parent->c_assign (lvar, mvar.get(idx), e->tok); | |
dff50e09 | 5385 | c_assignop (res, lvar, rvar, e->tok); |
d02548c0 GH |
5386 | o->newline() << mvar.set (idx, lvar) << ";"; |
5387 | } | |
57b73400 | 5388 | |
d02548c0 | 5389 | o->newline() << res << ";"; |
dff50e09 | 5390 | } |
57b73400 | 5391 | else |
d02548c0 | 5392 | { |
dc09353a | 5393 | throw SEMANTIC_ERROR(_("cannot assign to histogram buckets"), e->tok); |
57b73400 | 5394 | } |
2b066ec1 FCE |
5395 | } |
5396 | ||
5397 | ||
4383d78c FCE |
5398 | void |
5399 | c_unparser::visit_functioncall (functioncall* e) | |
2b066ec1 | 5400 | { |
ed238a16 | 5401 | assert (e->referent != 0); |
2b066ec1 FCE |
5402 | functiondecl* r = e->referent; |
5403 | ||
5404 | if (r->formal_args.size() != e->args.size()) | |
dc09353a | 5405 | throw SEMANTIC_ERROR (_("invalid length argument list"), e->tok); |
2b066ec1 | 5406 | |
dff50e09 | 5407 | stmt_expr block(*this); |
2b066ec1 FCE |
5408 | |
5409 | // NB: we store all actual arguments in temporary variables, | |
5410 | // to avoid colliding sharing of context variables with | |
5411 | // nested function calls: f(f(f(1))) | |
5412 | ||
69c68955 | 5413 | // compute actual arguments |
313b2f74 | 5414 | vector<tmpvar> tmp; |
4383d78c | 5415 | |
2b066ec1 FCE |
5416 | for (unsigned i=0; i<e->args.size(); i++) |
5417 | { | |
313b2f74 | 5418 | tmpvar t = gensym(e->args[i]->type); |
4383d78c | 5419 | |
2b066ec1 | 5420 | if (r->formal_args[i]->type != e->args[i]->type) |
dc09353a | 5421 | throw SEMANTIC_ERROR (_("function argument type mismatch"), |
e26c2f83 | 5422 | e->args[i]->tok, r->formal_args[i]->tok); |
ce10591c | 5423 | |
e92d43e9 | 5424 | symbol *sym_out; |
b2d74f03 JS |
5425 | if (r->formal_args[i]->char_ptr_arg && e->args[i]->is_symbol(sym_out) |
5426 | && is_local(sym_out->referent, sym_out->tok)) | |
5427 | t.override(getvar(sym_out->referent, sym_out->tok).value()); | |
94603dab | 5428 | else |
b2d74f03 JS |
5429 | c_assign (t, e->args[i], |
5430 | _("function actual argument evaluation")); | |
94603dab | 5431 | tmp.push_back(t); |
2b066ec1 FCE |
5432 | } |
5433 | ||
4383d78c | 5434 | // copy in actual arguments |
2b066ec1 FCE |
5435 | for (unsigned i=0; i<e->args.size(); i++) |
5436 | { | |
5437 | if (r->formal_args[i]->type != e->args[i]->type) | |
dc09353a | 5438 | throw SEMANTIC_ERROR (_("function argument type mismatch"), |
e26c2f83 | 5439 | e->args[i]->tok, r->formal_args[i]->tok); |
ce10591c | 5440 | |
e92d43e9 AJ |
5441 | if (r->formal_args[i]->char_ptr_arg) |
5442 | o->newline() << "c->locals[c->nesting+1]." + c_funcname (r->name) + "." | |
5443 | + c_localname (r->formal_args[i]->name) << " = " | |
5444 | << tmp[i].value() << ";"; | |
5445 | else | |
5446 | c_assign ("c->locals[c->nesting+1]." + | |
5447 | c_funcname (r->name) + "." + | |
5448 | c_localname (r->formal_args[i]->name), | |
5449 | tmp[i].value(), | |
5450 | e->args[i]->type, | |
5451 | "function actual argument copy", | |
5452 | e->args[i]->tok); | |
2b066ec1 FCE |
5453 | } |
5454 | ||
6c22bc26 AJ |
5455 | // store the return value after the function arguments have been worked out |
5456 | // to avoid problems that may occure with nesting. | |
296c059b JS |
5457 | tmpvar tmp_ret = gensym (e->type); |
5458 | ||
5459 | // optimized string returns need a local storage pointer. | |
5460 | bool pointer_ret = (e->type == pe_string && !session->unoptimized); | |
5461 | if (pointer_ret) | |
5462 | { | |
5463 | if (e == assigned_functioncall) | |
5464 | tmp_ret.override (*assigned_functioncall_retval); | |
5465 | o->newline() << "c->locals[c->nesting+1]." << c_funcname(r->name) | |
5466 | << ".__retvalue = &" << tmp_ret.value() << "[0];"; | |
5467 | } | |
6c22bc26 | 5468 | |
2b066ec1 | 5469 | // call function |
0386bbcf | 5470 | o->newline() << c_funcname (r->name) << " (c);"; |
12363146 | 5471 | o->newline() << "if (unlikely(c->last_error)) goto out;"; |
bb788f9f | 5472 | |
765e6976 AJ |
5473 | if (!already_checked_action_count && !session->suppress_time_limits |
5474 | && !session->unoptimized) | |
5475 | { | |
5476 | max_action_info mai (*session); | |
5477 | e->referent->body->visit(&mai); | |
5478 | // if an unoptimized function/probe called an optimized function, then | |
5479 | // increase the counter, since the subtraction isn't done within an | |
5480 | // optimized function | |
5481 | if(mai.statement_count_finite()) | |
5482 | record_actions (mai.statement_count, e->tok, true); | |
5483 | } | |
0c5ef9de FCE |
5484 | |
5485 | // return result from retvalue slot NB: this must be last, for the | |
5486 | // enclosing statement-expression ({ ... }) to carry this value. | |
f281029c JS |
5487 | if (r->type == pe_unknown || tmp_ret.is_overridden()) |
5488 | // If we passed typechecking with pe_unknown, or if we directly assigned | |
5489 | // the functioncall retval, then nothing will use this return value | |
0c5ef9de | 5490 | o->newline() << "(void) 0;"; |
296c059b | 5491 | else if (!pointer_ret) |
0c5ef9de FCE |
5492 | o->newline() << "c->locals[c->nesting+1]" |
5493 | << "." << c_funcname (r->name) | |
5494 | << ".__retvalue;"; | |
f281029c | 5495 | else |
cfaa0635 | 5496 | o->newline() << tmp_ret.value() << ";"; |
0c5ef9de | 5497 | |
2b066ec1 FCE |
5498 | } |
5499 | ||
5b1fa53b | 5500 | |
d6fa4974 JS |
5501 | // returns true if it should print directly to a stream |
5502 | static bool | |
5b1fa53b JS |
5503 | preprocess_print_format(print_format* e, vector<tmpvar>& tmp, |
5504 | vector<print_format::format_component>& components, | |
5505 | string& format_string) | |
5506 | { | |
5b1fa53b JS |
5507 | if (e->print_with_format) |
5508 | { | |
5509 | format_string = e->raw_components; | |
5510 | components = e->components; | |
5511 | } | |
5512 | else | |
5513 | { | |
5514 | string delim; | |
5515 | if (e->print_with_delim) | |
5516 | { | |
5517 | stringstream escaped_delim; | |
d70e3afe | 5518 | interned_string dstr = e->delimiter; |
47d349b1 | 5519 | for (interned_string::const_iterator i = dstr.begin(); |
5b1fa53b JS |
5520 | i != dstr.end(); ++i) |
5521 | { | |
5522 | if (*i == '%') | |
5523 | escaped_delim << '%'; | |
5524 | escaped_delim << *i; | |
5525 | } | |
5526 | delim = escaped_delim.str(); | |
5527 | } | |
5528 | ||
5529 | // Synthesize a print-format string if the user didn't | |
5530 | // provide one; the synthetic string simply contains one | |
5531 | // directive for each argument. | |
5532 | stringstream format; | |
5533 | for (unsigned i = 0; i < e->args.size(); ++i) | |
5534 | { | |
5535 | if (i > 0 && e->print_with_delim) | |
5536 | format << delim; | |
5537 | switch (e->args[i]->type) | |
5538 | { | |
5539 | default: | |
5540 | case pe_unknown: | |
dc09353a | 5541 | throw SEMANTIC_ERROR(_("cannot print unknown expression type"), e->args[i]->tok); |
5b1fa53b | 5542 | case pe_stats: |
dc09353a | 5543 | throw SEMANTIC_ERROR(_("cannot print a raw stats object"), e->args[i]->tok); |
5b1fa53b JS |
5544 | case pe_long: |
5545 | format << "%d"; | |
5546 | break; | |
5547 | case pe_string: | |
5548 | format << "%s"; | |
5549 | break; | |
5550 | } | |
5551 | } | |
5552 | if (e->print_with_newline) | |
5553 | format << "\\n"; | |
5554 | ||
5555 | format_string = format.str(); | |
5556 | components = print_format::string_to_components(format_string); | |
5557 | } | |
5558 | ||
5559 | ||
d6fa4974 JS |
5560 | // optimize simple string prints |
5561 | if (e->print_to_stream && tmp.size() <= 1 | |
5562 | && format_string.find("%%") == string::npos) | |
5b1fa53b | 5563 | { |
d6fa4974 JS |
5564 | // just a plain format string itself, or |
5565 | // simply formatting a string verbatim. | |
5566 | if (tmp.empty() || format_string == "%s") | |
5567 | return true; | |
5568 | ||
5569 | // just a string without formatting plus newline, and it's been | |
5570 | // overridden with a literal, then we can token-paste the newline. | |
5571 | // TODO could allow any prefix and suffix around "%s", C-escaped. | |
b2d74f03 | 5572 | if (tmp[0].is_overridden() && format_string == "%s\\n") |
d6fa4974 JS |
5573 | { |
5574 | tmp[0].override(tmp[0].value() + "\"\\n\""); | |
5575 | return true; | |
5576 | } | |
5b1fa53b JS |
5577 | } |
5578 | ||
d6fa4974 | 5579 | return false; |
5b1fa53b JS |
5580 | } |
5581 | ||
d02548c0 | 5582 | |
dff50e09 | 5583 | void |
d02548c0 GH |
5584 | c_unparser::visit_print_format (print_format* e) |
5585 | { | |
5586 | // Print formats can contain a general argument list *or* a special | |
5587 | // type of argument which gets its own processing: a single, | |
5588 | // non-format-string'ed, histogram-type stat_op expression. | |
5589 | ||
a4636912 | 5590 | if (e->hist) |
d02548c0 | 5591 | { |
dff50e09 | 5592 | stmt_expr block(*this); |
a4636912 | 5593 | aggvar agg = gensym_aggregate (); |
a4636912 | 5594 | |
c4782e01 | 5595 | var *v = load_aggregate(e->hist->stat, agg); |
1820694f JS |
5596 | v->assert_hist_compatible(*e->hist); |
5597 | ||
5598 | { | |
35ba8b83 | 5599 | // PR 2142+2610: empty aggregates |
11b52b73 | 5600 | o->newline() << "if (unlikely (" << agg.value() << " == NULL)" |
99613db7 | 5601 | << " || " << agg.value() << "->count == 0) {"; |
b5f561be LB |
5602 | o->newline(1) << "c->last_error = "; |
5603 | o->line() << STAP_T_06; | |
99613db7 | 5604 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; |
12363146 | 5605 | o->newline() << "goto out;"; |
99613db7 | 5606 | o->newline(-1) << "} else"; |
b15c465c PP |
5607 | if (e->print_to_stream) |
5608 | { | |
5609 | o->newline(1) << "_stp_stat_print_histogram (" << v->hist() << ", " << agg.value() << ");"; | |
5610 | o->indent(-1); | |
5611 | } | |
5612 | else | |
5613 | { | |
5614 | exp_type ty = pe_string; | |
5615 | tmpvar res = gensym (ty); | |
5616 | o->newline(1) << "_stp_stat_print_histogram_buf (" << res.value() << ", MAXSTRINGLEN, " << v->hist() << ", " << agg.value() << ");"; | |
5617 | o->newline(-1) << res.value() << ";"; | |
5618 | } | |
1820694f JS |
5619 | } |
5620 | ||
5621 | delete v; | |
d02548c0 GH |
5622 | } |
5623 | else | |
5624 | { | |
dff50e09 | 5625 | stmt_expr block(*this); |
d02548c0 | 5626 | |
8f805d33 JS |
5627 | // PR10750: Enforce a reasonable limit on # of varargs |
5628 | // 32 varargs leads to max 256 bytes on the stack | |
5629 | if (e->args.size() > 32) | |
dc09353a | 5630 | throw SEMANTIC_ERROR(_NF("additional argument to print", "too many arguments to print (%zu)", |
52c2652f | 5631 | e->args.size(), e->args.size()), e->tok); |
8f805d33 | 5632 | |
d02548c0 GH |
5633 | // Compute actual arguments |
5634 | vector<tmpvar> tmp; | |
dff50e09 | 5635 | |
d02548c0 GH |
5636 | for (unsigned i=0; i<e->args.size(); i++) |
5637 | { | |
5638 | tmpvar t = gensym(e->args[i]->type); | |
b2d74f03 JS |
5639 | c_assign (t, e->args[i], |
5640 | "print format actual argument evaluation"); | |
d02548c0 | 5641 | tmp.push_back(t); |
d02548c0 GH |
5642 | } |
5643 | ||
d02548c0 GH |
5644 | // Allocate the result |
5645 | exp_type ty = e->print_to_stream ? pe_long : pe_string; | |
dff50e09 | 5646 | tmpvar res = gensym (ty); |
5b1fa53b JS |
5647 | |
5648 | // Munge so we can find our compiled printf | |
5649 | vector<print_format::format_component> components; | |
1386d8fc | 5650 | string format_string, format_string_out; |
d6fa4974 | 5651 | bool use_print = preprocess_print_format(e, tmp, components, format_string); |
1386d8fc | 5652 | format_string_out = print_format::components_to_string(components); |
d02548c0 | 5653 | |
12363146 | 5654 | // Make the [s]printf call... |
ec03bd4b | 5655 | |
0da35eae | 5656 | // Generate code to check that any pointer arguments are actually accessible. |
929eb962 | 5657 | size_t arg_ix = 0; |
ec03bd4b DB |
5658 | for (unsigned i = 0; i < components.size(); ++i) { |
5659 | if (components[i].type == print_format::conv_literal) | |
5660 | continue; | |
5661 | ||
5662 | /* Take note of the width and precision arguments, if any. */ | |
5663 | int width_ix = -1, prec_ix= -1; | |
5664 | if (components[i].widthtype == print_format::width_dynamic) | |
5665 | width_ix = arg_ix++; | |
5666 | if (components[i].prectype == print_format::prec_dynamic) | |
5667 | prec_ix = arg_ix++; | |
5668 | ||
5d8a0aea FCE |
5669 | (void) width_ix; /* XXX: notused */ |
5670 | ||
63db23df | 5671 | /* %m and %M need special care for digging into memory. */ |
30c94a80 | 5672 | if (components[i].type == print_format::conv_memory |
63db23df JS |
5673 | || components[i].type == print_format::conv_memory_hex) |
5674 | { | |
5675 | string mem_size; | |
54975cd8 | 5676 | const token* prec_tok = e->tok; |
63db23df | 5677 | if (prec_ix != -1) |
54975cd8 JS |
5678 | { |
5679 | mem_size = tmp[prec_ix].value(); | |
5680 | prec_tok = e->args[prec_ix]->tok; | |
5681 | } | |
63db23df JS |
5682 | else if (components[i].prectype == print_format::prec_static && |
5683 | components[i].precision > 0) | |
5684 | mem_size = lex_cast(components[i].precision) + "LL"; | |
5685 | else | |
5686 | mem_size = "1LL"; | |
5687 | ||
5688 | /* Limit how much can be printed at a time. (see also PR10490) */ | |
2ec6b38c | 5689 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*prec_tok) << ";"; |
63db23df JS |
5690 | o->newline() << "if (" << mem_size << " > 1024) {"; |
5691 | o->newline(1) << "snprintf(c->error_buffer, sizeof(c->error_buffer), " | |
060b2633 | 5692 | << "\"%lld is too many bytes for a memory dump\", (long long)" |
63db23df JS |
5693 | << mem_size << ");"; |
5694 | o->newline() << "c->last_error = c->error_buffer;"; | |
5695 | o->newline() << "goto out;"; | |
5696 | o->newline(-1) << "}"; | |
63db23df | 5697 | } |
ec03bd4b DB |
5698 | |
5699 | ++arg_ix; | |
5700 | } | |
5701 | ||
929eb962 | 5702 | // Shortcuts for cases that aren't formatted at all |
d02548c0 | 5703 | if (e->print_to_stream) |
f5334f06 | 5704 | { |
32784362 MH |
5705 | if (e->print_char) |
5706 | { | |
5707 | o->newline() << "_stp_print_char ("; | |
5708 | if (tmp.size()) | |
5709 | o->line() << tmp[0].value() << ");"; | |
5710 | else | |
1386d8fc | 5711 | o->line() << '"' << format_string_out << "\");"; |
dff50e09 | 5712 | return; |
32784362 MH |
5713 | } |
5714 | if (use_print) | |
5715 | { | |
5716 | o->newline() << "_stp_print ("; | |
5717 | if (tmp.size()) | |
5718 | o->line() << tmp[0].value() << ");"; | |
5719 | else | |
1386d8fc | 5720 | o->line() << '"' << format_string_out << "\");"; |
32784362 MH |
5721 | return; |
5722 | } | |
929eb962 JS |
5723 | } |
5724 | ||
0da35eae JS |
5725 | // The default it to use the new compiled-printf, but one can fall back |
5726 | // to the old code with -DSTP_LEGACY_PRINT if desired. | |
5727 | o->newline() << "#ifndef STP_LEGACY_PRINT"; | |
5728 | o->indent(1); | |
5729 | ||
5b1fa53b JS |
5730 | // Copy all arguments to the compiled-printf's space, then call it |
5731 | const string& compiled_printf = | |
5732 | get_compiled_printf (e->print_to_stream, format_string); | |
5733 | for (unsigned i = 0; i < tmp.size(); ++i) | |
5734 | o->newline() << "c->printf_locals." << compiled_printf | |
5735 | << ".arg" << i << " = " << tmp[i].value() << ";"; | |
929eb962 | 5736 | if (e->print_to_stream) |
5b1fa53b JS |
5737 | // We'll just hardcode the result of 0 instead of using the |
5738 | // temporary. | |
5739 | res.override("((int64_t)0LL)"); | |
5740 | else | |
5741 | o->newline() << "c->printf_locals." << compiled_printf | |
5742 | << ".__retvalue = " << res.value() << ";"; | |
5743 | o->newline() << compiled_printf << " (c);"; | |
0da35eae JS |
5744 | |
5745 | o->newline(-1) << "#else // STP_LEGACY_PRINT"; | |
5746 | o->indent(1); | |
5747 | ||
5748 | // Generate the legacy call that goes through _stp_vsnprintf. | |
5749 | if (e->print_to_stream) | |
5750 | o->newline() << "_stp_printf ("; | |
5751 | else | |
5752 | o->newline() << "_stp_snprintf (" << res.value() << ", MAXSTRINGLEN, "; | |
1386d8fc | 5753 | o->line() << '"' << format_string_out << '"'; |
0da35eae JS |
5754 | |
5755 | // Make sure arguments match the expected type of the format specifier. | |
5756 | arg_ix = 0; | |
5757 | for (unsigned i = 0; i < components.size(); ++i) | |
5758 | { | |
5759 | if (components[i].type == print_format::conv_literal) | |
5760 | continue; | |
5761 | ||
5762 | /* Cast the width and precision arguments, if any, to 'int'. */ | |
5763 | if (components[i].widthtype == print_format::width_dynamic) | |
5764 | o->line() << ", (int)" << tmp[arg_ix++].value(); | |
5765 | if (components[i].prectype == print_format::prec_dynamic) | |
5766 | o->line() << ", (int)" << tmp[arg_ix++].value(); | |
5767 | ||
5768 | /* The type of the %m argument is 'char*'. */ | |
5769 | if (components[i].type == print_format::conv_memory | |
5770 | || components[i].type == print_format::conv_memory_hex) | |
5771 | o->line() << ", (char*)(uintptr_t)" << tmp[arg_ix++].value(); | |
5772 | /* The type of the %c argument is 'int'. */ | |
5773 | else if (components[i].type == print_format::conv_char) | |
5774 | o->line() << ", (int)" << tmp[arg_ix++].value(); | |
5775 | else if (arg_ix < tmp.size()) | |
5776 | o->line() << ", " << tmp[arg_ix++].value(); | |
5777 | } | |
5778 | o->line() << ");"; | |
5779 | o->newline(-1) << "#endif // STP_LEGACY_PRINT"; | |
bcc1790f | 5780 | o->newline() << "if (unlikely(c->last_error)) goto out;"; |
11b52b73 | 5781 | o->newline() << res.value() << ";"; |
d02548c0 GH |
5782 | } |
5783 | } | |
5784 | ||
dff50e09 | 5785 | void |
d02548c0 GH |
5786 | c_unparser::visit_stat_op (stat_op* e) |
5787 | { | |
d02548c0 GH |
5788 | // Stat ops can be *applied* to two types of expression: |
5789 | // | |
dff50e09 | 5790 | // 1. An arrayindex expression on a pe_stats-valued array. |
d02548c0 | 5791 | // |
dff50e09 | 5792 | // 2. A symbol of type pe_stats. |
d02548c0 GH |
5793 | |
5794 | // FIXME: classify the expression the stat_op is being applied to, | |
5795 | // call appropriate stp_get_stat() / stp_pmap_get_stat() helper, | |
5796 | // then reach into resultant struct stat_data. | |
5797 | ||
07c17d67 GH |
5798 | // FIXME: also note that summarizing anything is expensive, and we |
5799 | // really ought to pass a timeout handler into the summary routine, | |
5800 | // check its response, possibly exit if it ran out of cycles. | |
dff50e09 | 5801 | |
07c17d67 | 5802 | { |
a4636912 | 5803 | stmt_expr block(*this); |
07c17d67 | 5804 | aggvar agg = gensym_aggregate (); |
dff50e09 | 5805 | tmpvar res = gensym (pe_long); |
c4782e01 | 5806 | var *v = load_aggregate(e->stat, agg); |
07c17d67 | 5807 | { |
35ba8b83 | 5808 | // PR 2142+2610: empty aggregates |
cb034dff JS |
5809 | if ((e->ctype == sc_count) || |
5810 | (e->ctype == sc_sum && | |
5811 | strverscmp(session->compatible.c_str(), "1.5") >= 0)) | |
35ba8b83 | 5812 | { |
11b52b73 | 5813 | o->newline() << "if (unlikely (" << agg.value() << " == NULL))"; |
35ba8b83 FCE |
5814 | o->indent(1); |
5815 | c_assign(res, "0", e->tok); | |
5816 | o->indent(-1); | |
5817 | } | |
5db2fa89 | 5818 | else |
35ba8b83 | 5819 | { |
11b52b73 | 5820 | o->newline() << "if (unlikely (" << agg.value() << " == NULL)" |
12363146 | 5821 | << " || " << agg.value() << "->count == 0) {"; |
b5f561be LB |
5822 | o->newline(1) << "c->last_error = "; |
5823 | o->line() << STAP_T_06; | |
12363146 JS |
5824 | o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; |
5825 | o->newline() << "goto out;"; | |
5826 | o->newline(-1) << "}"; | |
35ba8b83 FCE |
5827 | } |
5828 | o->newline() << "else"; | |
5db2fa89 | 5829 | o->indent(1); |
07c17d67 | 5830 | switch (e->ctype) |
35ba8b83 FCE |
5831 | { |
5832 | case sc_average: | |
12363146 | 5833 | c_assign(res, ("_stp_div64(NULL, " + agg.value() + "->sum, " |
11b52b73 | 5834 | + agg.value() + "->count)"), |
35ba8b83 FCE |
5835 | e->tok); |
5836 | break; | |
5837 | case sc_count: | |
11b52b73 | 5838 | c_assign(res, agg.value() + "->count", e->tok); |
35ba8b83 FCE |
5839 | break; |
5840 | case sc_sum: | |
11b52b73 | 5841 | c_assign(res, agg.value() + "->sum", e->tok); |
35ba8b83 FCE |
5842 | break; |
5843 | case sc_min: | |
11b52b73 | 5844 | c_assign(res, agg.value() + "->min", e->tok); |
35ba8b83 FCE |
5845 | break; |
5846 | case sc_max: | |
11b52b73 | 5847 | c_assign(res, agg.value() + "->max", e->tok); |
35ba8b83 | 5848 | break; |
fd5689dc FCE |
5849 | case sc_none: |
5850 | assert (0); // should not happen, as sc_none is only used in foreach sorts | |
35ba8b83 FCE |
5851 | } |
5852 | o->indent(-1); | |
dff50e09 | 5853 | } |
07c17d67 | 5854 | o->newline() << res << ";"; |
c4782e01 | 5855 | delete v; |
07c17d67 | 5856 | } |
d02548c0 GH |
5857 | } |
5858 | ||
5859 | ||
dff50e09 | 5860 | void |
78f6bba6 | 5861 | c_unparser::visit_hist_op (hist_op*) |
d02548c0 | 5862 | { |
07c17d67 GH |
5863 | // Hist ops can only occur in a limited set of circumstances: |
5864 | // | |
5865 | // 1. Inside an arrayindex expression, as the base referent. See | |
5866 | // c_unparser::visit_arrayindex for handling of this case. | |
5867 | // | |
5868 | // 2. Inside a foreach statement, as the base referent. See | |
5869 | // c_unparser::visit_foreach_loop for handling this case. | |
5870 | // | |
5871 | // 3. Inside a print_format expression, as the sole argument. See | |
5872 | // c_unparser::visit_print_format for handling this case. | |
5873 | // | |
5874 | // Note that none of these cases involves the c_unparser ever | |
5875 | // visiting this node. We should not get here. | |
5876 | ||
d02548c0 GH |
5877 | assert(false); |
5878 | } | |
2b066ec1 | 5879 | |
fa670082 | 5880 | |
c9970555 | 5881 | typedef map<Dwarf_Addr,const char*> addrmap_t; // NB: plain map, sorted by address |
fa670082 | 5882 | |
f5973d67 | 5883 | struct unwindsym_dump_context |
fa670082 | 5884 | { |
f5973d67 FCE |
5885 | systemtap_session& session; |
5886 | ostream& output; | |
1b94bf6d | 5887 | unsigned stp_module_index; |
c9970555 MW |
5888 | |
5889 | int build_id_len; | |
5890 | unsigned char *build_id_bits; | |
5891 | GElf_Addr build_id_vaddr; | |
5892 | ||
129de9ef | 5893 | unsigned long stp_kretprobe_trampoline_addr; |
c9970555 MW |
5894 | Dwarf_Addr stext_offset; |
5895 | ||
5896 | vector<pair<string,unsigned> > seclist; // encountered relocation bases | |
5897 | // (section names and sizes) | |
5898 | map<unsigned, addrmap_t> addrmap; // per-relocation-base sorted addrmap | |
5899 | ||
5900 | void *debug_frame; | |
5901 | size_t debug_len; | |
5902 | void *debug_frame_hdr; | |
5903 | size_t debug_frame_hdr_len; | |
5904 | Dwarf_Addr debug_frame_off; | |
5905 | void *eh_frame; | |
5906 | void *eh_frame_hdr; | |
5907 | size_t eh_len; | |
5908 | size_t eh_frame_hdr_len; | |
5909 | Dwarf_Addr eh_addr; | |
5910 | Dwarf_Addr eh_frame_hdr_addr; | |
ee533a58 AJ |
5911 | void *debug_line; |
5912 | size_t debug_line_len; | |
c9970555 | 5913 | |
4464a6bb | 5914 | set<string> undone_unwindsym_modules; |
f5973d67 FCE |
5915 | }; |
5916 | ||
9424498b MW |
5917 | static void create_debug_frame_hdr (const unsigned char e_ident[], |
5918 | Elf_Data *debug_frame, | |
5919 | void **debug_frame_hdr, | |
5920 | size_t *debug_frame_hdr_len, | |
4d83bd9b | 5921 | Dwarf_Addr *debug_frame_off, |
9424498b | 5922 | systemtap_session& session, |
4d83bd9b | 5923 | Dwfl_Module *mod) |
9424498b MW |
5924 | { |
5925 | *debug_frame_hdr = NULL; | |
5926 | *debug_frame_hdr_len = 0; | |
5927 | ||
5928 | int cies = 0; | |
5929 | set< pair<Dwarf_Addr, Dwarf_Off> > fdes; | |
5930 | set< pair<Dwarf_Addr, Dwarf_Off> >::iterator it; | |
5931 | ||
5932 | // In the .debug_frame the FDE encoding is always DW_EH_PE_absptr. | |
5933 | // So there is no need to read the CIEs. And the size is either 4 | |
5934 | // or 8, depending on the elf class from e_ident. | |
5935 | int size = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8; | |
5936 | int res = 0; | |
5937 | Dwarf_Off off = 0; | |
5938 | Dwarf_CFI_Entry entry; | |
5939 | ||
822a6a3d | 5940 | while (res != 1) |
9424498b MW |
5941 | { |
5942 | Dwarf_Off next_off; | |
5943 | res = dwarf_next_cfi (e_ident, debug_frame, false, off, &next_off, | |
5944 | &entry); | |
5945 | if (res == 0) | |
5946 | { | |
5947 | if (entry.CIE_id == DW_CIE_ID_64) | |
5948 | cies++; // We can just ignore the CIEs. | |
5949 | else | |
5950 | { | |
5951 | Dwarf_Addr addr; | |
5952 | if (size == 4) | |
5953 | addr = (*((uint32_t *) entry.fde.start)); | |
5954 | else | |
5955 | addr = (*((uint64_t *) entry.fde.start)); | |
5956 | fdes.insert(pair<Dwarf_Addr, Dwarf_Off>(addr, off)); | |
5957 | } | |
5958 | } | |
5959 | else if (res > 0) | |
5960 | ; // Great, all done. | |
5961 | else | |
5962 | { | |
5963 | // Warn, but continue, backtracing will be slow... | |
5964 | if (session.verbose > 2 && ! session.suppress_warnings) | |
4d83bd9b MW |
5965 | { |
5966 | const char *modname = dwfl_module_info (mod, NULL, | |
5967 | NULL, NULL, NULL, | |
5968 | NULL, NULL, NULL); | |
5969 | session.print_warning("Problem creating debug frame hdr for " | |
5970 | + lex_cast_qstring(modname) | |
5971 | + ", " + dwarf_errmsg (-1)); | |
5972 | } | |
9424498b MW |
5973 | return; |
5974 | } | |
5975 | off = next_off; | |
5976 | } | |
5977 | ||
4d83bd9b MW |
5978 | if (fdes.size() > 0) |
5979 | { | |
5980 | it = fdes.begin(); | |
5981 | Dwarf_Addr first_addr = (*it).first; | |
5982 | int res = dwfl_module_relocate_address (mod, &first_addr); | |
e1c3b13a | 5983 | DWFL_ASSERT ("create_debug_frame_hdr, dwfl_module_relocate_address", |
4d83bd9b MW |
5984 | res >= 0); |
5985 | *debug_frame_off = (*it).first - first_addr; | |
5986 | } | |
5987 | ||
9424498b MW |
5988 | size_t total_size = 4 + (2 * size) + (2 * size * fdes.size()); |
5989 | uint8_t *hdr = (uint8_t *) malloc(total_size); | |
5990 | *debug_frame_hdr = hdr; | |
5991 | *debug_frame_hdr_len = total_size; | |
5992 | ||
5993 | hdr[0] = 1; // version | |
5994 | hdr[1] = DW_EH_PE_absptr; // ptr encoding | |
5995 | hdr[2] = (size == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8; // count encoding | |
5996 | hdr[3] = DW_EH_PE_absptr; // table encoding | |
5997 | if (size == 4) | |
5998 | { | |
5999 | uint32_t *table = (uint32_t *)(hdr + 4); | |
6000 | *table++ = (uint32_t) 0; // eh_frame_ptr, unused | |
6001 | *table++ = (uint32_t) fdes.size(); | |
6002 | for (it = fdes.begin(); it != fdes.end(); it++) | |
6003 | { | |
6004 | *table++ = (*it).first; | |
6005 | *table++ = (*it).second; | |
6006 | } | |
6007 | } | |
6008 | else | |
6009 | { | |
6010 | uint64_t *table = (uint64_t *)(hdr + 4); | |
6011 | *table++ = (uint64_t) 0; // eh_frame_ptr, unused | |
6012 | *table++ = (uint64_t) fdes.size(); | |
6013 | for (it = fdes.begin(); it != fdes.end(); it++) | |
6014 | { | |
6015 | *table++ = (*it).first; | |
6016 | *table++ = (*it).second; | |
6017 | } | |
6018 | } | |
6019 | } | |
6020 | ||
081b45d1 MW |
6021 | static set<string> vdso_paths; |
6022 | ||
4285dc9a MW |
6023 | // Get the .debug_frame end .eh_frame sections for the given module. |
6024 | // Also returns the lenght of both sections when found, plus the section | |
9424498b MW |
6025 | // address (offset) of the eh_frame data. If a debug_frame is found, a |
6026 | // synthesized debug_frame_hdr is also returned. | |
4285dc9a MW |
6027 | static void get_unwind_data (Dwfl_Module *m, |
6028 | void **debug_frame, void **eh_frame, | |
6029 | size_t *debug_len, size_t *eh_len, | |
0f33053e | 6030 | Dwarf_Addr *eh_addr, |
9424498b MW |
6031 | void **eh_frame_hdr, size_t *eh_frame_hdr_len, |
6032 | void **debug_frame_hdr, | |
6033 | size_t *debug_frame_hdr_len, | |
4d83bd9b | 6034 | Dwarf_Addr *debug_frame_off, |
9424498b | 6035 | Dwarf_Addr *eh_frame_hdr_addr, |
c9970555 | 6036 | systemtap_session& session) |
61a80584 | 6037 | { |
c65358e8 | 6038 | Dwarf_Addr start, bias = 0; |
61a80584 MW |
6039 | GElf_Ehdr *ehdr, ehdr_mem; |
6040 | GElf_Shdr *shdr, shdr_mem; | |
4285dc9a | 6041 | Elf_Scn *scn; |
6b65ca81 | 6042 | Elf_Data *data = NULL; |
4285dc9a MW |
6043 | Elf *elf; |
6044 | ||
6045 | // fetch .eh_frame info preferably from main elf file. | |
e9068f4d | 6046 | dwfl_module_info (m, NULL, &start, NULL, NULL, NULL, NULL, NULL); |
4285dc9a MW |
6047 | elf = dwfl_module_getelf(m, &bias); |
6048 | ehdr = gelf_getehdr(elf, &ehdr_mem); | |
081b45d1 | 6049 | |
4285dc9a | 6050 | scn = NULL; |
ef187c96 CM |
6051 | bool eh_frame_seen = false; |
6052 | bool eh_frame_hdr_seen = false; | |
4285dc9a | 6053 | while ((scn = elf_nextscn(elf, scn))) |
61a80584 | 6054 | { |
4285dc9a | 6055 | shdr = gelf_getshdr(scn, &shdr_mem); |
0f33053e | 6056 | const char* scn_name = elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name); |
9cc3e70c MW |
6057 | if (!eh_frame_seen |
6058 | && strcmp(scn_name, ".eh_frame") == 0 | |
6059 | && shdr->sh_type == SHT_PROGBITS) | |
61a80584 | 6060 | { |
4285dc9a MW |
6061 | data = elf_rawdata(scn, NULL); |
6062 | *eh_frame = data->d_buf; | |
6063 | *eh_len = data->d_size; | |
c65358e8 | 6064 | // For ".dynamic" sections we want the offset, not absolute addr. |
c3999423 MW |
6065 | // Note we don't trust dwfl_module_relocations() for ET_EXEC. |
6066 | if (ehdr->e_type != ET_EXEC && dwfl_module_relocations (m) > 0) | |
c65358e8 MW |
6067 | *eh_addr = shdr->sh_addr - start + bias; |
6068 | else | |
6069 | *eh_addr = shdr->sh_addr; | |
0f33053e | 6070 | eh_frame_seen = true; |
61a80584 | 6071 | } |
9cc3e70c MW |
6072 | else if (!eh_frame_hdr_seen |
6073 | && strcmp(scn_name, ".eh_frame_hdr") == 0 | |
6074 | && shdr->sh_type == SHT_PROGBITS) | |
0f33053e TM |
6075 | { |
6076 | data = elf_rawdata(scn, NULL); | |
6077 | *eh_frame_hdr = data->d_buf; | |
6078 | *eh_frame_hdr_len = data->d_size; | |
c3999423 | 6079 | if (ehdr->e_type != ET_EXEC && dwfl_module_relocations (m) > 0) |
0f33053e TM |
6080 | *eh_frame_hdr_addr = shdr->sh_addr - start + bias; |
6081 | else | |
6082 | *eh_frame_hdr_addr = shdr->sh_addr; | |
6083 | eh_frame_hdr_seen = true; | |
6084 | } | |
6085 | if (eh_frame_seen && eh_frame_hdr_seen) | |
6086 | break; | |
61a80584 MW |
6087 | } |
6088 | ||
4285dc9a MW |
6089 | // fetch .debug_frame info preferably from dwarf debuginfo file. |
6090 | elf = (dwarf_getelf (dwfl_module_getdwarf (m, &bias)) | |
6091 | ?: dwfl_module_getelf (m, &bias)); | |
6092 | ehdr = gelf_getehdr(elf, &ehdr_mem); | |
6093 | scn = NULL; | |
6094 | while ((scn = elf_nextscn(elf, scn))) | |
61a80584 | 6095 | { |
4285dc9a MW |
6096 | shdr = gelf_getshdr(scn, &shdr_mem); |
6097 | if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name), | |
6098 | ".debug_frame") == 0) | |
6099 | { | |
6100 | data = elf_rawdata(scn, NULL); | |
6101 | *debug_frame = data->d_buf; | |
6102 | *debug_len = data->d_size; | |
6103 | break; | |
6104 | } | |
61a80584 | 6105 | } |
9424498b MW |
6106 | |
6107 | if (*debug_frame != NULL && *debug_len > 0) | |
6108 | create_debug_frame_hdr (ehdr->e_ident, data, | |
6109 | debug_frame_hdr, debug_frame_hdr_len, | |
c9970555 | 6110 | debug_frame_off, session, m); |
61a80584 MW |
6111 | } |
6112 | ||
fa670082 | 6113 | static int |
c9970555 MW |
6114 | dump_build_id (Dwfl_Module *m, |
6115 | unwindsym_dump_context *c, | |
dabd71bb | 6116 | const char *name, Dwarf_Addr) |
fa670082 | 6117 | { |
f5973d67 FCE |
6118 | string modname = name; |
6119 | ||
29495972 WH |
6120 | //extract build-id from debuginfo file |
6121 | int build_id_len = 0; | |
6122 | unsigned char *build_id_bits; | |
6123 | GElf_Addr build_id_vaddr; | |
6124 | ||
6125 | if ((build_id_len=dwfl_module_build_id(m, | |
6126 | (const unsigned char **)&build_id_bits, | |
6127 | &build_id_vaddr)) > 0) | |
6128 | { | |
155bb07a | 6129 | if (modname != "kernel") |
77123275 FCE |
6130 | { |
6131 | Dwarf_Addr reloc_vaddr = build_id_vaddr; | |
6132 | const char *secname; | |
6133 | int i; | |
71fa1fe3 | 6134 | |
77123275 | 6135 | i = dwfl_module_relocate_address (m, &reloc_vaddr); |
e1c3b13a | 6136 | DWFL_ASSERT ("dwfl_module_relocate_address reloc_vaddr", i >= 0); |
71fa1fe3 | 6137 | |
77123275 | 6138 | secname = dwfl_module_relocation_info (m, i, NULL); |
71fa1fe3 | 6139 | |
77123275 | 6140 | // assert same section name as in runtime/transport/symbols.c |
1f6e8810 FCE |
6141 | // NB: this is applicable only to module("...") probes. |
6142 | // process("...") ones may have relocation bases like '.dynamic', | |
6143 | // and so we'll have to store not just a generic offset but | |
6144 | // the relocation section/symbol name too: just like we do | |
155bb07a SC |
6145 | // for probe PC addresses themselves. We want to set build_id_vaddr for |
6146 | // user modules even though they will not have a secname. | |
6147 | ||
6148 | if (modname[0] != '/') | |
6149 | if (!secname || strcmp(secname, ".note.gnu.build-id")) | |
dc09353a | 6150 | throw SEMANTIC_ERROR (_("unexpected build-id reloc section ") + |
155bb07a | 6151 | string(secname ?: "null")); |
77123275 FCE |
6152 | |
6153 | build_id_vaddr = reloc_vaddr; | |
6154 | } | |
71fa1fe3 | 6155 | |
1bb61ae1 MW |
6156 | if (c->session.verbose > 1) |
6157 | { | |
2a97f50b | 6158 | clog << _F("Found build-id in %s, length %d, start at %#" PRIx64, |
1e41115c | 6159 | name, build_id_len, build_id_vaddr) << endl; |
1bb61ae1 | 6160 | } |
c9970555 MW |
6161 | |
6162 | c->build_id_len = build_id_len; | |
6163 | c->build_id_vaddr = build_id_vaddr; | |
6164 | c->build_id_bits = build_id_bits; | |
29495972 WH |
6165 | } |
6166 | ||
c9970555 MW |
6167 | return DWARF_CB_OK; |
6168 | } | |
6169 | ||
6170 | static int | |
59218439 MW |
6171 | dump_section_list (Dwfl_Module *m, |
6172 | unwindsym_dump_context *c, | |
dabd71bb | 6173 | const char *name, Dwarf_Addr) |
59218439 MW |
6174 | { |
6175 | // Depending on ELF section names normally means you are doing it WRONG. | |
6176 | // Sadly it seems we do need it for the kernel modules. Which are ET_REL | |
6177 | // files, which are "dynamically loaded" by the kernel. We keep a section | |
6178 | // list for them to know which symbol corresponds to which section. | |
6179 | // | |
6180 | // Luckily for the kernel, normal executables (ET_EXEC) or shared | |
6181 | // libraries (ET_DYN) we don't need it. We just have one "section", | |
6182 | // which we will just give the arbitrary names "_stext", ".absolute" | |
6183 | // or ".dynamic" | |
c9970555 | 6184 | |
59218439 | 6185 | string modname = name; |
c9970555 | 6186 | |
59218439 MW |
6187 | // Use start and end as to calculate size for _stext, .dynamic and |
6188 | // .absolute sections. | |
60ad8eba | 6189 | Dwarf_Addr start, end; |
c9970555 | 6190 | dwfl_module_info (m, NULL, &start, &end, NULL, NULL, NULL, NULL); |
d6377d44 | 6191 | |
1b94bf6d FCE |
6192 | // Look up the relocation basis for symbols |
6193 | int n = dwfl_module_relocations (m); | |
e1c3b13a | 6194 | DWFL_ASSERT ("dwfl_module_relocations", n >= 0); |
59218439 MW |
6195 | |
6196 | if (n == 0) | |
6197 | { | |
6198 | // ET_EXEC, no relocations. | |
6199 | string secname = ".absolute"; | |
6200 | unsigned size = end - start; | |
6201 | c->seclist.push_back (make_pair (secname, size)); | |
6202 | return DWARF_CB_OK; | |
6203 | } | |
6204 | else if (n == 1) | |
6205 | { | |
6206 | // kernel or shared library (ET_DYN). | |
6207 | string secname; | |
6208 | secname = (modname == "kernel") ? "_stext" : ".dynamic"; | |
6209 | unsigned size = end - start; | |
6210 | c->seclist.push_back (make_pair (secname, size)); | |
6211 | return DWARF_CB_OK; | |
6212 | } | |
6213 | else if (n > 1) | |
6214 | { | |
6215 | // ET_REL, kernel module. | |
6216 | string secname; | |
6217 | unsigned size; | |
6218 | Dwarf_Addr bias; | |
6219 | GElf_Ehdr *ehdr, ehdr_mem; | |
6220 | GElf_Shdr *shdr, shdr_mem; | |
6221 | Elf *elf = dwfl_module_getelf(m, &bias); | |
6222 | ehdr = gelf_getehdr(elf, &ehdr_mem); | |
6223 | Elf_Scn *scn = NULL; | |
6224 | while ((scn = elf_nextscn(elf, scn))) | |
6225 | { | |
6226 | // Just the "normal" sections with program bits please. | |
6227 | shdr = gelf_getshdr(scn, &shdr_mem); | |
6228 | if ((shdr->sh_type == SHT_PROGBITS || shdr->sh_type == SHT_NOBITS) | |
6229 | && (shdr->sh_flags & SHF_ALLOC)) | |
6230 | { | |
6231 | size = shdr->sh_size; | |
6232 | const char* scn_name = elf_strptr(elf, ehdr->e_shstrndx, | |
6233 | shdr->sh_name); | |
6234 | secname = scn_name; | |
6235 | c->seclist.push_back (make_pair (secname, size)); | |
6236 | } | |
6237 | } | |
6238 | ||
6239 | return DWARF_CB_OK; | |
6240 | } | |
6241 | ||
6242 | // Impossible... dflw_assert above will have triggered. | |
6243 | return DWARF_CB_ABORT; | |
6244 | } | |
6245 | ||
51816238 AJ |
6246 | static void find_debug_frame_offset (Dwfl_Module *m, |
6247 | unwindsym_dump_context *c) | |
6248 | { | |
6249 | Dwarf_Addr start, bias = 0; | |
6250 | GElf_Ehdr *ehdr, ehdr_mem; | |
6251 | GElf_Shdr *shdr, shdr_mem; | |
6252 | Elf_Scn *scn = NULL; | |
6253 | Elf_Data *data = NULL; | |
6254 | Elf *elf; | |
6255 | ||
6256 | dwfl_module_info (m, NULL, &start, NULL, NULL, NULL, NULL, NULL); | |
6257 | ||
6258 | // fetch .debug_frame info preferably from dwarf debuginfo file. | |
6259 | elf = (dwarf_getelf (dwfl_module_getdwarf (m, &bias)) | |
6260 | ?: dwfl_module_getelf (m, &bias)); | |
6261 | ehdr = gelf_getehdr(elf, &ehdr_mem); | |
6262 | ||
6263 | while ((scn = elf_nextscn(elf, scn))) | |
6264 | { | |
6265 | shdr = gelf_getshdr(scn, &shdr_mem); | |
6266 | if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name), | |
6267 | ".debug_frame") == 0) | |
6268 | { | |
6269 | data = elf_rawdata(scn, NULL); | |
6270 | break; | |
6271 | } | |
6272 | } | |
6273 | ||
6274 | if (!data) // need this check since dwarf_next_cfi() doesn't do it | |
6275 | return; | |
6276 | ||
6277 | // In the .debug_frame the FDE encoding is always DW_EH_PE_absptr. | |
6278 | // So there is no need to read the CIEs. And the size is either 4 | |
6279 | // or 8, depending on the elf class from e_ident. | |
6280 | int size = (ehdr->e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8; | |
6281 | int res = 0; | |
6282 | Dwarf_Off off = 0; | |
6283 | Dwarf_CFI_Entry entry; | |
6284 | ||
6285 | while (res != 1) | |
6286 | { | |
6287 | Dwarf_Off next_off; | |
6288 | res = dwarf_next_cfi (ehdr->e_ident, data, false, off, &next_off, &entry); | |
6289 | if (res == 0) | |
6290 | { | |
6291 | if (entry.CIE_id != DW_CIE_ID_64) // ignore CIEs | |
6292 | { | |
6293 | Dwarf_Addr addr; | |
6294 | if (size == 4) | |
6295 | addr = (*((uint32_t *) entry.fde.start)); | |
6296 | else | |
6297 | addr = (*((uint64_t *) entry.fde.start)); | |
6298 | Dwarf_Addr first_addr = addr; | |
6299 | int res = dwfl_module_relocate_address (m, &first_addr); | |
6300 | DWFL_ASSERT ("find_debug_frame_offset, dwfl_module_relocate_address", | |
6301 | res >= 0); | |
6302 | c->debug_frame_off = addr - first_addr; | |
6303 | } | |
6304 | } | |
6305 | else if (res < 1) | |
6306 | return; | |
6307 | off = next_off; | |
6308 | } | |
6309 | } | |
6310 | ||
b8c579fb AJ |
6311 | static int |
6312 | dump_line_tables_check (void *data, size_t data_len) | |
6313 | { | |
6314 | uint64_t unit_length = 0, header_length = 0; | |
6315 | uint16_t version = 0; | |
b4bbee91 | 6316 | uint8_t *ptr = (uint8_t *)data, *endunitptr, opcode_base = 0; |
b8c579fb AJ |
6317 | unsigned length = 4; |
6318 | ||
b4bbee91 AJ |
6319 | while (ptr < ((uint8_t *)data + data_len)) |
6320 | { | |
5160c6f2 | 6321 | if (ptr + 4 > (uint8_t *)data + data_len) |
b8c579fb | 6322 | return DWARF_CB_ABORT; |
b8c579fb | 6323 | |
b4bbee91 | 6324 | unit_length = *((uint32_t *) ptr); |
b4bbee91 AJ |
6325 | ptr += 4; |
6326 | if (unit_length == 0xffffffff) | |
6327 | { | |
992b2254 | 6328 | if (ptr + 8 > (uint8_t *)data + data_len) |
b4bbee91 AJ |
6329 | return DWARF_CB_ABORT; |
6330 | length = 8; | |
6331 | unit_length = *((uint64_t *) ptr); | |
6332 | ptr += 8; | |
6333 | } | |
b8c579fb | 6334 | |
992b2254 | 6335 | if ((ptr + unit_length > (uint8_t *)data + data_len) || unit_length <= 2) |
b4bbee91 | 6336 | return DWARF_CB_ABORT; |
b8c579fb | 6337 | |
b4bbee91 | 6338 | endunitptr = ptr + unit_length; |
b8c579fb | 6339 | |
b4bbee91 AJ |
6340 | version = *((uint16_t *)ptr); |
6341 | ptr += 2; | |
b8c579fb | 6342 | |
b4bbee91 AJ |
6343 | if (unit_length <= (2 + length)) |
6344 | return DWARF_CB_ABORT; | |
b8c579fb | 6345 | |
b4bbee91 AJ |
6346 | if (length == 4) |
6347 | { | |
6348 | header_length = *((uint32_t *) ptr); | |
6349 | ptr += 4; | |
6350 | } | |
6351 | else | |
6352 | { | |
6353 | header_length = *((uint64_t *) ptr); | |
6354 | ptr += 8; | |
6355 | } | |
b8c579fb | 6356 | |
b4bbee91 AJ |
6357 | // safety check for the next few jumps |
6358 | if (header_length <= ((version >= 4 ? 5 : 4) + 2) | |
6359 | || (unit_length - (2 + length) < header_length)) | |
6360 | return DWARF_CB_ABORT; | |
6361 | ||
6362 | // skip past min instr length, max ops per instr, and line base | |
6363 | if (version >= 4) | |
6364 | ptr += 3; | |
6365 | else | |
6366 | ptr += 2; | |
b8c579fb | 6367 | |
b4bbee91 AJ |
6368 | // check that the line range is not 0 |
6369 | if (*ptr == 0) | |
6370 | return DWARF_CB_ABORT; | |
6371 | ptr++; | |
b8c579fb | 6372 | |
b4bbee91 AJ |
6373 | // check that the header accomodates the std opcode lens section |
6374 | opcode_base = *((uint8_t *) ptr); | |
6375 | if (header_length <= (uint64_t) (opcode_base + (version >= 4 ? 7 : 6))) | |
6376 | return DWARF_CB_ABORT; | |
b8c579fb | 6377 | |
b4bbee91 AJ |
6378 | // the initial checks stop here, before the directory table |
6379 | ptr = endunitptr; | |
6380 | } | |
b8c579fb AJ |
6381 | return DWARF_CB_OK; |
6382 | } | |
6383 | ||
ee533a58 AJ |
6384 | static void |
6385 | dump_line_tables (Dwfl_Module *m, unwindsym_dump_context *c, | |
dabd71bb | 6386 | const char *, Dwarf_Addr) |
ee533a58 AJ |
6387 | { |
6388 | Elf* elf; | |
6389 | Elf_Scn* scn = NULL; | |
6390 | Elf_Data* data; | |
6391 | GElf_Ehdr *ehdr, ehdr_mem; | |
6392 | GElf_Shdr* shdr, shdr_mem; | |
6393 | Dwarf_Addr bias, start; | |
6394 | ||
6395 | dwfl_module_info (m, NULL, &start, NULL, NULL, NULL, NULL, NULL); | |
6396 | ||
6397 | elf = dwfl_module_getelf (m, &bias); | |
6398 | if (elf == NULL) | |
6399 | return; | |
6400 | ||
6401 | // we do not have the index for debug_line, so we can't use elf_getscn() | |
6402 | // instead, we need to seach through the sections for the correct one as in | |
6403 | // get_unwind_data() | |
6404 | ehdr = gelf_getehdr(elf, &ehdr_mem); | |
6405 | while ((scn = elf_nextscn(elf, scn))) | |
6406 | { | |
6407 | shdr = gelf_getshdr(scn, &shdr_mem); | |
6408 | if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name), | |
6409 | ".debug_line") == 0) | |
6410 | { | |
6411 | data = elf_rawdata(scn, NULL); | |
b8c579fb AJ |
6412 | if (dump_line_tables_check(data->d_buf, data->d_size) == DWARF_CB_ABORT) |
6413 | return; | |
ee533a58 AJ |
6414 | c->debug_line = data->d_buf; |
6415 | c->debug_line_len = data->d_size; | |
6416 | break; | |
6417 | } | |
6418 | } | |
51816238 AJ |
6419 | |
6420 | // still need to get some kind of information about the sec_load_offset for | |
6421 | // kernel addresses if there is no unwind data | |
6422 | if (c->debug_line_len > 0 && !c->session.need_unwind) | |
6423 | find_debug_frame_offset (m, c); | |
ee533a58 AJ |
6424 | } |
6425 | ||
15c110ee MW |
6426 | /* Some architectures create special local symbols that are not |
6427 | interesting. */ | |
6428 | static int | |
6429 | skippable_arch_symbol (GElf_Half e_machine, const char *name, GElf_Sym *sym) | |
6430 | { | |
6431 | /* Filter out ARM mapping symbols */ | |
6432 | if (e_machine == EM_ARM | |
6433 | && GELF_ST_TYPE (sym->st_info) == STT_NOTYPE | |
6434 | && (! strcmp(name, "$a") || ! strcmp(name, "$t") | |
6435 | || ! strcmp(name, "$t.x") || ! strcmp(name, "$d") | |
6436 | || ! strcmp(name, "$v") || ! strcmp(name, "$d.realdata"))) | |
6437 | return 1; | |
6438 | ||
6439 | return 0; | |
6440 | } | |
6441 | ||
59218439 MW |
6442 | static int |
6443 | dump_symbol_tables (Dwfl_Module *m, | |
6444 | unwindsym_dump_context *c, | |
6445 | const char *modname, Dwarf_Addr base) | |
6446 | { | |
6447 | // Use end as sanity check when resolving symbol addresses. | |
6448 | Dwarf_Addr end; | |
6449 | dwfl_module_info (m, NULL, NULL, &end, NULL, NULL, NULL, NULL); | |
2c9438e3 | 6450 | |
59218439 | 6451 | int syments = dwfl_module_getsymtab(m); |
e1c3b13a | 6452 | DWFL_ASSERT (_F("Getting symbol table for %s", modname), syments >= 0); |
59218439 MW |
6453 | |
6454 | // Look up the relocation basis for symbols | |
6455 | int n = dwfl_module_relocations (m); | |
e1c3b13a | 6456 | DWFL_ASSERT ("dwfl_module_relocations", n >= 0); |
1b94bf6d | 6457 | |
a09fc5a4 MW |
6458 | /* Needed on ppc64, for function descriptors. */ |
6459 | Dwarf_Addr elf_bias; | |
6460 | GElf_Ehdr *ehdr, ehdr_mem; | |
6461 | Elf *elf; | |
6462 | elf = dwfl_module_getelf(m, &elf_bias); | |
6463 | ehdr = gelf_getehdr(elf, &ehdr_mem); | |
6464 | ||
1b94bf6d FCE |
6465 | // XXX: unfortunate duplication with tapsets.cxx:emit_address() |
6466 | ||
59218439 | 6467 | // extra_offset is for the special kernel case. |
1b94bf6d | 6468 | Dwarf_Addr extra_offset = 0; |
59218439 MW |
6469 | Dwarf_Addr kretprobe_trampoline_addr = (unsigned long) -1; |
6470 | int is_kernel = !strcmp(modname, "kernel"); | |
dff50e09 | 6471 | |
59218439 MW |
6472 | /* Set to bail early if we are just examining the kernel |
6473 | and don't need anything more. */ | |
6474 | int done = 0; | |
6475 | for (int i = 0; i < syments && !done; ++i) | |
fa670082 | 6476 | { |
ebc08b50 FCE |
6477 | if (pending_interrupts) |
6478 | return DWARF_CB_ABORT; | |
6479 | ||
fa670082 | 6480 | GElf_Sym sym; |
d6377d44 | 6481 | GElf_Word shndxp; |
ebc08b50 | 6482 | |
d6377d44 | 6483 | const char *name = dwfl_module_getsym(m, i, &sym, &shndxp); |
f5973d67 | 6484 | if (name) |
dff50e09 | 6485 | { |
59218439 MW |
6486 | Dwarf_Addr sym_addr = sym.st_value; |
6487 | ||
6488 | // We always need two special values from the kernel. | |
6489 | // _stext for extra_offset and kretprobe_trampoline_holder | |
6490 | // for the unwinder. | |
6491 | if (is_kernel) | |
6492 | { | |
6493 | // NB: Yey, we found the kernel's _stext value. | |
6494 | // Sess.sym_stext may be unset (0) at this point, since | |
6495 | // there may have been no kernel probes set. We could | |
6496 | // use tapsets.cxx:lookup_symbol_address(), but then | |
6497 | // we're already iterating over the same data here... | |
ea15e536 | 6498 | if (! strcmp(name, KERNEL_RELOC_SYMBOL)) |
59218439 MW |
6499 | { |
6500 | int ki; | |
6501 | extra_offset = sym_addr; | |
6502 | ki = dwfl_module_relocate_address (m, &extra_offset); | |
e1c3b13a | 6503 | DWFL_ASSERT ("dwfl_module_relocate_address extra_offset", |
59218439 MW |
6504 | ki >= 0); |
6505 | ||
6506 | if (c->session.verbose > 2) | |
6507 | clog << _F("Found kernel _stext extra offset %#" PRIx64, | |
6508 | extra_offset) << endl; | |
6509 | ||
6510 | if (! c->session.need_symbols | |
6511 | && (kretprobe_trampoline_addr != (unsigned long) -1 | |
6512 | || ! c->session.need_unwind)) | |
6513 | done = 1; | |
6514 | } | |
6515 | else if (kretprobe_trampoline_addr == (unsigned long) -1 | |
6516 | && c->session.need_unwind | |
6517 | && ! strcmp(name, "kretprobe_trampoline_holder")) | |
6518 | { | |
6519 | int ki; | |
6520 | kretprobe_trampoline_addr = sym_addr; | |
6521 | ki = dwfl_module_relocate_address(m, | |
6522 | &kretprobe_trampoline_addr); | |
e1c3b13a | 6523 | DWFL_ASSERT ("dwfl_module_relocate_address, kretprobe_trampoline_addr", ki >= 0); |
59218439 MW |
6524 | |
6525 | if (! c->session.need_symbols | |
6526 | && extra_offset != 0) | |
6527 | done = 1; | |
6528 | } | |
1b94bf6d FCE |
6529 | } |
6530 | ||
d6377d44 | 6531 | // We are only interested in "real" symbols. |
a09fc5a4 MW |
6532 | // We omit symbols that have suspicious addresses |
6533 | // (before base, or after end). | |
59218439 | 6534 | if (!done && c->session.need_symbols |
15c110ee | 6535 | && ! skippable_arch_symbol(ehdr->e_machine, name, &sym) |
59218439 | 6536 | && (GELF_ST_TYPE (sym.st_info) == STT_FUNC |
a09fc5a4 | 6537 | || (GELF_ST_TYPE (sym.st_info) == STT_NOTYPE |
17e446b2 MW |
6538 | && (ehdr->e_type == ET_REL // PR10206 ppc fn-desc in .opd |
6539 | || is_kernel)) // kernel entry functions are NOTYPE | |
cd0ae7e5 | 6540 | || GELF_ST_TYPE (sym.st_info) == STT_OBJECT) // PR10000: .data |
d6377d44 MW |
6541 | && !(sym.st_shndx == SHN_UNDEF // Value undefined, |
6542 | || shndxp == (GElf_Word) -1 // in a non-allocated section, | |
59218439 MW |
6543 | || sym_addr >= end // beyond current module, |
6544 | || sym_addr < base)) // before first section. | |
37ddf6e5 | 6545 | { |
2c9438e3 | 6546 | const char *secname = NULL; |
59218439 | 6547 | unsigned secidx = 0; /* Most things have just one section. */ |
a09fc5a4 MW |
6548 | Dwarf_Addr func_desc_addr = 0; /* Function descriptor */ |
6549 | ||
6550 | /* PPC64 uses function descriptors. | |
6551 | Note: for kernel ET_REL modules we rely on finding the | |
6552 | .function symbols instead of going through the opd function | |
6553 | descriptors. */ | |
6554 | if (ehdr->e_machine == EM_PPC64 | |
6555 | && GELF_ST_TYPE (sym.st_info) == STT_FUNC | |
6556 | && ehdr->e_type != ET_REL) | |
6557 | { | |
6558 | Elf64_Addr opd_addr; | |
6559 | Dwarf_Addr opd_bias; | |
6560 | Elf_Scn *opd; | |
6561 | ||
6562 | func_desc_addr = sym_addr; | |
6563 | ||
6564 | opd = dwfl_module_address_section (m, &sym_addr, &opd_bias); | |
e1c3b13a | 6565 | DWFL_ASSERT ("dwfl_module_address_section opd", opd != NULL); |
a09fc5a4 MW |
6566 | |
6567 | Elf_Data *opd_data = elf_rawdata (opd, NULL); | |
6568 | assert(opd_data != NULL); | |
6569 | ||
6570 | Elf_Data opd_in, opd_out; | |
6571 | opd_out.d_buf = &opd_addr; | |
6572 | opd_in.d_buf = (char *) opd_data->d_buf + sym_addr; | |
6573 | opd_out.d_size = opd_in.d_size = sizeof (Elf64_Addr); | |
6574 | opd_out.d_type = opd_in.d_type = ELF_T_ADDR; | |
6575 | if (elf64_xlatetom (&opd_out, &opd_in, | |
6576 | ehdr->e_ident[EI_DATA]) == NULL) | |
6577 | throw runtime_error ("elf64_xlatetom failed"); | |
6578 | ||
6579 | // So the real address of the function is... | |
6580 | sym_addr = opd_addr + opd_bias; | |
6581 | } | |
1b94bf6d | 6582 | |
2c9438e3 | 6583 | if (n > 0) // only try to relocate if there exist relocation bases |
1b94bf6d | 6584 | { |
94687c8d | 6585 | int ki = dwfl_module_relocate_address (m, &sym_addr); |
e1c3b13a | 6586 | DWFL_ASSERT ("dwfl_module_relocate_address sym_addr", ki >= 0); |
94687c8d | 6587 | secname = dwfl_module_relocation_info (m, ki, NULL); |
a09fc5a4 MW |
6588 | |
6589 | if (func_desc_addr != 0) | |
6590 | dwfl_module_relocate_address (m, &func_desc_addr); | |
7774095b | 6591 | } |
2c9438e3 | 6592 | |
59218439 | 6593 | if (n == 1 && is_kernel) |
1b94bf6d | 6594 | { |
6f8b6801 FCE |
6595 | // This is a symbol within a (possibly relocatable) |
6596 | // kernel image. | |
3f6b6682 | 6597 | |
d6377d44 MW |
6598 | // We only need the function symbols to identify kernel-mode |
6599 | // PC's, so we omit undefined or "fake" absolute addresses. | |
6600 | // These fake absolute addresses occur in some older i386 | |
6601 | // kernels to indicate they are vDSO symbols, not real | |
6602 | // functions in the kernel. We also omit symbols that have | |
6603 | if (GELF_ST_TYPE (sym.st_info) == STT_FUNC | |
6604 | && sym.st_shndx == SHN_ABS) | |
6605 | continue; | |
6606 | ||
7795c7e7 | 6607 | secname = "_stext"; |
59218439 MW |
6608 | // NB: don't subtract session.sym_stext, which could be |
6609 | // inconveniently NULL. Instead, sym_addr will get | |
6610 | // compensated later via extra_offset. | |
1b94bf6d | 6611 | } |
7795c7e7 | 6612 | else if (n > 0) |
1b94bf6d | 6613 | { |
7795c7e7 | 6614 | assert (secname != NULL); |
f76427a2 | 6615 | // secname adequately set |
17c128f2 FCE |
6616 | |
6617 | // NB: it may be an empty string for ET_DYN objects | |
6618 | // like shared libraries, as their relocation base | |
6619 | // is implicit. | |
6620 | if (secname[0] == '\0') | |
59218439 MW |
6621 | secname = ".dynamic"; |
6622 | else | |
6623 | { | |
6624 | // Compute our section number | |
6625 | for (secidx = 0; secidx < c->seclist.size(); secidx++) | |
6626 | if (c->seclist[secidx].first==secname) | |
6627 | break; | |
6628 | ||
6629 | if (secidx == c->seclist.size()) // whoa! We messed up... | |
6630 | { | |
6631 | string m = _F("%s has unknown section %s for sym %s", | |
6632 | modname, secname, name); | |
6633 | throw runtime_error(m); | |
6634 | } | |
6635 | } | |
1b94bf6d | 6636 | } |
dff50e09 | 6637 | else |
2c9438e3 | 6638 | { |
7795c7e7 | 6639 | assert (n == 0); |
59218439 MW |
6640 | // sym_addr is absolute, as it must be since there are |
6641 | // no relocation bases | |
dff50e09 | 6642 | secname = ".absolute"; // sentinel |
2c9438e3 | 6643 | } |
37ddf6e5 | 6644 | |
59218439 | 6645 | (c->addrmap[secidx])[sym_addr] = name; |
a09fc5a4 MW |
6646 | /* If we have a function descriptor, register that address |
6647 | under the same name */ | |
6648 | if (func_desc_addr != 0) | |
6649 | (c->addrmap[secidx])[func_desc_addr] = name; | |
37ddf6e5 | 6650 | } |
f5973d67 | 6651 | } |
fa670082 | 6652 | } |
1b94bf6d | 6653 | |
59218439 MW |
6654 | if (is_kernel) |
6655 | { | |
6656 | c->stext_offset = extra_offset; | |
6657 | // Must be relative to actual kernel load address. | |
6658 | if (kretprobe_trampoline_addr != (unsigned long) -1) | |
6659 | c->stp_kretprobe_trampoline_addr = (kretprobe_trampoline_addr | |
6660 | - extra_offset); | |
6661 | } | |
129de9ef | 6662 | |
c9970555 MW |
6663 | return DWARF_CB_OK; |
6664 | } | |
5738a982 | 6665 | |
c9970555 MW |
6666 | static int |
6667 | dump_unwind_tables (Dwfl_Module *m, | |
6668 | unwindsym_dump_context *c, | |
dabd71bb | 6669 | const char *, Dwarf_Addr) |
c9970555 MW |
6670 | { |
6671 | // Add unwind data to be included if it exists for this module. | |
59218439 MW |
6672 | get_unwind_data (m, &c->debug_frame, &c->eh_frame, |
6673 | &c->debug_len, &c->eh_len, | |
6674 | &c->eh_addr, &c->eh_frame_hdr, &c->eh_frame_hdr_len, | |
6675 | &c->debug_frame_hdr, &c->debug_frame_hdr_len, | |
6676 | &c->debug_frame_off, &c->eh_frame_hdr_addr, | |
6677 | c->session); | |
c9970555 MW |
6678 | return DWARF_CB_OK; |
6679 | } | |
6680 | ||
4472fb4d JS |
6681 | static void |
6682 | dump_unwindsym_cxt_table(systemtap_session& session, ostream& output, | |
6683 | const string& modname, unsigned modindex, | |
6684 | const string& secname, unsigned secindex, | |
6685 | const string& table, void*& data, size_t& len) | |
6686 | { | |
6687 | if (data == NULL || len == 0) | |
6688 | return; | |
6689 | ||
6690 | if (len > MAX_UNWIND_TABLE_SIZE) | |
6691 | { | |
6692 | if (secname.empty()) | |
6693 | session.print_warning (_F("skipping module %s %s table (too big: %zi > %zi)", | |
6694 | modname.c_str(), table.c_str(), | |
6695 | len, (size_t)MAX_UNWIND_TABLE_SIZE)); | |
6696 | else | |
6697 | session.print_warning (_F("skipping module %s, section %s %s table (too big: %zi > %zi)", | |
6698 | modname.c_str(), secname.c_str(), table.c_str(), | |
6699 | len, (size_t)MAX_UNWIND_TABLE_SIZE)); | |
6700 | data = NULL; | |
6701 | len = 0; | |
6702 | return; | |
6703 | } | |
6704 | ||
ee533a58 AJ |
6705 | // if it is the debug_line data, do not need the unwind flags to be defined |
6706 | if(table == "debug_line") | |
6707 | output << "#if defined(STP_NEED_LINE_DATA)\n"; | |
6708 | else | |
6709 | output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n"; | |
4472fb4d JS |
6710 | output << "static uint8_t _stp_module_" << modindex << "_" << table; |
6711 | if (!secname.empty()) | |
6712 | output << "_" << secindex; | |
6713 | output << "[] = \n"; | |
6714 | output << " {"; | |
6715 | for (size_t i = 0; i < len; i++) | |
6716 | { | |
6717 | int h = ((uint8_t *)data)[i]; | |
6718 | output << h << ","; // decimal is less wordy than hex | |
6719 | if ((i + 1) % 16 == 0) | |
6720 | output << "\n" << " "; | |
6721 | } | |
6722 | output << "};\n"; | |
ee533a58 AJ |
6723 | if (table == "debug_line") |
6724 | output << "#endif /* STP_NEED_LINE_DATA */\n"; | |
6725 | else | |
6726 | output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA */\n"; | |
4472fb4d JS |
6727 | } |
6728 | ||
c9970555 MW |
6729 | static int |
6730 | dump_unwindsym_cxt (Dwfl_Module *m, | |
6731 | unwindsym_dump_context *c, | |
6732 | const char *name, Dwarf_Addr base) | |
6733 | { | |
6734 | string modname = name; | |
6735 | unsigned stpmod_idx = c->stp_module_index; | |
6736 | void *debug_frame = c->debug_frame; | |
6737 | size_t debug_len = c->debug_len; | |
6738 | void *debug_frame_hdr = c->debug_frame_hdr; | |
6739 | size_t debug_frame_hdr_len = c->debug_frame_hdr_len; | |
6740 | Dwarf_Addr debug_frame_off = c->debug_frame_off; | |
6741 | void *eh_frame = c->eh_frame; | |
6742 | void *eh_frame_hdr = c->eh_frame_hdr; | |
6743 | size_t eh_len = c->eh_len; | |
6744 | size_t eh_frame_hdr_len = c->eh_frame_hdr_len; | |
6745 | Dwarf_Addr eh_addr = c->eh_addr; | |
6746 | Dwarf_Addr eh_frame_hdr_addr = c->eh_frame_hdr_addr; | |
ee533a58 AJ |
6747 | void *debug_line = c->debug_line; |
6748 | size_t debug_line_len = c->debug_line_len; | |
5738a982 | 6749 | |
4472fb4d JS |
6750 | dump_unwindsym_cxt_table(c->session, c->output, modname, stpmod_idx, "", 0, |
6751 | "debug_frame", debug_frame, debug_len); | |
4285dc9a | 6752 | |
4472fb4d JS |
6753 | dump_unwindsym_cxt_table(c->session, c->output, modname, stpmod_idx, "", 0, |
6754 | "eh_frame", eh_frame, eh_len); | |
6755 | ||
6756 | dump_unwindsym_cxt_table(c->session, c->output, modname, stpmod_idx, "", 0, | |
6757 | "eh_frame_hdr", eh_frame_hdr, eh_frame_hdr_len); | |
4285dc9a | 6758 | |
ee533a58 AJ |
6759 | dump_unwindsym_cxt_table(c->session, c->output, modname, stpmod_idx, "", 0, |
6760 | "debug_line", debug_line, debug_line_len); | |
6761 | ||
5738a982 | 6762 | if (c->session.need_unwind && debug_frame == NULL && eh_frame == NULL) |
61a80584 | 6763 | { |
41a6bdc9 FCE |
6764 | // There would be only a small benefit to warning. A user |
6765 | // likely can't do anything about this; backtraces for the | |
6766 | // affected module would just get all icky heuristicy. | |
d6377d44 | 6767 | // So only report in verbose mode. |
2713ea24 | 6768 | if (c->session.verbose > 2) |
d6377d44 MW |
6769 | c->session.print_warning ("No unwind data for " + modname |
6770 | + ", " + dwfl_errmsg (-1)); | |
61a80584 MW |
6771 | } |
6772 | ||
ee533a58 AJ |
6773 | if (c->session.need_lines && debug_line == NULL) |
6774 | { | |
6775 | if (c->session.verbose > 2) | |
6776 | c->session.print_warning ("No debug line data for " + modname + ", " + | |
6777 | dwfl_errmsg (-1)); | |
6778 | } | |
6779 | ||
c9970555 | 6780 | for (unsigned secidx = 0; secidx < c->seclist.size(); secidx++) |
1b94bf6d | 6781 | { |
4c2732a1 | 6782 | c->output << "static struct _stp_symbol " |
1751e667 | 6783 | << "_stp_module_" << stpmod_idx<< "_symbols_" << secidx << "[] = {\n"; |
1b94bf6d | 6784 | |
c9970555 MW |
6785 | string secname = c->seclist[secidx].first; |
6786 | Dwarf_Addr extra_offset; | |
6787 | extra_offset = (secname == "_stext") ? c->stext_offset : 0; | |
6788 | ||
82762adc | 6789 | // Only include symbols if they will be used |
8af41ec2 MW |
6790 | if (c->session.need_symbols) |
6791 | { | |
8af41ec2 MW |
6792 | // We write out a *sorted* symbol table, so the runtime doesn't |
6793 | // have to sort them later. | |
c9970555 MW |
6794 | for (addrmap_t::iterator it = c->addrmap[secidx].begin(); |
6795 | it != c->addrmap[secidx].end(); it++) | |
8af41ec2 MW |
6796 | { |
6797 | // skip symbols that occur before our chosen base address | |
6798 | if (it->first < extra_offset) | |
6799 | continue; | |
82762adc | 6800 | |
8af41ec2 MW |
6801 | c->output << " { 0x" << hex << it->first-extra_offset << dec |
6802 | << ", " << lex_cast_qstring (it->second) << " },\n"; | |
bb12c3df FCE |
6803 | // XXX: these literal strings all suffer ELF relocation bloat too. |
6804 | // See if the tapsets.cxx:dwarf_derived_probe_group::emit_module_decls | |
6805 | // CALCIT hack could work here. | |
8af41ec2 MW |
6806 | } |
6807 | } | |
82762adc | 6808 | |
1751e667 | 6809 | c->output << "};\n"; |
4d83bd9b MW |
6810 | |
6811 | /* For now output debug_frame index only in "magic" sections. */ | |
4d83bd9b MW |
6812 | if (secname == ".dynamic" || secname == ".absolute" |
6813 | || secname == ".text" || secname == "_stext") | |
6814 | { | |
4472fb4d JS |
6815 | dump_unwindsym_cxt_table(c->session, c->output, modname, stpmod_idx, secname, secidx, |
6816 | "debug_frame_hdr", debug_frame_hdr, debug_frame_hdr_len); | |
4d83bd9b | 6817 | } |
7795c7e7 FCE |
6818 | } |
6819 | ||
1751e667 | 6820 | c->output << "static struct _stp_section _stp_module_" << stpmod_idx<< "_sections[] = {\n"; |
60ad8eba MW |
6821 | // For the kernel, executables (ET_EXEC) or shared libraries (ET_DYN) |
6822 | // there is just one section that covers the whole address space of | |
6823 | // the module. For kernel modules (ET_REL) there can be multiple | |
6824 | // sections that get relocated separately. | |
c9970555 | 6825 | for (unsigned secidx = 0; secidx < c->seclist.size(); secidx++) |
7795c7e7 | 6826 | { |
1751e667 | 6827 | c->output << "{\n" |
c9970555 MW |
6828 | << ".name = " << lex_cast_qstring(c->seclist[secidx].first) << ",\n" |
6829 | << ".size = 0x" << hex << c->seclist[secidx].second << dec << ",\n" | |
1751e667 | 6830 | << ".symbols = _stp_module_" << stpmod_idx << "_symbols_" << secidx << ",\n" |
c9970555 | 6831 | << ".num_symbols = " << c->addrmap[secidx].size() << ",\n"; |
4d83bd9b MW |
6832 | |
6833 | /* For now output debug_frame index only in "magic" sections. */ | |
c9970555 | 6834 | string secname = c->seclist[secidx].first; |
4d83bd9b MW |
6835 | if (debug_frame_hdr && (secname == ".dynamic" || secname == ".absolute" |
6836 | || secname == ".text" || secname == "_stext")) | |
6837 | { | |
6838 | c->output << "#if defined(STP_USE_DWARF_UNWINDER)" | |
6839 | << " && defined(STP_NEED_UNWIND_DATA)\n"; | |
6840 | ||
6841 | c->output << ".debug_hdr = " | |
6842 | << "_stp_module_" << stpmod_idx | |
6843 | << "_debug_frame_hdr_" << secidx << ",\n"; | |
6844 | c->output << ".debug_hdr_len = " << debug_frame_hdr_len << ", \n"; | |
6845 | ||
6846 | Dwarf_Addr dwbias = 0; | |
6847 | dwfl_module_getdwarf (m, &dwbias); | |
6848 | c->output << ".sec_load_offset = 0x" | |
6849 | << hex << debug_frame_off - dwbias << dec << "\n"; | |
6850 | ||
6851 | c->output << "#else\n"; | |
6852 | c->output << ".debug_hdr = NULL,\n"; | |
6853 | c->output << ".debug_hdr_len = 0,\n"; | |
6854 | c->output << ".sec_load_offset = 0\n"; | |
6855 | c->output << "#endif /* STP_USE_DWARF_UNWINDER" | |
6856 | << " && STP_NEED_UNWIND_DATA */\n"; | |
6857 | ||
6858 | } | |
6859 | else | |
6860 | { | |
6861 | c->output << ".debug_hdr = NULL,\n"; | |
6862 | c->output << ".debug_hdr_len = 0,\n"; | |
51816238 AJ |
6863 | if (c->session.need_lines && secname == ".text") |
6864 | { | |
6865 | c->output << "#if defined(STP_NEED_LINE_DATA)\n"; | |
6866 | Dwarf_Addr dwbias = 0; | |
6867 | dwfl_module_getdwarf (m, &dwbias); | |
6868 | c->output << ".sec_load_offset = 0x" | |
6869 | << hex << debug_frame_off - dwbias << dec << "\n"; | |
6870 | c->output << "#else\n"; | |
6871 | } | |
4d83bd9b | 6872 | c->output << ".sec_load_offset = 0\n"; |
51816238 AJ |
6873 | if (c->session.need_lines && secname == ".text") |
6874 | c->output << "#endif /* STP_NEED_LINE_DATA */\n"; | |
4d83bd9b MW |
6875 | } |
6876 | ||
6877 | c->output << "},\n"; | |
1b94bf6d | 6878 | } |
1751e667 | 6879 | c->output << "};\n"; |
1b94bf6d | 6880 | |
c9970555 MW |
6881 | // Get the canonical path of the main file for comparison at runtime. |
6882 | // When given directly by the user through -d or in case of the kernel | |
6883 | // name and path might differ. path should be used for matching. | |
6884 | const char *mainfile; | |
6885 | dwfl_module_info (m, NULL, NULL, NULL, NULL, NULL, &mainfile, NULL); | |
6886 | ||
496fec26 | 6887 | // For user space modules store canonical path. |
c92a217d | 6888 | // For kernel modules just the name itself. |
5bca76a8 | 6889 | string mainpath = resolve_path(mainfile); |
496fec26 | 6890 | string mainname; |
4766b1e6 | 6891 | if (is_user_module(modname)) // userspace |
496fec26 | 6892 | mainname = lex_cast_qstring (path_remove_sysroot(c->session,mainpath)); |
c92a217d | 6893 | else |
4766b1e6 JL |
6894 | { // kernel module |
6895 | ||
6896 | // If the module name is the full path to the ko, then we have to retrieve | |
6897 | // the actual name by which the module will be known inside the kernel. | |
6898 | // Otherwise, section relocations would be mismatched. | |
6899 | if (is_fully_resolved(modname, c->session.sysroot, c->session.sysenv)) | |
6900 | mainname = lex_cast_qstring (modname_from_path(modname)); | |
6901 | else | |
6902 | mainname = lex_cast_qstring (modname); | |
6903 | } | |
671ceda8 | 6904 | |
1751e667 | 6905 | c->output << "static struct _stp_module _stp_module_" << stpmod_idx << " = {\n"; |
496fec26 | 6906 | c->output << ".name = " << mainname.c_str() << ",\n"; |
65e2141c | 6907 | c->output << ".path = " << lex_cast_qstring (path_remove_sysroot(c->session,mainpath)) << ",\n"; |
4d83bd9b MW |
6908 | c->output << ".eh_frame_addr = 0x" << hex << eh_addr << dec << ", \n"; |
6909 | c->output << ".unwind_hdr_addr = 0x" << hex << eh_frame_hdr_addr | |
6910 | << dec << ", \n"; | |
4285dc9a MW |
6911 | |
6912 | if (debug_frame != NULL) | |
6913 | { | |
6914 | c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n"; | |
6915 | c->output << ".debug_frame = " | |
6916 | << "_stp_module_" << stpmod_idx << "_debug_frame, \n"; | |
6917 | c->output << ".debug_frame_len = " << debug_len << ", \n"; | |
6918 | c->output << "#else\n"; | |
6919 | } | |
6920 | ||
6921 | c->output << ".debug_frame = NULL,\n"; | |
6922 | c->output << ".debug_frame_len = 0,\n"; | |
6923 | ||
6924 | if (debug_frame != NULL) | |
6925 | c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA*/\n"; | |
61a80584 | 6926 | |
4285dc9a | 6927 | if (eh_frame != NULL) |
61a80584 | 6928 | { |
1751e667 | 6929 | c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n"; |
4285dc9a MW |
6930 | c->output << ".eh_frame = " |
6931 | << "_stp_module_" << stpmod_idx << "_eh_frame, \n"; | |
6932 | c->output << ".eh_frame_len = " << eh_len << ", \n"; | |
0f33053e TM |
6933 | if (eh_frame_hdr) |
6934 | { | |
6935 | c->output << ".unwind_hdr = " | |
6936 | << "_stp_module_" << stpmod_idx << "_eh_frame_hdr, \n"; | |
6937 | c->output << ".unwind_hdr_len = " << eh_frame_hdr_len << ", \n"; | |
6938 | } | |
6939 | else | |
6940 | { | |
6941 | c->output << ".unwind_hdr = NULL,\n"; | |
6942 | c->output << ".unwind_hdr_len = 0,\n"; | |
6943 | } | |
1751e667 | 6944 | c->output << "#else\n"; |
61a80584 MW |
6945 | } |
6946 | ||
4285dc9a MW |
6947 | c->output << ".eh_frame = NULL,\n"; |
6948 | c->output << ".eh_frame_len = 0,\n"; | |
1751e667 FCE |
6949 | c->output << ".unwind_hdr = NULL,\n"; |
6950 | c->output << ".unwind_hdr_len = 0,\n"; | |
0f33053e TM |
6951 | if (eh_frame != NULL) |
6952 | c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA*/\n"; | |
ee533a58 AJ |
6953 | |
6954 | if (debug_line != NULL) | |
6955 | { | |
ca6031ac | 6956 | c->output << "#if defined(STP_NEED_LINE_DATA)\n"; |
ee533a58 AJ |
6957 | c->output << ".debug_line = " |
6958 | << "_stp_module_" << stpmod_idx << "_debug_line, \n"; | |
6959 | c->output << ".debug_line_len = " << debug_line_len << ", \n"; | |
ca6031ac | 6960 | c->output << "#else\n"; |
ee533a58 | 6961 | } |
ca6031ac AJ |
6962 | |
6963 | c->output << ".debug_line = NULL,\n"; | |
6964 | c->output << ".debug_line_len = 0,\n"; | |
6965 | ||
6966 | if (debug_line != NULL) | |
6967 | c->output << "#endif /* STP_NEED_LINE_DATA */\n"; | |
ee533a58 | 6968 | |
1751e667 | 6969 | c->output << ".sections = _stp_module_" << stpmod_idx << "_sections" << ",\n"; |
7795c7e7 | 6970 | c->output << ".num_sections = sizeof(_stp_module_" << stpmod_idx << "_sections)/" |
1751e667 | 6971 | << "sizeof(struct _stp_section),\n"; |
dff50e09 | 6972 | |
66f65c4f EM |
6973 | /* Don't save build-id if it is located before _stext. |
6974 | * This probably means that build-id will not be loaded at all and | |
d1d13a8b SC |
6975 | * happens for example with ARM kernel. Allow user space modules since the |
6976 | * check fails for a shared object. | |
66f65c4f EM |
6977 | * |
6978 | * See also: | |
306dd4f8 | 6979 | * http://sourceware.org/ml/systemtap/2009-q4/msg00574.html |
66f65c4f | 6980 | */ |
c9970555 MW |
6981 | if (c->build_id_len > 0 |
6982 | && (modname != "kernel" || (c->build_id_vaddr > base + c->stext_offset))) { | |
3a894f7e | 6983 | c->output << ".build_id_bits = (unsigned char *)\"" ; |
c9970555 | 6984 | for (int j=0; j<c->build_id_len;j++) |
1751e667 | 6985 | c->output << "\\x" << hex |
c9970555 | 6986 | << (unsigned short) *(c->build_id_bits+j) << dec; |
3f6b6682 | 6987 | |
1751e667 | 6988 | c->output << "\",\n"; |
c9970555 | 6989 | c->output << ".build_id_len = " << c->build_id_len << ",\n"; |
3f6b6682 | 6990 | |
1751e667 | 6991 | /* XXX: kernel data boot-time relocation works differently from text. |
201e18a8 EM |
6992 | This hack assumes that offset between _stext and build id |
6993 | stays constant after relocation, but that's not necessarily | |
1751e667 FCE |
6994 | correct either. We may instead need a relocation basis different |
6995 | from _stext, such as __start_notes. */ | |
6996 | if (modname == "kernel") | |
c9970555 | 6997 | c->output << ".build_id_offset = 0x" << hex << c->build_id_vaddr - (base + c->stext_offset) |
1751e667 | 6998 | << dec << ",\n"; |
155bb07a | 6999 | // ET_DYN: task finder gives the load address. ET_EXEC: this is absolute address |
1751e667 FCE |
7000 | else |
7001 | c->output << ".build_id_offset = 0x" << hex | |
c9970555 | 7002 | << c->build_id_vaddr /* - base */ |
1751e667 | 7003 | << dec << ",\n"; |
29495972 | 7004 | } else |
1751e667 | 7005 | c->output << ".build_id_len = 0,\n"; |
3f6b6682 | 7006 | |
29495972 | 7007 | //initialize the note section representing unloaded |
1751e667 | 7008 | c->output << ".notes_sect = 0,\n"; |
29495972 | 7009 | |
1751e667 | 7010 | c->output << "};\n\n"; |
37ddf6e5 | 7011 | |
4464a6bb FCE |
7012 | c->undone_unwindsym_modules.erase (modname); |
7013 | ||
e7899657 | 7014 | // release various malloc'd tables |
bd2a3e38 | 7015 | // if (eh_frame_hdr) free (eh_frame_hdr); -- nope, this one comes from the elf image in memory |
e7899657 FCE |
7016 | if (debug_frame_hdr) free (debug_frame_hdr); |
7017 | ||
fa670082 MH |
7018 | return DWARF_CB_OK; |
7019 | } | |
7020 | ||
7b65c066 FL |
7021 | static void dump_kallsyms(unwindsym_dump_context *c) |
7022 | { | |
7023 | ifstream kallsyms("/proc/kallsyms"); | |
7024 | unsigned stpmod_idx = c->stp_module_index; | |
7025 | string line; | |
7026 | unsigned size = 0; | |
7027 | Dwarf_Addr start = 0; | |
7028 | Dwarf_Addr end = 0; | |
7029 | Dwarf_Addr prev = 0; | |
7030 | ||
7031 | c->output << "static struct _stp_symbol " | |
7032 | << "_stp_module_" << stpmod_idx << "_symbols_" << 0 << "[] = {\n"; | |
7033 | ||
7034 | while (getline(kallsyms, line)) | |
7035 | { | |
7036 | Dwarf_Addr addr; | |
7037 | string name; | |
7038 | string module; | |
7039 | char type; | |
7040 | istringstream iss(line); | |
7041 | ||
7042 | iss >> hex >> addr >> type >> name >> module; | |
7043 | ||
7044 | if (name == KERNEL_RELOC_SYMBOL) | |
7045 | start = addr; | |
7046 | else if (name == "_end" || module != "") | |
7047 | { | |
7048 | end = prev; | |
7049 | break; | |
7050 | } | |
7051 | ||
7052 | if (!start || addr == 0 || prev == addr) | |
7053 | continue; | |
7054 | ||
7055 | c->output << " { 0x" << hex << addr - start << dec | |
7056 | << ", " << lex_cast_qstring(name) << " },\n"; | |
7057 | ||
7058 | size++; | |
7059 | prev = addr; | |
7060 | } | |
7061 | ||
7062 | c->output << "};\n"; | |
7063 | c->output << "static struct _stp_section _stp_module_" << stpmod_idx << "_sections[] = {\n"; | |
7064 | c->output << "{\n" | |
7065 | << ".name = " << lex_cast_qstring(KERNEL_RELOC_SYMBOL) << ",\n" | |
7066 | << ".size = 0x" << hex << end - start << dec << ",\n" | |
7067 | << ".symbols = _stp_module_" << stpmod_idx << "_symbols_" << 0 << ",\n" | |
7068 | << ".num_symbols = " << size << ",\n"; | |
7069 | c->output << "},\n"; | |
7070 | c->output << "};\n"; | |
7071 | c->output << "static struct _stp_module _stp_module_" << stpmod_idx << " = {\n"; | |
7072 | c->output << ".name = " << lex_cast_qstring("kernel") << ",\n"; | |
7073 | c->output << ".sections = _stp_module_" << stpmod_idx << "_sections" << ",\n"; | |
7074 | c->output << ".num_sections = sizeof(_stp_module_" << stpmod_idx << "_sections)/" | |
7075 | << "sizeof(struct _stp_section),\n"; | |
7076 | c->output << "};\n\n"; | |
7077 | ||
7078 | c->undone_unwindsym_modules.erase("kernel"); | |
7079 | c->stp_module_index++; | |
7080 | } | |
7081 | ||
c9970555 MW |
7082 | static int |
7083 | dump_unwindsyms (Dwfl_Module *m, | |
7084 | void **userdata __attribute__ ((unused)), | |
7085 | const char *name, | |
7086 | Dwarf_Addr base, | |
7087 | void *arg) | |
7088 | { | |
7089 | if (pending_interrupts) | |
7090 | return DWARF_CB_ABORT; | |
7091 | ||
7092 | unwindsym_dump_context *c = (unwindsym_dump_context*) arg; | |
7093 | assert (c); | |
7094 | ||
7095 | // skip modules/files we're not actually interested in | |
7096 | string modname = name; | |
7097 | if (c->session.unwindsym_modules.find(modname) | |
7098 | == c->session.unwindsym_modules.end()) | |
7099 | return DWARF_CB_OK; | |
7100 | ||
7101 | if (c->session.verbose > 1) | |
7102 | clog << "dump_unwindsyms " << name | |
7103 | << " index=" << c->stp_module_index | |
7104 | << " base=0x" << hex << base << dec << endl; | |
7105 | ||
7106 | // We want to extract several bits of information: | |
7107 | // | |
7108 | // - parts of the program-header that map the file's physical offsets to the text section | |
7109 | // - section table: just a list of section (relocation) base addresses | |
7110 | // - symbol table of the text-like sections, with all addresses relativized to each base | |
7111 | // - the contents of .debug_frame and/or .eh_frame section, for unwinding purposes | |
7112 | ||
7113 | int res = DWARF_CB_OK; | |
7114 | ||
7115 | c->build_id_len = 0; | |
7116 | c->build_id_vaddr = 0; | |
7117 | c->build_id_bits = NULL; | |
7118 | res = dump_build_id (m, c, name, base); | |
c9970555 MW |
7119 | |
7120 | c->seclist.clear(); | |
59218439 MW |
7121 | if (res == DWARF_CB_OK) |
7122 | res = dump_section_list(m, c, name, base); | |
7123 | ||
7124 | // We always need to check the symbols of the kernel if we use it, | |
7125 | // for the extra_offset (also used for build_ids) and possibly | |
7126 | // stp_kretprobe_trampoline_addr for the dwarf unwinder. | |
c9970555 | 7127 | c->addrmap.clear(); |
59218439 MW |
7128 | if (res == DWARF_CB_OK |
7129 | && (c->session.need_symbols || ! strcmp(name, "kernel"))) | |
7130 | res = dump_symbol_tables (m, c, name, base); | |
c9970555 MW |
7131 | |
7132 | c->debug_frame = NULL; | |
7133 | c->debug_len = 0; | |
7134 | c->debug_frame_hdr = NULL; | |
7135 | c->debug_frame_hdr_len = 0; | |
7136 | c->debug_frame_off = 0; | |
7137 | c->eh_frame = NULL; | |
7138 | c->eh_frame_hdr = NULL; | |
7139 | c->eh_len = 0; | |
7140 | c->eh_frame_hdr_len = 0; | |
7141 | c->eh_addr = 0; | |
7142 | c->eh_frame_hdr_addr = 0; | |
59218439 MW |
7143 | if (res == DWARF_CB_OK && c->session.need_unwind) |
7144 | res = dump_unwind_tables (m, c, name, base); | |
c9970555 | 7145 | |
ee533a58 AJ |
7146 | c->debug_line = NULL; |
7147 | c->debug_line_len = 0; | |
7148 | if (res == DWARF_CB_OK && c->session.need_lines) | |
7149 | // we dont set res = dump_line_tables() because unwindsym stuff should still | |
7150 | // get dumped to the output even if gathering debug_line data fails | |
7151 | (void) dump_line_tables (m, c, name, base); | |
7152 | ||
c9970555 | 7153 | /* And finally dump everything collected in the output. */ |
59218439 MW |
7154 | if (res == DWARF_CB_OK) |
7155 | res = dump_unwindsym_cxt (m, c, name, base); | |
7156 | ||
7157 | if (res == DWARF_CB_OK) | |
7158 | c->stp_module_index++; | |
7159 | ||
c9970555 MW |
7160 | return res; |
7161 | } | |
7162 | ||
1a0dbc5a | 7163 | |
1b94bf6d FCE |
7164 | // Emit symbol table & unwind data, plus any calls needed to register |
7165 | // them with the runtime. | |
62d950bb | 7166 | void emit_symbol_data_done (unwindsym_dump_context*, systemtap_session&); |
1b94bf6d | 7167 | |
ef06c938 | 7168 | |
6bbcd339 | 7169 | void |
bbbc7241 | 7170 | add_unwindsym_iol_callback (set<string> *added, const char *data) |
6bbcd339 | 7171 | { |
6bbcd339 SC |
7172 | added->insert (string (data)); |
7173 | } | |
7174 | ||
7175 | ||
7176 | static int | |
7177 | query_module (Dwfl_Module *mod, | |
7178 | void **, | |
822a6a3d FCE |
7179 | const char *, |
7180 | Dwarf_Addr, | |
06de3a04 | 7181 | struct dwflpp *dwflpp) |
6bbcd339 | 7182 | { |
06de3a04 | 7183 | dwflpp->focus_on_module(mod, NULL); |
6bbcd339 SC |
7184 | return DWARF_CB_OK; |
7185 | } | |
7186 | ||
7187 | ||
ef06c938 FCE |
7188 | void |
7189 | add_unwindsym_ldd (systemtap_session &s) | |
7190 | { | |
7191 | std::set<std::string> added; | |
7192 | ||
ef06c938 FCE |
7193 | for (std::set<std::string>::iterator it = s.unwindsym_modules.begin(); |
7194 | it != s.unwindsym_modules.end(); | |
7195 | it++) | |
7196 | { | |
7197 | string modname = *it; | |
7198 | assert (modname.length() != 0); | |
7199 | if (! is_user_module (modname)) continue; | |
7200 | ||
2d590ebe JS |
7201 | dwflpp mod_dwflpp (s, modname, false); |
7202 | mod_dwflpp.iterate_over_modules(&query_module, &mod_dwflpp); | |
7203 | if (mod_dwflpp.module) // existing binary | |
0ce08aaa | 7204 | { |
2d590ebe JS |
7205 | assert (mod_dwflpp.module_name != ""); |
7206 | mod_dwflpp.iterate_over_libraries (&add_unwindsym_iol_callback, &added); | |
0ce08aaa | 7207 | } |
ef06c938 | 7208 | } |
6bbcd339 | 7209 | |
ef06c938 FCE |
7210 | s.unwindsym_modules.insert (added.begin(), added.end()); |
7211 | } | |
7212 | ||
822a6a3d | 7213 | static int find_vdso(const char *path, const struct stat *, int type) |
18da5887 MW |
7214 | { |
7215 | if (type == FTW_F) | |
7216 | { | |
b3131710 DS |
7217 | /* Assume that if the path's basename starts with 'vdso' and |
7218 | * ends with '.so', it is the vdso. | |
7219 | * | |
7220 | * Note that this logic should match up with the logic in the | |
7221 | * _stp_vma_match_vdso() function in runtime/vma.c. */ | |
18da5887 MW |
7222 | const char *name = strrchr(path, '/'); |
7223 | if (name) | |
7224 | { | |
b3131710 DS |
7225 | const char *ext; |
7226 | ||
18da5887 | 7227 | name++; |
b3131710 | 7228 | ext = strrchr(name, '.'); |
18da5887 MW |
7229 | if (ext |
7230 | && strncmp("vdso", name, 4) == 0 | |
7231 | && strcmp(".so", ext) == 0) | |
7232 | vdso_paths.insert(path); | |
7233 | } | |
7234 | } | |
7235 | return 0; | |
7236 | } | |
7237 | ||
7238 | void | |
7239 | add_unwindsym_vdso (systemtap_session &s) | |
7240 | { | |
7241 | // This is to disambiguate between -r REVISION vs -r BUILDDIR. | |
7242 | // See also dwflsetup.c (setup_dwfl_kernel). In case of only | |
7243 | // having the BUILDDIR we need to do a deep search (the specific | |
7244 | // arch name dir in the kernel build tree is unknown). | |
7245 | string vdso_dir; | |
05fb3e0c | 7246 | if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/" |
18da5887 MW |
7247 | + s.kernel_release |
7248 | + "/build")) | |
05fb3e0c | 7249 | vdso_dir = s.sysroot + "/lib/modules/" + s.kernel_release + "/vdso"; |
18da5887 MW |
7250 | else |
7251 | vdso_dir = s.kernel_build_tree + "/arch/"; | |
7252 | ||
7253 | if (s.verbose > 1) | |
1e41115c | 7254 | clog << _("Searching for vdso candidates: ") << vdso_dir << endl; |
18da5887 MW |
7255 | |
7256 | ftw(vdso_dir.c_str(), find_vdso, 1); | |
7257 | ||
7258 | for (set<string>::iterator it = vdso_paths.begin(); | |
7259 | it != vdso_paths.end(); | |
7260 | it++) | |
7261 | { | |
7262 | s.unwindsym_modules.insert(*it); | |
7263 | if (s.verbose > 1) | |
1e41115c | 7264 | clog << _("vdso candidate: ") << *it << endl; |
18da5887 MW |
7265 | } |
7266 | } | |
ef06c938 | 7267 | |
d13bcfd8 JS |
7268 | static void |
7269 | prepare_symbol_data (systemtap_session& s) | |
fa670082 | 7270 | { |
ef06c938 FCE |
7271 | // step 0: run ldd on any user modules if requested |
7272 | if (s.unwindsym_ldd) | |
7273 | add_unwindsym_ldd (s); | |
18da5887 MW |
7274 | // step 0.5: add vdso(s) when vma tracker was requested |
7275 | if (vma_tracker_enabled (s)) | |
7276 | add_unwindsym_vdso (s); | |
ef06c938 | 7277 | // NB: do this before the ctx.unwindsym_modules copy is taken |
d13bcfd8 JS |
7278 | } |
7279 | ||
7280 | void | |
7281 | emit_symbol_data (systemtap_session& s) | |
7282 | { | |
7283 | string symfile = "stap-symbols.h"; | |
7284 | ||
7285 | s.op->newline() << "#include " << lex_cast_qstring (symfile); | |
7286 | ||
7287 | ofstream kallsyms_out ((s.tmpdir + "/" + symfile).c_str()); | |
ef06c938 | 7288 | |
c9970555 MW |
7289 | vector<pair<string,unsigned> > seclist; |
7290 | map<unsigned, addrmap_t> addrmap; | |
7291 | unwindsym_dump_context ctx = { s, kallsyms_out, | |
7292 | 0, /* module index */ | |
7293 | 0, NULL, 0, /* build_id len, bits, vaddr */ | |
47caa991 | 7294 | ~0UL, /* stp_kretprobe_trampoline_addr */ |
c9970555 MW |
7295 | 0, /* stext_offset */ |
7296 | seclist, addrmap, | |
7297 | NULL, /* debug_frame */ | |
7298 | 0, /* debug_len */ | |
7299 | NULL, /* debug_frame_hdr */ | |
7300 | 0, /* debug_frame_hdr_len */ | |
7301 | 0, /* debug_frame_off */ | |
7302 | NULL, /* eh_frame */ | |
7303 | NULL, /* eh_frame_hdr */ | |
7304 | 0, /* eh_len */ | |
7305 | 0, /* eh_frame_hdr_len */ | |
7306 | 0, /* eh_addr */ | |
7307 | 0, /* eh_frame_hdr_addr */ | |
ee533a58 AJ |
7308 | NULL, /* debug_line */ |
7309 | 0, /* debug_line_len */ | |
c9970555 | 7310 | s.unwindsym_modules }; |
f5973d67 | 7311 | |
62d950bb MW |
7312 | // Micro optimization, mainly to speed up tiny regression tests |
7313 | // using just begin probe. | |
7314 | if (s.unwindsym_modules.size () == 0) | |
7315 | { | |
7316 | emit_symbol_data_done(&ctx, s); | |
7317 | return; | |
7318 | } | |
7319 | ||
f5973d67 | 7320 | // ---- step 1: process any kernel modules listed |
3db9c843 MW |
7321 | set<string> offline_search_modules; |
7322 | unsigned count; | |
ae2552da FCE |
7323 | for (set<string>::iterator it = s.unwindsym_modules.begin(); |
7324 | it != s.unwindsym_modules.end(); | |
7325 | it++) | |
7326 | { | |
7327 | string foo = *it; | |
5f8ca04f MW |
7328 | if (! is_user_module (foo)) /* Omit user-space, since we're only |
7329 | using this for kernel space | |
7330 | offline searches. */ | |
ae2552da FCE |
7331 | offline_search_modules.insert (foo); |
7332 | } | |
ccf2c922 | 7333 | Dwfl *dwfl = setup_dwfl_kernel (offline_search_modules, &count, s); |
73562400 FCE |
7334 | /* NB: It's not an error to find a few fewer modules than requested. |
7335 | There might be third-party modules loaded (e.g. uprobes). */ | |
e1c3b13a | 7336 | /* DWFL_ASSERT("all kernel modules found", |
73562400 | 7337 | count >= offline_search_modules.size()); */ |
ae2552da | 7338 | |
ae2552da FCE |
7339 | ptrdiff_t off = 0; |
7340 | do | |
f5973d67 | 7341 | { |
e19ebcf7 | 7342 | assert_no_interrupts(); |
ae2552da | 7343 | if (ctx.undone_unwindsym_modules.empty()) break; |
68983551 | 7344 | off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, off); |
f5973d67 | 7345 | } |
ae2552da | 7346 | while (off > 0); |
e1c3b13a | 7347 | DWFL_ASSERT("dwfl_getmodules", off == 0); |
ccf2c922 | 7348 | dwfl_end(dwfl); |
f5973d67 FCE |
7349 | |
7350 | // ---- step 2: process any user modules (files) listed | |
f5973d67 FCE |
7351 | for (std::set<std::string>::iterator it = s.unwindsym_modules.begin(); |
7352 | it != s.unwindsym_modules.end(); | |
7353 | it++) | |
7354 | { | |
7355 | string modname = *it; | |
7356 | assert (modname.length() != 0); | |
5f8ca04f | 7357 | if (! is_user_module (modname)) continue; |
ccf2c922 | 7358 | Dwfl *dwfl = setup_dwfl_user (modname); |
5f8ca04f | 7359 | if (dwfl != NULL) // tolerate missing data; will warn below |
f5973d67 | 7360 | { |
4464a6bb FCE |
7361 | ptrdiff_t off = 0; |
7362 | do | |
7363 | { | |
e19ebcf7 | 7364 | assert_no_interrupts(); |
c87193cf | 7365 | if (ctx.undone_unwindsym_modules.empty()) break; |
68983551 | 7366 | off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, off); |
4464a6bb | 7367 | } |
5d6b0142 | 7368 | while (off > 0); |
e1c3b13a | 7369 | DWFL_ASSERT("dwfl_getmodules", off == 0); |
f5973d67 | 7370 | } |
ccf2c922 | 7371 | dwfl_end(dwfl); |
f5973d67 | 7372 | } |
1b94bf6d | 7373 | |
7b65c066 FL |
7374 | // Use /proc/kallsyms if debuginfo not found. |
7375 | if (ctx.undone_unwindsym_modules.find("kernel") != ctx.undone_unwindsym_modules.end()) | |
7376 | dump_kallsyms(&ctx); | |
7377 | ||
62d950bb MW |
7378 | emit_symbol_data_done (&ctx, s); |
7379 | } | |
1b94bf6d | 7380 | |
8dca3463 LB |
7381 | void |
7382 | self_unwind_declarations(unwindsym_dump_context *ctx) | |
7383 | { | |
7384 | ctx->output << "static uint8_t _stp_module_self_eh_frame [] = {0,};\n"; | |
7385 | ctx->output << "static struct _stp_symbol _stp_module_self_symbols_0[] = {{0},};\n"; | |
7386 | ctx->output << "static struct _stp_symbol _stp_module_self_symbols_1[] = {{0},};\n"; | |
7387 | ctx->output << "static struct _stp_section _stp_module_self_sections[] = {\n"; | |
7388 | ctx->output << "{.name = \".symtab\", .symbols = _stp_module_self_symbols_0, .num_symbols = 0},\n"; | |
7389 | ctx->output << "{.name = \".text\", .symbols = _stp_module_self_symbols_1, .num_symbols = 0},\n"; | |
7390 | ctx->output << "};\n"; | |
7391 | ctx->output << "static struct _stp_module _stp_module_self = {\n"; | |
7392 | ctx->output << ".name = \"stap_self_tmp_value\",\n"; | |
7393 | ctx->output << ".path = \"stap_self_tmp_value\",\n"; | |
7394 | ctx->output << ".num_sections = 2,\n"; | |
7395 | ctx->output << ".sections = _stp_module_self_sections,\n"; | |
7396 | ctx->output << ".eh_frame = _stp_module_self_eh_frame,\n"; | |
7397 | ctx->output << ".eh_frame_len = 0,\n"; | |
7398 | ctx->output << ".unwind_hdr_addr = 0x0,\n"; | |
7399 | ctx->output << ".unwind_hdr = NULL,\n"; | |
7400 | ctx->output << ".unwind_hdr_len = 0,\n"; | |
7401 | ctx->output << ".debug_frame = NULL,\n"; | |
7402 | ctx->output << ".debug_frame_len = 0,\n"; | |
ee533a58 AJ |
7403 | ctx->output << ".debug_line = NULL,\n"; |
7404 | ctx->output << ".debug_line_len = 0,\n"; | |
8dca3463 LB |
7405 | ctx->output << "};\n"; |
7406 | } | |
7407 | ||
62d950bb MW |
7408 | void |
7409 | emit_symbol_data_done (unwindsym_dump_context *ctx, systemtap_session& s) | |
7410 | { | |
80d74c6b FCE |
7411 | // Add a .eh_frame terminator dummy object file, much like |
7412 | // libgcc/crtstuff.c's EH_FRAME_SECTION_NAME closer. We need this in | |
7413 | // order for runtime/sym.c | |
7414 | translator_output *T_800 = s.op_create_auxiliary(true); | |
7415 | T_800->newline() << "__extension__ unsigned int T_800 []"; // assumed 32-bits wide | |
7416 | T_800->newline(1) << "__attribute__((used, section(\".eh_frame\"), aligned(4)))"; | |
7417 | T_800->newline() << "= { 0 };"; | |
7418 | T_800->newline(-1); | |
7419 | T_800->assert_0_indent (); // flush to disk | |
7420 | ||
1b94bf6d | 7421 | // Print out a definition of the runtime's _stp_modules[] globals. |
62d950bb | 7422 | ctx->output << "\n"; |
8dca3463 LB |
7423 | self_unwind_declarations(ctx); |
7424 | ctx->output << "static struct _stp_module *_stp_modules [] = {\n"; | |
62d950bb | 7425 | for (unsigned i=0; i<ctx->stp_module_index; i++) |
1b94bf6d | 7426 | { |
62d950bb | 7427 | ctx->output << "& _stp_module_" << i << ",\n"; |
1b94bf6d | 7428 | } |
3222365c | 7429 | ctx->output << "& _stp_module_self,\n"; |
62d950bb | 7430 | ctx->output << "};\n"; |
89815df7 | 7431 | ctx->output << "static const unsigned _stp_num_modules = ARRAY_SIZE(_stp_modules);\n"; |
4464a6bb | 7432 | |
3f6b6682 RM |
7433 | ctx->output << "static unsigned long _stp_kretprobe_trampoline = "; |
7434 | // Special case for -1, which is invalid in hex if host width > target width. | |
7435 | if (ctx->stp_kretprobe_trampoline_addr == (unsigned long) -1) | |
7436 | ctx->output << "-1;\n"; | |
7437 | else | |
7438 | ctx->output << "0x" << hex << ctx->stp_kretprobe_trampoline_addr << dec | |
7439 | << ";\n"; | |
4464a6bb FCE |
7440 | |
7441 | // Some nonexistent modules may have been identified with "-d". Note them. | |
83ca3872 MW |
7442 | if (! s.suppress_warnings) |
7443 | for (set<string>::iterator it = ctx->undone_unwindsym_modules.begin(); | |
7444 | it != ctx->undone_unwindsym_modules.end(); | |
7445 | it ++) | |
1e41115c | 7446 | s.print_warning (_("missing unwind/symbol data for module '") |
83ca3872 | 7447 | + (*it) + "'"); |
33f88a80 FCE |
7448 | } |
7449 | ||
a7ed0d3e FCE |
7450 | struct recursion_info: public traversing_visitor |
7451 | { | |
7452 | recursion_info (systemtap_session& s): sess(s), nesting_max(0), recursive(false) {} | |
7453 | systemtap_session& sess; | |
7454 | unsigned nesting_max; | |
7455 | bool recursive; | |
7456 | std::vector <functiondecl *> current_nesting; | |
7457 | ||
7458 | void visit_functioncall (functioncall* e) { | |
7459 | traversing_visitor::visit_functioncall (e); // for arguments | |
7460 | ||
7461 | // check for nesting level | |
7462 | unsigned nesting_depth = current_nesting.size() + 1; | |
7463 | if (nesting_max < nesting_depth) | |
7464 | { | |
7465 | if (sess.verbose > 3) | |
1e41115c | 7466 | clog << _F("identified max-nested function: %s (%d)", |
7371cd19 | 7467 | e->referent->name.to_string().c_str(), nesting_depth) << endl; |
a7ed0d3e FCE |
7468 | nesting_max = nesting_depth; |
7469 | } | |
7470 | ||
7471 | // check for (direct or mutual) recursion | |
7472 | for (unsigned j=0; j<current_nesting.size(); j++) | |
7473 | if (current_nesting[j] == e->referent) | |
7474 | { | |
7475 | recursive = true; | |
7476 | if (sess.verbose > 3) | |
7371cd19 JS |
7477 | clog << _F("identified recursive function: %s", |
7478 | e->referent->name.to_string().c_str()) << endl; | |
a7ed0d3e FCE |
7479 | return; |
7480 | } | |
7481 | ||
7482 | // non-recursive traversal | |
7483 | current_nesting.push_back (e->referent); | |
7484 | e->referent->body->visit (this); | |
7485 | current_nesting.pop_back (); | |
7486 | } | |
7487 | }; | |
7488 | ||
7489 | ||
b5f561be LB |
7490 | void translate_runtime(systemtap_session& s) |
7491 | { | |
7492 | s.op->newline() << "#define STAP_MSG_RUNTIME_H_01 " | |
7493 | << lex_cast_qstring(_("myproc-unprivileged tapset function called " | |
7494 | "without is_myproc checking for pid %d (euid %d)")); | |
7495 | ||
7496 | s.op->newline() << "#define STAP_MSG_LOC2C_01 " | |
6003d4bc | 7497 | << lex_cast_qstring(_("read fault [man error::fault] at 0x%p (%s)")); |
b5f561be | 7498 | s.op->newline() << "#define STAP_MSG_LOC2C_02 " |
6003d4bc | 7499 | << lex_cast_qstring(_("write fault [man error::fault] at 0x%p (%s)")); |
fa2e3415 MW |
7500 | s.op->newline() << "#define STAP_MSG_LOC2C_03 " |
7501 | << lex_cast_qstring(_("divide by zero in DWARF operand (%s)")); | |
b5f561be | 7502 | } |
cfa5d9e0 FCE |
7503 | |
7504 | ||
d13bcfd8 JS |
7505 | int |
7506 | prepare_translate_pass (systemtap_session& s) | |
7507 | { | |
cfa5d9e0 FCE |
7508 | int rc = 0; |
7509 | try | |
7510 | { | |
7511 | prepare_symbol_data (s); | |
7512 | } | |
7513 | catch (const semantic_error& e) | |
7514 | { | |
7515 | s.print_error (e); | |
7516 | rc = 1; | |
7517 | } | |
7518 | ||
7519 | return rc; | |
d13bcfd8 | 7520 | } |
a7ed0d3e FCE |
7521 | |
7522 | ||
2b066ec1 FCE |
7523 | int |
7524 | translate_pass (systemtap_session& s) | |
7525 | { | |
7526 | int rc = 0; | |
7527 | ||
f4b28491 | 7528 | s.op = new translator_output (s.translated_source); |
a4b9c3b3 | 7529 | // additional outputs might be found in s.auxiliary_outputs |
4383d78c FCE |
7530 | c_unparser cup (& s); |
7531 | s.up = & cup; | |
b5f561be | 7532 | translate_runtime(s); |
2b066ec1 FCE |
7533 | |
7534 | try | |
7535 | { | |
176e25af JS |
7536 | int64_t major=0, minor=0; |
7537 | try | |
7538 | { | |
7539 | vector<string> versions; | |
7540 | tokenize (s.compatible, versions, "."); | |
7541 | if (versions.size() >= 1) | |
7542 | major = lex_cast<int64_t> (versions[0]); | |
7543 | if (versions.size() >= 2) | |
7544 | minor = lex_cast<int64_t> (versions[1]); | |
7545 | if (versions.size() >= 3 && s.verbose > 1) | |
1e41115c | 7546 | clog << _F("ignoring extra parts of compat version: %s", s.compatible.c_str()) << endl; |
176e25af JS |
7547 | } |
7548 | catch (const runtime_error) | |
7549 | { | |
dc09353a | 7550 | throw SEMANTIC_ERROR(_F("parse error in compatibility version: %s", s.compatible.c_str())); |
176e25af JS |
7551 | } |
7552 | if (major < 0 || major > 255 || minor < 0 || minor > 255) | |
dc09353a | 7553 | throw SEMANTIC_ERROR(_F("compatibility version out of range: %s", s.compatible.c_str())); |
176e25af JS |
7554 | s.op->newline() << "#define STAP_VERSION(a, b) ( ((a) << 8) + (b) )"; |
7555 | s.op->newline() << "#ifndef STAP_COMPAT_VERSION"; | |
7556 | s.op->newline() << "#define STAP_COMPAT_VERSION STAP_VERSION(" | |
7557 | << major << ", " << minor << ")"; | |
7558 | s.op->newline() << "#endif"; | |
7559 | ||
a7ed0d3e FCE |
7560 | recursion_info ri (s); |
7561 | ||
7562 | // NB: we start our traversal from the s.functions[] rather than the probes. | |
7563 | // We assume that each function is called at least once, or else it would have | |
7564 | // been elided already. | |
7565 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) | |
7566 | { | |
7567 | functiondecl *fd = it->second; | |
7568 | fd->body->visit (& ri); | |
7569 | } | |
7570 | ||
7571 | if (s.verbose > 1) | |
1e41115c LB |
7572 | clog << _F("function recursion-analysis: max-nesting %d %s", ri.nesting_max, |
7573 | (ri.recursive ? _(" recursive") : _(" non-recursive"))) << endl; | |
a7ed0d3e FCE |
7574 | unsigned nesting = ri.nesting_max + 1; /* to account for initial probe->function call */ |
7575 | if (ri.recursive) nesting += 10; | |
dff50e09 | 7576 | |
a7ed0d3e | 7577 | // This is at the very top of the file. |
a34a9fe0 | 7578 | // All "static" defines (not dependend on session state). |
f2013cc9 | 7579 | s.op->newline() << "#include \"runtime_defines.h\""; |
3689db05 SC |
7580 | if (s.perf_derived_probes) |
7581 | s.op->newline() << "#define _HAVE_PERF_ 1"; | |
7582 | s.op->newline() << "#include \"linux/perf_read.h\""; | |
a34a9fe0 | 7583 | |
9a1917ff | 7584 | // Generated macros describing the privilege level required to load/run this module. |
f2013cc9 | 7585 | s.op->newline() << "#define STP_PR_STAPUSR 0x" << hex << pr_stapusr << dec; |
f6be7c06 | 7586 | s.op->newline() << "#define STP_PR_STAPSYS 0x" << hex << pr_stapsys << dec; |
f2013cc9 DB |
7587 | s.op->newline() << "#define STP_PR_STAPDEV 0x" << hex << pr_stapdev << dec; |
7588 | s.op->newline() << "#define STP_PRIVILEGE 0x" << hex << s.privilege << dec; | |
a34a9fe0 | 7589 | |
f2013cc9 | 7590 | // Generate a section containing a mask of the privilege levels required to load/run this |
9a1917ff | 7591 | // module. |
f2013cc9 | 7592 | s.op->newline() << "int stp_required_privilege " |
bb4470ca | 7593 | << "__attribute__ ((section (\"" << STAP_PRIVILEGE_SECTION <<"\")))" |
f2013cc9 | 7594 | << " = STP_PRIVILEGE;"; |
9a1917ff | 7595 | |
ed10c639 | 7596 | s.op->newline() << "#ifndef MAXNESTING"; |
a7ed0d3e | 7597 | s.op->newline() << "#define MAXNESTING " << nesting; |
ed10c639 | 7598 | s.op->newline() << "#endif"; |
1eed9afc | 7599 | |
e5fcd199 SM |
7600 | // Generated macros specifying how much storage is required for |
7601 | // regexp subexpressions: | |
7602 | s.op->newline() << "#define STAPREGEX_MAX_STATE" << s.dfa_maxstate; | |
7603 | s.op->newline() << "#define STAPREGEX_MAX_TAG" << s.dfa_maxtag; | |
7604 | ||
dcfd7fed FCE |
7605 | s.op->newline() << "#define STP_SKIP_BADVARS " << (s.skip_badvars ? 1 : 0); |
7606 | ||
f12b2552 | 7607 | if (s.bulk_mode) |
e65b03c1 | 7608 | s.op->newline() << "#define STP_BULKMODE"; |
dff50e09 | 7609 | |
f6429b94 | 7610 | if (s.timing || s.monitor) |
08badca8 MW |
7611 | s.op->newline() << "#define STP_TIMING"; |
7612 | ||
7613 | if (s.need_unwind) | |
7614 | s.op->newline() << "#define STP_NEED_UNWIND_DATA 1"; | |
4b17d6af | 7615 | |
ee533a58 AJ |
7616 | if (s.need_lines) |
7617 | s.op->newline() << "#define STP_NEED_LINE_DATA 1"; | |
7618 | ||
7c3e97f4 JS |
7619 | // Emit the total number of probes (not regarding merged probe handlers) |
7620 | s.op->newline() << "#define STP_PROBE_COUNT " << s.probes.size(); | |
7621 | ||
ba7276fa | 7622 | // Emit systemtap_module_refresh() prototype so we can reference it |
19d62b5b | 7623 | s.op->newline() << "static void systemtap_module_refresh (const char* modname);"; |
ba7276fa | 7624 | |
320e1ecb DS |
7625 | // Be sure to include runtime.h before any real code. |
7626 | s.op->newline() << "#include \"runtime.h\""; | |
7627 | ||
4bf3d59d JL |
7628 | if (!s.runtime_usermode_p()) |
7629 | { | |
4619bb71 JL |
7630 | // When on-the-fly [dis]arming is used, module_refresh can be called from |
7631 | // both the module notifier, as well as when probes need to be | |
7632 | // armed/disarmed. We need to protect it to ensure it's only run one at a | |
7633 | // time. | |
4bf3d59d JL |
7634 | s.op->newline() << "#include <linux/mutex.h>"; |
7635 | s.op->newline() << "static DEFINE_MUTEX(module_refresh_mutex);"; | |
4619bb71 JL |
7636 | |
7637 | // For some probes, on-the-fly support is provided through a | |
7638 | // background timer (module_refresh_timer). We need to disable that | |
7639 | // part if hrtimers are not supported. | |
7640 | s.op->newline() << "#include <linux/version.h>"; | |
7641 | s.op->newline() << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)"; | |
7642 | s.op->newline() << "#define STP_ON_THE_FLY_TIMER_ENABLE"; | |
7643 | s.op->newline() << "#endif"; | |
4bf3d59d | 7644 | } |
9c91d9d5 | 7645 | |
f58e7aa8 | 7646 | // Emit embeds ahead of time, in case they affect context layout |
54dfabe9 FCE |
7647 | for (unsigned i=0; i<s.embeds.size(); i++) |
7648 | { | |
db22e55f | 7649 | s.op->newline() << s.embeds[i]->code << "\n"; |
54dfabe9 FCE |
7650 | } |
7651 | ||
f58e7aa8 FCE |
7652 | s.up->emit_common_header (); // context etc. |
7653 | ||
1f88b7b7 MW |
7654 | if (s.need_unwind) |
7655 | s.op->newline() << "#include \"stack.c\""; | |
7656 | ||
63438a79 JS |
7657 | if (s.globals.size()>0) |
7658 | { | |
7659 | s.op->newline() << "struct stp_globals {"; | |
7660 | s.op->indent(1); | |
7661 | for (unsigned i=0; i<s.globals.size(); i++) | |
7662 | { | |
7663 | s.up->emit_global (s.globals[i]); | |
7664 | } | |
7665 | s.op->newline(-1) << "};"; | |
7666 | ||
7667 | // We only need to statically initialize globals in kernel modules, | |
7668 | // where module parameters may want to override the script's value. In | |
bd268288 SM |
7669 | // stapdyn, the globals are actually part of the dynamic shared memory, |
7670 | // and the static structure is merely used as a source of default values. | |
7671 | s.op->newline(); | |
7672 | if (!s.runtime_usermode_p ()) | |
7673 | s.op->newline() << "static struct stp_globals stp_global = {"; | |
7674 | else | |
7675 | { | |
7676 | s.op->newline() << "static struct {"; | |
7677 | s.op->indent(1); | |
7678 | for (unsigned i=0; i<s.globals.size(); i++) | |
7679 | { | |
7680 | assert_no_interrupts(); | |
7681 | s.up->emit_global_init_type (s.globals[i]); | |
7682 | } | |
7683 | s.op->newline(-1) << "} stp_global_init = {"; | |
7684 | } | |
7685 | s.op->newline(1); | |
7686 | for (unsigned i=0; i<s.globals.size(); i++) | |
63438a79 | 7687 | { |
bd268288 SM |
7688 | assert_no_interrupts(); |
7689 | s.up->emit_global_init (s.globals[i]); | |
63438a79 | 7690 | } |
bd268288 | 7691 | s.op->newline(-1) << "};"; |
63438a79 JS |
7692 | |
7693 | s.op->assert_0_indent(); | |
7694 | } | |
2caba859 DS |
7695 | else |
7696 | // stp_runtime_session wants to incorporate globals, but it | |
7697 | // can be empty | |
63438a79 JS |
7698 | s.op->newline() << "struct stp_globals {};"; |
7699 | ||
7700 | // Common (static atomic) state of the stap session. | |
8b2f930e | 7701 | s.op->newline(); |
63438a79 JS |
7702 | s.op->newline() << "#include \"common_session_state.h\""; |
7703 | ||
f58e7aa8 FCE |
7704 | s.op->newline() << "#include \"probe_lock.h\" "; |
7705 | ||
63438a79 JS |
7706 | s.op->newline() << "#ifdef STAP_NEED_GETTIMEOFDAY"; |
7707 | s.op->newline() << "#include \"time.c\""; // Don't we all need more? | |
7708 | s.op->newline() << "#endif"; | |
f4b28491 | 7709 | |
d2548fe7 SM |
7710 | for (map<string,stapdfa*>::iterator it = s.dfas.begin(); it != s.dfas.end(); it++) |
7711 | { | |
7712 | assert_no_interrupts(); | |
7713 | s.op->newline(); | |
5a14b9b8 SM |
7714 | try |
7715 | { | |
7716 | it->second->emit_declaration (s.op); | |
7717 | } | |
7718 | catch (const semantic_error &e) | |
7719 | { | |
60cf5fae | 7720 | s.print_error(e); |
5a14b9b8 | 7721 | } |
d2548fe7 SM |
7722 | } |
7723 | s.op->assert_0_indent(); | |
7724 | ||
f76427a2 | 7725 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) |
8a43522c | 7726 | { |
e19ebcf7 | 7727 | assert_no_interrupts(); |
8a43522c | 7728 | s.op->newline(); |
f76427a2 | 7729 | s.up->emit_functionsig (it->second); |
8a43522c | 7730 | } |
1384b663 | 7731 | s.op->assert_0_indent(); |
f4b28491 | 7732 | |
f4b28491 | 7733 | |
faea5e16 JS |
7734 | // Let's find some stats for the embedded pp strings. Maybe they |
7735 | // are small and uniform enough to justify putting char[MAX]'s into | |
7736 | // the array instead of relocated char*'s. | |
26e63673 JS |
7737 | size_t pp_max = 0, pn_max = 0, location_max = 0, derivation_max = 0; |
7738 | size_t pp_tot = 0, pn_tot = 0, location_tot = 0, derivation_tot = 0; | |
faea5e16 JS |
7739 | for (unsigned i=0; i<s.probes.size(); i++) |
7740 | { | |
7741 | derived_probe* p = s.probes[i]; | |
7742 | #define DOIT(var,expr) do { \ | |
7743 | size_t var##_size = (expr) + 1; \ | |
7744 | var##_max = max (var##_max, var##_size); \ | |
7745 | var##_tot += var##_size; } while (0) | |
7746 | DOIT(pp, lex_cast_qstring(*p->sole_location()).size()); | |
d48df0cf | 7747 | DOIT(pn, lex_cast_qstring(*p->script_location()).size()); |
26e63673 JS |
7748 | DOIT(location, lex_cast_qstring(p->tok->location).size()); |
7749 | DOIT(derivation, lex_cast_qstring(p->derived_locations()).size()); | |
faea5e16 JS |
7750 | #undef DOIT |
7751 | } | |
7752 | ||
7753 | // Decide whether it's worthwhile to use char[] or char* by comparing | |
7754 | // the amount of average waste (max - avg) to the relocation data size | |
7755 | // (3 native long words). | |
7756 | #define CALCIT(var) \ | |
1af06529 FCE |
7757 | if (s.verbose > 2) \ |
7758 | clog << "adapt " << #var << ":" << var##_max << "max - " << var##_tot << "/" << s.probes.size() << "tot =>"; \ | |
faea5e16 JS |
7759 | if ((var##_max-(var##_tot/s.probes.size())) < (3 * sizeof(void*))) \ |
7760 | { \ | |
7761 | s.op->newline() << "const char " << #var << "[" << var##_max << "];"; \ | |
7762 | if (s.verbose > 2) \ | |
1af06529 | 7763 | clog << "[]" << endl; \ |
faea5e16 JS |
7764 | } \ |
7765 | else \ | |
7766 | { \ | |
7767 | s.op->newline() << "const char * const " << #var << ";"; \ | |
7768 | if (s.verbose > 2) \ | |
1af06529 | 7769 | clog << "*" << endl; \ |
faea5e16 JS |
7770 | } |
7771 | ||
8b2f930e | 7772 | s.op->newline(); |
7c3e97f4 | 7773 | s.op->newline() << "struct stap_probe {"; |
100354e5 | 7774 | s.op->newline(1) << "const size_t index;"; |
7c3e97f4 | 7775 | s.op->newline() << "void (* const ph) (struct context*);"; |
d02d9b1c | 7776 | s.op->newline() << "unsigned cond_enabled:1;"; // just one bit required |
653e6a9a | 7777 | s.op->newline() << "#if defined(STP_TIMING) || defined(STP_ALIBI)"; |
26e63673 JS |
7778 | CALCIT(location); |
7779 | CALCIT(derivation); | |
7780 | s.op->newline() << "#define STAP_PROBE_INIT_TIMING(L, D) " | |
7781 | << ".location=(L), .derivation=(D),"; | |
994aac0e | 7782 | s.op->newline() << "#else"; |
26e63673 | 7783 | s.op->newline() << "#define STAP_PROBE_INIT_TIMING(L, D)"; |
994aac0e | 7784 | s.op->newline() << "#endif"; |
faea5e16 | 7785 | CALCIT(pp); |
d48df0cf JS |
7786 | s.op->newline() << "#ifdef STP_NEED_PROBE_NAME"; |
7787 | CALCIT(pn); | |
994aac0e | 7788 | s.op->newline() << "#define STAP_PROBE_INIT_NAME(PN) .pn=(PN),"; |
2d767770 | 7789 | s.op->newline() << "#else"; |
994aac0e | 7790 | s.op->newline() << "#define STAP_PROBE_INIT_NAME(PN)"; |
2d767770 | 7791 | s.op->newline() << "#endif"; |
7c3e97f4 | 7792 | s.op->newline() << "#define STAP_PROBE_INIT(I, PH, PP, PN, L, D) " |
61d88614 | 7793 | << "{ .index=(I), .ph=(PH), .cond_enabled=1, .pp=(PP), " |
994aac0e | 7794 | << "STAP_PROBE_INIT_NAME(PN) " |
26e63673 | 7795 | << "STAP_PROBE_INIT_TIMING(L, D) " |
994aac0e | 7796 | << "}"; |
3ef65016 JL |
7797 | s.op->newline(-1) << "} static stap_probes[];"; |
7798 | s.op->assert_0_indent(); | |
7799 | #undef CALCIT | |
7800 | ||
7801 | // Run a varuse_collecting_visitor over probes that need global | |
7802 | // variable locks. We'll use this information later in | |
7803 | // emit_locks()/emit_unlocks(). | |
7804 | for (unsigned i=0; i<s.probes.size(); i++) | |
7805 | { | |
7806 | assert_no_interrupts(); | |
05a072cf | 7807 | s.probes[i]->session_index = i; |
3ef65016 JL |
7808 | if (s.probes[i]->needs_global_locks()) |
7809 | s.probes[i]->body->visit (&cup.vcv_needs_global_locks); | |
7810 | } | |
7811 | s.op->assert_0_indent(); | |
7812 | ||
7813 | for (unsigned i=0; i<s.probes.size(); i++) | |
7814 | { | |
7815 | assert_no_interrupts(); | |
7816 | s.up->emit_probe (s.probes[i]); | |
7817 | } | |
7818 | s.op->assert_0_indent(); | |
7819 | ||
7820 | s.op->newline() << "static struct stap_probe stap_probes[] = {"; | |
26e63673 JS |
7821 | s.op->indent(1); |
7822 | for (unsigned i=0; i<s.probes.size(); ++i) | |
7823 | { | |
7824 | derived_probe* p = s.probes[i]; | |
1341a03c | 7825 | s.op->newline() << "STAP_PROBE_INIT(" << i << ", &" << p->name() << ", " |
26e63673 JS |
7826 | << lex_cast_qstring (*p->sole_location()) << ", " |
7827 | << lex_cast_qstring (*p->script_location()) << ", " | |
7828 | << lex_cast_qstring (p->tok->location) << ", " | |
7829 | << lex_cast_qstring (p->derived_locations()) << "),"; | |
7830 | } | |
faea5e16 | 7831 | s.op->newline(-1) << "};"; |
faea5e16 | 7832 | |
f4d70a33 JS |
7833 | if (s.runtime_usermode_p()) |
7834 | { | |
7835 | s.op->newline() << "static const char* stp_probe_point(size_t index) {"; | |
7836 | s.op->newline(1) << "if (index < ARRAY_SIZE(stap_probes))"; | |
7837 | s.op->newline(1) << "return stap_probes[index].pp;"; | |
7838 | s.op->newline(-1) << "return NULL;"; | |
7839 | s.op->newline(-1) << "}"; | |
7840 | s.op->assert_0_indent(); | |
7841 | } | |
7842 | ||
6120441d FL |
7843 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) |
7844 | { | |
7845 | assert_no_interrupts(); | |
7846 | s.op->newline(); | |
7847 | s.up->emit_function (it->second); | |
7848 | } | |
7849 | ||
3ef65016 | 7850 | s.op->assert_0_indent(); |
bfb3d2d2 | 7851 | s.op->newline(); |
2b066ec1 | 7852 | s.up->emit_module_init (); |
1384b663 | 7853 | s.op->assert_0_indent(); |
bfb3d2d2 | 7854 | s.op->newline(); |
a60923e9 FCE |
7855 | s.up->emit_module_refresh (); |
7856 | s.op->assert_0_indent(); | |
7857 | s.op->newline(); | |
2b066ec1 | 7858 | s.up->emit_module_exit (); |
1384b663 | 7859 | s.op->assert_0_indent(); |
be66b6e1 DS |
7860 | s.up->emit_kernel_module_init (); |
7861 | s.op->assert_0_indent(); | |
7862 | s.up->emit_kernel_module_exit (); | |
7863 | s.op->assert_0_indent(); | |
f4b28491 | 7864 | s.op->newline(); |
f4b28491 | 7865 | |
ed35c8ac FCE |
7866 | emit_symbol_data (s); |
7867 | ||
7868 | s.op->newline() << "MODULE_DESCRIPTION(\"systemtap-generated probe\");"; | |
7869 | s.op->newline() << "MODULE_LICENSE(\"GPL\");"; | |
633e5ca7 FCE |
7870 | |
7871 | for (unsigned i = 0; i < s.modinfos.size(); i++) | |
7872 | { | |
7873 | const string& mi = s.modinfos[i]; | |
7874 | size_t loc = mi.find('='); | |
7875 | string tag = mi.substr (0, loc); | |
7876 | string value = mi.substr (loc+1); | |
7877 | s.op->newline() << "MODULE_INFO(" << tag << "," << lex_cast_qstring(value) << ");"; | |
7878 | } | |
7879 | ||
ed35c8ac FCE |
7880 | s.op->assert_0_indent(); |
7881 | ||
bd268288 SM |
7882 | if (s.runtime_usermode_p()) |
7883 | s.up->emit_global_init_setters(); | |
7884 | else | |
7885 | // PR10298: attempt to avoid collisions with symbols | |
7886 | for (unsigned i=0; i<s.globals.size(); i++) | |
7887 | { | |
7888 | s.op->newline(); | |
7889 | s.up->emit_global_param (s.globals[i]); | |
7890 | } | |
1384b663 | 7891 | s.op->assert_0_indent(); |
2b066ec1 FCE |
7892 | } |
7893 | catch (const semantic_error& e) | |
7894 | { | |
7895 | s.print_error (e); | |
7896 | } | |
7897 | ||
db22e55f | 7898 | s.op->line() << "\n"; |
33f88a80 | 7899 | |
f4b28491 FCE |
7900 | delete s.op; |
7901 | s.op = 0; | |
4383d78c | 7902 | s.up = 0; |
33f88a80 | 7903 | |
7e41d3dc | 7904 | return rc + s.num_errors(); |
2b066ec1 | 7905 | } |
73267b89 JS |
7906 | |
7907 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |