1 : // translation pass
2 : // Copyright (C) 2005-2008 Red Hat Inc.
3 : // Copyright (C) 2005-2007 Intel Corporation.
4 : //
5 : // This file is part of systemtap, and is free software. You can
6 : // redistribute it and/or modify it under the terms of the GNU General
7 : // Public License (GPL); either version 2, or (at your option) any
8 : // later version.
9 :
10 : #include "config.h"
11 : #include "staptree.h"
12 : #include "elaborate.h"
13 : #include "translate.h"
14 : #include "session.h"
15 : #include "tapsets.h"
16 : #include "util.h"
17 :
18 : #include <cstdlib>
19 : #include <iostream>
20 : #include <set>
21 : #include <sstream>
22 : #include <string>
23 : #include <cassert>
24 :
25 : extern "C" {
26 : #include <elfutils/libdwfl.h>
27 : }
28 :
29 : using namespace std;
30 :
31 : struct var;
32 : struct tmpvar;
33 : struct aggvar;
34 : struct mapvar;
35 : struct itervar;
36 :
37 : struct c_unparser: public unparser, public visitor
38 : {
39 : systemtap_session* session;
40 : translator_output* o;
41 :
42 : derived_probe* current_probe;
43 : functiondecl* current_function;
44 : unsigned tmpvar_counter;
45 : unsigned label_counter;
46 : bool probe_or_function_needs_deref_fault_handler;
47 :
48 : varuse_collecting_visitor vcv_needs_global_locks;
49 :
50 : map<string, string> probe_contents;
51 :
52 283 : c_unparser (systemtap_session* ss):
53 : session (ss), o (ss->op), current_probe(0), current_function (0),
54 283 : tmpvar_counter (0), label_counter (0) {}
55 283 : ~c_unparser () {}
56 :
57 : void emit_map_type_instantiations ();
58 : void emit_common_header ();
59 : void emit_global (vardecl* v);
60 : void emit_global_init (vardecl* v);
61 : void emit_global_param (vardecl* v);
62 : void emit_functionsig (functiondecl* v);
63 : void emit_module_init ();
64 : void emit_module_exit ();
65 : void emit_function (functiondecl* v);
66 : void emit_locks (const varuse_collecting_visitor& v);
67 : void emit_probe (derived_probe* v);
68 : void emit_unlocks (const varuse_collecting_visitor& v);
69 :
70 : // for use by stats (pmap) foreach
71 : set<string> aggregations_active;
72 :
73 : // for use by looping constructs
74 : vector<string> loop_break_labels;
75 : vector<string> loop_continue_labels;
76 :
77 : string c_typename (exp_type e);
78 : string c_varname (const string& e);
79 : string c_expression (expression* e);
80 :
81 : void c_assign (var& lvalue, const string& rvalue, const token* tok);
82 : void c_assign (const string& lvalue, expression* rvalue, const string& msg);
83 : void c_assign (const string& lvalue, const string& rvalue, exp_type type,
84 : const string& msg, const token* tok);
85 :
86 : void c_declare(exp_type ty, const string &name);
87 : void c_declare_static(exp_type ty, const string &name);
88 :
89 : void c_strcat (const string& lvalue, const string& rvalue);
90 : void c_strcat (const string& lvalue, expression* rvalue);
91 :
92 : void c_strcpy (const string& lvalue, const string& rvalue);
93 : void c_strcpy (const string& lvalue, expression* rvalue);
94 :
95 : bool is_local (vardecl const* r, token const* tok);
96 :
97 : tmpvar gensym(exp_type ty);
98 : aggvar gensym_aggregate();
99 :
100 : var getvar(vardecl* v, token const* tok = NULL);
101 : itervar getiter(symbol* s);
102 : mapvar getmap(vardecl* v, token const* tok = NULL);
103 :
104 : void load_map_indices(arrayindex* e,
105 : vector<tmpvar> & idx);
106 :
107 : void load_aggregate (expression *e, aggvar & agg, bool pre_agg=false);
108 : string histogram_index_check(var & vase, tmpvar & idx) const;
109 :
110 : void collect_map_index_types(vector<vardecl* > const & vars,
111 : set< pair<vector<exp_type>, exp_type> > & types);
112 :
113 : void visit_statement (statement* s, unsigned actions, bool stmtize);
114 :
115 : void visit_block (block* s);
116 : void visit_embeddedcode (embeddedcode* s);
117 : void visit_null_statement (null_statement* s);
118 : void visit_expr_statement (expr_statement* s);
119 : void visit_if_statement (if_statement* s);
120 : void visit_for_loop (for_loop* s);
121 : void visit_foreach_loop (foreach_loop* s);
122 : void visit_return_statement (return_statement* s);
123 : void visit_delete_statement (delete_statement* s);
124 : void visit_next_statement (next_statement* s);
125 : void visit_break_statement (break_statement* s);
126 : void visit_continue_statement (continue_statement* s);
127 : void visit_literal_string (literal_string* e);
128 : void visit_literal_number (literal_number* e);
129 : void visit_binary_expression (binary_expression* e);
130 : void visit_unary_expression (unary_expression* e);
131 : void visit_pre_crement (pre_crement* e);
132 : void visit_post_crement (post_crement* e);
133 : void visit_logical_or_expr (logical_or_expr* e);
134 : void visit_logical_and_expr (logical_and_expr* e);
135 : void visit_array_in (array_in* e);
136 : void visit_comparison (comparison* e);
137 : void visit_concatenation (concatenation* e);
138 : void visit_ternary_expression (ternary_expression* e);
139 : void visit_assignment (assignment* e);
140 : void visit_symbol (symbol* e);
141 : void visit_target_symbol (target_symbol* e);
142 : void visit_arrayindex (arrayindex* e);
143 : void visit_functioncall (functioncall* e);
144 : void visit_print_format (print_format* e);
145 : void visit_stat_op (stat_op* e);
146 : void visit_hist_op (hist_op* e);
147 : };
148 :
149 : // A shadow visitor, meant to generate temporary variable declarations
150 : // for function or probe bodies. Member functions should exactly match
151 : // the corresponding c_unparser logic and traversal sequence,
152 : // to ensure interlocking naming and declaration of temp variables.
153 : struct c_tmpcounter:
154 : public traversing_visitor
155 3359 : {
156 : c_unparser* parent;
157 3359 : c_tmpcounter (c_unparser* p):
158 3359 : parent (p)
159 : {
160 3359 : parent->tmpvar_counter = 0;
161 3359 : }
162 :
163 : void load_map_indices(arrayindex* e);
164 :
165 : void visit_block (block *s);
166 : void visit_for_loop (for_loop* s);
167 : void visit_foreach_loop (foreach_loop* s);
168 : // void visit_return_statement (return_statement* s);
169 : void visit_delete_statement (delete_statement* s);
170 : void visit_binary_expression (binary_expression* e);
171 : // void visit_unary_expression (unary_expression* e);
172 : void visit_pre_crement (pre_crement* e);
173 : void visit_post_crement (post_crement* e);
174 : // void visit_logical_or_expr (logical_or_expr* e);
175 : // void visit_logical_and_expr (logical_and_expr* e);
176 : void visit_array_in (array_in* e);
177 : // void visit_comparison (comparison* e);
178 : void visit_concatenation (concatenation* e);
179 : // void visit_ternary_expression (ternary_expression* e);
180 : void visit_assignment (assignment* e);
181 : void visit_arrayindex (arrayindex* e);
182 : void visit_functioncall (functioncall* e);
183 : void visit_print_format (print_format* e);
184 : void visit_stat_op (stat_op* e);
185 : };
186 :
187 : struct c_unparser_assignment:
188 : public throwing_visitor
189 6458 : {
190 : c_unparser* parent;
191 : string op;
192 : expression* rvalue;
193 : bool post; // true == value saved before modify operator
194 5709 : c_unparser_assignment (c_unparser* p, const string& o, expression* e):
195 : throwing_visitor ("invalid lvalue type"),
196 5709 : parent (p), op (o), rvalue (e), post (false) {}
197 749 : c_unparser_assignment (c_unparser* p, const string& o, bool pp):
198 : throwing_visitor ("invalid lvalue type"),
199 749 : parent (p), op (o), rvalue (0), post (pp) {}
200 :
201 : void prepare_rvalue (string const & op,
202 : tmpvar & rval,
203 : token const* tok);
204 :
205 : void c_assignop(tmpvar & res,
206 : var const & lvar,
207 : tmpvar const & tmp,
208 : token const* tok);
209 :
210 : // only symbols and arrayindex nodes are possible lvalues
211 : void visit_symbol (symbol* e);
212 : void visit_arrayindex (arrayindex* e);
213 : };
214 :
215 :
216 : struct c_tmpcounter_assignment:
217 : public traversing_visitor
218 : // leave throwing for illegal lvalues to the c_unparser_assignment instance
219 6459 : {
220 : c_tmpcounter* parent;
221 : const string& op;
222 : expression* rvalue;
223 : bool post; // true == value saved before modify operator
224 6459 : c_tmpcounter_assignment (c_tmpcounter* p, const string& o, expression* e, bool pp = false):
225 6459 : parent (p), op (o), rvalue (e), post (pp) {}
226 :
227 : void prepare_rvalue (tmpvar & rval);
228 :
229 : void c_assignop(tmpvar & res);
230 :
231 : // only symbols and arrayindex nodes are possible lvalues
232 : void visit_symbol (symbol* e);
233 : void visit_arrayindex (arrayindex* e);
234 : };
235 :
236 :
237 : ostream & operator<<(ostream & o, var const & v);
238 :
239 :
240 : /*
241 : Some clarification on the runtime structures involved in statistics:
242 :
243 : The basic type for collecting statistics in the runtime is struct
244 : stat_data. This contains the count, min, max, sum, and possibly
245 : histogram fields.
246 :
247 : There are two places struct stat_data shows up.
248 :
249 : 1. If you declare a statistic variable of any sort, you want to make
250 : a struct _Stat. A struct _Stat* is also called a Stat. Struct _Stat
251 : contains a per-CPU array of struct stat_data values, as well as a
252 : struct stat_data which it aggregates into. Writes into a Struct
253 : _Stat go into the per-CPU struct stat. Reads involve write-locking
254 : the struct _Stat, aggregating into its aggregate struct stat_data,
255 : unlocking, read-locking the struct _Stat, then reading values out of
256 : the aggregate and unlocking.
257 :
258 : 2. If you declare a statistic-valued map, you want to make a
259 : pmap. This is a per-CPU array of maps, each of which holds struct
260 : stat_data values, as well as an aggregate *map*. Writes into a pmap
261 : go into the per-CPU map. Reads involve write-locking the pmap,
262 : aggregating into its aggregate map, unlocking, read-locking the
263 : pmap, then reading values out of its aggregate (which is a normal
264 : map) and unlocking.
265 :
266 : Because, at the moment, the runtime does not support the concept of
267 : a statistic which collects multiple histogram types, we may need to
268 : instantiate one pmap or struct _Stat for each histogram variation
269 : the user wants to track.
270 : */
271 :
272 : class var
273 28733 : {
274 :
275 : protected:
276 : bool local;
277 : exp_type ty;
278 : statistic_decl sd;
279 : string name;
280 :
281 : public:
282 :
283 6321 : var(bool local, exp_type ty, statistic_decl const & sd, string const & name)
284 6321 : : local(local), ty(ty), sd(sd), name(name)
285 6321 : {}
286 :
287 84039 : var(bool local, exp_type ty, string const & name)
288 84039 : : local(local), ty(ty), name(name)
289 84039 : {}
290 :
291 113459 : virtual ~var() {}
292 :
293 : bool is_local() const
294 : {
295 : return local;
296 : }
297 :
298 25 : statistic_decl const & sdecl() const
299 : {
300 25 : return sd;
301 : }
302 :
303 112 : void assert_hist_compatible(hist_op const & hop)
304 : {
305 : // Semantic checks in elaborate should have caught this if it was
306 : // false. This is just a double-check.
307 112 : switch (sd.type)
308 : {
309 : case statistic_decl::linear:
310 53 : assert(hop.htype == hist_linear);
311 53 : assert(hop.params.size() == 3);
312 53 : assert(hop.params[0] == sd.linear_low);
313 53 : assert(hop.params[1] == sd.linear_high);
314 53 : assert(hop.params[2] == sd.linear_step);
315 53 : break;
316 : case statistic_decl::logarithmic:
317 59 : assert(hop.htype == hist_log);
318 59 : assert(hop.params.size() == 0);
319 59 : break;
320 : case statistic_decl::none:
321 0 : assert(false);
322 : }
323 112 : }
324 :
325 34124 : exp_type type() const
326 : {
327 34124 : return ty;
328 : }
329 :
330 66663 : string value() const
331 : {
332 66663 : if (local)
333 59809 : return "l->" + name;
334 : else
335 6854 : return "global.s_" + name;
336 : }
337 :
338 78 : virtual string hist() const
339 : {
340 78 : assert (ty == pe_stats);
341 78 : assert (sd.type != statistic_decl::none);
342 78 : return "(&(" + value() + "->hist))";
343 : }
344 :
345 21 : virtual string buckets() const
346 : {
347 21 : assert (ty == pe_stats);
348 21 : assert (sd.type != statistic_decl::none);
349 21 : return "(" + value() + "->hist.buckets)";
350 : }
351 :
352 1262 : string init() const
353 : {
354 1262 : switch (type())
355 : {
356 : case pe_string:
357 474 : if (! local)
358 18 : return ""; // module_param
359 : else
360 456 : return value() + "[0] = '\\0';";
361 : case pe_long:
362 747 : if (! local)
363 98 : return ""; // module_param
364 : else
365 649 : return value() + " = 0;";
366 : case pe_stats:
367 : {
368 : // See also mapvar::init().
369 :
370 41 : string prefix = value() + " = _stp_stat_init (";
371 : // Check for errors during allocation.
372 82 : string suffix = "if (" + value () + " == NULL) rc = -ENOMEM;";
373 :
374 41 : switch (sd.type)
375 : {
376 : case statistic_decl::none:
377 5 : prefix += "HIST_NONE";
378 5 : break;
379 :
380 : case statistic_decl::linear:
381 : prefix += string("HIST_LINEAR")
382 : + ", " + stringify(sd.linear_low)
383 : + ", " + stringify(sd.linear_high)
384 22 : + ", " + stringify(sd.linear_step);
385 22 : break;
386 :
387 : case statistic_decl::logarithmic:
388 14 : prefix += string("HIST_LOG");
389 14 : break;
390 :
391 : default:
392 0 : throw semantic_error("unsupported stats type for " + value());
393 : }
394 :
395 41 : prefix = prefix + "); ";
396 41 : return string (prefix + suffix);
397 : }
398 :
399 : default:
400 0 : throw semantic_error("unsupported initializer for " + value());
401 : }
402 : }
403 :
404 314 : string fini () const
405 : {
406 314 : switch (type())
407 : {
408 : case pe_string:
409 : case pe_long:
410 232 : return ""; // no action required
411 : case pe_stats:
412 82 : return "_stp_stat_del (" + value () + ");";
413 : default:
414 0 : throw semantic_error("unsupported deallocator for " + value());
415 : }
416 : }
417 :
418 19999 : void declare(c_unparser &c) const
419 : {
420 19999 : c.c_declare(ty, name);
421 19999 : }
422 : };
423 :
424 14124 : ostream & operator<<(ostream & o, var const & v)
425 : {
426 14124 : return o << v.value();
427 : }
428 :
429 : struct stmt_expr
430 : {
431 : c_unparser & c;
432 20282 : stmt_expr(c_unparser & c) : c(c)
433 : {
434 20282 : c.o->newline() << "({";
435 20282 : c.o->indent(1);
436 20282 : }
437 20282 : ~stmt_expr()
438 : {
439 20282 : c.o->newline(-1) << "})";
440 20282 : }
441 : };
442 :
443 :
444 : struct tmpvar
445 : : public var
446 120913 : {
447 : protected:
448 : bool overridden;
449 : string override_value;
450 :
451 : public:
452 : tmpvar(exp_type ty,
453 69239 : unsigned & counter)
454 69239 : : var(true, ty, ("__tmp" + stringify(counter++))), overridden(false)
455 69239 : {}
456 :
457 158 : tmpvar(const var& source)
458 158 : : var(source), overridden(false)
459 158 : {}
460 :
461 8443 : void override(const string &value)
462 : {
463 8443 : overridden = true;
464 8443 : override_value = value;
465 8443 : }
466 :
467 53157 : string value() const
468 : {
469 53157 : if (overridden)
470 11109 : return override_value;
471 : else
472 42048 : return var::value();
473 : }
474 : };
475 :
476 11644 : ostream & operator<<(ostream & o, tmpvar const & v)
477 : {
478 11644 : return o << v.value();
479 : }
480 :
481 : struct aggvar
482 : : public var
483 632 : {
484 632 : aggvar(unsigned & counter)
485 632 : : var(true, pe_stats, ("__tmp" + stringify(counter++)))
486 632 : {}
487 :
488 : string init() const
489 : {
490 : assert (type() == pe_stats);
491 : return value() + " = NULL;";
492 : }
493 :
494 316 : void declare(c_unparser &c) const
495 : {
496 316 : assert (type() == pe_stats);
497 316 : c.o->newline() << "struct stat_data *" << name << ";";
498 316 : }
499 : };
500 :
501 : struct mapvar
502 : : public var
503 2974 : {
504 : vector<exp_type> index_types;
505 : int maxsize;
506 : mapvar (bool local, exp_type ty,
507 : statistic_decl const & sd,
508 : string const & name,
509 : vector<exp_type> const & index_types,
510 2974 : int maxsize)
511 : : var (local, ty, sd, name),
512 : index_types (index_types),
513 2974 : maxsize (maxsize)
514 2974 : {}
515 :
516 : static string shortname(exp_type e);
517 : static string key_typename(exp_type e);
518 : static string value_typename(exp_type e);
519 :
520 2520 : string keysym () const
521 : {
522 2520 : string result;
523 2520 : vector<exp_type> tmp = index_types;
524 2520 : tmp.push_back (type ());
525 7998 : for (unsigned i = 0; i < tmp.size(); ++i)
526 : {
527 5478 : switch (tmp[i])
528 : {
529 : case pe_long:
530 3840 : result += 'i';
531 3840 : break;
532 : case pe_string:
533 1422 : result += 's';
534 1422 : break;
535 : case pe_stats:
536 216 : result += 'x';
537 216 : break;
538 : default:
539 0 : throw semantic_error("unknown type of map");
540 : break;
541 : }
542 : }
543 2520 : return result;
544 : }
545 :
546 2246 : string call_prefix (string const & fname, vector<tmpvar> const & indices, bool pre_agg=false) const
547 : {
548 2246 : string mtype = (is_parallel() && !pre_agg) ? "pmap" : "map";
549 4492 : string result = "_stp_" + mtype + "_" + fname + "_" + keysym() + " (";
550 2246 : result += pre_agg? fetch_existing_aggregate() : value();
551 4817 : for (unsigned i = 0; i < indices.size(); ++i)
552 : {
553 2571 : if (indices[i].type() != index_types[i])
554 0 : throw semantic_error("index type mismatch");
555 2571 : result += ", ";
556 2571 : result += indices[i].value();
557 : }
558 :
559 2246 : return result;
560 : }
561 :
562 3779 : bool is_parallel() const
563 : {
564 3779 : return type() == pe_stats;
565 : }
566 :
567 23 : string calculate_aggregate() const
568 : {
569 23 : if (!is_parallel())
570 0 : throw semantic_error("aggregating non-parallel map type");
571 :
572 23 : return "_stp_pmap_agg (" + value() + ")";
573 : }
574 :
575 159 : string fetch_existing_aggregate() const
576 : {
577 159 : if (!is_parallel())
578 0 : throw semantic_error("fetching aggregate of non-parallel map type");
579 :
580 159 : return "_stp_pmap_get_agg(" + value() + ")";
581 : }
582 :
583 180 : string del (vector<tmpvar> const & indices) const
584 : {
585 180 : return (call_prefix("del", indices) + ")");
586 : }
587 :
588 42 : string exists (vector<tmpvar> const & indices) const
589 : {
590 42 : if (type() == pe_long || type() == pe_string)
591 42 : return (call_prefix("exists", indices) + ")");
592 0 : else if (type() == pe_stats)
593 : return ("((uintptr_t)" + call_prefix("get", indices)
594 0 : + ") != (uintptr_t) 0)");
595 : else
596 0 : throw semantic_error("checking existence of an unsupported map type");
597 : }
598 :
599 1001 : string get (vector<tmpvar> const & indices, bool pre_agg=false) const
600 : {
601 : // see also itervar::get_key
602 1001 : if (type() == pe_string)
603 : // impedance matching: NULL -> empty strings
604 : return ("({ char *v = " + call_prefix("get", indices, pre_agg) + ");"
605 380 : + "if (!v) v = \"\"; v; })");
606 621 : else if (type() == pe_long || type() == pe_stats)
607 621 : return call_prefix("get", indices, pre_agg) + ")";
608 : else
609 0 : throw semantic_error("getting a value from an unsupported map type");
610 : }
611 :
612 65 : string add (vector<tmpvar> const & indices, tmpvar const & val) const
613 : {
614 65 : string res = "{ int rc = ";
615 :
616 : // impedance matching: empty strings -> NULL
617 65 : if (type() == pe_stats)
618 65 : res += (call_prefix("add", indices) + ", " + val.value() + ")");
619 : else
620 0 : throw semantic_error("adding a value of an unsupported map type");
621 :
622 : res += "; if (unlikely(rc)) c->last_error = \"Array overflow, check " +
623 : stringify(maxsize > 0 ?
624 : "size limit (" + stringify(maxsize) + ")" : "MAXMAPENTRIES")
625 65 : + "\"; }";
626 :
627 0 : return res;
628 : }
629 :
630 958 : string set (vector<tmpvar> const & indices, tmpvar const & val) const
631 : {
632 958 : string res = "{ int rc = ";
633 :
634 : // impedance matching: empty strings -> NULL
635 958 : if (type() == pe_string)
636 : res += (call_prefix("set", indices)
637 572 : + ", (" + val.value() + "[0] ? " + val.value() + " : NULL))");
638 386 : else if (type() == pe_long)
639 386 : res += (call_prefix("set", indices) + ", " + val.value() + ")");
640 : else
641 0 : throw semantic_error("setting a value of an unsupported map type");
642 :
643 : res += "; if (unlikely(rc)) c->last_error = \"Array overflow, check " +
644 : stringify(maxsize > 0 ?
645 : "size limit (" + stringify(maxsize) + ")" : "MAXMAPENTRIES")
646 958 : + "\"; }";
647 :
648 0 : return res;
649 : }
650 :
651 9 : string hist() const
652 : {
653 9 : assert (ty == pe_stats);
654 9 : assert (sd.type != statistic_decl::none);
655 9 : return "(&(" + fetch_existing_aggregate() + "->hist))";
656 : }
657 :
658 4 : string buckets() const
659 : {
660 4 : assert (ty == pe_stats);
661 4 : assert (sd.type != statistic_decl::none);
662 4 : return "(" + fetch_existing_aggregate() + "->hist.buckets)";
663 : }
664 :
665 274 : string init () const
666 : {
667 274 : string mtype = is_parallel() ? "pmap" : "map";
668 : string prefix = value() + " = _stp_" + mtype + "_new_" + keysym() + " (" +
669 293 : (maxsize > 0 ? stringify(maxsize) : "MAXMAPENTRIES") ;
670 :
671 : // See also var::init().
672 :
673 : // Check for errors during allocation.
674 274 : string suffix = "if (" + value () + " == NULL) rc = -ENOMEM;";
675 :
676 274 : if (type() == pe_stats)
677 : {
678 25 : switch (sdecl().type)
679 : {
680 : case statistic_decl::none:
681 18 : prefix = prefix + ", HIST_NONE";
682 18 : break;
683 :
684 : case statistic_decl::linear:
685 : // FIXME: check for "reasonable" values in linear stats
686 : prefix = prefix + ", HIST_LINEAR"
687 : + ", " + stringify(sdecl().linear_low)
688 : + ", " + stringify(sdecl().linear_high)
689 0 : + ", " + stringify(sdecl().linear_step);
690 0 : break;
691 :
692 : case statistic_decl::logarithmic:
693 7 : prefix = prefix + ", HIST_LOG";
694 : break;
695 : }
696 : }
697 :
698 274 : prefix = prefix + "); ";
699 274 : return (prefix + suffix);
700 : }
701 :
702 548 : string fini () const
703 : {
704 : // NB: fini() is safe to call even for globals that have not
705 : // successfully initialized (that is to say, on NULL pointers),
706 : // because the runtime specifically tolerates that in its _del
707 : // functions.
708 :
709 548 : if (is_parallel())
710 50 : return "_stp_pmap_del (" + value() + ");";
711 : else
712 498 : return "_stp_map_del (" + value() + ");";
713 : }
714 : };
715 :
716 :
717 : class itervar
718 204 : {
719 : exp_type referent_ty;
720 : string name;
721 :
722 : public:
723 :
724 204 : itervar (symbol* e, unsigned & counter)
725 : : referent_ty(e->referent->type),
726 204 : name("__tmp" + stringify(counter++))
727 : {
728 204 : if (referent_ty == pe_unknown)
729 0 : throw semantic_error("iterating over unknown reference type", e->tok);
730 204 : }
731 :
732 102 : string declare () const
733 : {
734 102 : return "struct map_node *" + name + ";";
735 : }
736 :
737 102 : string start (mapvar const & mv) const
738 : {
739 102 : string res;
740 :
741 102 : if (mv.type() != referent_ty)
742 0 : throw semantic_error("inconsistent iterator type in itervar::start()");
743 :
744 102 : if (mv.is_parallel())
745 23 : return "_stp_map_start (" + mv.fetch_existing_aggregate() + ")";
746 : else
747 79 : return "_stp_map_start (" + mv.value() + ")";
748 : }
749 :
750 102 : string next (mapvar const & mv) const
751 : {
752 102 : if (mv.type() != referent_ty)
753 0 : throw semantic_error("inconsistent iterator type in itervar::next()");
754 :
755 102 : if (mv.is_parallel())
756 23 : return "_stp_map_iter (" + mv.fetch_existing_aggregate() + ", " + value() + ")";
757 : else
758 79 : return "_stp_map_iter (" + mv.value() + ", " + value() + ")";
759 : }
760 :
761 532 : string value () const
762 : {
763 532 : return "l->" + name;
764 : }
765 :
766 124 : string get_key (exp_type ty, unsigned i) const
767 : {
768 : // bug translator/1175: runtime uses base index 1 for the first dimension
769 : // see also mapval::get
770 124 : switch (ty)
771 : {
772 : case pe_long:
773 91 : return "_stp_key_get_int64 ("+ value() + ", " + stringify(i+1) + ")";
774 : case pe_string:
775 : // impedance matching: NULL -> empty strings
776 : return "({ char *v = "
777 : "_stp_key_get_str ("+ value() + ", " + stringify(i+1) + "); "
778 : "if (! v) v = \"\"; "
779 33 : "v; })";
780 : default:
781 0 : throw semantic_error("illegal key type");
782 : }
783 : }
784 : };
785 :
786 306 : ostream & operator<<(ostream & o, itervar const & v)
787 : {
788 306 : return o << v.value();
789 : }
790 :
791 : // ------------------------------------------------------------------------
792 :
793 :
794 5023 : translator_output::translator_output (ostream& f):
795 5023 : buf(0), o2 (0), o (f), tablevel (0)
796 : {
797 5023 : }
798 :
799 :
800 283 : translator_output::translator_output (const string& filename, size_t bufsize):
801 : buf (new char[bufsize]),
802 : o2 (new ofstream (filename.c_str ())),
803 : o (*o2),
804 283 : tablevel (0)
805 : {
806 283 : o2->rdbuf()->pubsetbuf(buf, bufsize);
807 283 : }
808 :
809 :
810 5306 : translator_output::~translator_output ()
811 : {
812 5306 : delete o2;
813 5306 : delete [] buf;
814 5306 : }
815 :
816 :
817 : ostream&
818 567817 : translator_output::newline (int indent)
819 : {
820 567817 : if (! (indent > 0 || tablevel >= (unsigned)-indent)) o.flush ();
821 567817 : assert (indent > 0 || tablevel >= (unsigned)-indent);
822 :
823 567817 : tablevel += indent;
824 567817 : o << "\n";
825 1939793 : for (unsigned i=0; i<tablevel; i++)
826 1371976 : o << " ";
827 567817 : return o;
828 : }
829 :
830 :
831 : void
832 90379 : translator_output::indent (int indent)
833 : {
834 90379 : if (! (indent > 0 || tablevel >= (unsigned)-indent)) o.flush ();
835 90379 : assert (indent > 0 || tablevel >= (unsigned)-indent);
836 90379 : tablevel += indent;
837 90379 : }
838 :
839 :
840 : ostream&
841 182594 : translator_output::line ()
842 : {
843 182594 : return o;
844 : }
845 :
846 :
847 : // ------------------------------------------------------------------------
848 :
849 : void
850 283 : c_unparser::emit_common_header ()
851 : {
852 283 : o->newline() << "typedef char string_t[MAXSTRINGLEN];";
853 283 : o->newline();
854 283 : o->newline() << "#define STAP_SESSION_STARTING 0";
855 283 : o->newline() << "#define STAP_SESSION_RUNNING 1";
856 283 : o->newline() << "#define STAP_SESSION_ERROR 2";
857 283 : o->newline() << "#define STAP_SESSION_STOPPING 3";
858 283 : o->newline() << "#define STAP_SESSION_STOPPED 4";
859 283 : o->newline() << "atomic_t session_state = ATOMIC_INIT (STAP_SESSION_STARTING);";
860 283 : o->newline() << "atomic_t error_count = ATOMIC_INIT (0);";
861 283 : o->newline() << "atomic_t skipped_count = ATOMIC_INIT (0);";
862 283 : o->newline();
863 283 : o->newline() << "struct context {";
864 283 : o->newline(1) << "atomic_t busy;";
865 283 : o->newline() << "const char *probe_point;";
866 283 : o->newline() << "int actionremaining;";
867 283 : o->newline() << "unsigned nesting;";
868 283 : o->newline() << "string_t error_buffer;";
869 283 : o->newline() << "const char *last_error;";
870 : // NB: last_error is used as a health flag within a probe.
871 : // While it's 0, execution continues
872 : // When it's "", current function or probe unwinds and returns early
873 : // When it's "something", probe code unwinds, _stp_error's, sets error state
874 : // See c_unparser::visit_statement()
875 283 : o->newline() << "const char *last_stmt;";
876 283 : o->newline() << "struct pt_regs *regs;";
877 283 : o->newline() << "struct kretprobe_instance *pi;";
878 283 : o->newline() << "va_list *mark_va_list;";
879 283 : o->newline() << "void *data;";
880 283 : o->newline() << "#ifdef STP_TIMING";
881 283 : o->newline() << "Stat *statp;";
882 283 : o->newline() << "#endif";
883 283 : o->newline() << "#ifdef STP_OVERLOAD";
884 283 : o->newline() << "cycles_t cycles_base;";
885 283 : o->newline() << "cycles_t cycles_sum;";
886 283 : o->newline() << "#endif";
887 283 : o->newline() << "union {";
888 283 : o->indent(1);
889 :
890 : // To elide context variables for probe handler functions that
891 : // themselves are about to get duplicate-eliminated, we XXX
892 : // duplicate the parse-tree-hash method from ::emit_probe().
893 283 : map<string, string> tmp_probe_contents;
894 : // The reason we don't use c_unparser::probe_contents itself
895 : // for this is that we don't want to muck up the data for
896 : // that later routine.
897 :
898 9538 : for (unsigned i=0; i<session->probes.size(); i++)
899 : {
900 9256 : derived_probe* dp = session->probes[i];
901 :
902 : // NB: see c_unparser::emit_probe() for original copy of duplicate-hashing logic.
903 9256 : ostringstream oss;
904 9256 : oss << "c->statp = & time_" << dp->basest()->name << ";" << endl; // -t anti-dupe
905 9256 : oss << "# needs_global_locks: " << dp->needs_global_locks () << endl;
906 9256 : dp->body->print(oss);
907 : // NB: dependent probe conditions *could* be listed here, but don't need to be.
908 : // That's because they're only dependent on the probe body, which is already
909 : // "hashed" in above.
910 :
911 :
912 9256 : if (tmp_probe_contents.count(oss.str()) == 0) // unique
913 : {
914 2117 : tmp_probe_contents[oss.str()] = dp->name; // save it
915 :
916 : // XXX: probe locals need not be recursion-nested, only function locals
917 :
918 2117 : o->newline() << "struct " << dp->name << "_locals {";
919 2117 : o->indent(1);
920 13414 : for (unsigned j=0; j<dp->locals.size(); j++)
921 : {
922 4590 : vardecl* v = dp->locals[j];
923 : try
924 : {
925 : o->newline() << c_typename (v->type) << " "
926 4590 : << c_varname (v->name) << ";";
927 0 : } catch (const semantic_error& e) {
928 0 : semantic_error e2 (e);
929 0 : if (e2.tok1 == 0) e2.tok1 = v->tok;
930 0 : throw e2;
931 : }
932 : }
933 :
934 : // NB: This part is finicky. The logic here must
935 : // match up with
936 2117 : c_tmpcounter ct (this);
937 2117 : dp->emit_probe_context_vars (o);
938 2117 : dp->body->visit (& ct);
939 :
940 2116 : o->newline(-1) << "} " << dp->name << ";";
941 : }
942 : }
943 :
944 1524 : for (unsigned i=0; i<session->functions.size(); i++)
945 : {
946 1242 : functiondecl* fd = session->functions[i];
947 : o->newline()
948 1242 : << "struct function_" << c_varname (fd->name) << "_locals {";
949 1242 : o->indent(1);
950 2638 : for (unsigned j=0; j<fd->locals.size(); j++)
951 : {
952 77 : vardecl* v = fd->locals[j];
953 : try
954 : {
955 : o->newline() << c_typename (v->type) << " "
956 77 : << c_varname (v->name) << ";";
957 0 : } catch (const semantic_error& e) {
958 0 : semantic_error e2 (e);
959 0 : if (e2.tok1 == 0) e2.tok1 = v->tok;
960 0 : throw e2;
961 : }
962 : }
963 4058 : for (unsigned j=0; j<fd->formal_args.size(); j++)
964 : {
965 787 : vardecl* v = fd->formal_args[j];
966 : try
967 : {
968 : o->newline() << c_typename (v->type) << " "
969 787 : << c_varname (v->name) << ";";
970 0 : } catch (const semantic_error& e) {
971 0 : semantic_error e2 (e);
972 0 : if (e2.tok1 == 0) e2.tok1 = v->tok;
973 0 : throw e2;
974 : }
975 : }
976 1242 : c_tmpcounter ct (this);
977 1242 : fd->body->visit (& ct);
978 1242 : if (fd->type == pe_unknown)
979 214 : o->newline() << "/* no return value */";
980 : else
981 : {
982 1028 : o->newline() << c_typename (fd->type) << " __retvalue;";
983 : }
984 1242 : o->newline(-1) << "} function_" << c_varname (fd->name) << ";";
985 : }
986 282 : o->newline(-1) << "} locals [MAXNESTING];";
987 282 : o->newline(-1) << "};\n";
988 282 : o->newline() << "void *contexts = NULL; /* alloc_percpu */\n";
989 :
990 282 : emit_map_type_instantiations ();
991 :
992 282 : if (!session->stat_decls.empty())
993 46 : o->newline() << "#include \"stat.c\"\n";
994 :
995 283 : o->newline();
996 282 : }
997 :
998 :
999 : void
1000 431 : c_unparser::emit_global_param (vardecl *v)
1001 : {
1002 431 : string vn = c_varname (v->name);
1003 :
1004 : // NB: systemtap globals can collide with linux macros,
1005 : // e.g. VM_FAULT_MAJOR. We want the parameter name anyway. This
1006 : // #undef is spit out at the end of the C file, so that removing the
1007 : // definition won't affect any other embedded-C or generated code.
1008 : // XXX: better not have a global variable named module_param_named etc.!
1009 431 : o->newline() << "#undef " << vn;
1010 :
1011 : // Emit module_params for this global, if its type is convenient.
1012 529 : if (v->arity == 0 && v->type == pe_long)
1013 : {
1014 : o->newline() << "module_param_named (" << vn << ", "
1015 98 : << "global.s_" << vn << ", int64_t, 0);";
1016 : }
1017 333 : else if (v->arity == 0 && v->type == pe_string)
1018 : {
1019 : // NB: no special copying is needed.
1020 : o->newline() << "module_param_string (" << vn << ", "
1021 : << "global.s_" << vn
1022 18 : << ", MAXSTRINGLEN, 0);";
1023 431 : }
1024 431 : }
1025 :
1026 :
1027 : void
1028 431 : c_unparser::emit_global (vardecl *v)
1029 : {
1030 431 : string vn = c_varname (v->name);
1031 :
1032 431 : if (v->arity == 0)
1033 157 : o->newline() << c_typename (v->type) << " s_" << vn << ";";
1034 274 : else if (v->type == pe_stats)
1035 25 : o->newline() << "PMAP s_" << vn << ";";
1036 : else
1037 249 : o->newline() << "MAP s_" << vn << ";";
1038 431 : o->newline() << "rwlock_t s_" << vn << "_lock;";
1039 431 : }
1040 :
1041 :
1042 : void
1043 431 : c_unparser::emit_global_init (vardecl *v)
1044 : {
1045 431 : string vn = c_varname (v->name);
1046 :
1047 431 : if (v->arity == 0) // can only statically initialize some scalars
1048 : {
1049 157 : if (v->init)
1050 : {
1051 15 : o->line() << ".s_" << vn << " = ";
1052 15 : v->init->visit(this);
1053 15 : o->line() << ",";
1054 : }
1055 431 : }
1056 431 : }
1057 :
1058 :
1059 :
1060 : void
1061 1242 : c_unparser::emit_functionsig (functiondecl* v)
1062 : {
1063 : o->newline() << "static void function_" << v->name
1064 1242 : << " (struct context * __restrict__ c);";
1065 1242 : }
1066 :
1067 :
1068 :
1069 : void
1070 281 : c_unparser::emit_module_init ()
1071 : {
1072 281 : vector<derived_probe_group*> g = all_session_groups (*session);
1073 656 : for (unsigned i=0; i<g.size(); i++)
1074 375 : g[i]->emit_module_decls (*session);
1075 :
1076 281 : o->newline();
1077 281 : o->newline() << "int systemtap_module_init (void) {";
1078 281 : o->newline(1) << "int rc = 0;";
1079 281 : o->newline() << "int i=0, j=0;"; // for derived_probe_group use
1080 281 : o->newline() << "const char *probe_point = \"\";";
1081 :
1082 : // Compare actual and targeted kernel releases/machines. Sometimes
1083 : // one may install the incorrect debuginfo or -devel RPM, and try to
1084 : // run a probe compiled for a different version. Catch this early,
1085 : // just in case modversions didn't.
1086 281 : o->newline() << "down_read (& uts_sem);";
1087 281 : o->newline() << "{";
1088 281 : o->indent(1);
1089 :
1090 : // Args, linux 2.6.19+ did a switcheroo on system_utsname to utsname().
1091 281 : o->newline() << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)";
1092 281 : o->newline() << "const char* machine = utsname()->machine;";
1093 281 : o->newline() << "const char* release = utsname()->release;";
1094 281 : o->newline() << "#else";
1095 281 : o->newline() << "const char* machine = system_utsname.machine;";
1096 281 : o->newline() << "const char* release = system_utsname.release;";
1097 281 : o->newline() << "#endif";
1098 :
1099 : o->newline() << "if (strcmp (machine, "
1100 281 : << lex_cast_qstring (session->architecture) << ")) {";
1101 : o->newline(1) << "_stp_error (\"module machine mismatch (%s vs %s)\", "
1102 : << "machine, "
1103 : << lex_cast_qstring (session->architecture)
1104 281 : << ");";
1105 281 : o->newline() << "rc = -EINVAL;";
1106 281 : o->newline(-1) << "}";
1107 :
1108 : o->newline() << "if (strcmp (release, "
1109 281 : << lex_cast_qstring (session->kernel_release) << ")) {";
1110 : o->newline(1) << "_stp_error (\"module release mismatch (%s vs %s)\", "
1111 : << "release, "
1112 : << lex_cast_qstring (session->kernel_release)
1113 281 : << ");";
1114 281 : o->newline() << "rc = -EINVAL;";
1115 281 : o->newline(-1) << "}";
1116 :
1117 281 : o->newline(-1) << "}";
1118 281 : o->newline() << "up_read (& uts_sem);";
1119 281 : o->newline() << "if (rc) goto out;";
1120 :
1121 281 : o->newline() << "(void) probe_point;";
1122 281 : o->newline() << "(void) i;";
1123 281 : o->newline() << "(void) j;";
1124 281 : o->newline() << "atomic_set (&session_state, STAP_SESSION_STARTING);";
1125 : // This signals any other probes that may be invoked in the next little
1126 : // while to abort right away. Currently running probes are allowed to
1127 : // terminate. These may set STAP_SESSION_ERROR!
1128 :
1129 : // per-cpu context
1130 281 : o->newline() << "if (sizeof (struct context) <= 131072)";
1131 281 : o->newline(1) << "contexts = alloc_percpu (struct context);";
1132 281 : o->newline(-1) << "if (contexts == NULL) {";
1133 281 : o->newline(1) << "_stp_error (\"percpu context (size %lu) allocation failed\", sizeof (struct context));";
1134 281 : o->newline() << "rc = -ENOMEM;";
1135 281 : o->newline() << "goto out;";
1136 281 : o->newline(-1) << "}";
1137 :
1138 712 : for (unsigned i=0; i<session->globals.size(); i++)
1139 : {
1140 431 : vardecl* v = session->globals[i];
1141 431 : if (v->index_types.size() > 0)
1142 274 : o->newline() << getmap (v).init();
1143 : else
1144 157 : o->newline() << getvar (v).init();
1145 : // NB: in case of failure of allocation, "rc" will be set to non-zero.
1146 : // Allocation can in general continue.
1147 :
1148 431 : o->newline() << "if (rc) {";
1149 431 : o->newline(1) << "_stp_error (\"global variable " << v->name << " allocation failed\");";
1150 431 : o->newline() << "goto out;";
1151 431 : o->newline(-1) << "}";
1152 :
1153 431 : o->newline() << "rwlock_init (& global.s_" << c_varname (v->name) << "_lock);";
1154 : }
1155 :
1156 : // initialize each Stat used for timing information
1157 281 : o->newline() << "#ifdef STP_TIMING";
1158 281 : set<string> basest_names;
1159 9535 : for (unsigned i=0; i<session->probes.size(); i++)
1160 : {
1161 9254 : string nm = session->probes[i]->basest()->name;
1162 9254 : if (basest_names.find(nm) == basest_names.end())
1163 : {
1164 682 : o->newline() << "time_" << nm << " = _stp_stat_init (HIST_NONE);";
1165 : // NB: we don't check for null return here, but instead at
1166 : // passage to probe handlers and at final printing.
1167 682 : basest_names.insert (nm);
1168 : }
1169 : }
1170 281 : o->newline() << "#endif";
1171 :
1172 : // Print a message to the kernel log about this module. This is
1173 : // intended to help debug problems with systemtap modules.
1174 :
1175 : o->newline() << "_stp_print_kernel_info("
1176 : << "\"" << VERSION
1177 : << "/" << dwfl_version (NULL) << "\""
1178 : << ", (num_online_cpus() * sizeof(struct context))"
1179 : << ", " << session->probes.size()
1180 281 : << ");";
1181 :
1182 : // Run all probe registrations. This actually runs begin probes.
1183 :
1184 656 : for (unsigned i=0; i<g.size(); i++)
1185 : {
1186 375 : g[i]->emit_module_init (*session);
1187 : // NB: this gives O(N**2) amount of code, but luckily there
1188 : // are only seven or eight derived_probe_groups, so it's ok.
1189 375 : o->newline() << "if (rc) {";
1190 375 : o->newline(1) << "_stp_error (\"probe %s registration error (rc %d)\", probe_point, rc);";
1191 : // NB: we need to be in the error state so timers can shutdown cleanly,
1192 : // and so end probes don't run. OTOH, error probes can run.
1193 375 : o->newline() << "atomic_set (&session_state, STAP_SESSION_ERROR);";
1194 375 : if (i>0)
1195 217 : for (int j=i-1; j>=0; j--)
1196 122 : g[j]->emit_module_exit (*session);
1197 375 : o->newline() << "goto out;";
1198 375 : o->newline(-1) << "}";
1199 : }
1200 :
1201 : // All registrations were successful. Consider the system started.
1202 281 : o->newline() << "if (atomic_read (&session_state) == STAP_SESSION_STARTING)";
1203 : // NB: only other valid state value is ERROR, in which case we don't
1204 281 : o->newline(1) << "atomic_set (&session_state, STAP_SESSION_RUNNING);";
1205 281 : o->newline(-1) << "return 0;";
1206 :
1207 : // Error handling path; by now all partially registered probe groups
1208 : // have been unregistered.
1209 281 : o->newline(-1) << "out:";
1210 281 : o->indent(1);
1211 :
1212 : // If any registrations failed, we will need to deregister the globals,
1213 : // as this is our only chance.
1214 712 : for (unsigned i=0; i<session->globals.size(); i++)
1215 : {
1216 431 : vardecl* v = session->globals[i];
1217 431 : if (v->index_types.size() > 0)
1218 274 : o->newline() << getmap (v).fini();
1219 : else
1220 157 : o->newline() << getvar (v).fini();
1221 : }
1222 :
1223 281 : o->newline() << "return rc;";
1224 281 : o->newline(-1) << "}\n";
1225 281 : }
1226 :
1227 :
1228 : void
1229 281 : c_unparser::emit_module_exit ()
1230 : {
1231 281 : o->newline() << "void systemtap_module_exit (void) {";
1232 : // rc?
1233 281 : o->newline(1) << "int holdon;";
1234 281 : o->newline() << "int i=0, j=0;"; // for derived_probe_group use
1235 :
1236 281 : o->newline() << "(void) i;";
1237 281 : o->newline() << "(void) j;";
1238 : // If we aborted startup, then everything has been cleaned up already, and
1239 : // module_exit shouldn't even have been called. But since it might be, let's
1240 : // beat a hasty retreat to avoid double uninitialization.
1241 281 : o->newline() << "if (atomic_read (&session_state) == STAP_SESSION_STARTING)";
1242 281 : o->newline(1) << "return;";
1243 281 : o->indent(-1);
1244 :
1245 281 : o->newline() << "if (atomic_read (&session_state) == STAP_SESSION_RUNNING)";
1246 : // NB: only other valid state value is ERROR, in which case we don't
1247 281 : o->newline(1) << "atomic_set (&session_state, STAP_SESSION_STOPPING);";
1248 281 : o->indent(-1);
1249 : // This signals any other probes that may be invoked in the next little
1250 : // while to abort right away. Currently running probes are allowed to
1251 : // terminate. These may set STAP_SESSION_ERROR!
1252 :
1253 : // NB: systemtap_module_exit is assumed to be called from ordinary
1254 : // user context, say during module unload. Among other things, this
1255 : // means we can sleep a while.
1256 281 : o->newline() << "do {";
1257 281 : o->newline(1) << "int i;";
1258 281 : o->newline() << "holdon = 0;";
1259 281 : o->newline() << "for (i=0; i < NR_CPUS; i++)";
1260 : o->newline(1) << "if (cpu_possible (i) && "
1261 : << "atomic_read (& ((struct context *)per_cpu_ptr(contexts, i))->busy)) "
1262 281 : << "holdon = 1;";
1263 281 : o->newline () << "schedule ();";
1264 281 : o->newline(-2) << "} while (holdon);";
1265 :
1266 : // XXX: might like to have an escape hatch, in case some probe is
1267 : // genuinely stuck somehow
1268 :
1269 : // Notice we're processing the derived_probe_group list in reverse
1270 : // order. This ensures that probes get unregistered in reverse
1271 : // order of the way they were registered.
1272 281 : vector<derived_probe_group*> g = all_session_groups (*session);
1273 656 : for (vector<derived_probe_group*>::reverse_iterator i = g.rbegin();
1274 : i != g.rend(); i++)
1275 375 : (*i)->emit_module_exit (*session); // NB: runs "end" probes
1276 :
1277 712 : for (unsigned i=0; i<session->globals.size(); i++)
1278 : {
1279 431 : vardecl* v = session->globals[i];
1280 431 : if (v->index_types.size() > 0)
1281 274 : o->newline() << getmap (v).fini();
1282 : else
1283 157 : o->newline() << getvar (v).fini();
1284 : }
1285 :
1286 281 : o->newline() << "free_percpu (contexts);";
1287 :
1288 : // print probe timing statistics
1289 : {
1290 281 : o->newline() << "#ifdef STP_TIMING";
1291 281 : o->newline() << "{";
1292 281 : o->indent(1);
1293 281 : set<string> basest_names;
1294 9535 : for (unsigned i=0; i<session->probes.size(); i++)
1295 : {
1296 9254 : probe* p = session->probes[i]->basest();
1297 9254 : string nm = p->name;
1298 9254 : if (basest_names.find(nm) == basest_names.end())
1299 : {
1300 682 : basest_names.insert (nm);
1301 : // NB: check for null stat object
1302 682 : o->newline() << "if (likely (time_" << p->name << ")) {";
1303 : o->newline(1) << "const char *probe_point = "
1304 : << lex_cast_qstring (* p->locations[0])
1305 : << (p->locations.size() > 1 ? "\"+\"" : "")
1306 : << (p->locations.size() > 1 ? lex_cast_qstring(p->locations.size()-1) : "")
1307 682 : << ";";
1308 : o->newline() << "const char *decl_location = "
1309 : << lex_cast_qstring (p->tok->location)
1310 682 : << ";";
1311 : o->newline() << "struct stat_data *stats = _stp_stat_get (time_"
1312 : << p->name
1313 682 : << ", 0);";
1314 682 : o->newline() << "const char *error;";
1315 682 : o->newline() << "if (stats->count) {";
1316 682 : o->newline(1) << "int64_t avg = _stp_div64 (&error, stats->sum, stats->count);";
1317 682 : o->newline() << "_stp_printf (\"probe %s (%s), hits: %lld, cycles: %lldmin/%lldavg/%lldmax\\n\",";
1318 682 : o->newline() << "probe_point, decl_location, (long long) stats->count, (long long) stats->min, (long long) avg, (long long) stats->max);";
1319 682 : o->newline(-1) << "}";
1320 682 : o->newline() << "_stp_stat_del (time_" << p->name << ");";
1321 682 : o->newline(-1) << "}";
1322 : }
1323 : }
1324 281 : o->newline() << "_stp_print_flush();";
1325 281 : o->newline(-1) << "}";
1326 281 : o->newline() << "#endif";
1327 : }
1328 :
1329 : // print final error/reentrancy counts if non-zero
1330 : o->newline() << "if (atomic_read (& skipped_count) || "
1331 281 : << "atomic_read (& error_count)) {";
1332 : o->newline(1) << "_stp_warn (\"Number of errors: %d, "
1333 : << "skipped probes: %d\\n\", "
1334 : << "(int) atomic_read (& error_count), "
1335 281 : << "(int) atomic_read (& skipped_count));";
1336 281 : o->newline() << "_stp_print_flush();";
1337 281 : o->newline(-1) << "}";
1338 281 : o->newline(-1) << "}\n";
1339 281 : }
1340 :
1341 :
1342 : void
1343 1242 : c_unparser::emit_function (functiondecl* v)
1344 : {
1345 : o->newline() << "void function_" << c_varname (v->name)
1346 1242 : << " (struct context* __restrict__ c) {";
1347 1242 : o->indent(1);
1348 1242 : this->current_probe = 0;
1349 1242 : this->current_function = v;
1350 1242 : this->tmpvar_counter = 0;
1351 :
1352 : o->newline()
1353 : << "struct function_" << c_varname (v->name) << "_locals * "
1354 2484 : << " __restrict__ l =";
1355 : o->newline(1)
1356 : << "& c->locals[c->nesting+1].function_" << c_varname (v->name) // NB: nesting+1
1357 2484 : << ";";
1358 1242 : o->newline(-1) << "(void) l;"; // make sure "l" is marked used
1359 1242 : o->newline() << "#define CONTEXT c";
1360 1242 : o->newline() << "#define THIS l";
1361 1242 : o->newline() << "if (0) goto out;"; // make sure out: is marked used
1362 :
1363 : // check/increment nesting level
1364 1242 : o->newline() << "if (unlikely (c->nesting+2 >= MAXNESTING)) {";
1365 1242 : o->newline(1) << "c->last_error = \"MAXNESTING exceeded\";";
1366 1242 : o->newline() << "return;";
1367 1242 : o->newline(-1) << "} else {";
1368 1242 : o->newline(1) << "c->nesting ++;";
1369 1242 : o->newline(-1) << "}";
1370 :
1371 : // initialize locals
1372 : // XXX: optimization: use memset instead
1373 2638 : for (unsigned i=0; i<v->locals.size(); i++)
1374 : {
1375 77 : if (v->locals[i]->index_types.size() > 0) // array?
1376 : throw semantic_error ("array locals not supported, missing global declaration?",
1377 0 : v->locals[i]->tok);
1378 :
1379 77 : o->newline() << getvar (v->locals[i]).init();
1380 : }
1381 :
1382 : // initialize return value, if any
1383 1242 : if (v->type != pe_unknown)
1384 : {
1385 1028 : var retvalue = var(true, v->type, "__retvalue");
1386 2056 : o->newline() << retvalue.init();
1387 : }
1388 :
1389 1242 : o->newline() << "#define return goto out"; // redirect embedded-C return
1390 1242 : this->probe_or_function_needs_deref_fault_handler = false;
1391 1242 : v->body->visit (this);
1392 1242 : o->newline() << "#undef return";
1393 :
1394 1242 : this->current_function = 0;
1395 :
1396 1242 : o->newline(-1) << "out:";
1397 1242 : o->newline(1) << ";";
1398 :
1399 : // Function prologue: this is why we redirect the "return" above.
1400 : // Decrement nesting level.
1401 1242 : o->newline() << "c->nesting --;";
1402 : // Reset last_error to NULL if it was set to "" by script-level return()
1403 1242 : o->newline() << "if (c->last_error && ! c->last_error[0])";
1404 1242 : o->newline(1) << "c->last_error = 0;";
1405 1242 : o->indent(-1);
1406 :
1407 1242 : if (this->probe_or_function_needs_deref_fault_handler) {
1408 : // Emit this handler only if the body included a
1409 : // print/printf/etc. using a string or memory buffer!
1410 0 : o->newline(1) << "return;";
1411 0 : o->newline() << "CATCH_DEREF_FAULT ();";
1412 0 : o->newline() << "goto out;";
1413 0 : o->indent(-1);
1414 : }
1415 :
1416 1242 : o->newline() << "#undef CONTEXT";
1417 1242 : o->newline() << "#undef THIS";
1418 1242 : o->newline(-1) << "}\n";
1419 1242 : }
1420 :
1421 :
1422 : #define DUPMETHOD_CALL 0
1423 : #define DUPMETHOD_ALIAS 0
1424 : #define DUPMETHOD_RENAME 1
1425 :
1426 : void
1427 9255 : c_unparser::emit_probe (derived_probe* v)
1428 : {
1429 9255 : this->current_function = 0;
1430 9255 : this->current_probe = v;
1431 9255 : this->tmpvar_counter = 0;
1432 :
1433 : // If we about to emit a probe that is exactly the same as another
1434 : // probe previously emitted, make the second probe just call the
1435 : // first one.
1436 : //
1437 : // Notice we're using the probe body itself instead of the emitted C
1438 : // probe body to compare probes. We need to do this because the
1439 : // emitted C probe body has stuff in it like:
1440 : // c->last_stmt = "identifier 'printf' at foo.stp:<line>:<column>";
1441 : //
1442 : // which would make comparisons impossible.
1443 : //
1444 : // --------------------------------------------------------------------------
1445 : // NB: see also c_unparser:emit_common_header(), which deliberately but sadly
1446 : // duplicates this calculation.
1447 : // --------------------------------------------------------------------------
1448 : //
1449 9255 : ostringstream oss;
1450 :
1451 : // NB: statp is just for avoiding designation as duplicate. It need not be C.
1452 : // NB: This code *could* be enclosed in an "if (session->timing)". That would
1453 : // recognize more duplicate probe handlers, but then the generated code could
1454 : // be very different with or without -t.
1455 9255 : oss << "c->statp = & time_" << v->basest()->name << ";" << endl;
1456 :
1457 9255 : v->body->print(oss);
1458 :
1459 : // Since the generated C changes based on whether or not the probe
1460 : // needs locks around global variables, this needs to be reflected
1461 : // here. We don't want to treat as duplicate the handlers of
1462 : // begin/end and normal probes that differ only in need_global_locks.
1463 9255 : oss << "# needs_global_locks: " << v->needs_global_locks () << endl;
1464 :
1465 : // If an identical probe has already been emitted, just call that
1466 : // one.
1467 9255 : if (probe_contents.count(oss.str()) != 0)
1468 : {
1469 7139 : string dupe = probe_contents[oss.str()];
1470 :
1471 : // NB: Elision of context variable structs is a separate
1472 : // operation which has already taken place by now.
1473 7139 : if (session->verbose > 1)
1474 0 : clog << v->name << " elided, duplicates " << dupe << endl;
1475 :
1476 : #if DUPMETHOD_CALL
1477 : // This one emits a direct call to the first copy.
1478 : o->newline();
1479 : o->newline() << "static void " << v->name << " (struct context * __restrict__ c) ";
1480 : o->newline() << "{ " << dupe << " (c); }";
1481 : #elif DUPMETHOD_ALIAS
1482 : // This one defines a function alias, arranging gcc to emit
1483 : // several equivalent symbols for the same function body.
1484 : // For some reason, on gcc 4.1, this is twice as slow as
1485 : // the CALL option.
1486 : o->newline();
1487 : o->newline() << "static void " << v->name << " (struct context * __restrict__ c) ";
1488 : o->line() << "__attribute__ ((alias (\"" << dupe << "\")));";
1489 : #elif DUPMETHOD_RENAME
1490 : // This one is sneaky. It emits nothing for duplicate probe
1491 : // handlers. It instead redirects subsequent references to the
1492 : // probe handler function to the first copy, *by name*.
1493 7139 : v->name = dupe;
1494 : #else
1495 : #error "Unknown duplicate elimination method"
1496 : #endif
1497 : }
1498 : else // This probe is unique. Remember it and output it.
1499 : {
1500 2116 : this->probe_or_function_needs_deref_fault_handler = false;
1501 :
1502 2116 : o->newline();
1503 2116 : o->newline() << "#ifdef STP_TIMING";
1504 2116 : o->newline() << "static __cacheline_aligned Stat " << "time_" << v->basest()->name << ";";
1505 2116 : o->newline() << "#endif";
1506 2116 : o->newline();
1507 2116 : o->newline() << "static void " << v->name << " (struct context * __restrict__ c) ";
1508 2116 : o->line () << "{";
1509 2116 : o->indent (1);
1510 :
1511 2116 : probe_contents[oss.str()] = v->name;
1512 :
1513 : // initialize frame pointer
1514 2116 : o->newline() << "struct " << v->name << "_locals * __restrict__ l =";
1515 2116 : o->newline(1) << "& c->locals[0]." << v->name << ";";
1516 2116 : o->newline(-1) << "(void) l;"; // make sure "l" is marked used
1517 :
1518 2116 : o->newline() << "#ifdef STP_TIMING";
1519 2116 : o->newline() << "c->statp = & time_" << v->basest()->name << ";";
1520 2116 : o->newline() << "#endif";
1521 :
1522 : // emit all read/write locks for global variables
1523 2116 : varuse_collecting_visitor vut;
1524 2116 : if (v->needs_global_locks ())
1525 : {
1526 1714 : v->body->visit (& vut);
1527 1714 : emit_locks (vut);
1528 : }
1529 :
1530 : // initialize locals
1531 6704 : for (unsigned j=0; j<v->locals.size(); j++)
1532 : {
1533 4589 : if (v->locals[j]->index_types.size() > 0) // array?
1534 : throw semantic_error ("array locals not supported, missing global declaration?",
1535 1 : v->locals[j]->tok);
1536 4588 : else if (v->locals[j]->type == pe_long)
1537 : o->newline() << "l->" << c_varname (v->locals[j]->name)
1538 1069 : << " = 0;";
1539 3519 : else if (v->locals[j]->type == pe_string)
1540 : o->newline() << "l->" << c_varname (v->locals[j]->name)
1541 3519 : << "[0] = '\\0';";
1542 : else
1543 : throw semantic_error ("unsupported local variable type",
1544 0 : v->locals[j]->tok);
1545 : }
1546 :
1547 2115 : v->initialize_probe_context_vars (o);
1548 :
1549 2115 : v->body->visit (this);
1550 :
1551 2115 : o->newline(-1) << "out:";
1552 : // NB: no need to uninitialize locals, except if arrays/stats can
1553 : // someday be local
1554 :
1555 : // XXX: do this flush only if the body included a
1556 : // print/printf/etc. routine!
1557 2115 : o->newline(1) << "_stp_print_flush();";
1558 :
1559 2115 : if (v->needs_global_locks ())
1560 1714 : emit_unlocks (vut);
1561 :
1562 2115 : if (this->probe_or_function_needs_deref_fault_handler) {
1563 : // Emit this handler only if the body included a
1564 : // print/printf/etc. using a string or memory buffer!
1565 4 : o->newline() << "return;";
1566 4 : o->newline() << "CATCH_DEREF_FAULT ();";
1567 4 : o->newline() << "goto out;";
1568 : }
1569 :
1570 2115 : o->newline(-1) << "}\n";
1571 : }
1572 :
1573 :
1574 9255 : this->current_probe = 0;
1575 9254 : }
1576 :
1577 :
1578 : void
1579 1714 : c_unparser::emit_locks(const varuse_collecting_visitor& vut)
1580 : {
1581 1714 : o->newline() << "{";
1582 1714 : o->newline(1) << "unsigned numtrylock = 0;";
1583 1714 : o->newline() << "(void) numtrylock;";
1584 :
1585 1714 : string last_locked_var;
1586 10671 : for (unsigned i = 0; i < session->globals.size(); i++)
1587 : {
1588 7650 : vardecl* v = session->globals[i];
1589 7650 : bool read_p = vut.read.find(v) != vut.read.end();
1590 7650 : bool write_p = vut.written.find(v) != vut.written.end();
1591 7650 : if (!read_p && !write_p) continue;
1592 :
1593 1837 : if (v->type == pe_stats) // read and write locks are flipped
1594 : // Specifically, a "<<<" to a stats object is considered a
1595 : // "shared-lock" operation, since it's implicitly done
1596 : // per-cpu. But a "@op(x)" extraction is an "exclusive-lock"
1597 : // one, as is a (sorted or unsorted) foreach, so those cases
1598 : // are excluded by the w & !r condition below.
1599 : {
1600 34 : if (write_p && !read_p) { read_p = true; write_p = false; }
1601 8 : else if (read_p && !write_p) { read_p = false; write_p = true; }
1602 : }
1603 :
1604 : // We don't need to read lock "read-mostly" global variables. A
1605 : // "read-mostly" global variable is only written to within
1606 : // probes that don't need global variable locking (such as
1607 : // begin/end probes). If vcv_needs_global_locks doesn't mark
1608 : // the global as written to, then we don't have to lock it
1609 : // here to read it safely.
1610 1837 : if (read_p && !write_p)
1611 : {
1612 585 : if (vcv_needs_global_locks.written.find(v)
1613 : == vcv_needs_global_locks.written.end())
1614 530 : continue;
1615 : }
1616 :
1617 : string lockcall =
1618 : string (write_p ? "write" : "read") +
1619 1307 : "_trylock (& global.s_" + v->name + "_lock)";
1620 :
1621 : o->newline() << "while (! " << lockcall
1622 2614 : << "&& (++numtrylock < MAXTRYLOCK))";
1623 1307 : o->newline(1) << "ndelay (TRYLOCKDELAY);";
1624 1307 : o->newline(-1) << "if (unlikely (numtrylock >= MAXTRYLOCK)) {";
1625 1307 : o->newline(1) << "atomic_inc (& skipped_count);";
1626 : // The following works even if i==0. Note that using
1627 : // globals[i-1]->name is wrong since that global may not have
1628 : // been lockworthy by this probe.
1629 1307 : o->newline() << "goto unlock_" << last_locked_var << ";";
1630 1307 : o->newline(-1) << "}";
1631 :
1632 1307 : last_locked_var = v->name;
1633 : }
1634 :
1635 1714 : o->newline() << "if (0) goto unlock_;";
1636 :
1637 1714 : o->newline(-1) << "}";
1638 1714 : }
1639 :
1640 :
1641 : void
1642 1714 : c_unparser::emit_unlocks(const varuse_collecting_visitor& vut)
1643 : {
1644 1714 : unsigned numvars = 0;
1645 :
1646 1714 : if (session->verbose>1)
1647 0 : clog << current_probe->name << " locks ";
1648 :
1649 9364 : for (int i = session->globals.size()-1; i>=0; i--) // in reverse order!
1650 : {
1651 7650 : vardecl* v = session->globals[i];
1652 7650 : bool read_p = vut.read.find(v) != vut.read.end();
1653 7650 : bool write_p = vut.written.find(v) != vut.written.end();
1654 7650 : if (!read_p && !write_p) continue;
1655 :
1656 : // Duplicate lock flipping logic from above
1657 1837 : if (v->type == pe_stats)
1658 : {
1659 34 : if (write_p && !read_p) { read_p = true; write_p = false; }
1660 8 : else if (read_p && !write_p) { read_p = false; write_p = true; }
1661 : }
1662 :
1663 : // Duplicate "read-mostly" global variable logic from above.
1664 1837 : if (read_p && !write_p)
1665 : {
1666 585 : if (vcv_needs_global_locks.written.find(v)
1667 : == vcv_needs_global_locks.written.end())
1668 530 : continue;
1669 : }
1670 :
1671 1307 : numvars ++;
1672 1307 : o->newline(-1) << "unlock_" << v->name << ":";
1673 1307 : o->indent(1);
1674 :
1675 1307 : if (session->verbose>1)
1676 : clog << v->name << "[" << (read_p ? "r" : "")
1677 0 : << (write_p ? "w" : "") << "] ";
1678 :
1679 1307 : if (write_p) // emit write lock
1680 1252 : o->newline() << "write_unlock (& global.s_" << v->name << "_lock);";
1681 : else // (read_p && !write_p) : emit read lock
1682 55 : o->newline() << "read_unlock (& global.s_" << v->name << "_lock);";
1683 :
1684 : // fall through to next variable; thus the reverse ordering
1685 : }
1686 :
1687 : // emit plain "unlock" label, used if the very first lock failed.
1688 1714 : o->newline(-1) << "unlock_: ;";
1689 1714 : o->indent(1);
1690 :
1691 1714 : if (numvars) // is there a chance that any lock attempt failed?
1692 : {
1693 617 : o->newline() << "if (atomic_read (& skipped_count) > MAXSKIPPED) {";
1694 : // XXX: In this known non-reentrant context, we could print a more
1695 : // informative error.
1696 617 : o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
1697 617 : o->newline() << "_stp_exit();";
1698 617 : o->newline(-1) << "}";
1699 :
1700 617 : if (session->verbose>1)
1701 0 : clog << endl;
1702 : }
1703 1097 : else if (session->verbose>1)
1704 0 : clog << "nothing" << endl;
1705 1714 : }
1706 :
1707 :
1708 : void
1709 : c_unparser::collect_map_index_types(vector<vardecl *> const & vars,
1710 10779 : set< pair<vector<exp_type>, exp_type> > & types)
1711 : {
1712 18484 : for (unsigned i = 0; i < vars.size(); ++i)
1713 : {
1714 7705 : vardecl *v = vars[i];
1715 7705 : if (v->arity > 0)
1716 : {
1717 275 : types.insert(make_pair(v->index_types, v->type));
1718 : }
1719 : }
1720 10779 : }
1721 :
1722 : string
1723 120 : mapvar::value_typename(exp_type e)
1724 : {
1725 120 : switch (e)
1726 : {
1727 : case pe_long:
1728 58 : return "INT64";
1729 : case pe_string:
1730 24 : return "STRING";
1731 : case pe_stats:
1732 38 : return "STAT";
1733 : default:
1734 0 : throw semantic_error("array type is neither string nor long");
1735 : }
1736 : return "";
1737 : }
1738 :
1739 : string
1740 172 : mapvar::key_typename(exp_type e)
1741 : {
1742 172 : switch (e)
1743 : {
1744 : case pe_long:
1745 123 : return "INT64";
1746 : case pe_string:
1747 49 : return "STRING";
1748 : default:
1749 0 : throw semantic_error("array key is neither string nor long");
1750 : }
1751 : return "";
1752 : }
1753 :
1754 : string
1755 0 : mapvar::shortname(exp_type e)
1756 : {
1757 0 : switch (e)
1758 : {
1759 : case pe_long:
1760 0 : return "i";
1761 : case pe_string:
1762 0 : return "s";
1763 : default:
1764 0 : throw semantic_error("array type is neither string nor long");
1765 : }
1766 : return "";
1767 : }
1768 :
1769 :
1770 : void
1771 282 : c_unparser::emit_map_type_instantiations ()
1772 : {
1773 282 : set< pair<vector<exp_type>, exp_type> > types;
1774 :
1775 282 : collect_map_index_types(session->globals, types);
1776 :
1777 9537 : for (unsigned i = 0; i < session->probes.size(); ++i)
1778 9255 : collect_map_index_types(session->probes[i]->locals, types);
1779 :
1780 1524 : for (unsigned i = 0; i < session->functions.size(); ++i)
1781 1242 : collect_map_index_types(session->functions[i]->locals, types);
1782 :
1783 282 : if (!types.empty())
1784 66 : o->newline() << "#include \"alloc.c\"";
1785 :
1786 383 : for (set< pair<vector<exp_type>, exp_type> >::const_iterator i = types.begin();
1787 : i != types.end(); ++i)
1788 : {
1789 101 : o->newline() << "#define VALUE_TYPE " << mapvar::value_typename(i->second);
1790 248 : for (unsigned j = 0; j < i->first.size(); ++j)
1791 : {
1792 147 : string ktype = mapvar::key_typename(i->first.at(j));
1793 147 : o->newline() << "#define KEY" << (j+1) << "_TYPE " << ktype;
1794 : }
1795 101 : if (i->second == pe_stats)
1796 19 : o->newline() << "#include \"pmap-gen.c\"";
1797 : else
1798 82 : o->newline() << "#include \"map-gen.c\"";
1799 101 : o->newline() << "#undef VALUE_TYPE";
1800 248 : for (unsigned j = 0; j < i->first.size(); ++j)
1801 : {
1802 147 : o->newline() << "#undef KEY" << (j+1) << "_TYPE";
1803 : }
1804 :
1805 : /* FIXME
1806 : * For pmaps, we also need to include map-gen.c, because we might be accessing
1807 : * the aggregated map. The better way to handle this is for pmap-gen.c to make
1808 : * this include, but that's impossible with the way they are set up now.
1809 : */
1810 101 : if (i->second == pe_stats)
1811 : {
1812 19 : o->newline() << "#define VALUE_TYPE " << mapvar::value_typename(i->second);
1813 44 : for (unsigned j = 0; j < i->first.size(); ++j)
1814 : {
1815 25 : string ktype = mapvar::key_typename(i->first.at(j));
1816 25 : o->newline() << "#define KEY" << (j+1) << "_TYPE " << ktype;
1817 : }
1818 19 : o->newline() << "#include \"map-gen.c\"";
1819 19 : o->newline() << "#undef VALUE_TYPE";
1820 44 : for (unsigned j = 0; j < i->first.size(); ++j)
1821 : {
1822 25 : o->newline() << "#undef KEY" << (j+1) << "_TYPE";
1823 : }
1824 : }
1825 : }
1826 :
1827 282 : if (!types.empty())
1828 66 : o->newline() << "#include \"map.c\"";
1829 :
1830 282 : };
1831 :
1832 :
1833 : string
1834 26638 : c_unparser::c_typename (exp_type e)
1835 : {
1836 26638 : switch (e)
1837 : {
1838 11600 : case pe_long: return string("int64_t");
1839 14996 : case pe_string: return string("string_t");
1840 42 : case pe_stats: return string("Stat");
1841 : case pe_unknown:
1842 : default:
1843 0 : throw semantic_error ("cannot expand unknown type");
1844 : }
1845 : }
1846 :
1847 :
1848 : string
1849 59611 : c_unparser::c_varname (const string& e)
1850 : {
1851 : // XXX: safeify, uniquefy, given name
1852 59611 : return e;
1853 : }
1854 :
1855 :
1856 : string
1857 5023 : c_unparser::c_expression (expression *e)
1858 : {
1859 : // We want to evaluate expression 'e' and return its value as a
1860 : // string. In the case of expressions that are just numeric
1861 : // constants, if we just print the value into a string, it won't
1862 : // have the same value as being visited by c_unparser. For
1863 : // instance, a numeric constant evaluated using print() would return
1864 : // "5", while c_unparser::visit_literal_number() would
1865 : // return "((int64_t)5LL)". String constants evaluated using
1866 : // print() would just return the string, while
1867 : // c_unparser::visit_literal_string() would return the string with
1868 : // escaped double quote characters. So, we need to "visit" the
1869 : // expression.
1870 :
1871 : // However, we have to be careful of side effects. Currently this
1872 : // code is only being used for evaluating literal numbers and
1873 : // strings, which currently have no side effects. Until needed
1874 : // otherwise, limit the use of this function to literal numbers and
1875 : // strings.
1876 5023 : if (e->tok->type != tok_number && e->tok->type != tok_string)
1877 0 : throw semantic_error("unsupported c_expression token type");
1878 :
1879 : // Create a fake output stream so we can grab the string output.
1880 5023 : ostringstream oss;
1881 5023 : translator_output tmp_o(oss);
1882 :
1883 : // Temporarily swap out the real translator_output stream with our
1884 : // fake one.
1885 5023 : translator_output *saved_o = o;
1886 5023 : o = &tmp_o;
1887 :
1888 : // Visit the expression then restore the original output stream
1889 5023 : e->visit (this);
1890 5023 : o = saved_o;
1891 :
1892 5023 : return (oss.str());
1893 : }
1894 :
1895 :
1896 : void
1897 1309 : c_unparser::c_assign (var& lvalue, const string& rvalue, const token *tok)
1898 : {
1899 1309 : switch (lvalue.type())
1900 : {
1901 : case pe_string:
1902 413 : c_strcpy(lvalue.value(), rvalue);
1903 413 : break;
1904 : case pe_long:
1905 896 : o->newline() << lvalue << " = " << rvalue << ";";
1906 896 : break;
1907 : default:
1908 0 : throw semantic_error ("unknown lvalue type in assignment", tok);
1909 : }
1910 1309 : }
1911 :
1912 : void
1913 : c_unparser::c_assign (const string& lvalue, expression* rvalue,
1914 16855 : const string& msg)
1915 : {
1916 16855 : if (rvalue->type == pe_long)
1917 : {
1918 7144 : o->newline() << lvalue << " = ";
1919 7144 : rvalue->visit (this);
1920 7144 : o->line() << ";";
1921 : }
1922 9711 : else if (rvalue->type == pe_string)
1923 : {
1924 9711 : c_strcpy (lvalue, rvalue);
1925 : }
1926 : else
1927 : {
1928 0 : string fullmsg = msg + " type unsupported";
1929 0 : throw semantic_error (fullmsg, rvalue->tok);
1930 : }
1931 16855 : }
1932 :
1933 :
1934 : void
1935 : c_unparser::c_assign (const string& lvalue, const string& rvalue,
1936 2854 : exp_type type, const string& msg, const token* tok)
1937 : {
1938 2854 : if (type == pe_long)
1939 : {
1940 2135 : o->newline() << lvalue << " = " << rvalue << ";";
1941 : }
1942 719 : else if (type == pe_string)
1943 : {
1944 719 : c_strcpy (lvalue, rvalue);
1945 : }
1946 : else
1947 : {
1948 0 : string fullmsg = msg + " type unsupported";
1949 0 : throw semantic_error (fullmsg, tok);
1950 : }
1951 2854 : }
1952 :
1953 :
1954 : void
1955 : c_unparser_assignment::c_assignop(tmpvar & res,
1956 : var const & lval,
1957 : tmpvar const & rval,
1958 6393 : token const * tok)
1959 : {
1960 : // This is common code used by scalar and array-element assignments.
1961 : // It assumes an operator-and-assignment (defined by the 'pre' and
1962 : // 'op' fields of c_unparser_assignment) is taking place between the
1963 : // following set of variables:
1964 : //
1965 : // res: the result of evaluating the expression, a temporary
1966 : // lval: the lvalue of the expression, which may be damaged
1967 : // rval: the rvalue of the expression, which is a temporary or constant
1968 :
1969 : // we'd like to work with a local tmpvar so we can overwrite it in
1970 : // some optimized cases
1971 :
1972 6393 : translator_output* o = parent->o;
1973 :
1974 6393 : if (res.type() == pe_string)
1975 : {
1976 3769 : if (post)
1977 : throw semantic_error ("post assignment on strings not supported",
1978 0 : tok);
1979 3769 : if (op == "=")
1980 : {
1981 3754 : parent->c_strcpy (lval.value(), rval.value());
1982 : // no need for second copy
1983 3754 : res = rval;
1984 : }
1985 15 : else if (op == ".=")
1986 : {
1987 15 : parent->c_strcat (lval.value(), rval.value());
1988 30 : res = lval;
1989 : }
1990 : else
1991 : throw semantic_error ("string assignment operator " +
1992 0 : op + " unsupported", tok);
1993 : }
1994 2624 : else if (op == "<<<")
1995 : {
1996 175 : assert(lval.type() == pe_stats);
1997 175 : assert(rval.type() == pe_long);
1998 175 : assert(res.type() == pe_long);
1999 175 : o->newline() << res << " = " << rval << ";";
2000 175 : o->newline() << "_stp_stat_add (" << lval << ", " << res << ");";
2001 : }
2002 2449 : else if (res.type() == pe_long)
2003 : {
2004 : // a lot of operators come through this "gate":
2005 : // - vanilla assignment "="
2006 : // - stats aggregation "<<<"
2007 : // - modify-accumulate "+=" and many friends
2008 : // - pre/post-crement "++"/"--"
2009 : // - "/" and "%" operators, but these need special handling in kernel
2010 :
2011 : // compute the modify portion of a modify-accumulate
2012 2449 : string macop;
2013 2449 : unsigned oplen = op.size();
2014 2449 : if (op == "=")
2015 1657 : macop = "*error*"; // special shortcuts below
2016 792 : else if (op == "++" || op == "+=")
2017 697 : macop = "+=";
2018 95 : else if (op == "--" || op == "-=")
2019 77 : macop = "-=";
2020 18 : else if (oplen > 1 && op[oplen-1] == '=') // for *=, <<=, etc...
2021 18 : macop = op;
2022 : else
2023 : // internal error
2024 0 : throw semantic_error ("unknown macop for assignment", tok);
2025 :
2026 2449 : if (post)
2027 : {
2028 649 : if (macop == "/" || macop == "%" || op == "=")
2029 0 : throw semantic_error ("invalid post-mode operator", tok);
2030 :
2031 649 : o->newline() << res << " = " << lval << ";";
2032 :
2033 649 : if (macop == "+=" || macop == "-=")
2034 649 : o->newline() << lval << " " << macop << " " << rval << ";";
2035 : else
2036 0 : o->newline() << lval << " = " << res << " " << macop << " " << rval << ";";
2037 : }
2038 : else
2039 : {
2040 1800 : if (op == "=") // shortcut simple assignment
2041 : {
2042 1657 : o->newline() << lval << " = " << rval << ";";
2043 1657 : res = rval;
2044 : }
2045 : else
2046 : {
2047 143 : if (macop == "/=")
2048 : o->newline() << lval << " = _stp_div64 (&c->last_error, "
2049 3 : << lval << ", " << rval << ");";
2050 140 : else if (macop == "%=")
2051 : o->newline() << lval << " = _stp_mod64 (&c->last_error, "
2052 3 : << lval << ", " << rval << ");";
2053 : else
2054 137 : o->newline() << lval << " " << macop << " " << rval << ";";
2055 143 : res = lval;
2056 : }
2057 2449 : }
2058 : }
2059 : else
2060 0 : throw semantic_error ("assignment type not yet implemented", tok);
2061 6393 : }
2062 :
2063 :
2064 : void
2065 19999 : c_unparser::c_declare(exp_type ty, const string &name)
2066 : {
2067 19999 : o->newline() << c_typename (ty) << " " << c_varname (name) << ";";
2068 19999 : }
2069 :
2070 :
2071 : void
2072 0 : c_unparser::c_declare_static(exp_type ty, const string &name)
2073 : {
2074 0 : o->newline() << "static " << c_typename (ty) << " " << c_varname (name) << ";";
2075 0 : }
2076 :
2077 :
2078 : void
2079 4886 : c_unparser::c_strcpy (const string& lvalue, const string& rvalue)
2080 : {
2081 : o->newline() << "strlcpy ("
2082 : << lvalue << ", "
2083 4886 : << rvalue << ", MAXSTRINGLEN);";
2084 4886 : }
2085 :
2086 :
2087 : void
2088 9711 : c_unparser::c_strcpy (const string& lvalue, expression* rvalue)
2089 : {
2090 9711 : o->newline() << "strlcpy (" << lvalue << ", ";
2091 9711 : rvalue->visit (this);
2092 9711 : o->line() << ", MAXSTRINGLEN);";
2093 9711 : }
2094 :
2095 :
2096 : void
2097 15 : c_unparser::c_strcat (const string& lvalue, const string& rvalue)
2098 : {
2099 : o->newline() << "strlcat ("
2100 : << lvalue << ", "
2101 15 : << rvalue << ", MAXSTRINGLEN);";
2102 15 : }
2103 :
2104 :
2105 : void
2106 265 : c_unparser::c_strcat (const string& lvalue, expression* rvalue)
2107 : {
2108 265 : o->newline() << "strlcat (" << lvalue << ", ";
2109 265 : rvalue->visit (this);
2110 265 : o->line() << ", MAXSTRINGLEN);";
2111 265 : }
2112 :
2113 :
2114 : bool
2115 19462 : c_unparser::is_local(vardecl const *r, token const *tok)
2116 : {
2117 19462 : if (current_probe)
2118 : {
2119 47653 : for (unsigned i=0; i<current_probe->locals.size(); i++)
2120 : {
2121 43107 : if (current_probe->locals[i] == r)
2122 11216 : return true;
2123 : }
2124 : }
2125 3700 : else if (current_function)
2126 : {
2127 2851 : for (unsigned i=0; i<current_function->locals.size(); i++)
2128 : {
2129 1359 : if (current_function->locals[i] == r)
2130 598 : return true;
2131 : }
2132 :
2133 1664 : for (unsigned i=0; i<current_function->formal_args.size(); i++)
2134 : {
2135 1498 : if (current_function->formal_args[i] == r)
2136 1326 : return true;
2137 : }
2138 : }
2139 :
2140 64556 : for (unsigned i=0; i<session->globals.size(); i++)
2141 : {
2142 64555 : if (session->globals[i] == r)
2143 6321 : return false;
2144 : }
2145 :
2146 1 : if (tok)
2147 1 : throw semantic_error ("unresolved symbol", tok);
2148 : else
2149 0 : throw semantic_error ("unresolved symbol: " + r->name);
2150 : }
2151 :
2152 :
2153 : tmpvar
2154 69239 : c_unparser::gensym(exp_type ty)
2155 : {
2156 69239 : return tmpvar (ty, tmpvar_counter);
2157 : }
2158 :
2159 : aggvar
2160 632 : c_unparser::gensym_aggregate()
2161 : {
2162 632 : return aggvar (tmpvar_counter);
2163 : }
2164 :
2165 :
2166 : var
2167 16488 : c_unparser::getvar(vardecl *v, token const *tok)
2168 : {
2169 16488 : bool loc = is_local (v, tok);
2170 16487 : if (loc)
2171 13140 : return var (loc, v->type, v->name);
2172 : else
2173 : {
2174 3347 : statistic_decl sd;
2175 3347 : std::map<std::string, statistic_decl>::const_iterator i;
2176 3347 : i = session->stat_decls.find(v->name);
2177 3347 : if (i != session->stat_decls.end())
2178 1288 : sd = i->second;
2179 3347 : return var (loc, v->type, sd, v->name);
2180 : }
2181 : }
2182 :
2183 :
2184 : mapvar
2185 2974 : c_unparser::getmap(vardecl *v, token const *tok)
2186 : {
2187 2974 : if (v->arity < 1)
2188 0 : throw semantic_error("attempt to use scalar where map expected", tok);
2189 2974 : statistic_decl sd;
2190 2974 : std::map<std::string, statistic_decl>::const_iterator i;
2191 2974 : i = session->stat_decls.find(v->name);
2192 2974 : if (i != session->stat_decls.end())
2193 309 : sd = i->second;
2194 : return mapvar (is_local (v, tok), v->type, sd,
2195 2974 : v->name, v->index_types, v->maxsize);
2196 : }
2197 :
2198 :
2199 : itervar
2200 204 : c_unparser::getiter(symbol *s)
2201 : {
2202 204 : return itervar (s, tmpvar_counter);
2203 : }
2204 :
2205 :
2206 :
2207 : // An artificial common "header" for each statement. This is where
2208 : // activity counts limits and error state early exits are enforced.
2209 : void
2210 15209 : c_unparser::visit_statement (statement *s, unsigned actions, bool stmtize)
2211 : {
2212 : // For some constructs, it is important to avoid an error branch
2213 : // right to the bottom of the probe/function. The foreach()
2214 : // iteration construct is one example. Instead, if we are nested
2215 : // within a loop, we branch merely to its "break" label. The next
2216 : // statement will branch one level higher, and so on, until we can
2217 : // go straight "out".
2218 15209 : string outlabel = "out";
2219 30418 : unsigned loops = loop_break_labels.size();
2220 15209 : if (loops > 0)
2221 375 : outlabel = loop_break_labels[loops-1];
2222 :
2223 15209 : if (s)
2224 : {
2225 15004 : o->newline() << "if (unlikely (c->last_error)) goto " << outlabel << ";";
2226 15004 : assert (s->tok);
2227 15004 : if (stmtize)
2228 0 : o->newline() << "c->last_stmt = " << lex_cast_qstring(*s->tok) << ";";
2229 : }
2230 :
2231 15209 : if (actions > 0)
2232 : {
2233 15209 : o->newline() << "c->actionremaining -= " << actions << ";";
2234 : // XXX: This check is inserted too frequently.
2235 15209 : o->newline() << "if (unlikely (c->actionremaining <= 0)) {";
2236 15209 : o->newline(1) << "c->last_error = \"MAXACTION exceeded\";";
2237 15209 : o->newline() << "goto " << outlabel << ";";
2238 15209 : o->newline(-1) << "}";
2239 15209 : }
2240 15209 : }
2241 :
2242 :
2243 : void
2244 2895 : c_unparser::visit_block (block *s)
2245 : {
2246 2895 : o->newline() << "{";
2247 2895 : o->indent (1);
2248 :
2249 : // visit_statement (s, 0, false);
2250 : //
2251 : // NB: this is not necessary, since the last_error can be handled
2252 : // just as easily by the first real body statement, and the
2253 : // last_stmt won't be used since this nesting structure cannot
2254 : // itself cause an error.
2255 :
2256 17963 : for (unsigned i=0; i<s->statements.size(); i++)
2257 : {
2258 : try
2259 : {
2260 15068 : s->statements[i]->visit (this);
2261 15066 : o->newline();
2262 : }
2263 4 : catch (const semantic_error& e)
2264 : {
2265 2 : session->print_error (e);
2266 : }
2267 : }
2268 2895 : o->newline(-1) << "}";
2269 2895 : }
2270 :
2271 :
2272 : void
2273 1052 : c_unparser::visit_embeddedcode (embeddedcode *s)
2274 : {
2275 : // visit_statement (s, 1, true);
2276 : //
2277 : // NB: this is not necessary, since this can occur only at the top
2278 : // level of a function (so no errors can be pending), and the
2279 : // action-count is already incremented at the point of call.
2280 :
2281 1052 : o->newline() << "{";
2282 1052 : o->newline(1) << s->code;
2283 1052 : o->newline(-1) << "}";
2284 1052 : }
2285 :
2286 :
2287 : void
2288 3764 : c_unparser::visit_null_statement (null_statement *)
2289 : {
2290 : // visit_statement (s, 0, false);
2291 : //
2292 : // NB: this is not necessary, since the last_error can be handled just as
2293 : // easily by the next statement, and the last_stmt won't be used since this
2294 : // statement cannot cause an error.
2295 :
2296 3764 : o->newline() << "/* null */;";
2297 3764 : }
2298 :
2299 :
2300 : void
2301 10319 : c_unparser::visit_expr_statement (expr_statement *s)
2302 : {
2303 10319 : visit_statement (s, 1, false);
2304 10319 : o->newline() << "(void) ";
2305 10319 : s->value->visit (this);
2306 10319 : o->line() << ";";
2307 10319 : }
2308 :
2309 :
2310 : void
2311 3092 : c_unparser::visit_if_statement (if_statement *s)
2312 : {
2313 3092 : visit_statement (s, 1, false);
2314 3092 : o->newline() << "if (";
2315 3092 : o->indent (1);
2316 3092 : s->condition->visit (this);
2317 3092 : o->indent (-1);
2318 3092 : o->line() << ") {";
2319 3092 : o->indent (1);
2320 3092 : s->thenblock->visit (this);
2321 3092 : o->newline(-1) << "}";
2322 3092 : if (s->elseblock)
2323 : {
2324 815 : o->newline() << "else {";
2325 815 : o->indent (1);
2326 815 : s->elseblock->visit (this);
2327 815 : o->newline(-1) << "}";
2328 : }
2329 3092 : }
2330 :
2331 :
2332 : void
2333 2897 : c_tmpcounter::visit_block (block *s)
2334 : {
2335 : // Key insight: individual statements of a block can reuse
2336 : // temporary variable slots, since temporaries don't survive
2337 : // statement boundaries. So we use gcc's anonymous union/struct
2338 : // facility to explicitly overlay the temporaries.
2339 2897 : parent->o->newline() << "union {";
2340 2897 : parent->o->indent(1);
2341 17967 : for (unsigned i=0; i<s->statements.size(); i++)
2342 : {
2343 : // To avoid lots of empty structs inside the union, remember
2344 : // where we are now. Then, output the struct start and remember
2345 : // that positon. If when we get done with the statement we
2346 : // haven't moved, then we don't really need the struct. To get
2347 : // rid of the struct start we output, we'll seek back to where
2348 : // we were before we output the struct.
2349 15071 : std::ostream::pos_type before_struct_pos = parent->o->tellp();
2350 15071 : parent->o->newline() << "struct {";
2351 15071 : parent->o->indent(1);
2352 15071 : std::ostream::pos_type after_struct_pos = parent->o->tellp();
2353 15071 : s->statements[i]->visit (this);
2354 15070 : parent->o->indent(-1);
2355 15070 : if (after_struct_pos == parent->o->tellp())
2356 7632 : parent->o->seekp(before_struct_pos);
2357 : else
2358 7438 : parent->o->newline() << "};";
2359 : }
2360 2896 : parent->o->newline(-1) << "};";
2361 2896 : }
2362 :
2363 : void
2364 103 : c_tmpcounter::visit_for_loop (for_loop *s)
2365 : {
2366 103 : if (s->init) s->init->visit (this);
2367 103 : s->cond->visit (this);
2368 103 : s->block->visit (this);
2369 103 : if (s->incr) s->incr->visit (this);
2370 103 : }
2371 :
2372 :
2373 : void
2374 103 : c_unparser::visit_for_loop (for_loop *s)
2375 : {
2376 103 : visit_statement (s, 1, false);
2377 :
2378 103 : string ctr = stringify (label_counter++);
2379 103 : string toplabel = "top_" + ctr;
2380 103 : string contlabel = "continue_" + ctr;
2381 103 : string breaklabel = "break_" + ctr;
2382 :
2383 : // initialization
2384 103 : if (s->init) s->init->visit (this);
2385 :
2386 : // condition
2387 103 : o->newline(-1) << toplabel << ":";
2388 :
2389 : // Emit an explicit action here to cover the act of iteration.
2390 : // Equivalently, it can stand for the evaluation of the condition
2391 : // expression.
2392 103 : o->indent(1);
2393 103 : visit_statement (0, 1, false);
2394 :
2395 103 : o->newline() << "if (! (";
2396 103 : if (s->cond->type != pe_long)
2397 0 : throw semantic_error ("expected numeric type", s->cond->tok);
2398 103 : s->cond->visit (this);
2399 103 : o->line() << ")) goto " << breaklabel << ";";
2400 :
2401 : // body
2402 103 : loop_break_labels.push_back (breaklabel);
2403 103 : loop_continue_labels.push_back (contlabel);
2404 103 : s->block->visit (this);
2405 103 : loop_break_labels.pop_back ();
2406 103 : loop_continue_labels.pop_back ();
2407 :
2408 : // iteration
2409 103 : o->newline(-1) << contlabel << ":";
2410 103 : o->indent(1);
2411 103 : if (s->incr) s->incr->visit (this);
2412 103 : o->newline() << "goto " << toplabel << ";";
2413 :
2414 : // exit
2415 103 : o->newline(-1) << breaklabel << ":";
2416 103 : o->newline(1) << "; /* dummy statement */";
2417 103 : }
2418 :
2419 :
2420 : struct arrayindex_downcaster
2421 : : public traversing_visitor
2422 262 : {
2423 : arrayindex *& arr;
2424 :
2425 262 : arrayindex_downcaster (arrayindex *& arr)
2426 262 : : arr(arr)
2427 262 : {}
2428 :
2429 262 : void visit_arrayindex (arrayindex* e)
2430 : {
2431 262 : arr = e;
2432 262 : }
2433 : };
2434 :
2435 :
2436 : static bool
2437 : expression_is_arrayindex (expression *e,
2438 262 : arrayindex *& hist)
2439 : {
2440 262 : arrayindex *h = NULL;
2441 262 : arrayindex_downcaster d(h);
2442 262 : e->visit (&d);
2443 262 : if (static_cast<void*>(h) == static_cast<void*>(e))
2444 : {
2445 262 : hist = h;
2446 262 : return true;
2447 : }
2448 0 : return false;
2449 : }
2450 :
2451 :
2452 : void
2453 108 : c_tmpcounter::visit_foreach_loop (foreach_loop *s)
2454 : {
2455 : symbol *array;
2456 : hist_op *hist;
2457 108 : classify_indexable (s->base, array, hist);
2458 :
2459 108 : if (array)
2460 : {
2461 102 : itervar iv = parent->getiter (array);
2462 102 : parent->o->newline() << iv.declare();
2463 : }
2464 : else
2465 : {
2466 : // See commentary in c_tmpcounter::visit_arrayindex for
2467 : // discussion of tmpvars required to look into @hist_op(...)
2468 : // expressions.
2469 :
2470 : // First make sure we have exactly one pe_long variable to use as
2471 : // our bucket index.
2472 :
2473 6 : if (s->indexes.size() != 1 || s->indexes[0]->referent->type != pe_long)
2474 0 : throw semantic_error("Invalid indexing of histogram", s->tok);
2475 :
2476 : // Then declare what we need to form the aggregate we're
2477 : // iterating over, and all the tmpvars needed by our call to
2478 : // load_aggregate().
2479 :
2480 6 : aggvar agg = parent->gensym_aggregate ();
2481 6 : agg.declare(*(this->parent));
2482 :
2483 6 : symbol *sym = get_symbol_within_expression (hist->stat);
2484 6 : var v = parent->getvar(sym->referent, sym->tok);
2485 6 : if (sym->referent->arity != 0)
2486 : {
2487 0 : arrayindex *arr = NULL;
2488 0 : if (!expression_is_arrayindex (hist->stat, arr))
2489 0 : throw semantic_error("expected arrayindex expression in iterated hist_op", s->tok);
2490 :
2491 0 : for (unsigned i=0; i<sym->referent->index_types.size(); i++)
2492 : {
2493 0 : tmpvar ix = parent->gensym (sym->referent->index_types[i]);
2494 0 : ix.declare (*parent);
2495 0 : arr->indexes[i]->visit(this);
2496 : }
2497 6 : }
2498 : }
2499 :
2500 : // Create a temporary for the loop limit counter and the limit
2501 : // expression result.
2502 108 : if (s->limit)
2503 : {
2504 18 : tmpvar res_limit = parent->gensym (pe_long);
2505 18 : res_limit.declare(*parent);
2506 :
2507 18 : s->limit->visit (this);
2508 :
2509 18 : tmpvar limitv = parent->gensym (pe_long);
2510 18 : limitv.declare(*parent);
2511 : }
2512 :
2513 108 : s->block->visit (this);
2514 108 : }
2515 :
2516 : void
2517 108 : c_unparser::visit_foreach_loop (foreach_loop *s)
2518 : {
2519 : symbol *array;
2520 : hist_op *hist;
2521 108 : classify_indexable (s->base, array, hist);
2522 :
2523 108 : if (array)
2524 : {
2525 102 : visit_statement (s, 1, false);
2526 :
2527 102 : mapvar mv = getmap (array->referent, s->tok);
2528 102 : itervar iv = getiter (array);
2529 102 : vector<var> keys;
2530 :
2531 102 : string ctr = stringify (label_counter++);
2532 102 : string toplabel = "top_" + ctr;
2533 102 : string contlabel = "continue_" + ctr;
2534 102 : string breaklabel = "break_" + ctr;
2535 :
2536 : // NB: structure parallels for_loop
2537 :
2538 : // initialization
2539 :
2540 102 : tmpvar *res_limit = NULL;
2541 102 : if (s->limit)
2542 : {
2543 : // Evaluate the limit expression once.
2544 17 : res_limit = new tmpvar(gensym(pe_long));
2545 34 : c_assign (res_limit->value(), s->limit, "foreach limit");
2546 : }
2547 :
2548 : // aggregate array if required
2549 102 : if (mv.is_parallel())
2550 : {
2551 23 : o->newline() << "if (unlikely(NULL == " << mv.calculate_aggregate() << "))";
2552 23 : o->newline(1) << "c->last_error = \"aggregation overflow in " << mv << "\";";
2553 23 : o->indent(-1);
2554 :
2555 : // sort array if desired
2556 23 : if (s->sort_direction)
2557 : {
2558 : int sort_column;
2559 :
2560 : // If the user wanted us to sort by value, we'll sort by
2561 : // @count instead for aggregates. '-5' tells the
2562 : // runtime to sort by count.
2563 16 : if (s->sort_column == 0)
2564 8 : sort_column = -5;
2565 : else
2566 8 : sort_column = s->sort_column;
2567 :
2568 16 : o->newline() << "else"; // only sort if aggregation was ok
2569 16 : if (s->limit)
2570 : {
2571 : o->newline(1) << "_stp_map_sortn ("
2572 : << mv.fetch_existing_aggregate() << ", "
2573 : << *res_limit << ", " << sort_column << ", "
2574 7 : << - s->sort_direction << ");";
2575 : }
2576 : else
2577 : {
2578 : o->newline(1) << "_stp_map_sort ("
2579 : << mv.fetch_existing_aggregate() << ", "
2580 : << sort_column << ", "
2581 9 : << - s->sort_direction << ");";
2582 : }
2583 16 : o->indent(-1);
2584 : }
2585 : }
2586 : else
2587 : {
2588 : // sort array if desired
2589 79 : if (s->sort_direction)
2590 : {
2591 22 : if (s->limit)
2592 : {
2593 : o->newline() << "_stp_map_sortn (" << mv.value() << ", "
2594 : << *res_limit << ", " << s->sort_column << ", "
2595 8 : << - s->sort_direction << ");";
2596 : }
2597 : else
2598 : {
2599 : o->newline() << "_stp_map_sort (" << mv.value() << ", "
2600 : << s->sort_column << ", "
2601 14 : << - s->sort_direction << ");";
2602 : }
2603 : }
2604 : }
2605 :
2606 : // NB: sort direction sense is opposite in runtime, thus the negation
2607 :
2608 102 : if (mv.is_parallel())
2609 23 : aggregations_active.insert(mv.value());
2610 102 : o->newline() << iv << " = " << iv.start (mv) << ";";
2611 :
2612 102 : tmpvar *limitv = NULL;
2613 102 : if (s->limit)
2614 : {
2615 : // Create the loop limit variable here and initialize it.
2616 17 : limitv = new tmpvar(gensym (pe_long));
2617 34 : o->newline() << *limitv << " = 0LL;";
2618 : }
2619 :
2620 : // condition
2621 102 : o->newline(-1) << toplabel << ":";
2622 :
2623 : // Emit an explicit action here to cover the act of iteration.
2624 : // Equivalently, it can stand for the evaluation of the
2625 : // condition expression.
2626 102 : o->indent(1);
2627 102 : visit_statement (0, 1, false);
2628 :
2629 102 : o->newline() << "if (! (" << iv << ")) goto " << breaklabel << ";";
2630 :
2631 : // body
2632 102 : loop_break_labels.push_back (breaklabel);
2633 102 : loop_continue_labels.push_back (contlabel);
2634 102 : o->newline() << "{";
2635 102 : o->indent (1);
2636 :
2637 102 : if (s->limit)
2638 : {
2639 : // If we've been through LIMIT loop iterations, quit.
2640 : o->newline() << "if (" << *limitv << "++ >= " << *res_limit
2641 17 : << ") goto " << breaklabel << ";";
2642 :
2643 : // We're done with limitv and res_limit.
2644 17 : delete limitv;
2645 17 : delete res_limit;
2646 : }
2647 :
2648 226 : for (unsigned i = 0; i < s->indexes.size(); ++i)
2649 : {
2650 : // copy the iter values into the specified locals
2651 124 : var v = getvar (s->indexes[i]->referent);
2652 124 : c_assign (v, iv.get_key (v.type(), i), s->tok);
2653 : }
2654 102 : s->block->visit (this);
2655 102 : o->newline(-1) << "}";
2656 102 : loop_break_labels.pop_back ();
2657 102 : loop_continue_labels.pop_back ();
2658 :
2659 : // iteration
2660 102 : o->newline(-1) << contlabel << ":";
2661 102 : o->newline(1) << iv << " = " << iv.next (mv) << ";";
2662 102 : o->newline() << "goto " << toplabel << ";";
2663 :
2664 : // exit
2665 102 : o->newline(-1) << breaklabel << ":";
2666 102 : o->newline(1) << "; /* dummy statement */";
2667 :
2668 102 : if (mv.is_parallel())
2669 23 : aggregations_active.erase(mv.value());
2670 : }
2671 : else
2672 : {
2673 : // Iterating over buckets in a histogram.
2674 6 : assert(s->indexes.size() == 1);
2675 6 : assert(s->indexes[0]->referent->type == pe_long);
2676 6 : var bucketvar = getvar (s->indexes[0]->referent);
2677 :
2678 6 : aggvar agg = gensym_aggregate ();
2679 6 : load_aggregate(hist->stat, agg);
2680 :
2681 6 : symbol *sym = get_symbol_within_expression (hist->stat);
2682 6 : var v = getvar(sym->referent, sym->tok);
2683 6 : v.assert_hist_compatible(*hist);
2684 :
2685 6 : tmpvar *res_limit = NULL;
2686 6 : tmpvar *limitv = NULL;
2687 6 : if (s->limit)
2688 : {
2689 : // Evaluate the limit expression once.
2690 1 : res_limit = new tmpvar(gensym(pe_long));
2691 2 : c_assign (res_limit->value(), s->limit, "foreach limit");
2692 :
2693 : // Create the loop limit variable here and initialize it.
2694 2 : limitv = new tmpvar(gensym (pe_long));
2695 2 : o->newline() << *limitv << " = 0LL;";
2696 : }
2697 :
2698 : // XXX: break / continue don't work here yet
2699 : o->newline() << "for (" << bucketvar << " = 0; "
2700 : << bucketvar << " < " << v.buckets() << "; "
2701 6 : << bucketvar << "++) { ";
2702 6 : o->newline(1);
2703 :
2704 6 : if (s->limit)
2705 : {
2706 : // If we've been through LIMIT loop iterations, quit.
2707 : o->newline() << "if (" << *limitv << "++ >= " << *res_limit
2708 1 : << ") break;";
2709 :
2710 : // We're done with limitv and res_limit.
2711 1 : delete limitv;
2712 1 : delete res_limit;
2713 : }
2714 :
2715 6 : s->block->visit (this);
2716 6 : o->newline(-1) << "}";
2717 : }
2718 108 : }
2719 :
2720 :
2721 : void
2722 1102 : c_unparser::visit_return_statement (return_statement* s)
2723 : {
2724 1102 : visit_statement (s, 1, false);
2725 :
2726 1102 : if (current_function == 0)
2727 0 : throw semantic_error ("cannot 'return' from probe", s->tok);
2728 :
2729 1102 : if (s->value->type != current_function->type)
2730 : throw semantic_error ("return type mismatch", current_function->tok,
2731 0 : "vs", s->tok);
2732 :
2733 1102 : c_assign ("l->__retvalue", s->value, "return value");
2734 1102 : o->newline() << "c->last_error = \"\";";
2735 : // NB: last_error needs to get reset to NULL in the caller
2736 : // probe/function
2737 1102 : }
2738 :
2739 :
2740 : void
2741 18 : c_unparser::visit_next_statement (next_statement* s)
2742 : {
2743 18 : visit_statement (s, 1, false);
2744 :
2745 18 : if (current_probe == 0)
2746 0 : throw semantic_error ("cannot 'next' from function", s->tok);
2747 :
2748 18 : o->newline() << "c->last_error = \"\";";
2749 18 : }
2750 :
2751 :
2752 : struct delete_statement_operand_tmp_visitor:
2753 : public traversing_visitor
2754 258 : {
2755 : c_tmpcounter *parent;
2756 258 : delete_statement_operand_tmp_visitor (c_tmpcounter *p):
2757 258 : parent (p)
2758 258 : {}
2759 : //void visit_symbol (symbol* e);
2760 : void visit_arrayindex (arrayindex* e);
2761 : };
2762 :
2763 :
2764 : struct delete_statement_operand_visitor:
2765 : public throwing_visitor
2766 258 : {
2767 : c_unparser *parent;
2768 258 : delete_statement_operand_visitor (c_unparser *p):
2769 : throwing_visitor ("invalid operand of delete expression"),
2770 258 : parent (p)
2771 258 : {}
2772 : void visit_symbol (symbol* e);
2773 : void visit_arrayindex (arrayindex* e);
2774 : };
2775 :
2776 : void
2777 78 : delete_statement_operand_visitor::visit_symbol (symbol* e)
2778 : {
2779 78 : assert (e->referent != 0);
2780 78 : if (e->referent->arity > 0)
2781 : {
2782 19 : mapvar mvar = parent->getmap(e->referent, e->tok);
2783 : /* NB: Memory deallocation/allocation operations
2784 : are not generally safe.
2785 : parent->o->newline() << mvar.fini ();
2786 : parent->o->newline() << mvar.init ();
2787 : */
2788 19 : if (mvar.is_parallel())
2789 7 : parent->o->newline() << "_stp_pmap_clear (" << mvar.value() << ");";
2790 : else
2791 12 : parent->o->newline() << "_stp_map_clear (" << mvar.value() << ");";
2792 : }
2793 : else
2794 : {
2795 59 : var v = parent->getvar(e->referent, e->tok);
2796 59 : switch (e->type)
2797 : {
2798 : case pe_stats:
2799 55 : parent->o->newline() << "_stp_stat_clear (" << v.value() << ");";
2800 55 : break;
2801 : case pe_long:
2802 2 : parent->o->newline() << v.value() << " = 0;";
2803 2 : break;
2804 : case pe_string:
2805 2 : parent->o->newline() << v.value() << "[0] = '\\0';";
2806 2 : break;
2807 : case pe_unknown:
2808 : default:
2809 0 : throw semantic_error("Cannot delete unknown expression type", e->tok);
2810 59 : }
2811 : }
2812 78 : }
2813 :
2814 : void
2815 180 : delete_statement_operand_tmp_visitor::visit_arrayindex (arrayindex* e)
2816 : {
2817 : symbol *array;
2818 : hist_op *hist;
2819 180 : classify_indexable (e->base, array, hist);
2820 :
2821 180 : if (array)
2822 : {
2823 180 : assert (array->referent != 0);
2824 180 : vardecl* r = array->referent;
2825 :
2826 : // One temporary per index dimension.
2827 433 : for (unsigned i=0; i<r->index_types.size(); i++)
2828 : {
2829 253 : tmpvar ix = parent->parent->gensym (r->index_types[i]);
2830 253 : ix.declare (*(parent->parent));
2831 253 : e->indexes[i]->visit(parent);
2832 : }
2833 : }
2834 : else
2835 : {
2836 0 : throw semantic_error("cannot delete histogram bucket entries\n", e->tok);
2837 : }
2838 180 : }
2839 :
2840 : void
2841 180 : delete_statement_operand_visitor::visit_arrayindex (arrayindex* e)
2842 : {
2843 : symbol *array;
2844 : hist_op *hist;
2845 180 : classify_indexable (e->base, array, hist);
2846 :
2847 180 : if (array)
2848 : {
2849 180 : vector<tmpvar> idx;
2850 180 : parent->load_map_indices (e, idx);
2851 :
2852 : {
2853 180 : mapvar mvar = parent->getmap (array->referent, e->tok);
2854 180 : parent->o->newline() << mvar.del (idx) << ";";
2855 180 : }
2856 : }
2857 : else
2858 : {
2859 0 : throw semantic_error("cannot delete histogram bucket entries\n", e->tok);
2860 : }
2861 180 : }
2862 :
2863 :
2864 : void
2865 258 : c_tmpcounter::visit_delete_statement (delete_statement* s)
2866 : {
2867 258 : delete_statement_operand_tmp_visitor dv (this);
2868 258 : s->value->visit (&dv);
2869 258 : }
2870 :
2871 :
2872 : void
2873 258 : c_unparser::visit_delete_statement (delete_statement* s)
2874 : {
2875 258 : visit_statement (s, 1, false);
2876 258 : delete_statement_operand_visitor dv (this);
2877 258 : s->value->visit (&dv);
2878 258 : }
2879 :
2880 :
2881 : void
2882 5 : c_unparser::visit_break_statement (break_statement* s)
2883 : {
2884 5 : visit_statement (s, 1, false);
2885 5 : if (loop_break_labels.size() == 0)
2886 1 : throw semantic_error ("cannot 'break' outside loop", s->tok);
2887 :
2888 4 : string label = loop_break_labels[loop_break_labels.size()-1];
2889 4 : o->newline() << "goto " << label << ";";
2890 4 : }
2891 :
2892 :
2893 : void
2894 5 : c_unparser::visit_continue_statement (continue_statement* s)
2895 : {
2896 5 : visit_statement (s, 1, false);
2897 5 : if (loop_continue_labels.size() == 0)
2898 1 : throw semantic_error ("cannot 'continue' outside loop", s->tok);
2899 :
2900 4 : string label = loop_continue_labels[loop_continue_labels.size()-1];
2901 4 : o->newline() << "goto " << label << ";";
2902 4 : }
2903 :
2904 :
2905 :
2906 : void
2907 4763 : c_unparser::visit_literal_string (literal_string* e)
2908 : {
2909 4763 : const string& v = e->value;
2910 4763 : o->line() << '"';
2911 39479 : for (unsigned i=0; i<v.size(); i++)
2912 : // NB: The backslash character is specifically passed through as is.
2913 : // This is because our parser treats "\" as an ordinary character, not
2914 : // an escape sequence, leaving it to the C compiler (and this function)
2915 : // to treat it as such. If we were to escape it, there would be no way
2916 : // of generating C-level escapes from script code.
2917 : // See also print_format::components_to_string and lex_cast_qstring
2918 34716 : if (v[i] == '"') // or other escapeworthy characters?
2919 2 : o->line() << '\\' << '"';
2920 : else
2921 34714 : o->line() << v[i];
2922 4763 : o->line() << '"';
2923 4763 : }
2924 :
2925 :
2926 : void
2927 4180 : c_unparser::visit_literal_number (literal_number* e)
2928 : {
2929 : // This looks ugly, but tries to be warning-free on 32- and 64-bit
2930 : // hosts.
2931 : // NB: this needs to be signed!
2932 4180 : if (e->value == -9223372036854775807LL-1) // PR 5023
2933 8 : o->line() << "((int64_t)" << (unsigned long long) e->value << "ULL)";
2934 : else
2935 4172 : o->line() << "((int64_t)" << e->value << "LL)";
2936 4180 : }
2937 :
2938 :
2939 : void
2940 585 : c_tmpcounter::visit_binary_expression (binary_expression* e)
2941 : {
2942 585 : if (e->op == "/" || e->op == "%")
2943 : {
2944 89 : tmpvar left = parent->gensym (pe_long);
2945 89 : tmpvar right = parent->gensym (pe_long);
2946 89 : if (e->left->tok->type != tok_number)
2947 68 : left.declare (*parent);
2948 89 : if (e->right->tok->type != tok_number)
2949 30 : right.declare (*parent);
2950 : }
2951 :
2952 585 : e->left->visit (this);
2953 585 : e->right->visit (this);
2954 585 : }
2955 :
2956 :
2957 : void
2958 585 : c_unparser::visit_binary_expression (binary_expression* e)
2959 : {
2960 585 : if (e->type != pe_long ||
2961 : e->left->type != pe_long ||
2962 : e->right->type != pe_long)
2963 0 : throw semantic_error ("expected numeric types", e->tok);
2964 :
2965 585 : if (e->op == "+" ||
2966 : e->op == "-" ||
2967 : e->op == "*" ||
2968 : e->op == "&" ||
2969 : e->op == "|" ||
2970 : e->op == "^")
2971 : {
2972 487 : o->line() << "((";
2973 487 : e->left->visit (this);
2974 487 : o->line() << ") " << e->op << " (";
2975 487 : e->right->visit (this);
2976 487 : o->line() << "))";
2977 : }
2978 98 : else if (e->op == ">>" ||
2979 : e->op == "<<")
2980 : {
2981 9 : o->line() << "((";
2982 9 : e->left->visit (this);
2983 9 : o->line() << ") " << e->op << "max(min(";
2984 9 : e->right->visit (this);
2985 9 : o->line() << ", (int64_t)64LL), (int64_t)0LL))"; // between 0 and 64
2986 : }
2987 89 : else if (e->op == "/" ||
2988 : e->op == "%")
2989 : {
2990 : // % and / need a division-by-zero check; and thus two temporaries
2991 : // for proper evaluation order
2992 89 : tmpvar left = gensym (pe_long);
2993 89 : tmpvar right = gensym (pe_long);
2994 :
2995 89 : o->line() << "({";
2996 89 : o->indent(1);
2997 : // NB: Need last_stmt set here because of possible last_error generation
2998 89 : o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
2999 :
3000 89 : if (e->left->tok->type == tok_number)
3001 21 : left.override(c_expression(e->left));
3002 : else
3003 : {
3004 68 : o->newline() << left << " = ";
3005 68 : e->left->visit (this);
3006 68 : o->line() << ";";
3007 : }
3008 :
3009 89 : if (e->right->tok->type == tok_number)
3010 59 : right.override(c_expression(e->right));
3011 : else
3012 : {
3013 30 : o->newline() << right << " = ";
3014 30 : e->right->visit (this);
3015 30 : o->line() << ";";
3016 : }
3017 :
3018 : o->newline() << ((e->op == "/") ? "_stp_div64" : "_stp_mod64")
3019 89 : << " (&c->last_error, " << left << ", " << right << ");";
3020 :
3021 89 : o->newline(-1) << "})";
3022 : }
3023 : else
3024 0 : throw semantic_error ("operator not yet implemented", e->tok);
3025 585 : }
3026 :
3027 :
3028 : void
3029 228 : c_unparser::visit_unary_expression (unary_expression* e)
3030 : {
3031 228 : if (e->type != pe_long ||
3032 : e->operand->type != pe_long)
3033 0 : throw semantic_error ("expected numeric types", e->tok);
3034 :
3035 228 : if (e->op == "-")
3036 : {
3037 : // NB: Subtraction is special, since negative literals in the
3038 : // script language show up as unary negations over positive
3039 : // literals here. This makes it "exciting" for emitting pure
3040 : // C since: - 0x8000_0000_0000_0000 ==> - (- 9223372036854775808)
3041 : // This would constitute a signed overflow, which gcc warns on
3042 : // unless -ftrapv/-J are in CFLAGS - which they're not.
3043 :
3044 131 : o->line() << "(int64_t)(0 " << e->op << " (uint64_t)(";
3045 131 : e->operand->visit (this);
3046 131 : o->line() << "))";
3047 : }
3048 : else
3049 : {
3050 97 : o->line() << "(" << e->op << " (";
3051 97 : e->operand->visit (this);
3052 97 : o->line() << "))";
3053 : }
3054 228 : }
3055 :
3056 : void
3057 4 : c_unparser::visit_logical_or_expr (logical_or_expr* e)
3058 : {
3059 4 : if (e->type != pe_long ||
3060 : e->left->type != pe_long ||
3061 : e->right->type != pe_long)
3062 0 : throw semantic_error ("expected numeric types", e->tok);
3063 :
3064 4 : o->line() << "((";
3065 4 : e->left->visit (this);
3066 4 : o->line() << ") " << e->op << " (";
3067 4 : e->right->visit (this);
3068 4 : o->line() << "))";
3069 4 : }
3070 :
3071 :
3072 : void
3073 31 : c_unparser::visit_logical_and_expr (logical_and_expr* e)
3074 : {
3075 31 : if (e->type != pe_long ||
3076 : e->left->type != pe_long ||
3077 : e->right->type != pe_long)
3078 0 : throw semantic_error ("expected numeric types", e->tok);
3079 :
3080 31 : o->line() << "((";
3081 31 : e->left->visit (this);
3082 31 : o->line() << ") " << e->op << " (";
3083 31 : e->right->visit (this);
3084 31 : o->line() << "))";
3085 31 : }
3086 :
3087 :
3088 : void
3089 43 : c_tmpcounter::visit_array_in (array_in* e)
3090 : {
3091 : symbol *array;
3092 : hist_op *hist;
3093 43 : classify_indexable (e->operand->base, array, hist);
3094 :
3095 43 : if (array)
3096 : {
3097 42 : assert (array->referent != 0);
3098 42 : vardecl* r = array->referent;
3099 :
3100 : // One temporary per index dimension.
3101 95 : for (unsigned i=0; i<r->index_types.size(); i++)
3102 : {
3103 53 : tmpvar ix = parent->gensym (r->index_types[i]);
3104 53 : ix.declare (*parent);
3105 53 : e->operand->indexes[i]->visit(this);
3106 : }
3107 :
3108 : // A boolean result.
3109 42 : tmpvar res = parent->gensym (e->type);
3110 42 : res.declare (*parent);
3111 : }
3112 : else
3113 : {
3114 : // By definition:
3115 : //
3116 : // 'foo in @hist_op(...)' is true iff
3117 : // '@hist_op(...)[foo]' is nonzero
3118 : //
3119 : // so we just delegate to the latter call, since int64_t is also
3120 : // our boolean type.
3121 1 : e->operand->visit(this);
3122 : }
3123 43 : }
3124 :
3125 :
3126 : void
3127 43 : c_unparser::visit_array_in (array_in* e)
3128 : {
3129 : symbol *array;
3130 : hist_op *hist;
3131 43 : classify_indexable (e->operand->base, array, hist);
3132 :
3133 43 : if (array)
3134 : {
3135 42 : stmt_expr block(*this);
3136 :
3137 42 : vector<tmpvar> idx;
3138 42 : load_map_indices (e->operand, idx);
3139 : // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
3140 :
3141 42 : tmpvar res = gensym (pe_long);
3142 42 : mapvar mvar = getmap (array->referent, e->tok);
3143 42 : c_assign (res, mvar.exists(idx), e->tok);
3144 :
3145 42 : o->newline() << res << ";";
3146 : }
3147 : else
3148 : {
3149 : // By definition:
3150 : //
3151 : // 'foo in @hist_op(...)' is true iff
3152 : // '@hist_op(...)[foo]' is nonzero
3153 : //
3154 : // so we just delegate to the latter call, since int64_t is also
3155 : // our boolean type.
3156 1 : e->operand->visit(this);
3157 : }
3158 43 : }
3159 :
3160 :
3161 : void
3162 2598 : c_unparser::visit_comparison (comparison* e)
3163 : {
3164 2598 : o->line() << "(";
3165 :
3166 2598 : if (e->left->type == pe_string)
3167 : {
3168 993 : if (e->left->type != pe_string ||
3169 : e->right->type != pe_string)
3170 0 : throw semantic_error ("expected string types", e->tok);
3171 :
3172 993 : o->line() << "strncmp (";
3173 993 : e->left->visit (this);
3174 993 : o->line() << ", ";
3175 993 : e->right->visit (this);
3176 993 : o->line() << ", MAXSTRINGLEN";
3177 993 : o->line() << ") " << e->op << " 0";
3178 : }
3179 1605 : else if (e->left->type == pe_long)
3180 : {
3181 1605 : if (e->left->type != pe_long ||
3182 : e->right->type != pe_long)
3183 0 : throw semantic_error ("expected numeric types", e->tok);
3184 :
3185 1605 : o->line() << "((";
3186 1605 : e->left->visit (this);
3187 1605 : o->line() << ") " << e->op << " (";
3188 1605 : e->right->visit (this);
3189 1605 : o->line() << "))";
3190 : }
3191 : else
3192 0 : throw semantic_error ("unexpected type", e->left->tok);
3193 :
3194 2598 : o->line() << ")";
3195 2598 : }
3196 :
3197 :
3198 : void
3199 265 : c_tmpcounter::visit_concatenation (concatenation* e)
3200 : {
3201 265 : tmpvar t = parent->gensym (e->type);
3202 265 : t.declare (*parent);
3203 265 : e->left->visit (this);
3204 265 : e->right->visit (this);
3205 265 : }
3206 :
3207 :
3208 : void
3209 265 : c_unparser::visit_concatenation (concatenation* e)
3210 : {
3211 265 : if (e->op != ".")
3212 0 : throw semantic_error ("unexpected concatenation operator", e->tok);
3213 :
3214 265 : if (e->type != pe_string ||
3215 : e->left->type != pe_string ||
3216 : e->right->type != pe_string)
3217 0 : throw semantic_error ("expected string types", e->tok);
3218 :
3219 265 : tmpvar t = gensym (e->type);
3220 :
3221 265 : o->line() << "({ ";
3222 265 : o->indent(1);
3223 : // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
3224 265 : c_assign (t.value(), e->left, "assignment");
3225 530 : c_strcat (t.value(), e->right);
3226 265 : o->newline() << t << ";";
3227 265 : o->newline(-1) << "})";
3228 265 : }
3229 :
3230 :
3231 : void
3232 30 : c_unparser::visit_ternary_expression (ternary_expression* e)
3233 : {
3234 30 : if (e->cond->type != pe_long)
3235 0 : throw semantic_error ("expected numeric condition", e->cond->tok);
3236 :
3237 30 : if (e->truevalue->type != e->falsevalue->type ||
3238 : e->type != e->truevalue->type ||
3239 : (e->truevalue->type != pe_long && e->truevalue->type != pe_string))
3240 0 : throw semantic_error ("expected matching types", e->tok);
3241 :
3242 30 : o->line() << "((";
3243 30 : e->cond->visit (this);
3244 30 : o->line() << ") ? (";
3245 30 : e->truevalue->visit (this);
3246 30 : o->line() << ") : (";
3247 30 : e->falsevalue->visit (this);
3248 30 : o->line() << "))";
3249 30 : }
3250 :
3251 :
3252 : void
3253 5710 : c_tmpcounter::visit_assignment (assignment *e)
3254 : {
3255 5710 : c_tmpcounter_assignment tav (this, e->op, e->right);
3256 5710 : e->left->visit (& tav);
3257 5710 : }
3258 :
3259 :
3260 : void
3261 5709 : c_unparser::visit_assignment (assignment* e)
3262 : {
3263 5709 : if (e->op == "<<<")
3264 : {
3265 240 : if (e->type != pe_long)
3266 0 : throw semantic_error ("non-number <<< expression", e->tok);
3267 :
3268 240 : if (e->left->type != pe_stats)
3269 0 : throw semantic_error ("non-stats left operand to <<< expression", e->left->tok);
3270 :
3271 240 : if (e->right->type != pe_long)
3272 0 : throw semantic_error ("non-number right operand to <<< expression", e->right->tok);
3273 :
3274 : }
3275 : else
3276 : {
3277 5469 : if (e->type != e->left->type)
3278 : throw semantic_error ("type mismatch", e->tok,
3279 0 : "vs", e->left->tok);
3280 5469 : if (e->right->type != e->left->type)
3281 : throw semantic_error ("type mismatch", e->right->tok,
3282 0 : "vs", e->left->tok);
3283 : }
3284 :
3285 5709 : c_unparser_assignment tav (this, e->op, e->right);
3286 5709 : e->left->visit (& tav);
3287 5709 : }
3288 :
3289 :
3290 : void
3291 100 : c_tmpcounter::visit_pre_crement (pre_crement* e)
3292 : {
3293 100 : c_tmpcounter_assignment tav (this, e->op, 0);
3294 100 : e->operand->visit (& tav);
3295 100 : }
3296 :
3297 :
3298 : void
3299 100 : c_unparser::visit_pre_crement (pre_crement* e)
3300 : {
3301 100 : if (e->type != pe_long ||
3302 : e->type != e->operand->type)
3303 0 : throw semantic_error ("expected numeric type", e->tok);
3304 :
3305 100 : c_unparser_assignment tav (this, e->op, false);
3306 100 : e->operand->visit (& tav);
3307 100 : }
3308 :
3309 :
3310 : void
3311 649 : c_tmpcounter::visit_post_crement (post_crement* e)
3312 : {
3313 649 : c_tmpcounter_assignment tav (this, e->op, 0, true);
3314 649 : e->operand->visit (& tav);
3315 649 : }
3316 :
3317 :
3318 : void
3319 649 : c_unparser::visit_post_crement (post_crement* e)
3320 : {
3321 649 : if (e->type != pe_long ||
3322 : e->type != e->operand->type)
3323 0 : throw semantic_error ("expected numeric type", e->tok);
3324 :
3325 649 : c_unparser_assignment tav (this, e->op, true);
3326 649 : e->operand->visit (& tav);
3327 649 : }
3328 :
3329 :
3330 : void
3331 9380 : c_unparser::visit_symbol (symbol* e)
3332 : {
3333 9380 : assert (e->referent != 0);
3334 9380 : vardecl* r = e->referent;
3335 :
3336 9380 : if (r->index_types.size() != 0)
3337 0 : throw semantic_error ("invalid reference to array", e->tok);
3338 :
3339 9380 : var v = getvar(r, e->tok);
3340 9380 : o->line() << v;
3341 9380 : }
3342 :
3343 :
3344 : void
3345 6459 : c_tmpcounter_assignment::prepare_rvalue (tmpvar & rval)
3346 : {
3347 6459 : if (rvalue)
3348 : {
3349 : // literal number and strings don't need any temporaries declared
3350 5710 : if (rvalue->tok->type != tok_number && rvalue->tok->type != tok_string)
3351 2958 : rval.declare (*(parent->parent));
3352 :
3353 5710 : rvalue->visit (parent);
3354 : }
3355 6459 : }
3356 :
3357 : void
3358 6394 : c_tmpcounter_assignment::c_assignop(tmpvar & res)
3359 : {
3360 6394 : if (res.type() == pe_string)
3361 : {
3362 : // string assignment doesn't need any temporaries declared
3363 : }
3364 2625 : else if (op == "<<<")
3365 175 : res.declare (*(parent->parent));
3366 2450 : else if (res.type() == pe_long)
3367 : {
3368 : // Only the 'post' operators ('x++') need a temporary declared.
3369 2450 : if (post)
3370 649 : res.declare (*(parent->parent));
3371 : }
3372 6394 : }
3373 :
3374 : // Assignment expansion is tricky.
3375 : //
3376 : // Because assignments are nestable expressions, we have
3377 : // to emit C constructs that are nestable expressions too.
3378 : // We have to evaluate the given expressions the proper number of times,
3379 : // including array indices.
3380 : // We have to lock the lvalue (if global) against concurrent modification,
3381 : // especially with modify-assignment operations (+=, ++).
3382 : // We have to check the rvalue (for division-by-zero checks).
3383 :
3384 : // In the normal "pre=false" case, for (A op B) emit:
3385 : // ({ tmp = B; check(B); lock(A); res = A op tmp; A = res; unlock(A); res; })
3386 : // In the "pre=true" case, emit instead:
3387 : // ({ tmp = B; check(B); lock(A); res = A; A = res op tmp; unlock(A); res; })
3388 : //
3389 : // (op is the plain operator portion of a combined calculate/assignment:
3390 : // "+" for "+=", and so on. It is in the "macop" variable below.)
3391 : //
3392 : // For array assignments, additional temporaries are used for each
3393 : // index, which are expanded before the "tmp=B" expression, in order
3394 : // to consistently order evaluation of lhs before rhs.
3395 : //
3396 :
3397 : void
3398 5435 : c_tmpcounter_assignment::visit_symbol (symbol *e)
3399 : {
3400 5435 : exp_type ty = rvalue ? rvalue->type : e->type;
3401 5435 : tmpvar rval = parent->parent->gensym (ty);
3402 5435 : tmpvar res = parent->parent->gensym (ty);
3403 :
3404 5435 : prepare_rvalue(rval);
3405 :
3406 5435 : c_assignop (res);
3407 5435 : }
3408 :
3409 :
3410 : void
3411 : c_unparser_assignment::prepare_rvalue (string const & op,
3412 : tmpvar & rval,
3413 6458 : token const * tok)
3414 : {
3415 6458 : if (rvalue)
3416 : {
3417 8460 : if (rvalue->tok->type == tok_number || rvalue->tok->type == tok_string)
3418 : // Instead of assigning the numeric or string constant to a
3419 : // temporary, then assigning the temporary to the final, let's
3420 : // just override the temporary with the constant.
3421 2751 : rval.override(parent->c_expression(rvalue));
3422 : else
3423 2958 : parent->c_assign (rval.value(), rvalue, "assignment");
3424 : }
3425 : else
3426 : {
3427 749 : if (op == "++" || op == "--")
3428 : // Here is part of the conversion proccess of turning "x++" to
3429 : // "x += 1".
3430 749 : rval.override("1");
3431 : else
3432 0 : throw semantic_error ("need rvalue for assignment", tok);
3433 : }
3434 6458 : }
3435 :
3436 : void
3437 5435 : c_unparser_assignment::visit_symbol (symbol *e)
3438 : {
3439 5435 : stmt_expr block(*parent);
3440 :
3441 5435 : assert (e->referent != 0);
3442 5435 : if (e->referent->index_types.size() != 0)
3443 0 : throw semantic_error ("unexpected reference to array", e->tok);
3444 :
3445 : // parent->o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
3446 5435 : exp_type ty = rvalue ? rvalue->type : e->type;
3447 5435 : tmpvar rval = parent->gensym (ty);
3448 5435 : tmpvar res = parent->gensym (ty);
3449 :
3450 5435 : prepare_rvalue (op, rval, e->tok);
3451 :
3452 5435 : var lvar = parent->getvar (e->referent, e->tok);
3453 5435 : c_assignop (res, lvar, rval, e->tok);
3454 :
3455 5435 : parent->o->newline() << res << ";";
3456 5435 : }
3457 :
3458 :
3459 : void
3460 0 : c_unparser::visit_target_symbol (target_symbol* e)
3461 : {
3462 0 : throw semantic_error("cannot translate general target-symbol expression", e->tok);
3463 : }
3464 :
3465 :
3466 : void
3467 1675 : c_tmpcounter::load_map_indices(arrayindex *e)
3468 : {
3469 : symbol *array;
3470 : hist_op *hist;
3471 1675 : classify_indexable (e->base, array, hist);
3472 :
3473 1675 : if (array)
3474 : {
3475 1675 : assert (array->referent != 0);
3476 1675 : vardecl* r = array->referent;
3477 :
3478 : // One temporary per index dimension, except in the case of
3479 : // number or string constants.
3480 3554 : for (unsigned i=0; i<r->index_types.size(); i++)
3481 : {
3482 1879 : tmpvar ix = parent->gensym (r->index_types[i]);
3483 1879 : if (e->indexes[i]->tok->type == tok_number
3484 : || e->indexes[i]->tok->type == tok_string)
3485 : {
3486 : // Do nothing
3487 : }
3488 : else
3489 1188 : ix.declare (*parent);
3490 1879 : e->indexes[i]->visit(this);
3491 : }
3492 : }
3493 1675 : }
3494 :
3495 :
3496 : void
3497 : c_unparser::load_map_indices(arrayindex *e,
3498 2037 : vector<tmpvar> & idx)
3499 : {
3500 : symbol *array;
3501 : hist_op *hist;
3502 2037 : classify_indexable (e->base, array, hist);
3503 :
3504 2037 : if (array)
3505 : {
3506 2018 : idx.clear();
3507 :
3508 2018 : assert (array->referent != 0);
3509 2018 : vardecl* r = array->referent;
3510 :
3511 2018 : if (r->index_types.size() == 0 ||
3512 : r->index_types.size() != e->indexes.size())
3513 0 : throw semantic_error ("invalid array reference", e->tok);
3514 :
3515 4338 : for (unsigned i=0; i<r->index_types.size(); i++)
3516 : {
3517 2320 : if (r->index_types[i] != e->indexes[i]->type)
3518 0 : throw semantic_error ("array index type mismatch", e->indexes[i]->tok);
3519 :
3520 2320 : tmpvar ix = gensym (r->index_types[i]);
3521 2320 : if (e->indexes[i]->tok->type == tok_number
3522 : || e->indexes[i]->tok->type == tok_string)
3523 : // Instead of assigning the numeric or string constant to a
3524 : // temporary, then using the temporary, let's just
3525 : // override the temporary with the constant.
3526 756 : ix.override(c_expression(e->indexes[i]));
3527 : else
3528 : {
3529 : // o->newline() << "c->last_stmt = "
3530 : // << lex_cast_qstring(*e->indexes[i]->tok) << ";";
3531 1564 : c_assign (ix.value(), e->indexes[i], "array index copy");
3532 : }
3533 2320 : idx.push_back (ix);
3534 : }
3535 : }
3536 : else
3537 : {
3538 19 : assert (e->indexes.size() == 1);
3539 19 : assert (e->indexes[0]->type == pe_long);
3540 19 : tmpvar ix = gensym (pe_long);
3541 : // o->newline() << "c->last_stmt = "
3542 : // << lex_cast_qstring(*e->indexes[0]->tok) << ";";
3543 19 : c_assign (ix.value(), e->indexes[0], "array index copy");
3544 38 : idx.push_back(ix);
3545 : }
3546 2037 : }
3547 :
3548 :
3549 : void
3550 316 : c_unparser::load_aggregate (expression *e, aggvar & agg, bool pre_agg)
3551 : {
3552 316 : symbol *sym = get_symbol_within_expression (e);
3553 :
3554 316 : if (sym->referent->type != pe_stats)
3555 0 : throw semantic_error ("unexpected aggregate of non-statistic", sym->tok);
3556 :
3557 316 : var v = getvar(sym->referent, e->tok);
3558 :
3559 316 : if (sym->referent->arity == 0)
3560 : {
3561 : // o->newline() << "c->last_stmt = " << lex_cast_qstring(*sym->tok) << ";";
3562 193 : o->newline() << agg << " = _stp_stat_get (" << v << ", 0);";
3563 : }
3564 : else
3565 : {
3566 123 : arrayindex *arr = NULL;
3567 123 : if (!expression_is_arrayindex (e, arr))
3568 0 : throw semantic_error("unexpected aggregate of non-arrayindex", e->tok);
3569 :
3570 123 : vector<tmpvar> idx;
3571 123 : load_map_indices (arr, idx);
3572 123 : mapvar mvar = getmap (sym->referent, sym->tok);
3573 : // o->newline() << "c->last_stmt = " << lex_cast_qstring(*sym->tok) << ";";
3574 123 : o->newline() << agg << " = " << mvar.get(idx, pre_agg) << ";";
3575 316 : }
3576 316 : }
3577 :
3578 :
3579 : string
3580 19 : c_unparser::histogram_index_check(var & base, tmpvar & idx) const
3581 : {
3582 : return "((" + idx.value() + " >= 0)"
3583 19 : + " && (" + idx.value() + " < " + base.buckets() + "))";
3584 : }
3585 :
3586 :
3587 : void
3588 670 : c_tmpcounter::visit_arrayindex (arrayindex *e)
3589 : {
3590 : symbol *array;
3591 : hist_op *hist;
3592 670 : classify_indexable (e->base, array, hist);
3593 :
3594 670 : if (array)
3595 : {
3596 651 : load_map_indices(e);
3597 :
3598 : // The index-expression result.
3599 651 : tmpvar res = parent->gensym (e->type);
3600 651 : res.declare (*parent);
3601 : }
3602 : else
3603 : {
3604 :
3605 19 : assert(hist);
3606 :
3607 : // Note: this is a slightly tricker-than-it-looks allocation of
3608 : // temporaries. The reason is that we're in the branch handling
3609 : // histogram-indexing, and the histogram might be build over an
3610 : // indexable entity itself. For example if we have:
3611 : //
3612 : // global foo
3613 : // ...
3614 : // foo[getpid(), geteuid()] <<< 1
3615 : // ...
3616 : // print @log_hist(foo[pid, euid])[bucket]
3617 : //
3618 : // We are looking at the @log_hist(...)[bucket] expression, so
3619 : // allocating one tmpvar for calculating bucket (the "index" of
3620 : // this arrayindex expression), and one tmpvar for storing the
3621 : // result in, just as normal.
3622 : //
3623 : // But we are *also* going to call load_aggregate on foo, which
3624 : // will itself require tmpvars for each of its indices. Since
3625 : // this is not handled by delving into the subexpression (it
3626 : // would be if hist were first-class in the type system, but
3627 : // it's not) we we allocate all the tmpvars used in such a
3628 : // subexpression up here: first our own aggvar, then our index
3629 : // (bucket) tmpvar, then all the index tmpvars of our
3630 : // pe_stat-valued subexpression, then our result.
3631 :
3632 :
3633 : // First all the stuff related to indexing into the histogram
3634 :
3635 19 : if (e->indexes.size() != 1)
3636 0 : throw semantic_error("Invalid indexing of histogram", e->tok);
3637 19 : tmpvar ix = parent->gensym (pe_long);
3638 19 : ix.declare (*parent);
3639 19 : e->indexes[0]->visit(this);
3640 19 : tmpvar res = parent->gensym (pe_long);
3641 19 : res.declare (*parent);
3642 :
3643 : // Then the aggregate, and all the tmpvars needed by our call to
3644 : // load_aggregate().
3645 :
3646 19 : aggvar agg = parent->gensym_aggregate ();
3647 19 : agg.declare(*(this->parent));
3648 :
3649 19 : symbol *sym = get_symbol_within_expression (hist->stat);
3650 19 : var v = parent->getvar(sym->referent, sym->tok);
3651 19 : if (sym->referent->arity != 0)
3652 : {
3653 4 : arrayindex *arr = NULL;
3654 4 : if (!expression_is_arrayindex (hist->stat, arr))
3655 0 : throw semantic_error("expected arrayindex expression in indexed hist_op", e->tok);
3656 :
3657 8 : for (unsigned i=0; i<sym->referent->index_types.size(); i++)
3658 : {
3659 4 : tmpvar ix = parent->gensym (sym->referent->index_types[i]);
3660 4 : ix.declare (*parent);
3661 4 : arr->indexes[i]->visit(this);
3662 : }
3663 19 : }
3664 : }
3665 670 : }
3666 :
3667 :
3668 : void
3669 669 : c_unparser::visit_arrayindex (arrayindex* e)
3670 : {
3671 : symbol *array;
3672 : hist_op *hist;
3673 669 : classify_indexable (e->base, array, hist);
3674 :
3675 669 : if (array)
3676 : {
3677 : // Visiting an statistic-valued array in a non-lvalue context is prohibited.
3678 650 : if (array->referent->type == pe_stats)
3679 0 : throw semantic_error ("statistic-valued array in rvalue context", e->tok);
3680 :
3681 650 : stmt_expr block(*this);
3682 :
3683 : // NB: Do not adjust the order of the next few lines; the tmpvar
3684 : // allocation order must remain the same between
3685 : // c_unparser::visit_arrayindex and c_tmpcounter::visit_arrayindex
3686 :
3687 650 : vector<tmpvar> idx;
3688 650 : load_map_indices (e, idx);
3689 650 : tmpvar res = gensym (e->type);
3690 :
3691 650 : mapvar mvar = getmap (array->referent, e->tok);
3692 : // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
3693 650 : c_assign (res, mvar.get(idx), e->tok);
3694 :
3695 650 : o->newline() << res << ";";
3696 : }
3697 : else
3698 : {
3699 : // See commentary in c_tmpcounter::visit_arrayindex
3700 :
3701 19 : assert(hist);
3702 19 : stmt_expr block(*this);
3703 :
3704 : // NB: Do not adjust the order of the next few lines; the tmpvar
3705 : // allocation order must remain the same between
3706 : // c_unparser::visit_arrayindex and c_tmpcounter::visit_arrayindex
3707 :
3708 19 : vector<tmpvar> idx;
3709 19 : load_map_indices (e, idx);
3710 19 : tmpvar res = gensym (e->type);
3711 :
3712 19 : aggvar agg = gensym_aggregate ();
3713 :
3714 : // These should have faulted during elaboration if not true.
3715 19 : assert(idx.size() == 1);
3716 19 : assert(idx[0].type() == pe_long);
3717 :
3718 19 : symbol *sym = get_symbol_within_expression (hist->stat);
3719 :
3720 : var *v;
3721 19 : if (sym->referent->arity < 1)
3722 15 : v = new var(getvar(sym->referent, e->tok));
3723 : else
3724 4 : v = new mapvar(getmap(sym->referent, e->tok));
3725 :
3726 19 : v->assert_hist_compatible(*hist);
3727 :
3728 19 : if (aggregations_active.count(v->value()))
3729 2 : load_aggregate(hist->stat, agg, true);
3730 : else
3731 17 : load_aggregate(hist->stat, agg, false);
3732 :
3733 19 : o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
3734 :
3735 : // PR 2142+2610: empty aggregates
3736 : o->newline() << "if (unlikely (" << agg.value() << " == NULL)"
3737 19 : << " || " << agg.value() << "->count == 0)";
3738 19 : o->newline(1) << "c->last_error = \"empty aggregate\";";
3739 19 : o->newline(-1) << "else {";
3740 19 : o->newline(1) << "if (" << histogram_index_check(*v, idx[0]) << ")";
3741 19 : o->newline(1) << res << " = " << agg << "->histogram[" << idx[0] << "];";
3742 19 : o->newline(-1) << "else";
3743 19 : o->newline(1) << "c->last_error = \"histogram index out of range\";";
3744 :
3745 19 : o->newline(-1) << "}";
3746 19 : o->newline(-1) << res << ";";
3747 :
3748 19 : delete v;
3749 : }
3750 669 : }
3751 :
3752 :
3753 : void
3754 1024 : c_tmpcounter_assignment::visit_arrayindex (arrayindex *e)
3755 : {
3756 : symbol *array;
3757 : hist_op *hist;
3758 1024 : classify_indexable (e->base, array, hist);
3759 :
3760 1024 : if (array)
3761 : {
3762 1024 : parent->load_map_indices(e);
3763 :
3764 : // The expression rval, lval, and result.
3765 1024 : exp_type ty = rvalue ? rvalue->type : e->type;
3766 1024 : tmpvar rval = parent->parent->gensym (ty);
3767 1024 : tmpvar lval = parent->parent->gensym (ty);
3768 1024 : tmpvar res = parent->parent->gensym (ty);
3769 :
3770 1024 : prepare_rvalue(rval);
3771 1024 : lval.declare (*(parent->parent));
3772 :
3773 1024 : if (op == "<<<")
3774 65 : res.declare (*(parent->parent));
3775 : else
3776 959 : c_assignop(res);
3777 : }
3778 : else
3779 : {
3780 0 : throw semantic_error("cannot assign to histogram buckets", e->tok);
3781 : }
3782 1024 : }
3783 :
3784 :
3785 : void
3786 1023 : c_unparser_assignment::visit_arrayindex (arrayindex *e)
3787 : {
3788 : symbol *array;
3789 : hist_op *hist;
3790 1023 : classify_indexable (e->base, array, hist);
3791 :
3792 1023 : if (array)
3793 : {
3794 :
3795 1023 : stmt_expr block(*parent);
3796 :
3797 1023 : translator_output *o = parent->o;
3798 :
3799 1023 : if (array->referent->index_types.size() == 0)
3800 0 : throw semantic_error ("unexpected reference to scalar", e->tok);
3801 :
3802 : // nb: Do not adjust the order of the next few lines; the tmpvar
3803 : // allocation order must remain the same between
3804 : // c_unparser_assignment::visit_arrayindex and
3805 : // c_tmpcounter_assignment::visit_arrayindex
3806 :
3807 1023 : vector<tmpvar> idx;
3808 1023 : parent->load_map_indices (e, idx);
3809 1023 : exp_type ty = rvalue ? rvalue->type : e->type;
3810 1023 : tmpvar rvar = parent->gensym (ty);
3811 1023 : tmpvar lvar = parent->gensym (ty);
3812 1023 : tmpvar res = parent->gensym (ty);
3813 :
3814 : // NB: because these expressions are nestable, emit this construct
3815 : // thusly:
3816 : // ({ tmp0=(idx0); ... tmpN=(idxN); rvar=(rhs); lvar; res;
3817 : // lock (array);
3818 : // lvar = get (array,idx0...N); // if necessary
3819 : // assignop (res, lvar, rvar);
3820 : // set (array, idx0...N, lvar);
3821 : // unlock (array);
3822 : // res; })
3823 : //
3824 : // we store all indices in temporary variables to avoid nasty
3825 : // reentrancy issues that pop up with nested expressions:
3826 : // e.g. ++a[a[c]=5] could deadlock
3827 : //
3828 : //
3829 : // There is an exception to the above form: if we're doign a <<< assigment to
3830 : // a statistic-valued map, there's a special form we follow:
3831 : //
3832 : // ({ tmp0=(idx0); ... tmpN=(idxN); rvar=(rhs);
3833 : // *no need to* lock (array);
3834 : // _stp_map_add_stat (array, idx0...N, rvar);
3835 : // *no need to* unlock (array);
3836 : // rvar; })
3837 : //
3838 : // To simplify variable-allocation rules, we assign rvar to lvar and
3839 : // res in this block as well, even though they are technically
3840 : // superfluous.
3841 :
3842 1023 : prepare_rvalue (op, rvar, e->tok);
3843 :
3844 1023 : if (op == "<<<")
3845 : {
3846 65 : assert (e->type == pe_stats);
3847 65 : assert (rvalue->type == pe_long);
3848 :
3849 65 : mapvar mvar = parent->getmap (array->referent, e->tok);
3850 : // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
3851 65 : o->newline() << mvar.add (idx, rvar) << ";";
3852 65 : res = rvar;
3853 : // no need for these dummy assignments
3854 : // o->newline() << lvar << " = " << rvar << ";";
3855 : // o->newline() << res << " = " << rvar << ";";
3856 : }
3857 : else
3858 : {
3859 958 : mapvar mvar = parent->getmap (array->referent, e->tok);
3860 : // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
3861 958 : if (op != "=") // don't bother fetch slot if we will just overwrite it
3862 228 : parent->c_assign (lvar, mvar.get(idx), e->tok);
3863 958 : c_assignop (res, lvar, rvar, e->tok);
3864 958 : o->newline() << mvar.set (idx, lvar) << ";";
3865 : }
3866 :
3867 1023 : o->newline() << res << ";";
3868 : }
3869 : else
3870 : {
3871 0 : throw semantic_error("cannot assign to histogram buckets", e->tok);
3872 : }
3873 1023 : }
3874 :
3875 :
3876 : void
3877 8245 : c_tmpcounter::visit_functioncall (functioncall *e)
3878 : {
3879 8245 : assert (e->referent != 0);
3880 8245 : functiondecl* r = e->referent;
3881 : // one temporary per argument, unless literal numbers or strings
3882 11099 : for (unsigned i=0; i<r->formal_args.size(); i++)
3883 : {
3884 2854 : tmpvar t = parent->gensym (r->formal_args[i]->type);
3885 2854 : if (e->args[i]->tok->type != tok_number
3886 : && e->args[i]->tok->type != tok_string)
3887 1816 : t.declare (*parent);
3888 2854 : e->args[i]->visit (this);
3889 : }
3890 8245 : }
3891 :
3892 :
3893 : void
3894 8245 : c_unparser::visit_functioncall (functioncall* e)
3895 : {
3896 8245 : assert (e->referent != 0);
3897 8245 : functiondecl* r = e->referent;
3898 :
3899 8245 : if (r->formal_args.size() != e->args.size())
3900 0 : throw semantic_error ("invalid length argument list", e->tok);
3901 :
3902 8245 : stmt_expr block(*this);
3903 :
3904 : // NB: we store all actual arguments in temporary variables,
3905 : // to avoid colliding sharing of context variables with
3906 : // nested function calls: f(f(f(1)))
3907 :
3908 : // compute actual arguments
3909 8245 : vector<tmpvar> tmp;
3910 :
3911 11099 : for (unsigned i=0; i<e->args.size(); i++)
3912 : {
3913 2854 : tmpvar t = gensym(e->args[i]->type);
3914 :
3915 2854 : if (r->formal_args[i]->type != e->args[i]->type)
3916 : throw semantic_error ("function argument type mismatch",
3917 0 : e->args[i]->tok, "vs", r->formal_args[i]->tok);
3918 :
3919 2854 : if (e->args[i]->tok->type == tok_number
3920 : || e->args[i]->tok->type == tok_string)
3921 1038 : t.override(c_expression(e->args[i]));
3922 : else
3923 : {
3924 : // o->newline() << "c->last_stmt = "
3925 : // << lex_cast_qstring(*e->args[i]->tok) << ";";
3926 : c_assign (t.value(), e->args[i],
3927 1816 : "function actual argument evaluation");
3928 : }
3929 2854 : tmp.push_back(t);
3930 : }
3931 :
3932 : // copy in actual arguments
3933 22198 : for (unsigned i=0; i<e->args.size(); i++)
3934 : {
3935 2854 : if (r->formal_args[i]->type != e->args[i]->type)
3936 : throw semantic_error ("function argument type mismatch",
3937 0 : e->args[i]->tok, "vs", r->formal_args[i]->tok);
3938 :
3939 : c_assign ("c->locals[c->nesting+1].function_" +
3940 : c_varname (r->name) + "." +
3941 : c_varname (r->formal_args[i]->name),
3942 : tmp[i].value(),
3943 : e->args[i]->type,
3944 : "function actual argument copy",
3945 2854 : e->args[i]->tok);
3946 : }
3947 :
3948 : // call function
3949 8245 : o->newline() << "function_" << c_varname (r->name) << " (c);";
3950 :
3951 : // return result from retvalue slot
3952 8245 : if (r->type == pe_unknown)
3953 : // If we passed typechecking, then nothing will use this return value
3954 562 : o->newline() << "(void) 0;";
3955 : else
3956 : o->newline() << "c->locals[c->nesting+1]"
3957 : << ".function_" << c_varname (r->name)
3958 7683 : << ".__retvalue;";
3959 8245 : }
3960 :
3961 : void
3962 4666 : c_tmpcounter::visit_print_format (print_format* e)
3963 : {
3964 4666 : if (e->hist)
3965 : {
3966 87 : symbol *sym = get_symbol_within_expression (e->hist->stat);
3967 87 : var v = parent->getvar(sym->referent, sym->tok);
3968 87 : aggvar agg = parent->gensym_aggregate ();
3969 :
3970 87 : agg.declare(*(this->parent));
3971 :
3972 87 : if (sym->referent->arity != 0)
3973 : {
3974 : // One temporary per index dimension.
3975 18 : for (unsigned i=0; i<sym->referent->index_types.size(); i++)
3976 : {
3977 9 : arrayindex *arr = NULL;
3978 9 : if (!expression_is_arrayindex (e->hist->stat, arr))
3979 0 : throw semantic_error("expected arrayindex expression in printed hist_op", e->tok);
3980 :
3981 9 : tmpvar ix = parent->gensym (sym->referent->index_types[i]);
3982 9 : ix.declare (*parent);
3983 9 : arr->indexes[i]->visit(this);
3984 : }
3985 87 : }
3986 : }
3987 : else
3988 : {
3989 : // One temporary per argument
3990 14091 : for (unsigned i=0; i < e->args.size(); i++)
3991 : {
3992 9513 : tmpvar t = parent->gensym (e->args[i]->type);
3993 9513 : if (e->args[i]->type == pe_unknown)
3994 : {
3995 : throw semantic_error("unknown type of arg to print operator",
3996 0 : e->args[i]->tok);
3997 : }
3998 :
3999 9513 : if (e->args[i]->tok->type != tok_number
4000 : && e->args[i]->tok->type != tok_string)
4001 9115 : t.declare (*parent);
4002 9513 : e->args[i]->visit (this);
4003 : }
4004 :
4005 : // And the result
4006 4578 : exp_type ty = e->print_to_stream ? pe_long : pe_string;
4007 4578 : tmpvar res = parent->gensym (ty);
4008 4578 : if (ty == pe_string)
4009 1230 : res.declare (*parent);
4010 : }
4011 4665 : }
4012 :
4013 :
4014 : void
4015 4664 : c_unparser::visit_print_format (print_format* e)
4016 : {
4017 : // Print formats can contain a general argument list *or* a special
4018 : // type of argument which gets its own processing: a single,
4019 : // non-format-string'ed, histogram-type stat_op expression.
4020 :
4021 4664 : if (e->hist)
4022 : {
4023 87 : stmt_expr block(*this);
4024 87 : symbol *sym = get_symbol_within_expression (e->hist->stat);
4025 87 : aggvar agg = gensym_aggregate ();
4026 :
4027 : var *v;
4028 87 : if (sym->referent->arity < 1)
4029 78 : v = new var(getvar(sym->referent, e->tok));
4030 : else
4031 9 : v = new mapvar(getmap(sym->referent, e->tok));
4032 :
4033 87 : v->assert_hist_compatible(*e->hist);
4034 :
4035 : {
4036 87 : if (aggregations_active.count(v->value()))
4037 4 : load_aggregate(e->hist->stat, agg, true);
4038 : else
4039 83 : load_aggregate(e->hist->stat, agg, false);
4040 :
4041 : // PR 2142+2610: empty aggregates
4042 : o->newline() << "if (unlikely (" << agg.value() << " == NULL)"
4043 87 : << " || " << agg.value() << "->count == 0) {";
4044 87 : o->newline(1) << "c->last_error = \"empty aggregate\";";
4045 87 : o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
4046 87 : o->newline(-1) << "} else";
4047 87 : o->newline(1) << "_stp_stat_print_histogram (" << v->hist() << ", " << agg.value() << ");";
4048 87 : o->indent(-1);
4049 : }
4050 :
4051 87 : delete v;
4052 : }
4053 : else
4054 : {
4055 4577 : stmt_expr block(*this);
4056 :
4057 : // Compute actual arguments
4058 4577 : vector<tmpvar> tmp;
4059 :
4060 14088 : for (unsigned i=0; i<e->args.size(); i++)
4061 : {
4062 9511 : tmpvar t = gensym(e->args[i]->type);
4063 9511 : tmp.push_back(t);
4064 :
4065 : // o->newline() << "c->last_stmt = "
4066 : // << lex_cast_qstring(*e->args[i]->tok) << ";";
4067 :
4068 : // If we've got a numeric or string constant, instead of
4069 : // assigning the numeric or string constant to a temporary,
4070 : // then passing the temporary to _stp_printf/_stp_snprintf,
4071 : // let's just override the temporary with the constant.
4072 9511 : if (e->args[i]->tok->type == tok_number
4073 : || e->args[i]->tok->type == tok_string)
4074 398 : tmp[i].override(c_expression(e->args[i]));
4075 : else
4076 : c_assign (t.value(), e->args[i],
4077 9113 : "print format actual argument evaluation");
4078 : }
4079 :
4080 4577 : std::vector<print_format::format_component> components;
4081 :
4082 4577 : if (e->print_with_format)
4083 : {
4084 4027 : components = e->components;
4085 : }
4086 : else
4087 : {
4088 : // Synthesize a print-format string if the user didn't
4089 : // provide one; the synthetic string simply contains one
4090 : // directive for each argument.
4091 1202 : for (unsigned i = 0; i < e->args.size(); ++i)
4092 : {
4093 652 : if (i > 0 && e->print_with_delim)
4094 46 : components.push_back (e->delimiter);
4095 652 : print_format::format_component curr;
4096 652 : curr.clear();
4097 652 : switch (e->args[i]->type)
4098 : {
4099 : case pe_unknown:
4100 0 : throw semantic_error("cannot print unknown expression type", e->args[i]->tok);
4101 : case pe_stats:
4102 0 : throw semantic_error("cannot print a raw stats object", e->args[i]->tok);
4103 : case pe_long:
4104 263 : curr.type = print_format::conv_signed_decimal;
4105 263 : break;
4106 : case pe_string:
4107 389 : curr.type = print_format::conv_string;
4108 : break;
4109 : }
4110 652 : components.push_back (curr);
4111 : }
4112 :
4113 550 : if (e->print_with_newline)
4114 : {
4115 136 : print_format::format_component curr;
4116 136 : curr.clear();
4117 136 : curr.type = print_format::conv_literal;
4118 136 : curr.literal_string = "\\n";
4119 136 : components.push_back (curr);
4120 : }
4121 : }
4122 :
4123 : // Allocate the result
4124 4577 : exp_type ty = e->print_to_stream ? pe_long : pe_string;
4125 4577 : tmpvar res = gensym (ty);
4126 4577 : int use_print = 0;
4127 :
4128 4577 : string format_string = print_format::components_to_string(components);
4129 4577 : if (tmp.size() == 0 || (tmp.size() == 1 && format_string == "%s"))
4130 669 : use_print = 1;
4131 3908 : else if (tmp.size() == 1
4132 : && e->args[0]->tok->type == tok_string
4133 : && format_string == "%s\\n")
4134 : {
4135 92 : use_print = 1;
4136 92 : tmp[0].override(tmp[0].value() + "\"\\n\"");
4137 92 : components[0].type = print_format::conv_literal;
4138 : }
4139 :
4140 : // Make the [s]printf call, but not if there was an error evaluating the args
4141 4577 : o->newline() << "if (likely (! c->last_error)) {";
4142 4577 : o->indent(1);
4143 :
4144 : // Generate code to check that any pointer arguments are actually accessible. */
4145 4577 : int arg_ix = 0;
4146 22581 : for (unsigned i = 0; i < components.size(); ++i) {
4147 18004 : if (components[i].type == print_format::conv_literal)
4148 8612 : continue;
4149 :
4150 : /* Take note of the width and precision arguments, if any. */
4151 9392 : int width_ix = -1, prec_ix= -1;
4152 9392 : if (components[i].widthtype == print_format::width_dynamic)
4153 13 : width_ix = arg_ix++;
4154 9392 : if (components[i].prectype == print_format::prec_dynamic)
4155 14 : prec_ix = arg_ix++;
4156 :
4157 : /* Generate a noop call to deref_buffer for %m. */
4158 9392 : if (components[i].type == print_format::conv_memory) {
4159 17 : this->probe_or_function_needs_deref_fault_handler = true;
4160 17 : o->newline() << "deref_buffer (0, " << tmp[arg_ix].value() << ", ";
4161 17 : if (prec_ix == -1)
4162 11 : if (width_ix != -1)
4163 3 : prec_ix = width_ix;
4164 17 : if (prec_ix != -1)
4165 9 : o->line() << tmp[prec_ix].value();
4166 : else
4167 8 : o->line() << "1";
4168 17 : o->line() << ");";
4169 : }
4170 :
4171 9392 : ++arg_ix;
4172 : }
4173 :
4174 4577 : if (e->print_to_stream)
4175 : {
4176 3347 : if (e->print_char)
4177 : {
4178 14 : o->newline() << "_stp_print_char (";
4179 14 : if (tmp.size())
4180 14 : o->line() << tmp[0].value() << ");";
4181 : else
4182 0 : o->line() << '"' << format_string << "\");";
4183 14 : o->newline(-1) << "}";
4184 768 : return;
4185 : }
4186 3333 : if (use_print)
4187 : {
4188 754 : o->newline() << "_stp_print (";
4189 754 : if (tmp.size())
4190 270 : o->line() << tmp[0].value() << ");";
4191 : else
4192 484 : o->line() << '"' << format_string << "\");";
4193 754 : o->newline(-1) << "}";
4194 : return;
4195 : }
4196 :
4197 : // We'll just hardcode the result of 0 instead of using the
4198 : // temporary.
4199 2579 : res.override("((int64_t)0LL)");
4200 5158 : o->newline() << "_stp_printf (";
4201 : }
4202 : else
4203 1230 : o->newline() << "_stp_snprintf (" << res.value() << ", MAXSTRINGLEN, ";
4204 :
4205 3809 : o->line() << '"' << format_string << '"';
4206 :
4207 : /* Generate the actual arguments. Make sure that they match the expected type of the
4208 : format specifier. */
4209 3809 : arg_ix = 0;
4210 20953 : for (unsigned i = 0; i < components.size(); ++i) {
4211 17144 : if (components[i].type == print_format::conv_literal)
4212 7944 : continue;
4213 :
4214 : /* Cast the width and precision arguments, if any, to 'int'. */
4215 9200 : if (components[i].widthtype == print_format::width_dynamic)
4216 13 : o->line() << ", (int)" << tmp[arg_ix++].value();
4217 9200 : if (components[i].prectype == print_format::prec_dynamic)
4218 14 : o->line() << ", (int)" << tmp[arg_ix++].value();
4219 :
4220 : /* The type of the %m argument is 'char*'. */
4221 9200 : if (components[i].type == print_format::conv_memory)
4222 17 : o->line() << ", (char*)(uintptr_t)" << tmp[arg_ix++].value();
4223 : else
4224 9183 : o->line() << ", " << tmp[arg_ix++].value();
4225 : }
4226 :
4227 3809 : o->line() << ");";
4228 3809 : o->newline(-1) << "}";
4229 3809 : o->newline() << res.value() << ";";
4230 : }
4231 : }
4232 :
4233 :
4234 : void
4235 205 : c_tmpcounter::visit_stat_op (stat_op* e)
4236 : {
4237 205 : symbol *sym = get_symbol_within_expression (e->stat);
4238 205 : var v = parent->getvar(sym->referent, e->tok);
4239 204 : aggvar agg = parent->gensym_aggregate ();
4240 204 : tmpvar res = parent->gensym (pe_long);
4241 :
4242 204 : agg.declare(*(this->parent));
4243 204 : res.declare(*(this->parent));
4244 :
4245 204 : if (sym->referent->arity != 0)
4246 : {
4247 : // One temporary per index dimension.
4248 236 : for (unsigned i=0; i<sym->referent->index_types.size(); i++)
4249 : {
4250 : // Sorry about this, but with no dynamic_cast<> and no
4251 : // constructor patterns, this is how things work.
4252 126 : arrayindex *arr = NULL;
4253 126 : if (!expression_is_arrayindex (e->stat, arr))
4254 0 : throw semantic_error("expected arrayindex expression in stat_op of array", e->tok);
4255 :
4256 126 : tmpvar ix = parent->gensym (sym->referent->index_types[i]);
4257 126 : ix.declare (*parent);
4258 126 : arr->indexes[i]->visit(this);
4259 : }
4260 204 : }
4261 204 : }
4262 :
4263 : void
4264 204 : c_unparser::visit_stat_op (stat_op* e)
4265 : {
4266 : // Stat ops can be *applied* to two types of expression:
4267 : //
4268 : // 1. An arrayindex expression on a pe_stats-valued array.
4269 : //
4270 : // 2. A symbol of type pe_stats.
4271 :
4272 : // FIXME: classify the expression the stat_op is being applied to,
4273 : // call appropriate stp_get_stat() / stp_pmap_get_stat() helper,
4274 : // then reach into resultant struct stat_data.
4275 :
4276 : // FIXME: also note that summarizing anything is expensive, and we
4277 : // really ought to pass a timeout handler into the summary routine,
4278 : // check its response, possibly exit if it ran out of cycles.
4279 :
4280 : {
4281 204 : stmt_expr block(*this);
4282 204 : symbol *sym = get_symbol_within_expression (e->stat);
4283 204 : aggvar agg = gensym_aggregate ();
4284 204 : tmpvar res = gensym (pe_long);
4285 204 : var v = getvar(sym->referent, e->tok);
4286 : {
4287 204 : if (aggregations_active.count(v.value()))
4288 78 : load_aggregate(e->stat, agg, true);
4289 : else
4290 126 : load_aggregate(e->stat, agg, false);
4291 :
4292 : // PR 2142+2610: empty aggregates
4293 204 : if (e->ctype == sc_count)
4294 : {
4295 61 : o->newline() << "if (unlikely (" << agg.value() << " == NULL))";
4296 61 : o->indent(1);
4297 61 : c_assign(res, "0", e->tok);
4298 61 : o->indent(-1);
4299 : }
4300 : else
4301 : {
4302 : o->newline() << "if (unlikely (" << agg.value() << " == NULL)"
4303 143 : << " || " << agg.value() << "->count == 0)";
4304 143 : o->newline(1) << "c->last_error = \"empty aggregate\";";
4305 143 : o->indent(-1);
4306 : }
4307 204 : o->newline() << "else";
4308 204 : o->indent(1);
4309 204 : switch (e->ctype)
4310 : {
4311 : case sc_average:
4312 : c_assign(res, ("_stp_div64(&c->last_error, " + agg.value() + "->sum, "
4313 : + agg.value() + "->count)"),
4314 37 : e->tok);
4315 37 : break;
4316 : case sc_count:
4317 61 : c_assign(res, agg.value() + "->count", e->tok);
4318 61 : break;
4319 : case sc_sum:
4320 44 : c_assign(res, agg.value() + "->sum", e->tok);
4321 44 : break;
4322 : case sc_min:
4323 31 : c_assign(res, agg.value() + "->min", e->tok);
4324 31 : break;
4325 : case sc_max:
4326 31 : c_assign(res, agg.value() + "->max", e->tok);
4327 : break;
4328 : }
4329 204 : o->indent(-1);
4330 : }
4331 204 : o->newline() << res << ";";
4332 : }
4333 204 : }
4334 :
4335 :
4336 : void
4337 0 : c_unparser::visit_hist_op (hist_op*)
4338 : {
4339 : // Hist ops can only occur in a limited set of circumstances:
4340 : //
4341 : // 1. Inside an arrayindex expression, as the base referent. See
4342 : // c_unparser::visit_arrayindex for handling of this case.
4343 : //
4344 : // 2. Inside a foreach statement, as the base referent. See
4345 : // c_unparser::visit_foreach_loop for handling this case.
4346 : //
4347 : // 3. Inside a print_format expression, as the sole argument. See
4348 : // c_unparser::visit_print_format for handling this case.
4349 : //
4350 : // Note that none of these cases involves the c_unparser ever
4351 : // visiting this node. We should not get here.
4352 :
4353 0 : assert(false);
4354 : }
4355 :
4356 : int
4357 283 : emit_symbol_data (systemtap_session& s)
4358 : {
4359 283 : int rc = 0;
4360 :
4361 : // Instead of processing elf symbol tables, for now we just snatch
4362 : // /proc/kallsyms and convert it to our use. We need it sorted by
4363 : // address (so we can binary search) , and filtered (to show text
4364 : // symbols only), a task that we defer to grep(1) and sort(1). It
4365 : // may be useful to cache the symbols.sorted file, perhaps indexed
4366 : // by md5sum(/proc/modules), but let's not until this simple method
4367 : // proves too costly. LC_ALL=C is already set to avoid the
4368 : // excessive penalty of i18n code in some glibc/coreutils versions.
4369 :
4370 283 : string sorted_kallsyms = s.tmpdir + "/symbols.sorted";
4371 283 : string sortcmd = "grep \" [AtT] \" /proc/kallsyms | ";
4372 :
4373 283 : if (s.symtab == false)
4374 : {
4375 283 : s.op->newline() << "/* filled in by runtime */";
4376 283 : s.op->newline() << "struct stap_symbol *stap_symbols;";
4377 283 : s.op->newline() << "unsigned stap_num_symbols;\n";
4378 283 : return 0;
4379 : }
4380 :
4381 0 : sortcmd += "sort ";
4382 : #if __LP64__
4383 0 : sortcmd += "-k 1,16 ";
4384 : #else
4385 : sortcmd += "-k 1,8 ";
4386 : #endif
4387 0 : sortcmd += "-s -o " + sorted_kallsyms;
4388 :
4389 0 : if (s.verbose>1) clog << "Running " << sortcmd << endl;
4390 0 : rc = system(sortcmd.c_str());
4391 0 : if (rc == 0)
4392 : {
4393 0 : ifstream kallsyms (sorted_kallsyms.c_str());
4394 : char kallsyms_outbuf [4096];
4395 0 : ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str());
4396 : kallsyms_out.rdbuf()->pubsetbuf (kallsyms_outbuf,
4397 0 : sizeof(kallsyms_outbuf));
4398 :
4399 0 : s.op->newline() << "\n\n#include \"stap-symbols.h\"";
4400 :
4401 0 : unsigned i=0;
4402 0 : kallsyms_out << "struct stap_symbol _stp_stap_symbols [] = {";
4403 0 : string lastaddr;
4404 0 : while (! kallsyms.eof())
4405 : {
4406 0 : string addr, type, sym, module;
4407 0 : kallsyms >> addr >> type >> sym;
4408 0 : kallsyms >> ws;
4409 0 : if (kallsyms.peek() == '[')
4410 : {
4411 0 : string bracketed;
4412 0 : kallsyms >> bracketed;
4413 0 : module = bracketed.substr (1, bracketed.length()-2);
4414 : }
4415 :
4416 : // NB: kallsyms includes some duplicate addresses
4417 0 : if ((type == "t" || type == "T" || type == "A") && lastaddr != addr)
4418 : {
4419 : kallsyms_out << " { 0x" << addr << ", "
4420 : << "\"" << sym << "\", "
4421 : << "\"" << module << "\" },"
4422 0 : << "\n";
4423 0 : lastaddr = addr;
4424 0 : i ++;
4425 : }
4426 : }
4427 0 : kallsyms_out << "};\n";
4428 0 : kallsyms_out << "struct stap_symbol *stap_symbols = _stp_stap_symbols;";
4429 0 : kallsyms_out << "unsigned stap_num_symbols = " << i << ";\n";
4430 : }
4431 :
4432 0 : return rc;
4433 : }
4434 :
4435 :
4436 : int
4437 283 : translate_pass (systemtap_session& s)
4438 : {
4439 283 : int rc = 0;
4440 :
4441 283 : s.op = new translator_output (s.translated_source);
4442 283 : c_unparser cup (& s);
4443 283 : s.up = & cup;
4444 :
4445 : try
4446 : {
4447 : // This is at the very top of the file.
4448 :
4449 : // XXX: the runtime uses #ifdef TEST_MODE to infer systemtap usage.
4450 283 : s.op->line() << "#define TEST_MODE 0\n";
4451 :
4452 283 : s.op->newline() << "#ifndef MAXNESTING";
4453 283 : s.op->newline() << "#define MAXNESTING 10";
4454 283 : s.op->newline() << "#endif";
4455 283 : s.op->newline() << "#ifndef MAXSTRINGLEN";
4456 283 : s.op->newline() << "#define MAXSTRINGLEN 128";
4457 283 : s.op->newline() << "#endif";
4458 283 : s.op->newline() << "#ifndef MAXACTION";
4459 283 : s.op->newline() << "#define MAXACTION 1000";
4460 283 : s.op->newline() << "#endif";
4461 283 : s.op->newline() << "#ifndef MAXACTION_INTERRUPTIBLE";
4462 283 : s.op->newline() << "#define MAXACTION_INTERRUPTIBLE (MAXACTION * 10)";
4463 283 : s.op->newline() << "#endif";
4464 283 : s.op->newline() << "#ifndef MAXTRYLOCK";
4465 283 : s.op->newline() << "#define MAXTRYLOCK MAXACTION";
4466 283 : s.op->newline() << "#endif";
4467 283 : s.op->newline() << "#ifndef TRYLOCKDELAY";
4468 283 : s.op->newline() << "#define TRYLOCKDELAY 100";
4469 283 : s.op->newline() << "#endif";
4470 283 : s.op->newline() << "#ifndef MAXMAPENTRIES";
4471 283 : s.op->newline() << "#define MAXMAPENTRIES 2048";
4472 283 : s.op->newline() << "#endif";
4473 283 : s.op->newline() << "#ifndef MAXERRORS";
4474 283 : s.op->newline() << "#define MAXERRORS 0";
4475 283 : s.op->newline() << "#endif";
4476 283 : s.op->newline() << "#ifndef MAXSKIPPED";
4477 283 : s.op->newline() << "#define MAXSKIPPED 100";
4478 283 : s.op->newline() << "#endif";
4479 283 : s.op->newline() << "#ifndef MINSTACKSPACE";
4480 283 : s.op->newline() << "#define MINSTACKSPACE 1024";
4481 283 : s.op->newline() << "#endif";
4482 :
4483 : // Overload processing
4484 283 : s.op->newline() << "#ifndef STP_OVERLOAD_INTERVAL";
4485 283 : s.op->newline() << "#define STP_OVERLOAD_INTERVAL 1000000000LL";
4486 283 : s.op->newline() << "#endif";
4487 283 : s.op->newline() << "#ifndef STP_OVERLOAD_THRESHOLD";
4488 283 : s.op->newline() << "#define STP_OVERLOAD_THRESHOLD 500000000LL";
4489 283 : s.op->newline() << "#endif";
4490 : // We allow the user to completely turn overload processing off
4491 : // (as opposed to tuning it by overriding the values above) by
4492 : // running: stap -DSTP_NO_OVERLOAD {other options}
4493 283 : s.op->newline() << "#ifndef STP_NO_OVERLOAD";
4494 283 : s.op->newline() << "#define STP_OVERLOAD";
4495 283 : s.op->newline() << "#endif";
4496 :
4497 283 : if (s.bulk_mode)
4498 7 : s.op->newline() << "#define STP_BULKMODE";
4499 :
4500 283 : if (s.timing)
4501 2 : s.op->newline() << "#define STP_TIMING";
4502 :
4503 283 : if (s.perfmon)
4504 0 : s.op->newline() << "#define STP_PERFMON";
4505 :
4506 283 : s.op->newline() << "#include \"runtime.h\"";
4507 283 : s.op->newline() << "#include \"regs.c\"";
4508 283 : s.op->newline() << "#include \"stack.c\"";
4509 283 : s.op->newline() << "#include \"regs-ia64.c\"";
4510 283 : s.op->newline() << "#include \"stat.c\"";
4511 283 : s.op->newline() << "#include <linux/string.h>";
4512 283 : s.op->newline() << "#include <linux/timer.h>";
4513 283 : s.op->newline() << "#include <linux/delay.h>";
4514 283 : s.op->newline() << "#include <linux/profile.h>";
4515 283 : s.op->newline() << "#include <linux/random.h>";
4516 283 : s.op->newline() << "#include <linux/utsname.h>";
4517 283 : s.op->newline() << "#include \"loc2c-runtime.h\" ";
4518 :
4519 : // XXX: old 2.6 kernel hack
4520 283 : s.op->newline() << "#ifndef read_trylock";
4521 283 : s.op->newline() << "#define read_trylock(x) ({ read_lock(x); 1; })";
4522 283 : s.op->newline() << "#endif";
4523 :
4524 283 : s.op->newline() << "#if defined(CONFIG_MARKERS)";
4525 283 : s.op->newline() << "#include <linux/marker.h>";
4526 283 : s.op->newline() << "#endif";
4527 :
4528 283 : s.up->emit_common_header (); // context etc.
4529 :
4530 565 : for (unsigned i=0; i<s.embeds.size(); i++)
4531 : {
4532 283 : s.op->newline() << s.embeds[i]->code << "\n";
4533 : }
4534 :
4535 282 : s.op->newline() << "static struct {";
4536 282 : s.op->indent(1);
4537 713 : for (unsigned i=0; i<s.globals.size(); i++)
4538 : {
4539 431 : s.up->emit_global (s.globals[i]);
4540 : }
4541 282 : s.op->newline(-1) << "} global = {";
4542 282 : s.op->newline(1);
4543 713 : for (unsigned i=0; i<s.globals.size(); i++)
4544 : {
4545 431 : if (pending_interrupts) return 1;
4546 431 : s.up->emit_global_init (s.globals[i]);
4547 : }
4548 282 : s.op->newline(-1) << "};";
4549 :
4550 1524 : for (unsigned i=0; i<s.functions.size(); i++)
4551 : {
4552 1242 : if (pending_interrupts) return 1;
4553 1242 : s.op->newline();
4554 1242 : s.up->emit_functionsig (s.functions[i]);
4555 : }
4556 :
4557 1524 : for (unsigned i=0; i<s.functions.size(); i++)
4558 : {
4559 1242 : if (pending_interrupts) return 1;
4560 1242 : s.op->newline();
4561 1242 : s.up->emit_function (s.functions[i]);
4562 : }
4563 :
4564 : // Run a varuse_collecting_visitor over probes that need global
4565 : // variable locks. We'll use this information later in
4566 : // emit_locks()/emit_unlocks().
4567 9537 : for (unsigned i=0; i<s.probes.size(); i++)
4568 : {
4569 9255 : if (pending_interrupts) return 1;
4570 9255 : if (s.probes[i]->needs_global_locks())
4571 8297 : s.probes[i]->body->visit (&cup.vcv_needs_global_locks);
4572 : }
4573 :
4574 9536 : for (unsigned i=0; i<s.probes.size(); i++)
4575 : {
4576 9255 : if (pending_interrupts) return 1;
4577 9255 : s.up->emit_probe (s.probes[i]);
4578 : }
4579 :
4580 281 : s.op->newline();
4581 281 : s.up->emit_module_init ();
4582 281 : s.op->newline();
4583 281 : s.up->emit_module_exit ();
4584 :
4585 281 : s.op->newline();
4586 :
4587 : // XXX impedance mismatch
4588 281 : s.op->newline() << "int probe_start () {";
4589 281 : s.op->newline(1) << "return systemtap_module_init () ? -1 : 0;";
4590 281 : s.op->newline(-1) << "}";
4591 281 : s.op->newline();
4592 281 : s.op->newline() << "void probe_exit () {";
4593 281 : s.op->newline(1) << "systemtap_module_exit ();";
4594 281 : s.op->newline(-1) << "}";
4595 :
4596 712 : for (unsigned i=0; i<s.globals.size(); i++)
4597 : {
4598 431 : s.op->newline();
4599 431 : s.up->emit_global_param (s.globals[i]);
4600 : }
4601 :
4602 281 : s.op->newline() << "MODULE_DESCRIPTION(\"systemtap probe\");";
4603 281 : s.op->newline() << "MODULE_LICENSE(\"GPL\");"; // XXX
4604 : }
4605 4 : catch (const semantic_error& e)
4606 : {
4607 2 : s.print_error (e);
4608 : }
4609 :
4610 283 : rc |= emit_symbol_data (s);
4611 :
4612 283 : s.op->line() << "\n";
4613 :
4614 283 : delete s.op;
4615 283 : s.op = 0;
4616 283 : s.up = 0;
4617 :
4618 283 : return rc + s.num_errors();
4619 2188 : }
|