]> sourceware.org Git - systemtap.git/blame - elaborate.cxx
levensh suggest unresolved probe points
[systemtap.git] / elaborate.cxx
CommitLineData
2b066ec1 1// elaboration functions
ad583484 2// Copyright (C) 2005-2013 Red Hat Inc.
1773fd03 3// Copyright (C) 2008 Intel Corporation
69c68955
FCE
4//
5// This file is part of systemtap, and is free software. You can
6// redistribute it and/or modify it under the terms of the GNU General
7// Public License (GPL); either version 2, or (at your option) any
8// later version.
2b066ec1
FCE
9
10#include "config.h"
11#include "elaborate.h"
2865d17a 12#include "translate.h"
2b066ec1 13#include "parse.h"
20c6c071 14#include "tapsets.h"
dc38c0ae 15#include "session.h"
72dbc915 16#include "util.h"
a057c85c 17#include "task_finder.h"
60cf5fae 18#include "stapregex.h"
d2548fe7 19
2b066ec1
FCE
20extern "C" {
21#include <sys/utsname.h>
a477f3f1 22#include <fnmatch.h>
4af765b2
LB
23#define __STDC_FORMAT_MACROS
24#include <inttypes.h>
2b066ec1
FCE
25}
26
2b066ec1 27#include <algorithm>
67c0a579
GH
28#include <fstream>
29#include <map>
29e64872 30#include <cassert>
67c0a579
GH
31#include <set>
32#include <vector>
1b07c728
FCE
33#include <algorithm>
34#include <iterator>
f4869658 35#include <climits>
1b07c728 36
2b066ec1 37
2b066ec1
FCE
38using namespace std;
39
40
41// ------------------------------------------------------------------------
42
5d23847d
FCE
43// Used in probe_point condition construction. Either argument may be
44// NULL; if both, return NULL too. Resulting expression is a deep
45// copy for symbol resolution purposes.
46expression* add_condition (expression* a, expression* b)
47{
48 if (!a && !b) return 0;
49 if (! a) return deep_copy_visitor::deep_copy(b);
50 if (! b) return deep_copy_visitor::deep_copy(a);
51 logical_and_expr la;
52 la.op = "&&";
53 la.left = a;
54 la.right = b;
55 la.tok = a->tok; // or could be b->tok
56 return deep_copy_visitor::deep_copy(& la);
57}
58
59// ------------------------------------------------------------------------
60
61
2b066ec1 62
4c5d1300 63derived_probe::derived_probe (probe *p, probe_point *l, bool rewrite_loc):
26e63673 64 base (p), base_pp(l), sdt_semaphore_addr(0), session_index((unsigned)-1)
2b066ec1 65{
5d23847d
FCE
66 assert (p);
67 this->tok = p->tok;
68 this->privileged = p->privileged;
69 this->body = deep_copy_visitor::deep_copy(p->body);
cbbe8080 70
5d23847d 71 assert (l);
4c5d1300
JS
72 // make a copy for subclasses which want to rewrite the location
73 if (rewrite_loc)
74 l = new probe_point(*l);
5d23847d 75 this->locations.push_back (l);
2b066ec1
FCE
76}
77
98afd80e 78
b8da0ad1
FCE
79void
80derived_probe::printsig (ostream& o) const
81{
82 probe::printsig (o);
83 printsig_nested (o);
84}
85
86void
87derived_probe::printsig_nested (ostream& o) const
88{
89 // We'd like to enclose the probe derivation chain in a /* */
90 // comment delimiter. But just printing /* base->printsig() */ is
91 // not enough, since base might itself be a derived_probe. So we,
92 // er, "cleverly" encode our nesting state as a formatting flag for
93 // the ostream.
94 ios::fmtflags f = o.flags (ios::internal);
95 if (f & ios::internal)
96 {
97 // already nested
98 o << " <- ";
99 base->printsig (o);
100 }
101 else
102 {
103 // outermost nesting
104 o << " /* <- ";
105 base->printsig (o);
106 o << " */";
107 }
108 // restore flags
109 (void) o.flags (f);
110}
111
112
c3a3c0c9 113void
d885563b 114derived_probe::collect_derivation_chain (std::vector<probe*> &probes_list) const
c3a3c0c9 115{
d885563b 116 probes_list.push_back(const_cast<derived_probe*>(this));
c3a3c0c9
WC
117 base->collect_derivation_chain(probes_list);
118}
119
120
f1b9a51a 121void
d885563b 122derived_probe::collect_derivation_pp_chain (std::vector<probe_point*> &pp_list) const
f1b9a51a 123{
8159bf55 124 pp_list.push_back(const_cast<probe_point*>(this->sole_location()));
f1b9a51a
JS
125 base->collect_derivation_pp_chain(pp_list);
126}
127
128
26e63673
JS
129string
130derived_probe::derived_locations ()
131{
132 ostringstream o;
133 vector<probe_point*> reference_point;
134 collect_derivation_pp_chain(reference_point);
d885563b
FCE
135 if (reference_point.size() > 0)
136 for(unsigned i=1; i<reference_point.size(); ++i)
137 o << " from: " << reference_point[i]->str(false); // no ?,!,etc
26e63673
JS
138 return o.str();
139}
140
141
b20febf3 142probe_point*
b8da0ad1 143derived_probe::sole_location () const
dc38c0ae 144{
4af765b2 145 if (locations.size() == 0 || locations.size() > 1)
dc09353a 146 throw SEMANTIC_ERROR (_N("derived_probe with no locations",
2a89b023 147 "derived_probe with too many locations",
d885563b 148 locations.size()), this->tok);
57148ee7 149 else
b20febf3 150 return locations[0];
dc38c0ae
DS
151}
152
153
c3df9bce
JS
154probe_point*
155derived_probe::script_location () const
156{
d885563b
FCE
157 // This feeds function::pn() in the tapset, which is documented as the
158 // script-level probe point expression, *after wildcard expansion*. If
159 // it were not for wildcard stuff, we'd just return the last item in the
160 // derivation chain. But alas ... we need to search for the last one
161 // that doesn't have a * in the textual representation. Heuristics, eww.
162 vector<probe_point*> chain;
163 collect_derivation_pp_chain (chain);
164
a126c5b1
JS
165 // NB: we actually start looking from the second-to-last item, so the user's
166 // direct input is not considered. Input like 'kernel.function("init_once")'
167 // will thus be listed with the resolved @file:line too, disambiguating the
168 // distinct functions by this name, and matching our historical behavior.
169 for (int i=chain.size()-2; i>=0; i--)
d885563b 170 {
5d9306df
FCE
171 probe_point pp_copy (* chain [i]);
172 // drop any ?/! denotations that would confuse a glob-char search
173 pp_copy.optional = false;
174 pp_copy.sufficient = false;
175 string pp_printed = lex_cast(pp_copy);
176 if (! contains_glob_chars(pp_printed))
d885563b
FCE
177 return chain[i];
178 }
179
8159bf55
FCE
180 // If that didn't work, just fallback to -something-.
181 return sole_location();
c3df9bce
JS
182}
183
184
2865d17a 185void
42e38653 186derived_probe::emit_privilege_assertion (translator_output* o)
2865d17a
DB
187{
188 // Emit code which will cause compilation to fail if it is compiled in
189 // unprivileged mode.
f6be7c06
DB
190 o->newline() << "#if ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPDEV) && \\";
191 o->newline() << " ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPSYS)";
2865d17a
DB
192 o->newline() << "#error Internal Error: Probe ";
193 probe::printsig (o->line());
194 o->line() << " generated in --unprivileged mode";
195 o->newline() << "#endif";
196}
197
198
199void
200derived_probe::emit_process_owner_assertion (translator_output* o)
201{
202 // Emit code which will abort should the current target not belong to the
203 // user in unprivileged mode.
f6be7c06
DB
204 o->newline() << "#if ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPDEV) && \\";
205 o->newline() << " ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPSYS)";
2865d17a
DB
206 o->newline(1) << "if (! is_myproc ()) {";
207 o->newline(1) << "snprintf(c->error_buffer, sizeof(c->error_buffer),";
208 o->newline() << " \"Internal Error: Process %d does not belong to user %d in probe %s in --unprivileged mode\",";
209 o->newline() << " current->tgid, _stp_uid, c->probe_point);";
210 o->newline() << "c->last_error = c->error_buffer;";
991bd3ba
JS
211 // NB: since this check occurs before probe locking, its exit should
212 // not be a "goto out", which would attempt unlocking.
213 o->newline() << "return;";
2865d17a
DB
214 o->newline(-1) << "}";
215 o->newline(-1) << "#endif";
216}
217
8f6d8c2b
DB
218void
219derived_probe::print_dupe_stamp_unprivileged(ostream& o)
220{
4af765b2 221 o << _("unprivileged users: authorized") << endl;
8f6d8c2b
DB
222}
223
224void
225derived_probe::print_dupe_stamp_unprivileged_process_owner(ostream& o)
226{
4af765b2 227 o << _("unprivileged users: authorized for process owner") << endl;
8f6d8c2b 228}
47dd066d 229
20c6c071 230// ------------------------------------------------------------------------
98afd80e
FCE
231// Members of derived_probe_builder
232
8eb6206c
SM
233void
234derived_probe_builder::build_with_suffix(systemtap_session & sess,
235 probe * use,
236 probe_point * location,
237 std::map<std::string, literal *>
238 const & parameters,
239 std::vector<derived_probe *>
240 & finished_results,
241 std::vector<probe_point::component *>
242 const & suffix) {
243 // XXX perhaps build the probe if suffix is empty?
244 // if (suffix.empty()) {
245 // build (sess, use, location, parameters, finished_results);
246 // return;
247 // }
dc09353a 248 throw SEMANTIC_ERROR (_("invalid suffix for probe"));
8eb6206c
SM
249}
250
98afd80e
FCE
251bool
252derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
253 const std::string& key,
254 std::string& value)
255{
256 map<string, literal *>::const_iterator i = params.find (key);
257 if (i == params.end())
258 return false;
259 literal_string * ls = dynamic_cast<literal_string *>(i->second);
260 if (!ls)
261 return false;
262 value = ls->value;
263 return true;
264}
265
20c6c071 266
98afd80e
FCE
267bool
268derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
269 const std::string& key,
270 int64_t& value)
271{
272 map<string, literal *>::const_iterator i = params.find (key);
273 if (i == params.end())
274 return false;
275 if (i->second == NULL)
276 return false;
277 literal_number * ln = dynamic_cast<literal_number *>(i->second);
278 if (!ln)
279 return false;
280 value = ln->value;
281 return true;
282}
283
284
888af770
FCE
285bool
286derived_probe_builder::has_null_param (std::map<std::string, literal*> const & params,
287 const std::string& key)
288{
289 map<string, literal *>::const_iterator i = params.find(key);
290 return (i != params.end() && i->second == NULL);
291}
292
293
98afd80e
FCE
294
295// ------------------------------------------------------------------------
20c6c071
GH
296// Members of match_key.
297
57148ee7
FCE
298match_key::match_key(string const & n)
299 : name(n),
300 have_parameter(false),
5d23847d 301 parameter_type(pe_unknown)
20c6c071
GH
302{
303}
304
305match_key::match_key(probe_point::component const & c)
306 : name(c.functor),
307 have_parameter(c.arg != NULL),
5d23847d 308 parameter_type(c.arg ? c.arg->type : pe_unknown)
20c6c071
GH
309{
310}
311
312match_key &
57148ee7 313match_key::with_number()
20c6c071
GH
314{
315 have_parameter = true;
5d23847d 316 parameter_type = pe_long;
20c6c071
GH
317 return *this;
318}
319
320match_key &
57148ee7 321match_key::with_string()
20c6c071
GH
322{
323 have_parameter = true;
5d23847d 324 parameter_type = pe_string;
20c6c071
GH
325 return *this;
326}
327
57148ee7 328string
20c6c071
GH
329match_key::str() const
330{
331 if (have_parameter)
332 switch (parameter_type)
333 {
5d23847d
FCE
334 case pe_string: return name + "(string)";
335 case pe_long: return name + "(number)";
20c6c071
GH
336 default: return name + "(...)";
337 }
338 return name;
339}
340
57148ee7 341bool
20c6c071
GH
342match_key::operator<(match_key const & other) const
343{
344 return ((name < other.name)
57148ee7
FCE
345
346 || (name == other.name
20c6c071 347 && have_parameter < other.have_parameter)
57148ee7
FCE
348
349 || (name == other.name
350 && have_parameter == other.have_parameter
20c6c071
GH
351 && parameter_type < other.parameter_type));
352}
2b066ec1 353
c0c7b466
FCE
354
355// NB: these are only used in the probe point name components, where
356// only "*" is permitted.
357//
358// Within module("bar"), function("foo"), process("baz") strings, real
359// wildcards are permitted too. See also util.h:contains_glob_chars
360
a477f3f1
DS
361static bool
362isglob(string const & str)
363{
364 return(str.find('*') != str.npos);
365}
366
122b4fcd
JS
367static bool
368isdoubleglob(string const & str)
369{
370 return(str.find("**") != str.npos);
371}
372
a477f3f1
DS
373bool
374match_key::globmatch(match_key const & other) const
375{
376 const char *other_str = other.name.c_str();
377 const char *name_str = name.c_str();
378
379 return ((fnmatch(name_str, other_str, FNM_NOESCAPE) == 0)
57148ee7 380 && have_parameter == other.have_parameter
a477f3f1
DS
381 && parameter_type == other.parameter_type);
382}
383
2b066ec1 384// ------------------------------------------------------------------------
20c6c071
GH
385// Members of match_node
386// ------------------------------------------------------------------------
387
27dc09b1 388match_node::match_node() :
f6be7c06 389 privilege(privilege_t (pr_stapdev | pr_stapsys))
d4935c2f 390{
d4935c2f 391}
20c6c071
GH
392
393match_node *
57148ee7 394match_node::bind(match_key const & k)
20c6c071 395{
b4ceace2 396 if (k.name == "*")
dc09353a 397 throw SEMANTIC_ERROR(_("invalid use of wildcard probe point component"));
b4ceace2 398
20c6c071
GH
399 map<match_key, match_node *>::const_iterator i = sub.find(k);
400 if (i != sub.end())
401 return i->second;
402 match_node * n = new match_node();
403 sub.insert(make_pair(k, n));
404 return n;
405}
406
57148ee7 407void
20c6c071
GH
408match_node::bind(derived_probe_builder * e)
409{
2531fc1e 410 ends.push_back (e);
20c6c071
GH
411}
412
57148ee7 413match_node *
20c6c071
GH
414match_node::bind(string const & k)
415{
416 return bind(match_key(k));
417}
418
419match_node *
420match_node::bind_str(string const & k)
421{
422 return bind(match_key(k).with_string());
423}
424
57148ee7 425match_node *
20c6c071
GH
426match_node::bind_num(string const & k)
427{
428 return bind(match_key(k).with_number());
429}
430
27dc09b1 431match_node *
42e38653 432match_node::bind_privilege(privilege_t p)
27dc09b1 433{
42e38653 434 privilege = p;
27dc09b1
DB
435 return this;
436}
437
b4ceace2
FCE
438void
439match_node::find_and_build (systemtap_session& s,
440 probe* p, probe_point *loc, unsigned pos,
441 vector<derived_probe *>& results)
20c6c071 442{
b4ceace2 443 assert (pos <= loc->components.size());
57148ee7 444 if (pos == loc->components.size()) // matched all probe point components so far
20c6c071 445 {
2531fc1e 446 if (ends.empty())
b4ceace2
FCE
447 {
448 string alternatives;
449 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
450 alternatives += string(" ") + i->first.str();
451
dc09353a 452 throw SEMANTIC_ERROR (_F("probe point truncated (follow: %s)",
8eb6206c 453 alternatives.c_str()),
4af765b2 454 loc->components.back()->tok);
b4ceace2
FCE
455 }
456
f66bb29a 457 if (! pr_contains (privilege, s.privilege))
27dc09b1 458 {
dc09353a 459 throw SEMANTIC_ERROR (_F("probe point is not allowed for --privilege=%s",
f66bb29a 460 pr_name (s.privilege)),
4af765b2 461 loc->components.back()->tok);
27dc09b1
DB
462 }
463
b4ceace2
FCE
464 map<string, literal *> param_map;
465 for (unsigned i=0; i<pos; i++)
466 param_map[loc->components[i]->functor] = loc->components[i]->arg;
467 // maybe 0
468
2531fc1e
FCE
469 // Iterate over all bound builders
470 for (unsigned k=0; k<ends.size(); k++)
471 {
472 derived_probe_builder *b = ends[k];
473 b->build (s, p, loc, param_map, results);
474 }
20c6c071 475 }
122b4fcd
JS
476 else if (isdoubleglob(loc->components[pos]->functor)) // ** wildcard?
477 {
478 unsigned int num_results = results.size();
479
480 // When faced with "foo**bar", we try "foo*bar" and "foo*.**bar"
481
482 const probe_point::component *comp = loc->components[pos];
483 const string &functor = comp->functor;
484 size_t glob_start = functor.find("**");
485 size_t glob_end = functor.find_first_not_of('*', glob_start);
486 const string prefix = functor.substr(0, glob_start);
487 const string suffix = ((glob_end != string::npos) ?
488 functor.substr(glob_end) : "");
489
490 // Synthesize "foo*bar"
491 probe_point *simple_pp = new probe_point(*loc);
492 probe_point::component *simple_comp = new probe_point::component(*comp);
493 simple_comp->functor = prefix + "*" + suffix;
494 simple_pp->components[pos] = simple_comp;
495 try
496 {
497 find_and_build (s, p, simple_pp, pos, results);
498 }
499 catch (const semantic_error& e)
500 {
501 // Ignore semantic_errors, but cleanup
502 delete simple_pp;
503 delete simple_comp;
504 }
505
506 // Synthesize "foo*.**bar"
507 // NB: any component arg should attach to the latter part only
508 probe_point *expanded_pp = new probe_point(*loc);
509 probe_point::component *expanded_comp_pre = new probe_point::component(*comp);
510 expanded_comp_pre->functor = prefix + "*";
511 expanded_comp_pre->arg = NULL;
512 probe_point::component *expanded_comp_post = new probe_point::component(*comp);
513 expanded_comp_post->functor = "**" + suffix;
514 expanded_pp->components[pos] = expanded_comp_pre;
515 expanded_pp->components.insert(expanded_pp->components.begin() + pos + 1,
516 expanded_comp_post);
517 try
518 {
519 find_and_build (s, p, expanded_pp, pos, results);
520 }
521 catch (const semantic_error& e)
522 {
523 // Ignore semantic_errors, but cleanup
524 delete expanded_pp;
525 delete expanded_comp_pre;
526 delete expanded_comp_post;
527 }
528
8eb6206c
SM
529 // Try suffix expansion only if no matches found:
530 if (num_results == results.size())
531 try
532 {
533 this->try_suffix_expansion (s, p, loc, pos, results);
534 }
535 catch (const recursive_expansion_error &e)
536 {
537 s.print_error(e); return; // Suppress probe mismatch msg.
538 }
539
122b4fcd
JS
540 if (! loc->optional && num_results == results.size())
541 {
542 // We didn't find any wildcard matches (since the size of
543 // the result vector didn't change). Throw an error.
5bcb7b4e
JL
544 string sugs = suggest_functors(functor);
545 throw SEMANTIC_ERROR (_F("probe point mismatch: didn't find any wildcard matches%s",
546 sugs.empty() ? "" : (" (similar: " + sugs + ")").c_str()),
547 comp->tok);
122b4fcd
JS
548 }
549 }
a477f3f1 550 else if (isglob(loc->components[pos]->functor)) // wildcard?
20c6c071 551 {
a477f3f1
DS
552 match_key match (* loc->components[pos]);
553
828c3ed5
DS
554 // Call find_and_build for each possible match. Ignore errors -
555 // unless we don't find any match.
556 unsigned int num_results = results.size();
b4ceace2
FCE
557 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
558 {
a477f3f1 559 const match_key& subkey = i->first;
828c3ed5 560 match_node* subnode = i->second;
a477f3f1 561
e19ebcf7 562 assert_no_interrupts();
49abf162 563
a477f3f1 564 if (match.globmatch(subkey))
828c3ed5 565 {
ddfc759e 566 if (s.verbose > 2)
4af765b2
LB
567 clog << _F("wildcard '%s' matched '%s'",
568 loc->components[pos]->functor.c_str(),
569 subkey.name.c_str()) << endl;
ddfc759e
DS
570
571 // When we have a wildcard, we need to create a copy of
572 // the probe point. Then we'll create a copy of the
573 // wildcard component, and substitute the non-wildcard
574 // functor.
575 probe_point *non_wildcard_pp = new probe_point(*loc);
576 probe_point::component *non_wildcard_component
577 = new probe_point::component(*loc->components[pos]);
578 non_wildcard_component->functor = subkey.name;
579 non_wildcard_pp->components[pos] = non_wildcard_component;
580
5d23847d
FCE
581 // NB: probe conditions are not attached at the wildcard
582 // (component/functor) level, but at the overall
583 // probe_point level.
584
ddfc759e 585 // recurse (with the non-wildcard probe point)
a477f3f1
DS
586 try
587 {
ddfc759e
DS
588 subnode->find_and_build (s, p, non_wildcard_pp, pos+1,
589 results);
a477f3f1
DS
590 }
591 catch (const semantic_error& e)
592 {
593 // Ignore semantic_errors while expanding wildcards.
594 // If we get done and nothing was expanded, the code
595 // following the loop will complain.
ddfc759e
DS
596
597 // If this wildcard didn't match, cleanup.
598 delete non_wildcard_pp;
599 delete non_wildcard_component;
a477f3f1 600 }
828c3ed5 601 }
a477f3f1 602 }
8eb6206c
SM
603
604 // Try suffix expansion only if no matches found:
605 if (num_results == results.size())
606 try
607 {
608 this->try_suffix_expansion (s, p, loc, pos, results);
609 }
610 catch (const recursive_expansion_error &e)
611 {
612 s.print_error(e); return; // Suppress probe mismatch msg.
613 }
614
cedd10f4 615 if (! loc->optional && num_results == results.size())
828c3ed5
DS
616 {
617 // We didn't find any wildcard matches (since the size of
618 // the result vector didn't change). Throw an error.
5bcb7b4e
JL
619 string sugs = suggest_functors(loc->components[pos]->functor);
620 throw SEMANTIC_ERROR (_F("probe point mismatch: didn't find any wildcard matches%s",
621 sugs.empty() ? "" : (" (similar: " + sugs + ")").c_str()),
622 loc->components[pos]->tok);
828c3ed5 623 }
b4ceace2 624 }
57148ee7 625 else
20c6c071 626 {
b4ceace2
FCE
627 match_key match (* loc->components[pos]);
628 sub_map_iterator_t i = sub.find (match);
8eb6206c
SM
629
630 if (i != sub.end()) // match found
b4ceace2 631 {
8eb6206c
SM
632 match_node* subnode = i->second;
633 // recurse
634 subnode->find_and_build (s, p, loc, pos+1, results);
635 return;
636 }
637
638 unsigned int num_results = results.size();
639
640 try
641 {
642 this->try_suffix_expansion (s, p, loc, pos, results);
643 }
644 catch (const recursive_expansion_error &e)
645 {
646 s.print_error(e); return; // Suppress probe mismatch msg.
647 }
648
649 // XXX: how to correctly report alternatives + position numbers
650 // for alias suffixes? file a separate PR to address the issue
651 if (! loc->optional && num_results == results.size())
652 {
653 // We didn't find any alias suffixes (since the size of the
654 // result vector didn't change). Throw an error.
5bcb7b4e
JL
655 string sugs = suggest_functors(loc->components[pos]->functor);
656 throw SEMANTIC_ERROR (_F("probe point mismatch%s",
657 sugs.empty() ? "" : (" (similar: " + sugs + ")").c_str()),
658 loc->components[pos]->tok);
b4ceace2 659 }
8eb6206c
SM
660 }
661}
662
5bcb7b4e
JL
663string
664match_node::suggest_functors(string functor)
665{
666 // only use prefix if globby (and prefix is non-empty)
667 size_t glob = functor.find('*');
668 if (glob != string::npos && glob != 0)
669 functor.erase(glob);
670 if (functor.empty())
671 return "";
672
673 set<string> functors;
674 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
675 {
676 string ftor = i->first.str();
677 if (ftor.find('(') != string::npos) // trim any parameter
678 ftor.erase(ftor.find('('));
679 functors.insert(ftor);
680 }
681 return levenshtein_suggest(functor, functors, 5); // print top 5
682}
b4ceace2 683
8eb6206c
SM
684void
685match_node::try_suffix_expansion (systemtap_session& s,
686 probe *p, probe_point *loc, unsigned pos,
687 vector<derived_probe *>& results)
688{
689 // PR12210: match alias suffixes. If the components thus far
690 // have been matched, but there is an additional unknown
691 // suffix, we have a potential alias suffix on our hands. We
692 // need to expand the preceding components as probe aliases,
693 // reattach the suffix, and re-run derive_probes() on the
694 // resulting expansion. This is done by the routine
695 // build_with_suffix().
696
697 if (strverscmp(s.compatible.c_str(), "2.0") >= 0)
698 {
699 // XXX: technically, param_map isn't used here. So don't
700 // bother actually assembling it unless some
701 // derived_probe_builder appears that actually takes
702 // suffixes *and* consults parameters (currently no such
703 // builders exist).
704 map<string, literal *> param_map;
705 // for (unsigned i=0; i<pos; i++)
706 // param_map[loc->components[i]->functor] = loc->components[i]->arg;
707 // maybe 0
708
709 vector<probe_point::component *> suffix (loc->components.begin()+pos,
710 loc->components.end());
711
712 // Multiple derived_probe_builders may be bound at a
713 // match_node due to the possibility of multiply defined
714 // aliases.
715 for (unsigned k=0; k < ends.size(); k++)
716 {
717 derived_probe_builder *b = ends[k];
718 try
719 {
720 b->build_with_suffix (s, p, loc, param_map, results, suffix);
721 }
722 catch (const recursive_expansion_error &e)
723 {
724 // Re-throw:
e758508b 725 throw semantic_error(e);
8eb6206c
SM
726 }
727 catch (const semantic_error &e)
728 {
729 // Adjust source coordinate and re-throw:
730 if (! loc->optional)
dc09353a 731 throw semantic_error(e.errsrc, e.what(), loc->components[pos]->tok);
8eb6206c
SM
732 }
733 }
20c6c071
GH
734 }
735}
736
b4ceace2 737
aa30ccd3
FCE
738void
739match_node::build_no_more (systemtap_session& s)
740{
741 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
742 i->second->build_no_more (s);
2531fc1e
FCE
743 for (unsigned k=0; k<ends.size(); k++)
744 {
745 derived_probe_builder *b = ends[k];
746 b->build_no_more (s);
747 }
aa30ccd3
FCE
748}
749
b82d77b4
DB
750void
751match_node::dump (systemtap_session &s, const string &name)
752{
753 // Dump this node, if it is complete.
754 for (unsigned k=0; k<ends.size(); k++)
755 {
756 // Don't print aliases at all (for now) until we can figure out how to determine whether
757 // the probes they resolve to are ok in unprivileged mode.
758 if (ends[k]->is_alias ())
759 continue;
760
761 // In unprivileged mode, don't show the probes which are not allowed for unprivileged
762 // users.
f66bb29a 763 if (pr_contains (privilege, s.privilege))
b82d77b4
DB
764 {
765 cout << name << endl;
766 break; // we need only print one instance.
767 }
768 }
769
770 // Recursively dump the children of this node
771 string dot;
772 if (! name.empty ())
773 dot = ".";
774 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
775 {
776 i->second->dump (s, name + dot + i->first.str());
777 }
778}
779
aa30ccd3 780
20c6c071
GH
781// ------------------------------------------------------------------------
782// Alias probes
783// ------------------------------------------------------------------------
784
c1d5f3f6
FCE
785struct alias_derived_probe: public derived_probe
786{
8eb6206c
SM
787 alias_derived_probe (probe* base, probe_point *l, const probe_alias *a,
788 const vector<probe_point::component *> *suffix = 0);
1e2efea5 789 ~alias_derived_probe();
c1d5f3f6 790
dc09353a 791 void upchuck () { throw SEMANTIC_ERROR (_("inappropriate"), this->tok); }
b20febf3
FCE
792
793 // Alias probes are immediately expanded to other derived_probe
794 // types, and are not themselves emitted or listed in
795 // systemtap_session.probes
dc38c0ae 796
78f6bba6 797 void join_group (systemtap_session&) { upchuck (); }
2c5a19c6
DB
798
799 virtual const probe_alias *get_alias () const { return alias; }
8eb6206c 800 virtual probe_point *get_alias_loc () const { return alias_loc; }
2a89b023 801 virtual probe_point *sole_location () const;
2c5a19c6
DB
802
803private:
804 const probe_alias *alias; // Used to check for recursion
8eb6206c 805 probe_point *alias_loc; // Hack to recover full probe name
c1d5f3f6
FCE
806};
807
8eb6206c
SM
808
809alias_derived_probe::alias_derived_probe(probe *base, probe_point *l,
810 const probe_alias *a,
811 const vector<probe_point::component *>
812 *suffix):
813 derived_probe (base, l), alias(a)
814{
815 // XXX pretty nasty -- this was cribbed from printscript() in main.cxx
816 assert (alias->alias_names.size() >= 1);
817 alias_loc = new probe_point(*alias->alias_names[0]); // XXX: [0] is arbitrary; it would make just as much sense to collect all of the names
818 if (suffix) {
819 alias_loc->components.insert(alias_loc->components.end(),
820 suffix->begin(), suffix->end());
821 }
822}
823
1e2efea5
SM
824alias_derived_probe::~alias_derived_probe ()
825{
826 delete alias_loc;
827}
828
8eb6206c 829
2a89b023
FCE
830probe_point*
831alias_derived_probe::sole_location () const
832{
833 return const_cast<probe_point*>(alias_loc);
834}
835
836
c72aa911
JS
837probe*
838probe::create_alias(probe_point* l, probe_point* a)
839{
840 vector<probe_point*> aliases(1, a);
841 probe_alias* p = new probe_alias(aliases);
842 p->tok = tok;
843 p->locations.push_back(l);
844 p->body = body;
d885563b 845 p->base = this;
c72aa911
JS
846 p->privileged = privileged;
847 p->epilogue_style = false;
848 return new alias_derived_probe(this, l, p);
849}
850
c1d5f3f6 851
e2012a7a
DB
852void
853alias_expansion_builder::build(systemtap_session & sess,
854 probe * use,
855 probe_point * location,
8eb6206c
SM
856 std::map<std::string, literal *>
857 const & parameters,
e2012a7a 858 vector<derived_probe *> & finished_results)
8eb6206c
SM
859{
860 vector<probe_point::component *> empty_suffix;
861 build_with_suffix (sess, use, location, parameters,
862 finished_results, empty_suffix);
863}
864
865void
866alias_expansion_builder::build_with_suffix(systemtap_session & sess,
867 probe * use,
868 probe_point * location,
869 std::map<std::string, literal *>
870 const &,
871 vector<derived_probe *>
872 & finished_results,
873 vector<probe_point::component *>
874 const & suffix)
20c6c071 875{
e2012a7a
DB
876 // Don't build the alias expansion if infinite recursion is detected.
877 if (checkForRecursiveExpansion (use)) {
878 stringstream msg;
4af765b2
LB
879 msg << _F("Recursive loop in alias expansion of %s at %s",
880 lex_cast(*location).c_str(), lex_cast(location->components.front()->tok->location).c_str());
8eb6206c
SM
881 // semantic_errors thrown here might be ignored, so we need a special class:
882 throw recursive_expansion_error (msg.str());
883 // XXX The point of throwing this custom error is to suppress a
884 // cascade of "probe mismatch" messages that appear in addition to
885 // the error. The current approach suppresses most of the error
886 // cascade, but leaves one spurious error; in any case, the way
887 // this particular error is reported could be improved.
e2012a7a 888 }
57148ee7 889
e2012a7a
DB
890 // We're going to build a new probe and wrap it up in an
891 // alias_expansion_probe so that the expansion loop recognizes it as
892 // such and re-expands its expansion.
20c6c071 893
8eb6206c 894 alias_derived_probe * n = new alias_derived_probe (use, location /* soon overwritten */, this->alias, &suffix);
e2012a7a 895 n->body = new block();
5d23847d 896
8eb6206c
SM
897 // The new probe gets a deep copy of the location list of the alias
898 // (with incoming condition joined) plus the suffix (if any),
e2012a7a
DB
899 n->locations.clear();
900 for (unsigned i=0; i<alias->locations.size(); i++)
901 {
902 probe_point *pp = new probe_point(*alias->locations[i]);
8eb6206c 903 pp->components.insert(pp->components.end(), suffix.begin(), suffix.end());
e2012a7a
DB
904 pp->condition = add_condition (pp->condition, location->condition);
905 n->locations.push_back(pp);
906 }
20c6c071 907
e2012a7a
DB
908 // the token location of the alias,
909 n->tok = location->components.front()->tok;
5227f1ea 910
e2012a7a
DB
911 // and statements representing the concatenation of the alias'
912 // body with the use's.
913 //
914 // NB: locals are *not* copied forward, from either alias or
915 // use. The expansion should have its locals re-inferred since
916 // there's concatenated code here and we only want one vardecl per
917 // resulting variable.
57148ee7 918
e2012a7a
DB
919 if (alias->epilogue_style)
920 n->body = new block (use->body, alias->body);
921 else
922 n->body = new block (alias->body, use->body);
a3b4f52c 923
e2012a7a 924 unsigned old_num_results = finished_results.size();
8eb6206c
SM
925 // If expanding for an alias suffix, be sure to pass on any errors
926 // to the caller instead of printing them in derive_probes():
927 derive_probes (sess, n, finished_results, location->optional, !suffix.empty());
2c5a19c6 928
e2012a7a
DB
929 // Check whether we resolved something. If so, put the
930 // whole library into the queue if not already there.
931 if (finished_results.size() > old_num_results)
932 {
933 stapfile *f = alias->tok->location.file;
934 if (find (sess.files.begin(), sess.files.end(), f)
935 == sess.files.end())
936 sess.files.push_back (f);
2c5a19c6 937 }
e2012a7a
DB
938}
939
940bool
941alias_expansion_builder::checkForRecursiveExpansion (probe *use)
942{
943 // Collect the derivation chain of this probe.
944 vector<probe*>derivations;
945 use->collect_derivation_chain (derivations);
946
947 // Check all probe points in the alias expansion against the currently-being-expanded probe point
948 // of each of the probes in the derivation chain, looking for a match. This
949 // indicates infinite recursion.
950 // The first element of the derivation chain will be the derived_probe representing 'use', so
951 // start the search with the second element.
952 assert (derivations.size() > 0);
953 assert (derivations[0] == use);
954 for (unsigned d = 1; d < derivations.size(); ++d) {
955 if (use->get_alias() == derivations[d]->get_alias())
956 return true; // recursion detected
2c5a19c6 957 }
e2012a7a
DB
958 return false;
959}
20c6c071
GH
960
961
962// ------------------------------------------------------------------------
963// Pattern matching
964// ------------------------------------------------------------------------
965
5227f1ea
GH
966static unsigned max_recursion = 100;
967
57148ee7 968struct
5227f1ea
GH
969recursion_guard
970{
971 unsigned & i;
972 recursion_guard(unsigned & i) : i(i)
973 {
974 if (i > max_recursion)
dc09353a 975 throw SEMANTIC_ERROR(_("recursion limit reached"));
5227f1ea
GH
976 ++i;
977 }
57148ee7 978 ~recursion_guard()
5227f1ea
GH
979 {
980 --i;
981 }
982};
983
20c6c071
GH
984// The match-and-expand loop.
985void
b4ceace2
FCE
986derive_probes (systemtap_session& s,
987 probe *p, vector<derived_probe*>& dps,
8eb6206c
SM
988 bool optional,
989 bool rethrow_errors)
20c6c071
GH
990{
991 for (unsigned i = 0; i < p->locations.size(); ++i)
992 {
e19ebcf7 993 assert_no_interrupts();
49abf162 994
20c6c071 995 probe_point *loc = p->locations[i];
a971b891 996
d885563b
FCE
997 if (s.verbose > 4)
998 clog << "derive-probes " << *loc << endl;
999
fe3d01fa
FCE
1000 try
1001 {
fe3d01fa 1002 unsigned num_atbegin = dps.size();
d898100a
FCE
1003
1004 // Pass down optional flag from e.g. alias reference to each
1005 // probe_point instance. We do this by temporarily overriding
1006 // the probe_point optional flag. We could instead deep-copy
1007 // and set a flag on the copy permanently.
1008 bool old_loc_opt = loc->optional;
1009 loc->optional = loc->optional || optional;
74efda8d
WH
1010 try
1011 {
1012 s.pattern_root->find_and_build (s, p, loc, 0, dps); // <-- actual derivation!
1013 }
1014 catch (const semantic_error& e)
1015 {
1016 if (!loc->optional)
1017 throw semantic_error(e);
1018 else /* tolerate failure for optional probe */
1019 continue;
1020 }
1021
d898100a 1022 loc->optional = old_loc_opt;
fe3d01fa 1023 unsigned num_atend = dps.size();
d898100a
FCE
1024
1025 if (! (loc->optional||optional) && // something required, but
cedd10f4 1026 num_atbegin == num_atend) // nothing new derived!
dc09353a 1027 throw SEMANTIC_ERROR (_("no match"));
d898100a
FCE
1028
1029 if (loc->sufficient && (num_atend > num_atbegin))
1030 {
1031 if (s.verbose > 1)
1032 {
1033 clog << "Probe point ";
1034 p->locations[i]->print(clog);
1035 clog << " sufficient, skipped";
1036 for (unsigned j = i+1; j < p->locations.size(); ++j)
1037 {
1038 clog << " ";
1039 p->locations[j]->print(clog);
1040 }
1041 clog << endl;
1042 }
1043 break; // we need not try to derive for any other locations
1044 }
fe3d01fa
FCE
1045 }
1046 catch (const semantic_error& e)
1047 {
8eb6206c
SM
1048 // The rethrow_errors parameter lets the caller decide an
1049 // alternative to printing the error. This is necessary when
1050 // calling derive_probes() recursively during expansion of
1051 // an alias with suffix -- any message printed here would
1052 // point to the alias declaration and not the invalid suffix
1053 // usage, so the caller needs to catch the error themselves
1054 // and print a more appropriate message.
1055 if (rethrow_errors)
1056 {
e758508b 1057 throw semantic_error(e);
8eb6206c
SM
1058 }
1059 // Only output in listing if -vv is supplied:
1060 else if (!s.listing_mode || (s.listing_mode && s.verbose > 1))
68ac5d0e
FCE
1061 {
1062 // XXX: prefer not to print_error at every nest/unroll level
dc09353a 1063 semantic_error* er = new SEMANTIC_ERROR (_("while resolving probe point"),
e26c2f83
FCE
1064 loc->components[0]->tok);
1065 er->chain = & e;
68ac5d0e
FCE
1066 s.print_error (* er);
1067 delete er;
1068 }
fe3d01fa 1069 }
a971b891 1070
20c6c071
GH
1071 }
1072}
1073
b4ceace2
FCE
1074
1075
20c6c071 1076// ------------------------------------------------------------------------
67c0a579 1077//
d02548c0 1078// Indexable usage checks
67c0a579
GH
1079//
1080
d02548c0 1081struct symbol_fetcher
07c17d67 1082 : public throwing_visitor
67c0a579 1083{
d02548c0 1084 symbol *&sym;
67c0a579 1085
57148ee7 1086 symbol_fetcher (symbol *&sym): sym(sym)
67c0a579
GH
1087 {}
1088
d02548c0
GH
1089 void visit_symbol (symbol* e)
1090 {
1091 sym = e;
1092 }
1093
b0be9bdb
FCE
1094 void visit_target_symbol (target_symbol* e)
1095 {
1096 sym = e;
1097 }
1098
d02548c0
GH
1099 void visit_arrayindex (arrayindex* e)
1100 {
d15d767c 1101 e->base->visit (this);
d02548c0
GH
1102 }
1103
bd1fcbad
YZ
1104 void visit_atvar_op (atvar_op *e)
1105 {
1106 sym = e;
1107 }
1108
9b5af295
JS
1109 void visit_cast_op (cast_op* e)
1110 {
1111 sym = e;
1112 }
1113
d02548c0
GH
1114 void throwone (const token* t)
1115 {
20882639 1116 if (t->type == tok_operator && t->content == ".") // guess someone misused . in $foo->bar.baz expression
dc09353a 1117 throw SEMANTIC_ERROR (_("Expecting symbol or array index expression, try -> instead"), t);
20882639 1118 else
dc09353a 1119 throw SEMANTIC_ERROR (_("Expecting symbol or array index expression"), t);
d02548c0
GH
1120 }
1121};
1122
07c17d67 1123symbol *
d02548c0
GH
1124get_symbol_within_expression (expression *e)
1125{
1126 symbol *sym = NULL;
1127 symbol_fetcher fetcher(sym);
1128 e->visit (&fetcher);
b0be9bdb 1129 return sym; // NB: may be null!
d02548c0
GH
1130}
1131
1132static symbol *
1133get_symbol_within_indexable (indexable *ix)
1134{
1135 symbol *array = NULL;
1136 hist_op *hist = NULL;
1137 classify_indexable(ix, array, hist);
1138 if (array)
1139 return array;
1140 else
1141 return get_symbol_within_expression (hist->stat);
1142}
1143
1144struct mutated_var_collector
07c17d67 1145 : public traversing_visitor
d02548c0
GH
1146{
1147 set<vardecl *> * mutated_vars;
1148
57148ee7 1149 mutated_var_collector (set<vardecl *> * mm)
d02548c0
GH
1150 : mutated_vars (mm)
1151 {}
1152
1153 void visit_assignment(assignment* e)
1154 {
1155 if (e->type == pe_stats && e->op == "<<<")
1156 {
1157 vardecl *vd = get_symbol_within_expression (e->left)->referent;
1158 if (vd)
1159 mutated_vars->insert (vd);
1160 }
1bbeef03 1161 traversing_visitor::visit_assignment(e);
d02548c0
GH
1162 }
1163
67c0a579
GH
1164 void visit_arrayindex (arrayindex *e)
1165 {
d02548c0
GH
1166 if (is_active_lvalue (e))
1167 {
1168 symbol *sym;
1169 if (e->base->is_symbol (sym))
1170 mutated_vars->insert (sym->referent);
1171 else
dc09353a 1172 throw SEMANTIC_ERROR(_("Assignment to read-only histogram bucket"), e->tok);
d02548c0 1173 }
1bbeef03 1174 traversing_visitor::visit_arrayindex (e);
67c0a579
GH
1175 }
1176};
1177
1178
d02548c0 1179struct no_var_mutation_during_iteration_check
07c17d67 1180 : public traversing_visitor
67c0a579
GH
1181{
1182 systemtap_session & session;
d02548c0
GH
1183 map<functiondecl *,set<vardecl *> *> & function_mutates_vars;
1184 vector<vardecl *> vars_being_iterated;
57148ee7
FCE
1185
1186 no_var_mutation_during_iteration_check
67c0a579 1187 (systemtap_session & sess,
d02548c0
GH
1188 map<functiondecl *,set<vardecl *> *> & fmv)
1189 : session(sess), function_mutates_vars (fmv)
67c0a579
GH
1190 {}
1191
1192 void visit_arrayindex (arrayindex *e)
1193 {
d7f3e0c5 1194 if (is_active_lvalue(e))
67c0a579 1195 {
d02548c0
GH
1196 vardecl *vd = get_symbol_within_indexable (e->base)->referent;
1197 if (vd)
67c0a579 1198 {
d02548c0 1199 for (unsigned i = 0; i < vars_being_iterated.size(); ++i)
67c0a579 1200 {
d02548c0
GH
1201 vardecl *v = vars_being_iterated[i];
1202 if (v == vd)
1203 {
4af765b2
LB
1204 string err = _F("variable '%s' modified during 'foreach' iteration",
1205 v->name.c_str());
dc09353a 1206 session.print_error (SEMANTIC_ERROR (err, e->tok));
d02548c0 1207 }
67c0a579
GH
1208 }
1209 }
1210 }
1bbeef03 1211 traversing_visitor::visit_arrayindex (e);
67c0a579
GH
1212 }
1213
1214 void visit_functioncall (functioncall* e)
1215 {
57148ee7 1216 map<functiondecl *,set<vardecl *> *>::const_iterator i
d02548c0 1217 = function_mutates_vars.find (e->referent);
67c0a579 1218
d02548c0 1219 if (i != function_mutates_vars.end())
67c0a579 1220 {
d02548c0 1221 for (unsigned j = 0; j < vars_being_iterated.size(); ++j)
67c0a579 1222 {
d02548c0 1223 vardecl *m = vars_being_iterated[j];
67c0a579
GH
1224 if (i->second->find (m) != i->second->end())
1225 {
4af765b2
LB
1226 string err = _F("function call modifies var '%s' during 'foreach' iteration",
1227 m->name.c_str());
dc09353a 1228 session.print_error (SEMANTIC_ERROR (err, e->tok));
67c0a579
GH
1229 }
1230 }
1231 }
1232
1bbeef03 1233 traversing_visitor::visit_functioncall (e);
67c0a579
GH
1234 }
1235
1236 void visit_foreach_loop(foreach_loop* s)
1237 {
d02548c0
GH
1238 vardecl *vd = get_symbol_within_indexable (s->base)->referent;
1239
1240 if (vd)
1241 vars_being_iterated.push_back (vd);
57148ee7 1242
1bbeef03 1243 traversing_visitor::visit_foreach_loop (s);
d02548c0
GH
1244
1245 if (vd)
1246 vars_being_iterated.pop_back();
67c0a579
GH
1247 }
1248};
20c6c071 1249
2b066ec1 1250
67c0a579
GH
1251// ------------------------------------------------------------------------
1252
07c17d67
GH
1253struct stat_decl_collector
1254 : public traversing_visitor
1255{
1256 systemtap_session & session;
57148ee7 1257
07c17d67
GH
1258 stat_decl_collector(systemtap_session & sess)
1259 : session(sess)
1260 {}
1261
1262 void visit_stat_op (stat_op* e)
1263 {
1264 symbol *sym = get_symbol_within_expression (e->stat);
1265 if (session.stat_decls.find(sym->name) == session.stat_decls.end())
1266 session.stat_decls[sym->name] = statistic_decl();
1267 }
1268
1269 void visit_assignment (assignment* e)
1270 {
1271 if (e->op == "<<<")
1272 {
1273 symbol *sym = get_symbol_within_expression (e->left);
1274 if (session.stat_decls.find(sym->name) == session.stat_decls.end())
1275 session.stat_decls[sym->name] = statistic_decl();
1276 }
1277 else
1278 traversing_visitor::visit_assignment(e);
1279 }
1280
1281 void visit_hist_op (hist_op* e)
1282 {
1283 symbol *sym = get_symbol_within_expression (e->stat);
1284 statistic_decl new_stat;
1285
1286 if (e->htype == hist_linear)
1287 {
1288 new_stat.type = statistic_decl::linear;
1289 assert (e->params.size() == 3);
1290 new_stat.linear_low = e->params[0];
1291 new_stat.linear_high = e->params[1];
1292 new_stat.linear_step = e->params[2];
1293 }
1294 else
1295 {
1296 assert (e->htype == hist_log);
1297 new_stat.type = statistic_decl::logarithmic;
e38723d2 1298 assert (e->params.size() == 0);
07c17d67
GH
1299 }
1300
1301 map<string, statistic_decl>::iterator i = session.stat_decls.find(sym->name);
1302 if (i == session.stat_decls.end())
1303 session.stat_decls[sym->name] = new_stat;
1304 else
1305 {
1306 statistic_decl & old_stat = i->second;
1307 if (!(old_stat == new_stat))
1308 {
1309 if (old_stat.type == statistic_decl::none)
1310 i->second = new_stat;
1311 else
1312 {
1313 // FIXME: Support multiple co-declared histogram types
dc09353a 1314 semantic_error se(ERR_SRC, _F("multiple histogram types declared on '%s'", sym->name.c_str()), e->tok);
07c17d67
GH
1315 session.print_error (se);
1316 }
1317 }
57148ee7 1318 }
07c17d67
GH
1319 }
1320
1321};
1322
1323static int
1324semantic_pass_stats (systemtap_session & sess)
1325{
1326 stat_decl_collector sdc(sess);
1327
f76427a2
FCE
1328 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
1329 it->second->body->visit (&sdc);
07c17d67 1330
57148ee7 1331 for (unsigned i = 0; i < sess.probes.size(); ++i)
07c17d67
GH
1332 sess.probes[i]->body->visit (&sdc);
1333
1334 for (unsigned i = 0; i < sess.globals.size(); ++i)
1335 {
1336 vardecl *v = sess.globals[i];
1337 if (v->type == pe_stats)
1338 {
57148ee7 1339
07c17d67
GH
1340 if (sess.stat_decls.find(v->name) == sess.stat_decls.end())
1341 {
dc09353a 1342 semantic_error se(ERR_SRC, _F("unable to infer statistic parameters for global '%s'", v->name.c_str()));
07c17d67
GH
1343 sess.print_error (se);
1344 }
1345 }
1346 }
57148ee7 1347
7e41d3dc 1348 return sess.num_errors();
07c17d67
GH
1349}
1350
5d23847d
FCE
1351// ------------------------------------------------------------------------
1352
1353// Enforce variable-related invariants: no modification of
1354// a foreach()-iterated array.
1355static int
1356semantic_pass_vars (systemtap_session & sess)
1357{
57148ee7 1358
5d23847d
FCE
1359 map<functiondecl *, set<vardecl *> *> fmv;
1360 no_var_mutation_during_iteration_check chk(sess, fmv);
57148ee7 1361
f76427a2 1362 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
5d23847d 1363 {
f76427a2 1364 functiondecl * fn = it->second;
5d23847d
FCE
1365 if (fn->body)
1366 {
1367 set<vardecl *> * m = new set<vardecl *>();
1368 mutated_var_collector mc (m);
1369 fn->body->visit (&mc);
1370 fmv[fn] = m;
1371 }
1372 }
1373
f76427a2 1374 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
5d23847d 1375 {
f76427a2
FCE
1376 functiondecl * fn = it->second;
1377 if (fn->body) fn->body->visit (&chk);
5d23847d
FCE
1378 }
1379
1380 for (unsigned i = 0; i < sess.probes.size(); ++i)
1381 {
1382 if (sess.probes[i]->body)
1383 sess.probes[i]->body->visit (&chk);
57148ee7 1384 }
5d23847d
FCE
1385
1386 return sess.num_errors();
1387}
1388
1389
1390// ------------------------------------------------------------------------
1391
1392// Rewrite probe condition expressions into probe bodies. Tricky and
1393// exciting business, this. This:
1394//
1395// probe foo if (g1 || g2) { ... }
1396// probe bar { ... g1 ++ ... }
1397//
1398// becomes:
1399//
1400// probe begin(MAX) { if (! (g1 || g2)) %{ disable_probe_foo %} }
1401// probe foo { if (! (g1 || g2)) next; ... }
57148ee7 1402// probe bar { ... g1 ++ ...;
5d23847d
FCE
1403// if (g1 || g2) %{ enable_probe_foo %} else %{ disable_probe_foo %}
1404// }
1405//
1406// XXX: As a first cut, do only the "inline probe condition" part of the
1407// transform.
1408
1409static int
1410semantic_pass_conditions (systemtap_session & sess)
1411{
1412 for (unsigned i = 0; i < sess.probes.size(); ++i)
1413 {
1414 derived_probe* p = sess.probes[i];
1415 expression* e = p->sole_location()->condition;
1416 if (e)
1417 {
313db8e6 1418 varuse_collecting_visitor vut(sess);
5d23847d
FCE
1419 e->visit (& vut);
1420
1421 if (! vut.written.empty())
1422 {
4af765b2 1423 string err = (_("probe condition must not modify any variables"));
dc09353a 1424 sess.print_error (SEMANTIC_ERROR (err, e->tok));
5d23847d
FCE
1425 }
1426 else if (vut.embedded_seen)
1427 {
dc09353a 1428 sess.print_error (SEMANTIC_ERROR (_("probe condition must not include impure embedded-C"), e->tok));
5d23847d
FCE
1429 }
1430
1431 // Add the condition expression to the front of the
1432 // derived_probe body.
1433 if_statement *ifs = new if_statement ();
1434 ifs->tok = e->tok;
1435 ifs->thenblock = new next_statement ();
1436 ifs->thenblock->tok = e->tok;
1437 ifs->elseblock = NULL;
1438 unary_expression *notex = new unary_expression ();
1439 notex->op = "!";
1440 notex->tok = e->tok;
1441 notex->operand = e;
1442 ifs->condition = notex;
ba6f838d 1443 p->body = new block (ifs, p->body);
5d23847d 1444 }
57148ee7 1445 }
5d23847d
FCE
1446
1447 return sess.num_errors();
1448}
1449
ac9ca50a
MW
1450// ------------------------------------------------------------------------
1451
1452
1453// Simple visitor that just goes through all embedded code blocks that
1454// are available at the end all the optimizations to register any
1455// relevant pragmas or other indicators found, so that session flags can
1456// be set that can be inspected at translation time to trigger any
1457// necessary initialization of code needed by the embedded code functions.
1458
1459// This is only for pragmas that don't have any other side-effect than
8af41ec2
MW
1460// needing some initialization at module init time. Currently handles
1461// /* pragma:vma */ /* pragma:unwind */ /* pragma:symbol */
ac9ca50a
MW
1462
1463// /* pragma:uprobes */ is handled during the typeresolution_info pass.
2363d2a5
DB
1464// /* pure */, /* unprivileged */. /* myproc-unprivileged */ and /* guru */
1465// are handled by the varuse_collecting_visitor.
ac9ca50a
MW
1466
1467struct embeddedcode_info: public functioncall_traversing_visitor
1468{
1469protected:
1470 systemtap_session& session;
1471
1472public:
1473 embeddedcode_info (systemtap_session& s): session(s) { }
1474
1475 void visit_embeddedcode (embeddedcode* c)
1476 {
a057c85c 1477 if (! vma_tracker_enabled(session)
ac9ca50a
MW
1478 && c->code.find("/* pragma:vma */") != string::npos)
1479 {
ac9ca50a 1480 if (session.verbose > 2)
4af765b2
LB
1481 clog << _F("Turning on task_finder vma_tracker, pragma:vma found in %s",
1482 current_function->name.c_str()) << endl;
7f085e3f
JS
1483
1484 // PR15052: stapdyn doesn't have VMA-tracking yet.
1485 if (session.runtime_usermode_p())
dc09353a 1486 throw SEMANTIC_ERROR(_("VMA-tracking is only supported by the kernel runtime (PR15052)"), c->tok);
7f085e3f
JS
1487
1488 enable_vma_tracker(session);
ac9ca50a 1489 }
08badca8
MW
1490
1491 if (! session.need_unwind
1492 && c->code.find("/* pragma:unwind */") != string::npos)
1493 {
1494 if (session.verbose > 2)
1495 clog << _F("Turning on unwind support, pragma:unwind found in %s",
1496 current_function->name.c_str()) << endl;
8af41ec2
MW
1497 session.need_unwind = true;
1498 }
1499
1500 if (! session.need_symbols
1501 && c->code.find("/* pragma:symbols */") != string::npos)
1502 {
1503 if (session.verbose > 2)
1504 clog << _F("Turning on symbol data collecting, pragma:symbols found in %s",
1505 current_function->name.c_str()) << endl;
1506 session.need_symbols = true;
1507 }
ac9ca50a
MW
1508 }
1509};
1510
1511void embeddedcode_info_pass (systemtap_session& s)
1512{
1513 embeddedcode_info eci (s);
1514 for (unsigned i=0; i<s.probes.size(); i++)
1515 s.probes[i]->body->visit (& eci);
1516}
5d23847d 1517
07c17d67
GH
1518// ------------------------------------------------------------------------
1519
2b066ec1 1520
d2548fe7
SM
1521// Simple visitor that collects all the regular expressions in the
1522// file and adds them to the session DFA table.
1523
1524struct regex_collecting_visitor: public functioncall_traversing_visitor
1525{
1526protected:
1527 systemtap_session& session;
1528
1529public:
1530 regex_collecting_visitor (systemtap_session& s): session(s) { }
1531
1532 void visit_regex_query (regex_query *q) {
d3bc48f0 1533 functioncall_traversing_visitor::visit_regex_query (q);
d2548fe7 1534
60cf5fae
SM
1535 string re = q->right->value;
1536 regex_to_stapdfa (&session, re, q->right->tok);
d2548fe7
SM
1537 }
1538};
1539
1540// Go through the regex match invocations and generate corresponding DFAs.
e471dfb0 1541int gen_dfa_table (systemtap_session& s)
d2548fe7 1542{
e471dfb0 1543 regex_collecting_visitor rcv(s);
d2548fe7
SM
1544
1545 for (unsigned i=0; i<s.probes.size(); i++)
1546 {
e471dfb0
SM
1547 try
1548 {
1549 s.probes[i]->body->visit (& rcv);
1550
1551 if (s.probes[i]->sole_location()->condition)
1552 s.probes[i]->sole_location()->condition->visit (& rcv);
1553 }
1554 catch (const semantic_error& e)
1555 {
1556 s.print_error (e);
1557 }
d2548fe7 1558 }
e471dfb0
SM
1559
1560 return s.num_errors();
d2548fe7
SM
1561}
1562
1563// ------------------------------------------------------------------------
1564
1565
2b066ec1 1566static int semantic_pass_symbols (systemtap_session&);
c214bd6a
DS
1567static int semantic_pass_optimize1 (systemtap_session&);
1568static int semantic_pass_optimize2 (systemtap_session&);
2b066ec1 1569static int semantic_pass_types (systemtap_session&);
d02548c0 1570static int semantic_pass_vars (systemtap_session&);
07c17d67 1571static int semantic_pass_stats (systemtap_session&);
5d23847d 1572static int semantic_pass_conditions (systemtap_session&);
2b066ec1
FCE
1573
1574
1575// Link up symbols to their declarations. Set the session's
1576// files/probes/functions/globals vectors from the transitively
1577// reached set of stapfiles in s.library_files, starting from
20c6c071 1578// s.user_file. Perform automatic tapset inclusion and probe
2b066ec1
FCE
1579// alias expansion.
1580static int
1581semantic_pass_symbols (systemtap_session& s)
1582{
1583 symresolution_info sym (s);
1584
1585 // NB: s.files can grow during this iteration, so size() can
1586 // return gradually increasing numbers.
1587 s.files.push_back (s.user_file);
1588 for (unsigned i = 0; i < s.files.size(); i++)
1589 {
e19ebcf7 1590 assert_no_interrupts();
2b066ec1
FCE
1591 stapfile* dome = s.files[i];
1592
1593 // Pass 1: add globals and functions to systemtap-session master list,
1594 // so the find_* functions find them
e26c2f83
FCE
1595 //
1596 // NB: tapset global/function definitions may duplicate or conflict
1597 // with those already in s.globals/functions. We need to deconflict
1598 // here.
2b066ec1
FCE
1599
1600 for (unsigned i=0; i<dome->globals.size(); i++)
e26c2f83
FCE
1601 {
1602 vardecl* g = dome->globals[i];
1603 for (unsigned j=0; j<s.globals.size(); j++)
1604 {
1605 vardecl* g2 = s.globals[j];
1606 if (g->name == g2->name)
1607 {
dc09353a 1608 s.print_error (SEMANTIC_ERROR (_("conflicting global variables"),
e26c2f83
FCE
1609 g->tok, g2->tok));
1610 }
1611 }
1612 s.globals.push_back (g);
1613 }
2b066ec1
FCE
1614
1615 for (unsigned i=0; i<dome->functions.size(); i++)
e26c2f83
FCE
1616 {
1617 functiondecl* f = dome->functions[i];
1618 functiondecl* f2 = s.functions[f->name];
1619 if (f2 && f != f2)
1620 {
dc09353a 1621 s.print_error (SEMANTIC_ERROR (_("conflicting functions"),
e26c2f83
FCE
1622 f->tok, f2->tok));
1623 }
1624 s.functions[f->name] = f;
1625 }
2b066ec1 1626
e26c2f83 1627 // NB: embeds don't conflict with each other
54dfabe9
FCE
1628 for (unsigned i=0; i<dome->embeds.size(); i++)
1629 s.embeds.push_back (dome->embeds[i]);
1630
f8809d54 1631 // Pass 2: derive probes and resolve any further symbols in the
57148ee7 1632 // derived results.
2b066ec1
FCE
1633
1634 for (unsigned i=0; i<dome->probes.size(); i++)
1635 {
e19ebcf7 1636 assert_no_interrupts();
2b066ec1
FCE
1637 probe* p = dome->probes [i];
1638 vector<derived_probe*> dps;
1639
a971b891
FCE
1640 // much magic happens here: probe alias expansion, wildcard
1641 // matching, low-level derived_probe construction.
b4ceace2 1642 derive_probes (s, p, dps);
2b066ec1
FCE
1643
1644 for (unsigned j=0; j<dps.size(); j++)
1645 {
e19ebcf7 1646 assert_no_interrupts();
2b066ec1 1647 derived_probe* dp = dps[j];
b20febf3
FCE
1648 s.probes.push_back (dp);
1649 dp->join_group (s);
2b066ec1 1650
57148ee7 1651 try
2b066ec1 1652 {
f80d9004 1653 for (unsigned k=0; k<s.code_filters.size(); k++)
8b095b45 1654 s.code_filters[k]->replace (dp->body);
f80d9004 1655
2b066ec1 1656 sym.current_function = 0;
5227f1ea 1657 sym.current_probe = dp;
2b066ec1 1658 dp->body->visit (& sym);
5d23847d
FCE
1659
1660 // Process the probe-point condition expression.
1661 sym.current_function = 0;
1662 sym.current_probe = 0;
1663 if (dp->sole_location()->condition)
1664 dp->sole_location()->condition->visit (& sym);
2b066ec1
FCE
1665 }
1666 catch (const semantic_error& e)
1667 {
1668 s.print_error (e);
1669 }
1670 }
1671 }
f8809d54
JS
1672
1673 // Pass 3: process functions
1674
1675 for (unsigned i=0; i<dome->functions.size(); i++)
1676 {
e19ebcf7 1677 assert_no_interrupts();
f8809d54
JS
1678 functiondecl* fd = dome->functions[i];
1679
1680 try
1681 {
1682 for (unsigned j=0; j<s.code_filters.size(); j++)
1683 s.code_filters[j]->replace (fd->body);
1684
1685 sym.current_function = fd;
1686 sym.current_probe = 0;
1687 fd->body->visit (& sym);
1688 }
1689 catch (const semantic_error& e)
1690 {
1691 s.print_error (e);
1692 }
1693 }
2b066ec1 1694 }
aa30ccd3
FCE
1695
1696 // Inform all derived_probe builders that we're done with
1697 // all resolution, so it's time to release caches.
1698 s.pattern_root->build_no_more (s);
57148ee7 1699
a07a2c28
LB
1700 if(s.systemtap_v_check){
1701 for(unsigned i=0;i<s.globals.size();i++){
1702 if(s.globals[i]->systemtap_v_conditional)
4af765b2 1703 s.print_warning(_("This global uses tapset constructs that are dependent on systemtap version"), s.globals[i]->tok);
a07a2c28
LB
1704 }
1705
1706 for(map<string, functiondecl*>::const_iterator i=s.functions.begin();i != s.functions.end();++i){
1707 if(i->second->systemtap_v_conditional)
4af765b2 1708 s.print_warning(_("This function uses tapset constructs that are dependent on systemtap version"), i->second->tok);
a07a2c28
LB
1709 }
1710
1711 for(unsigned i=0;i<s.probes.size();i++){
1712 vector<probe*> sysvc;
1713 s.probes[i]->collect_derivation_chain(sysvc);
1714 for(unsigned j=0;j<sysvc.size();j++){
1715 if(sysvc[j]->systemtap_v_conditional)
4af765b2 1716 s.print_warning(_("This probe uses tapset constructs that are dependent on systemtap version"), sysvc[j]->tok);
a07a2c28 1717 if(sysvc[j]->get_alias() && sysvc[j]->get_alias()->systemtap_v_conditional)
4af765b2 1718 s.print_warning(_("This alias uses tapset constructs that are dependent on systemtap version"), sysvc[j]->get_alias()->tok);
a07a2c28
LB
1719 }
1720 }
1721 }
1722
7e41d3dc 1723 return s.num_errors(); // all those print_error calls
2b066ec1
FCE
1724}
1725
1726
0a102c82
SC
1727// Keep unread global variables for probe end value display.
1728void add_global_var_display (systemtap_session& s)
1729{
5ae31731
FCE
1730 // Don't generate synthetic end probes when in listings mode;
1731 // it would clutter up the list of probe points with "end ...".
1732 if (s.listing_mode) return;
3438f38f 1733
313db8e6 1734 varuse_collecting_visitor vut(s);
9d8a6ba3 1735
0a102c82
SC
1736 for (unsigned i=0; i<s.probes.size(); i++)
1737 {
1738 s.probes[i]->body->visit (& vut);
1739
1740 if (s.probes[i]->sole_location()->condition)
1741 s.probes[i]->sole_location()->condition->visit (& vut);
1742 }
1743
1744 for (unsigned g=0; g < s.globals.size(); g++)
1745 {
1746 vardecl* l = s.globals[g];
9d8a6ba3
SC
1747 if ((vut.read.find (l) != vut.read.end()
1748 && vut.used.find (l) != vut.used.end())
e491a713 1749 || vut.written.find (l) == vut.written.end())
0a102c82
SC
1750 continue;
1751
b5852334 1752 // Don't generate synthetic end probes for unread globals
5ae31731
FCE
1753 // declared only within tapsets. (RHBZ 468139), but rather
1754 // only within the end-user script.
1755
7584f162
RA
1756 bool tapset_global = false;
1757 for (size_t m=0; m < s.library_files.size(); m++)
1758 {
1759 for (size_t n=0; n < s.library_files[m]->globals.size(); n++)
1760 {
1761 if (l->name == s.library_files[m]->globals[n]->name)
1762 {tapset_global = true; break;}
1763 }
1764 }
1765 if (tapset_global)
1766 continue;
5ae31731 1767
0a102c82 1768 probe_point::component* c = new probe_point::component("end");
d5e178c1
JS
1769 probe_point* pl = new probe_point;
1770 pl->components.push_back (c);
1771
0a102c82 1772 vector<derived_probe*> dps;
6d2685fe 1773 block *b = new block;
ead25cf5 1774 b->tok = l->tok;
0a102c82 1775
d5e178c1 1776 probe* p = new probe;
db48cbe9 1777 p->tok = l->tok;
0a102c82 1778 p->locations.push_back (pl);
0a102c82
SC
1779
1780 // Create a symbol
1781 symbol* g_sym = new symbol;
1782 g_sym->name = l->name;
1783 g_sym->tok = l->tok;
1784 g_sym->type = l->type;
57148ee7 1785 g_sym->referent = l;
0a102c82 1786
ead25cf5 1787 token* print_tok = new token(*l->tok);
d5e178c1
JS
1788 print_tok->type = tok_identifier;
1789 print_tok->content = "printf";
1790
1791 print_format* pf = print_format::create(print_tok);
0a102c82 1792 pf->raw_components += l->name;
0a102c82
SC
1793
1794 if (l->index_types.size() == 0) // Scalar
1795 {
e071e49b 1796 if (l->type == pe_stats)
49060244
WC
1797 if (strverscmp(s.compatible.c_str(), "1.4") >= 0)
1798 pf->raw_components += " @count=%#d @min=%#d @max=%#d @sum=%#d @avg=%#d\\n";
1799 else
1800 pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n";
e071e49b 1801 else if (l->type == pe_string)
0a102c82
SC
1802 pf->raw_components += "=\"%#s\"\\n";
1803 else
1804 pf->raw_components += "=%#x\\n";
0a102c82
SC
1805 pf->components = print_format::string_to_components(pf->raw_components);
1806 expr_statement* feb = new expr_statement;
1807 feb->value = pf;
1808 feb->tok = print_tok;
e071e49b
SC
1809 if (l->type == pe_stats)
1810 {
1811 struct stat_op* so [5];
1812 const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average};
1813
1814 for (unsigned si = 0;
1815 si < (sizeof(so)/sizeof(struct stat_op*));
1816 si++)
1817 {
1818 so[si]= new stat_op;
1819 so[si]->ctype = stypes[si];
1820 so[si]->type = pe_long;
1821 so[si]->stat = g_sym;
1822 so[si]->tok = l->tok;
1823 pf->args.push_back(so[si]);
1824 }
1825 }
1826 else
1827 pf->args.push_back(g_sym);
271d408e
WH
1828
1829 /* PR7053: Checking empty aggregate for global variable */
1830 if (l->type == pe_stats) {
1831 stat_op *so= new stat_op;
1832 so->ctype = sc_count;
1833 so->type = pe_long;
1834 so->stat = g_sym;
1835 so->tok = l->tok;
1836 comparison *be = new comparison;
1837 be->op = ">";
1838 be->tok = l->tok;
1839 be->left = so;
1840 be->right = new literal_number(0);
1841
1842 /* Create printf @count=0x0 in else block */
d5e178c1 1843 print_format* pf_0 = print_format::create(print_tok);
271d408e
WH
1844 pf_0->raw_components += l->name;
1845 pf_0->raw_components += " @count=0x0\\n";
271d408e
WH
1846 pf_0->components = print_format::string_to_components(pf_0->raw_components);
1847 expr_statement* feb_else = new expr_statement;
1848 feb_else->value = pf_0;
1849 feb_else->tok = print_tok;
1850 if_statement *ifs = new if_statement;
1851 ifs->tok = l->tok;
1852 ifs->condition = be;
1853 ifs->thenblock = feb ;
1854 ifs->elseblock = feb_else;
1855 b->statements.push_back(ifs);
1856 }
1857 else /* other non-stat cases */
1858 b->statements.push_back(feb);
0a102c82
SC
1859 }
1860 else // Array
1861 {
1862 int idx_count = l->index_types.size();
0a102c82
SC
1863 symbol* idx_sym[idx_count];
1864 vardecl* idx_v[idx_count];
1865 // Create a foreach loop
0a102c82 1866 foreach_loop* fe = new foreach_loop;
e91b23bc
FCE
1867 fe->sort_direction = -1; // imply decreasing sort on value
1868 fe->sort_column = 0; // as in foreach ([a,b,c] in array-) { }
1cdda92d 1869 fe->sort_aggr = sc_none; // as in default @count
c261711d 1870 fe->value = NULL;
0a102c82 1871 fe->limit = NULL;
ead25cf5 1872 fe->tok = l->tok;
0a102c82
SC
1873
1874 // Create indices for the foreach loop
1875 for (int i=0; i < idx_count; i++)
1876 {
0a102c82 1877 char *idx_name;
4310926e
LB
1878 if (asprintf (&idx_name, "idx%d", i) < 0) {
1879 delete pf;
1880 delete b;
1881 delete p;
1882 delete g_sym;
1883 delete fe;
1884 return;
1885 }
0a102c82 1886 idx_sym[i] = new symbol;
0a102c82 1887 idx_sym[i]->name = idx_name;
db48cbe9 1888 idx_sym[i]->tok = l->tok;
0a102c82
SC
1889 idx_v[i] = new vardecl;
1890 idx_v[i]->name = idx_name;
0a102c82 1891 idx_v[i]->type = l->index_types[i];
db48cbe9 1892 idx_v[i]->tok = l->tok;
0a102c82
SC
1893 idx_sym[i]->referent = idx_v[i];
1894 fe->indexes.push_back (idx_sym[i]);
1895 }
1896
1897 // Create a printf for the foreach loop
ead25cf5 1898 pf->raw_components += "[";
0a102c82 1899 for (int i=0; i < idx_count; i++)
ead25cf5
JS
1900 {
1901 if (i > 0)
1902 pf->raw_components += ",";
1903 if (l->index_types[i] == pe_string)
1904 pf->raw_components += "\"%#s\"";
1905 else
1906 pf->raw_components += "%#d";
1907 }
1908 pf->raw_components += "]";
e491a713 1909 if (l->type == pe_stats)
49060244
WC
1910 if (strverscmp(s.compatible.c_str(), "1.4") >= 0)
1911 pf->raw_components += " @count=%#d @min=%#d @max=%#d @sum=%#d @avg=%#d\\n";
1912 else
1913 pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n";
e491a713 1914 else if (l->type == pe_string)
0a102c82
SC
1915 pf->raw_components += "=\"%#s\"\\n";
1916 else
1917 pf->raw_components += "=%#x\\n";
1918
1919 // Create an index for the array
1920 struct arrayindex* ai = new arrayindex;
1921 ai->tok = l->tok;
1922 ai->base = g_sym;
e491a713 1923
0a102c82
SC
1924 for (int i=0; i < idx_count; i++)
1925 {
1926 ai->indexes.push_back (idx_sym[i]);
1927 pf->args.push_back(idx_sym[i]);
1928 }
e491a713
SC
1929 if (l->type == pe_stats)
1930 {
1931 struct stat_op* so [5];
e491a713 1932 const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average};
e071e49b
SC
1933
1934 ai->type = pe_stats;
db48cbe9
SC
1935 for (unsigned si = 0;
1936 si < (sizeof(so)/sizeof(struct stat_op*));
1937 si++)
e491a713
SC
1938 {
1939 so[si]= new stat_op;
1940 so[si]->ctype = stypes[si];
1941 so[si]->type = pe_long;
1942 so[si]->stat = ai;
db48cbe9 1943 so[si]->tok = l->tok;
e071e49b 1944 pf->args.push_back(so[si]);
e491a713 1945 }
e491a713
SC
1946 }
1947 else
c261711d
JS
1948 {
1949 // Create value for the foreach loop
1950 fe->value = new symbol;
1951 fe->value->name = "val";
1952 fe->value->tok = l->tok;
1953 pf->args.push_back(fe->value);
1954 }
57148ee7 1955
0a102c82
SC
1956 pf->components = print_format::string_to_components(pf->raw_components);
1957 expr_statement* feb = new expr_statement;
1958 feb->value = pf;
ead25cf5 1959 feb->tok = l->tok;
0a102c82
SC
1960 fe->base = g_sym;
1961 fe->block = (statement*)feb;
1962 b->statements.push_back(fe);
0a102c82
SC
1963 }
1964
0a102c82 1965 // Add created probe
6d2685fe
SC
1966 p->body = b;
1967 derive_probes (s, p, dps);
0a102c82
SC
1968 for (unsigned i = 0; i < dps.size(); i++)
1969 {
1970 derived_probe* dp = dps[i];
1971 s.probes.push_back (dp);
1972 dp->join_group (s);
1973 }
6d2685fe
SC
1974 // Repopulate symbol and type info
1975 symresolution_info sym (s);
1976 sym.current_function = 0;
1977 sym.current_probe = dps[0];
1978 dps[0]->body->visit (& sym);
0a102c82 1979
6d2685fe
SC
1980 semantic_pass_types(s);
1981 // Mark that variable is read
0a102c82
SC
1982 vut.read.insert (l);
1983 }
1984}
2b066ec1
FCE
1985
1986int
1987semantic_pass (systemtap_session& s)
1988{
59bafbe8 1989 int rc = 0;
20c6c071 1990
57148ee7 1991 try
59bafbe8
FCE
1992 {
1993 s.register_library_aliases();
1994 register_standard_tapsets(s);
57148ee7 1995
5d23847d
FCE
1996 if (rc == 0) rc = semantic_pass_symbols (s);
1997 if (rc == 0) rc = semantic_pass_conditions (s);
c0f56268 1998 if (rc == 0) rc = semantic_pass_optimize1 (s);
59bafbe8 1999 if (rc == 0) rc = semantic_pass_types (s);
e471dfb0 2000 if (rc == 0) rc = gen_dfa_table(s);
0a102c82 2001 if (rc == 0) add_global_var_display (s);
c0f56268 2002 if (rc == 0) rc = semantic_pass_optimize2 (s);
d02548c0 2003 if (rc == 0) rc = semantic_pass_vars (s);
07c17d67 2004 if (rc == 0) rc = semantic_pass_stats (s);
7b8548ee 2005 if (rc == 0) embeddedcode_info_pass (s);
57148ee7 2006
8c938ec7 2007 if (s.num_errors() == 0 && s.probes.size() == 0 && !s.listing_mode)
dc09353a 2008 throw SEMANTIC_ERROR (_("no probes found"));
59bafbe8
FCE
2009 }
2010 catch (const semantic_error& e)
2011 {
2012 s.print_error (e);
21beacc9 2013 rc ++;
59bafbe8 2014 }
57148ee7 2015
f119a57f 2016 // PR11443
f5b1b8bc
JS
2017 // NB: listing mode only cares whether we have any probes,
2018 // so all previous error conditions are disregarded.
2019 if (s.listing_mode)
2020 rc = s.probes.empty();
f119a57f 2021
2b066ec1
FCE
2022 return rc;
2023}
2024
2025
2b066ec1
FCE
2026// ------------------------------------------------------------------------
2027// semantic processing: symbol resolution
2028
2029
2030symresolution_info::symresolution_info (systemtap_session& s):
5227f1ea 2031 session (s), current_function (0), current_probe (0)
2b066ec1
FCE
2032{
2033}
2034
2035
2036void
2037symresolution_info::visit_block (block* e)
2038{
2039 for (unsigned i=0; i<e->statements.size(); i++)
2040 {
57148ee7 2041 try
2b066ec1
FCE
2042 {
2043 e->statements[i]->visit (this);
2044 }
2045 catch (const semantic_error& e)
2046 {
2047 session.print_error (e);
2048 }
2049 }
2050}
2051
2052
69c68955
FCE
2053void
2054symresolution_info::visit_foreach_loop (foreach_loop* e)
2055{
2056 for (unsigned i=0; i<e->indexes.size(); i++)
2057 e->indexes[i]->visit (this);
2058
57148ee7 2059 symbol *array = NULL;
d02548c0
GH
2060 hist_op *hist = NULL;
2061 classify_indexable (e->base, array, hist);
69c68955 2062
d02548c0
GH
2063 if (array)
2064 {
2065 if (!array->referent)
57148ee7 2066 {
2e526dab 2067 vardecl* d = find_var (array->name, e->indexes.size (), array->tok);
d02548c0
GH
2068 if (d)
2069 array->referent = d;
2070 else
60bebf58
JS
2071 {
2072 stringstream msg;
4af765b2
LB
2073 msg << _F("unresolved arity-%zu global array %s, missing global declaration?",
2074 e->indexes.size(), array->name.c_str());
dc09353a 2075 throw SEMANTIC_ERROR (msg.str(), e->tok);
60bebf58 2076 }
d02548c0
GH
2077 }
2078 }
57148ee7 2079 else
d02548c0
GH
2080 {
2081 assert (hist);
2082 hist->visit (this);
2083 }
69c68955 2084
c261711d
JS
2085 if (e->value)
2086 e->value->visit (this);
2087
27f21e8c
DS
2088 if (e->limit)
2089 e->limit->visit (this);
2090
69c68955
FCE
2091 e->block->visit (this);
2092}
2093
d02548c0 2094
57148ee7 2095struct
d98d459c
GH
2096delete_statement_symresolution_info:
2097 public traversing_visitor
2098{
2099 symresolution_info *parent;
2100
2101 delete_statement_symresolution_info (symresolution_info *p):
2102 parent(p)
2103 {}
2104
2105 void visit_arrayindex (arrayindex* e)
2106 {
2107 parent->visit_arrayindex (e);
2108 }
2109 void visit_functioncall (functioncall* e)
2110 {
2111 parent->visit_functioncall (e);
2112 }
2113
2114 void visit_symbol (symbol* e)
2115 {
2116 if (e->referent)
2117 return;
57148ee7 2118
2e526dab 2119 vardecl* d = parent->find_var (e->name, -1, e->tok);
d98d459c
GH
2120 if (d)
2121 e->referent = d;
2122 else
dc09353a 2123 throw SEMANTIC_ERROR (_("unresolved array in delete statement"), e->tok);
d98d459c
GH
2124 }
2125};
2126
57148ee7 2127void
d98d459c
GH
2128symresolution_info::visit_delete_statement (delete_statement* s)
2129{
2130 delete_statement_symresolution_info di (this);
2131 s->value->visit (&di);
2132}
2133
69c68955 2134
2b066ec1
FCE
2135void
2136symresolution_info::visit_symbol (symbol* e)
2137{
2138 if (e->referent)
2139 return;
2140
2e526dab 2141 vardecl* d = find_var (e->name, 0, e->tok);
2b066ec1
FCE
2142 if (d)
2143 e->referent = d;
2144 else
2145 {
2146 // new local
2147 vardecl* v = new vardecl;
2148 v->name = e->name;
2149 v->tok = e->tok;
58701b78 2150 v->set_arity(0, e->tok);
2b066ec1
FCE
2151 if (current_function)
2152 current_function->locals.push_back (v);
2153 else if (current_probe)
2154 current_probe->locals.push_back (v);
2155 else
5d23847d 2156 // must be probe-condition expression
dc09353a 2157 throw SEMANTIC_ERROR (_("probe condition must not reference undeclared global"), e->tok);
2b066ec1
FCE
2158 e->referent = v;
2159 }
2160}
2161
2162
2163void
2164symresolution_info::visit_arrayindex (arrayindex* e)
2165{
2166 for (unsigned i=0; i<e->indexes.size(); i++)
2167 e->indexes[i]->visit (this);
2168
57148ee7 2169 symbol *array = NULL;
d02548c0
GH
2170 hist_op *hist = NULL;
2171 classify_indexable(e->base, array, hist);
2b066ec1 2172
d02548c0 2173 if (array)
313b2f74 2174 {
d02548c0
GH
2175 if (array->referent)
2176 return;
2177
2e526dab 2178 vardecl* d = find_var (array->name, e->indexes.size (), array->tok);
d02548c0
GH
2179 if (d)
2180 array->referent = d;
313b2f74 2181 else
d02548c0 2182 {
60bebf58 2183 stringstream msg;
4af765b2
LB
2184 msg << _F("unresolved arity-%zu global array %s, missing global declaration?",
2185 e->indexes.size(), array->name.c_str());
dc09353a 2186 throw SEMANTIC_ERROR (msg.str(), e->tok);
57148ee7 2187 }
d02548c0
GH
2188 }
2189 else
2190 {
2191 assert (hist);
2192 hist->visit (this);
313b2f74 2193 }
2b066ec1
FCE
2194}
2195
2196
2197void
2198symresolution_info::visit_functioncall (functioncall* e)
2199{
5d23847d
FCE
2200 // XXX: we could relax this, if we're going to examine the
2201 // vartracking data recursively. See testsuite/semko/fortytwo.stp.
2202 if (! (current_function || current_probe))
2203 {
2204 // must be probe-condition expression
dc09353a 2205 throw SEMANTIC_ERROR (_("probe condition must not reference function"), e->tok);
5d23847d
FCE
2206 }
2207
2b066ec1
FCE
2208 for (unsigned i=0; i<e->args.size(); i++)
2209 e->args[i]->visit (this);
2210
2211 if (e->referent)
2212 return;
2213
2214 functiondecl* d = find_function (e->function, e->args.size ());
2215 if (d)
2216 e->referent = d;
2217 else
2a99f48f 2218 {
7e41d3dc 2219 stringstream msg;
4af765b2 2220 msg << _F("unresolved arity-%zu function", e->args.size());
dc09353a 2221 throw SEMANTIC_ERROR (msg.str(), e->tok);
2a99f48f 2222 }
2b066ec1
FCE
2223}
2224
a07a2c28
LB
2225/*find_var will return an argument other than zero if the name matches the var
2226 * name ie, if the current local name matches the name passed to find_var*/
57148ee7 2227vardecl*
2e526dab 2228symresolution_info::find_var (const string& name, int arity, const token* tok)
2b066ec1 2229{
5d23847d
FCE
2230 if (current_function || current_probe)
2231 {
2232 // search locals
57148ee7 2233 vector<vardecl*>& locals = (current_function ?
5d23847d
FCE
2234 current_function->locals :
2235 current_probe->locals);
57148ee7
FCE
2236
2237
5d23847d 2238 for (unsigned i=0; i<locals.size(); i++)
60bebf58 2239 if (locals[i]->name == name)
5d23847d 2240 {
58701b78 2241 locals[i]->set_arity (arity, tok);
5d23847d
FCE
2242 return locals[i];
2243 }
2244 }
2b066ec1 2245
313b2f74
GH
2246 // search function formal parameters (for scalars)
2247 if (arity == 0 && current_function)
2b066ec1
FCE
2248 for (unsigned i=0; i<current_function->formal_args.size(); i++)
2249 if (current_function->formal_args[i]->name == name)
8846477c
FCE
2250 {
2251 // NB: no need to check arity here: formal args always scalar
58701b78 2252 current_function->formal_args[i]->set_arity (0, tok);
8846477c
FCE
2253 return current_function->formal_args[i];
2254 }
2b066ec1 2255
313b2f74 2256 // search processed globals
2b066ec1 2257 for (unsigned i=0; i<session.globals.size(); i++)
60bebf58 2258 if (session.globals[i]->name == name)
8846477c 2259 {
2e526dab
FCE
2260 if (! session.suppress_warnings)
2261 {
2262 vardecl* v = session.globals[i];
2263 // clog << "resolved " << *tok << " to global " << *v->tok << endl;
2264 if (v->tok->location.file != tok->location.file)
2265 {
4af765b2
LB
2266 session.print_warning (_F("cross-file global variable reference to %s from",
2267 lex_cast(*v->tok).c_str()), tok);
2e526dab
FCE
2268 }
2269 }
2a7153bf
JS
2270 session.globals[i]->set_arity (arity, tok);
2271 return session.globals[i];
8846477c 2272 }
57148ee7 2273
2b066ec1
FCE
2274 // search library globals
2275 for (unsigned i=0; i<session.library_files.size(); i++)
2276 {
2277 stapfile* f = session.library_files[i];
2278 for (unsigned j=0; j<f->globals.size(); j++)
84e5ea0f
FCE
2279 {
2280 vardecl* g = f->globals[j];
60bebf58 2281 if (g->name == name)
84e5ea0f 2282 {
58701b78 2283 g->set_arity (arity, tok);
57148ee7
FCE
2284
2285 // put library into the queue if not already there
2286 if (find (session.files.begin(), session.files.end(), f)
84e5ea0f
FCE
2287 == session.files.end())
2288 session.files.push_back (f);
57148ee7 2289
84e5ea0f
FCE
2290 return g;
2291 }
2292 }
2b066ec1
FCE
2293 }
2294
2b066ec1 2295 return 0;
2b066ec1
FCE
2296}
2297
2298
57148ee7 2299functiondecl*
2b066ec1
FCE
2300symresolution_info::find_function (const string& name, unsigned arity)
2301{
f76427a2
FCE
2302 // the common path
2303 if (session.functions.find(name) != session.functions.end())
2b066ec1 2304 {
f76427a2
FCE
2305 functiondecl* fd = session.functions[name];
2306 assert (fd->name == name);
2307 if (fd->formal_args.size() == arity)
2b066ec1 2308 return fd;
e26c2f83
FCE
2309
2310 session.print_warning (_F("mismatched arity-%zu function found", fd->formal_args.size()),
2311 fd->tok);
2312 // and some semantic_error will shortly follow
2b066ec1
FCE
2313 }
2314
e26c2f83 2315 // search library functions
2b066ec1
FCE
2316 for (unsigned i=0; i<session.library_files.size(); i++)
2317 {
2318 stapfile* f = session.library_files[i];
2319 for (unsigned j=0; j<f->functions.size(); j++)
2320 if (f->functions[j]->name == name &&
2321 f->functions[j]->formal_args.size() == arity)
2322 {
2323 // put library into the queue if not already there
2324 if (0) // session.verbose_resolution
4af765b2
LB
2325 cerr << _F(" function %s is defined from %s",
2326 name.c_str(), f->name.c_str()) << endl;
2b066ec1 2327
57148ee7 2328 if (find (session.files.begin(), session.files.end(), f)
2b066ec1
FCE
2329 == session.files.end())
2330 session.files.push_back (f);
2331 // else .. print different message?
2332
2333 return f->functions[j];
2334 }
2335 }
2336
2337 return 0;
2b066ec1
FCE
2338}
2339
2340
cbfbbf69
FCE
2341
2342// ------------------------------------------------------------------------
2343// optimization
2344
2345
2346// Do away with functiondecls that are never (transitively) called
2347// from probes.
2348void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
2349{
2350 functioncall_traversing_visitor ftv;
2351 for (unsigned i=0; i<s.probes.size(); i++)
5d23847d
FCE
2352 {
2353 s.probes[i]->body->visit (& ftv);
2354 if (s.probes[i]->sole_location()->condition)
2355 s.probes[i]->sole_location()->condition->visit (& ftv);
2356 }
f76427a2
FCE
2357 vector<functiondecl*> new_unused_functions;
2358 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
cbfbbf69 2359 {
f76427a2
FCE
2360 functiondecl* fd = it->second;
2361 if (ftv.traversed.find(fd) == ftv.traversed.end())
cbfbbf69 2362 {
bad814e8 2363 if (fd->tok->location.file->name == s.user_file->name && ! fd->synthetic)// !tapset
4af765b2 2364 s.print_warning (_F("Eliding unused function '%s'", fd->name.c_str()), fd->tok);
f76427a2
FCE
2365 // s.functions.erase (it); // NB: can't, since we're already iterating upon it
2366 new_unused_functions.push_back (fd);
cbfbbf69 2367 relaxed_p = false;
cbfbbf69 2368 }
f76427a2
FCE
2369 }
2370 for (unsigned i=0; i<new_unused_functions.size(); i++)
2371 {
2372 map<string,functiondecl*>::iterator where = s.functions.find (new_unused_functions[i]->name);
2373 assert (where != s.functions.end());
2374 s.functions.erase (where);
2375 if (s.tapset_compile_coverage)
2376 s.unused_functions.push_back (new_unused_functions[i]);
cbfbbf69
FCE
2377 }
2378}
2379
2380
2381// ------------------------------------------------------------------------
2382
2383// Do away with local & global variables that are never
2384// written nor read.
cfd621bc 2385void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterations)
cbfbbf69 2386{
313db8e6 2387 varuse_collecting_visitor vut(s);
cfd621bc 2388
cbfbbf69 2389 for (unsigned i=0; i<s.probes.size(); i++)
5d23847d
FCE
2390 {
2391 s.probes[i]->body->visit (& vut);
2392
2393 if (s.probes[i]->sole_location()->condition)
2394 s.probes[i]->sole_location()->condition->visit (& vut);
2395 }
2396
cbfbbf69
FCE
2397 // NB: Since varuse_collecting_visitor also traverses down
2398 // actually called functions, we don't need to explicitly
2399 // iterate over them. Uncalled ones should have been pruned
2400 // in _opt1 above.
2401 //
2402 // for (unsigned i=0; i<s.functions.size(); i++)
2403 // s.functions[i]->body->visit (& vut);
57148ee7 2404
cbfbbf69 2405 // Now in vut.read/written, we have a mixture of all locals, globals
57148ee7
FCE
2406
2407 for (unsigned i=0; i<s.probes.size(); i++)
cbfbbf69
FCE
2408 for (unsigned j=0; j<s.probes[i]->locals.size(); /* see below */)
2409 {
2410 vardecl* l = s.probes[i]->locals[j];
a9e8f7e0 2411
a45664f4 2412 // skip over "special" locals
69aa668e 2413 if (l->synthetic) { j++; continue; }
a45664f4 2414
cbfbbf69
FCE
2415 if (vut.read.find (l) == vut.read.end() &&
2416 vut.written.find (l) == vut.written.end())
2417 {
bad814e8 2418 if (l->tok->location.file->name == s.user_file->name) // !tapset
4af765b2 2419 s.print_warning (_F("Eliding unused variable '%s'", l->name.c_str()), l->tok);
c3a3c0c9
WC
2420 if (s.tapset_compile_coverage) {
2421 s.probes[i]->unused_locals.push_back
2422 (s.probes[i]->locals[j]);
2423 }
cbfbbf69
FCE
2424 s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j);
2425 relaxed_p = false;
2426 // don't increment j
2427 }
2428 else
27d24ae2
FCE
2429 {
2430 if (vut.written.find (l) == vut.written.end())
cfd621bc 2431 if (iterations == 0 && ! s.suppress_warnings)
6643650d
SC
2432 {
2433 stringstream o;
2434 vector<vardecl*>::iterator it;
cfd621bc
FCE
2435 for (it = s.probes[i]->locals.begin(); it != s.probes[i]->locals.end(); it++)
2436 if (l->name != (*it)->name)
2437 o << " " << (*it)->name;
2438 for (it = s.globals.begin(); it != s.globals.end(); it++)
2439 if (l->name != (*it)->name)
2440 o << " " << (*it)->name;
2441
4af765b2
LB
2442 s.print_warning (_F("never-assigned local variable '%s' %s",
2443 l->name.c_str(), (o.str() == "" ? "" :
2444 (_("(alternatives:") + o.str() + ")")).c_str()), l->tok);
6643650d 2445 }
27d24ae2
FCE
2446 j++;
2447 }
cbfbbf69 2448 }
57148ee7 2449
f76427a2
FCE
2450 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2451 {
2452 functiondecl *fd = it->second;
2453 for (unsigned j=0; j<fd->locals.size(); /* see below */)
2454 {
2455 vardecl* l = fd->locals[j];
2456 if (vut.read.find (l) == vut.read.end() &&
2457 vut.written.find (l) == vut.written.end())
2458 {
bad814e8 2459 if (l->tok->location.file->name == s.user_file->name) // !tapset
4af765b2 2460 s.print_warning (_F("Eliding unused variable '%s'", l->name.c_str()), l->tok);
f76427a2
FCE
2461 if (s.tapset_compile_coverage) {
2462 fd->unused_locals.push_back (fd->locals[j]);
2463 }
2464 fd->locals.erase(fd->locals.begin() + j);
2465 relaxed_p = false;
2466 // don't increment j
2467 }
2468 else
2469 {
2470 if (vut.written.find (l) == vut.written.end())
2471 if (iterations == 0 && ! s.suppress_warnings)
2472 {
2473 stringstream o;
2474 vector<vardecl*>::iterator it;
2475 for (it = fd->formal_args.begin() ;
2476 it != fd->formal_args.end(); it++)
2477 if (l->name != (*it)->name)
2478 o << " " << (*it)->name;
2479 for (it = fd->locals.begin(); it != fd->locals.end(); it++)
2480 if (l->name != (*it)->name)
2481 o << " " << (*it)->name;
2482 for (it = s.globals.begin(); it != s.globals.end(); it++)
2483 if (l->name != (*it)->name)
2484 o << " " << (*it)->name;
2485
4af765b2
LB
2486 s.print_warning (_F("never-assigned local variable '%s' %s",
2487 l->name.c_str(), (o.str() == "" ? "" :
2488 (_("(alternatives:") + o.str() + ")")).c_str()), l->tok);
f76427a2 2489 }
cfd621bc 2490
f76427a2
FCE
2491 j++;
2492 }
2493 }
2494 }
cbfbbf69
FCE
2495 for (unsigned i=0; i<s.globals.size(); /* see below */)
2496 {
2497 vardecl* l = s.globals[i];
2498 if (vut.read.find (l) == vut.read.end() &&
2499 vut.written.find (l) == vut.written.end())
2500 {
bad814e8 2501 if (l->tok->location.file->name == s.user_file->name) // !tapset
4af765b2 2502 s.print_warning (_F("Eliding unused variable '%s'", l->name.c_str()), l->tok);
c3a3c0c9 2503 if (s.tapset_compile_coverage) {
0a102c82 2504 s.unused_globals.push_back(s.globals[i]);
c3a3c0c9 2505 }
0a102c82
SC
2506 s.globals.erase(s.globals.begin() + i);
2507 relaxed_p = false;
2508 // don't increment i
cbfbbf69
FCE
2509 }
2510 else
27d24ae2 2511 {
cfd621bc
FCE
2512 if (vut.written.find (l) == vut.written.end() && ! l->init) // no initializer
2513 if (iterations == 0 && ! s.suppress_warnings)
2514 {
2515 stringstream o;
2516 vector<vardecl*>::iterator it;
2517 for (it = s.globals.begin(); it != s.globals.end(); it++)
2518 if (l->name != (*it)->name)
2519 o << " " << (*it)->name;
57148ee7 2520
4af765b2
LB
2521 s.print_warning (_F("never assigned global variable '%s' %s", l->name.c_str(),
2522 (o.str() == "" ? "" : (_("(alternatives:") + o.str() + ")")).c_str()), l->tok);
cfd621bc
FCE
2523 }
2524
27d24ae2
FCE
2525 i++;
2526 }
cbfbbf69
FCE
2527 }
2528}
2529
2530
2531// ------------------------------------------------------------------------
2532
8bda6498 2533struct dead_assignment_remover: public update_visitor
cbfbbf69
FCE
2534{
2535 systemtap_session& session;
2536 bool& relaxed_p;
2537 const varuse_collecting_visitor& vut;
cbfbbf69
FCE
2538
2539 dead_assignment_remover(systemtap_session& s, bool& r,
57148ee7 2540 const varuse_collecting_visitor& v):
8bda6498 2541 session(s), relaxed_p(r), vut(v) {}
cbfbbf69
FCE
2542
2543 void visit_assignment (assignment* e);
f4fe2e93 2544 void visit_try_block (try_block *s);
cbfbbf69
FCE
2545};
2546
2547
cbfbbf69
FCE
2548void
2549dead_assignment_remover::visit_assignment (assignment* e)
2550{
8b095b45
JS
2551 replace (e->left);
2552 replace (e->right);
8bda6498 2553
cbfbbf69 2554 symbol* left = get_symbol_within_expression (e->left);
b0be9bdb 2555 vardecl* leftvar = left->referent; // NB: may be 0 for unresolved $target
8bda6498 2556 if (leftvar) // not unresolved $target, so intended sideeffect may be elided
cbfbbf69 2557 {
cbfbbf69
FCE
2558 if (vut.read.find(leftvar) == vut.read.end()) // var never read?
2559 {
cf9ff341
FCE
2560 // NB: Not so fast! The left side could be an array whose
2561 // index expressions may have side-effects. This would be
57148ee7 2562 // OK if we could replace the array assignment with a
cf9ff341
FCE
2563 // statement-expression containing all the index expressions
2564 // and the rvalue... but we can't.
0a102c82
SC
2565 // Another possibility is that we have an unread global variable
2566 // which are kept for probe end value display.
2567
2568 bool is_global = false;
2569 vector<vardecl*>::iterator it;
2570 for (it = session.globals.begin(); it != session.globals.end(); it++)
2571 if (leftvar->name == (*it)->name)
2572 {
2573 is_global = true;
2574 break;
2575 }
cf9ff341 2576
313db8e6 2577 varuse_collecting_visitor lvut(session);
8bda6498 2578 e->left->visit (& lvut);
df16cbea 2579 if (lvut.side_effect_free () && !is_global // XXX: use _wrt() once we track focal_vars
69aa668e 2580 && !leftvar->synthetic) // don't elide assignment to synthetic $context variables
cf9ff341 2581 {
a9e8f7e0
FCE
2582 /* PR 1119: NB: This is not necessary here. A write-only
2583 variable will also be elided soon at the next _opt2 iteration.
bad814e8
CM
2584 if (e->left->tok->location.file->name == session.user_file->name) // !tapset
2585 session.print_warning("eliding write-only ", *e->left->tok);
a9e8f7e0
FCE
2586 else
2587 */
bad814e8 2588 if (e->left->tok->location.file->name == session.user_file->name) // !tapset
2decd476 2589 session.print_warning(_F("Eliding assignment to '%s'", leftvar->name.c_str()), e->tok);
8bda6498 2590 provide (e->right); // goodbye assignment*
cf9ff341 2591 relaxed_p = false;
8bda6498 2592 return;
cf9ff341 2593 }
cbfbbf69
FCE
2594 }
2595 }
8bda6498 2596 provide (e);
e7625481 2597}
cbfbbf69 2598
f4fe2e93
FCE
2599
2600void
2601dead_assignment_remover::visit_try_block (try_block *s)
2602{
2603 replace (s->try_block);
2604 if (s->catch_error_var)
2605 {
2606 vardecl* errvar = s->catch_error_var->referent;
2607 if (vut.read.find(errvar) == vut.read.end()) // never read?
2608 {
2609 if (session.verbose>2)
4af765b2
LB
2610 clog << _F("Eliding unused error string catcher %s at %s",
2611 errvar->name.c_str(), lex_cast(*s->tok).c_str()) << endl;
f4fe2e93
FCE
2612 s->catch_error_var = 0;
2613 }
2614 }
2615 replace (s->catch_block);
2616 provide (s);
2617}
2618
2619
cbfbbf69
FCE
2620// Let's remove assignments to variables that are never read. We
2621// rewrite "(foo = expr)" as "(expr)". This makes foo a candidate to
2622// be optimized away as an unused variable, and expr a candidate to be
2623// removed as a side-effect-free statement expression. Wahoo!
2624void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p)
2625{
2626 // Recompute the varuse data, which will probably match the opt2
2627 // copy of the computation, except for those totally unused
2628 // variables that opt2 removed.
313db8e6 2629 varuse_collecting_visitor vut(s);
cbfbbf69
FCE
2630 for (unsigned i=0; i<s.probes.size(); i++)
2631 s.probes[i]->body->visit (& vut); // includes reachable functions too
2632
2633 dead_assignment_remover dar (s, relaxed_p, vut);
2634 // This instance may be reused for multiple probe/function body trims.
2635
2636 for (unsigned i=0; i<s.probes.size(); i++)
8b095b45 2637 dar.replace (s.probes[i]->body);
8bda6498
JS
2638 for (map<string,functiondecl*>::iterator it = s.functions.begin();
2639 it != s.functions.end(); it++)
8b095b45 2640 dar.replace (it->second->body);
cbfbbf69 2641 // The rewrite operation is performed within the visitor.
27d24ae2
FCE
2642
2643 // XXX: we could also zap write-only globals here
cbfbbf69
FCE
2644}
2645
2646
2647// ------------------------------------------------------------------------
2648
1cd151d5 2649struct dead_stmtexpr_remover: public update_visitor
cbfbbf69
FCE
2650{
2651 systemtap_session& session;
2652 bool& relaxed_p;
1b07c728 2653 set<vardecl*> focal_vars; // vars considered subject to side-effects
cbfbbf69 2654
57148ee7 2655 dead_stmtexpr_remover(systemtap_session& s, bool& r):
1cd151d5 2656 session(s), relaxed_p(r) {}
cbfbbf69
FCE
2657
2658 void visit_block (block *s);
f4fe2e93 2659 void visit_try_block (try_block *s);
ba6f838d 2660 void visit_null_statement (null_statement *s);
739a3e81
FCE
2661 void visit_if_statement (if_statement* s);
2662 void visit_foreach_loop (foreach_loop *s);
2663 void visit_for_loop (for_loop *s);
cbfbbf69
FCE
2664 // XXX: and other places where stmt_expr's might be nested
2665
2666 void visit_expr_statement (expr_statement *s);
2667};
2668
2669
ba6f838d
FCE
2670void
2671dead_stmtexpr_remover::visit_null_statement (null_statement *s)
2672{
2673 // easy!
2674 if (session.verbose>2)
4af765b2 2675 clog << _("Eliding side-effect-free null statement ") << *s->tok << endl;
1cd151d5
JS
2676 s = 0;
2677 provide (s);
ba6f838d
FCE
2678}
2679
2680
cbfbbf69
FCE
2681void
2682dead_stmtexpr_remover::visit_block (block *s)
2683{
ba6f838d
FCE
2684 vector<statement*> new_stmts;
2685 for (unsigned i=0; i<s->statements.size(); i++ )
cbfbbf69 2686 {
1cd151d5
JS
2687 statement* new_stmt = require (s->statements[i], true);
2688 if (new_stmt != 0)
bea72737
JS
2689 {
2690 // flatten nested blocks into this one
1cd151d5 2691 block *b = dynamic_cast<block *>(new_stmt);
bea72737
JS
2692 if (b)
2693 {
2694 if (session.verbose>2)
4af765b2 2695 clog << _("Flattening nested block ") << *b->tok << endl;
bea72737
JS
2696 new_stmts.insert(new_stmts.end(),
2697 b->statements.begin(), b->statements.end());
2698 relaxed_p = false;
2699 }
2700 else
1cd151d5 2701 new_stmts.push_back (new_stmt);
bea72737 2702 }
cbfbbf69 2703 }
ba6f838d
FCE
2704 if (new_stmts.size() == 0)
2705 {
2706 if (session.verbose>2)
4af765b2 2707 clog << _("Eliding side-effect-free empty block ") << *s->tok << endl;
1cd151d5 2708 s = 0;
ba6f838d
FCE
2709 }
2710 else if (new_stmts.size() == 1)
2711 {
2712 if (session.verbose>2)
4af765b2 2713 clog << _("Eliding side-effect-free singleton block ") << *s->tok << endl;
1cd151d5
JS
2714 provide (new_stmts[0]);
2715 return;
ba6f838d
FCE
2716 }
2717 else
1cd151d5
JS
2718 s->statements = new_stmts;
2719 provide (s);
cbfbbf69
FCE
2720}
2721
f4fe2e93
FCE
2722
2723void
2724dead_stmtexpr_remover::visit_try_block (try_block *s)
2725{
2726 replace (s->try_block, true);
2727 replace (s->catch_block, true); // null catch{} is ok and useful
2728 if (s->try_block == 0)
2729 {
2730 if (session.verbose>2)
4af765b2 2731 clog << _("Eliding empty try {} block ") << *s->tok << endl;
f4fe2e93
FCE
2732 s = 0;
2733 }
2734 provide (s);
2735}
2736
2737
739a3e81
FCE
2738void
2739dead_stmtexpr_remover::visit_if_statement (if_statement *s)
2740{
8b095b45
JS
2741 replace (s->thenblock, true);
2742 replace (s->elseblock, true);
ba6f838d 2743
bea72737 2744 if (s->thenblock == 0)
ba6f838d 2745 {
bea72737
JS
2746 if (s->elseblock == 0)
2747 {
2748 // We may be able to elide this statement, if the condition
2749 // expression is side-effect-free.
313db8e6 2750 varuse_collecting_visitor vct(session);
bea72737
JS
2751 s->condition->visit(& vct);
2752 if (vct.side_effect_free ())
2753 {
2754 if (session.verbose>2)
4af765b2 2755 clog << _("Eliding side-effect-free if statement ")
bea72737 2756 << *s->tok << endl;
1cd151d5 2757 s = 0; // yeah, baby
bea72737
JS
2758 }
2759 else
2760 {
2761 // We can still turn it into a simple expr_statement though...
2762 if (session.verbose>2)
4af765b2 2763 clog << _("Creating simple evaluation from if statement ")
bea72737
JS
2764 << *s->tok << endl;
2765 expr_statement *es = new expr_statement;
2766 es->value = s->condition;
2767 es->tok = es->value->tok;
1cd151d5
JS
2768 provide (es);
2769 return;
bea72737
JS
2770 }
2771 }
2772 else
ba6f838d 2773 {
bea72737
JS
2774 // For an else without a then, we can invert the condition logic to
2775 // avoid having a null statement in the thenblock
ba6f838d 2776 if (session.verbose>2)
4af765b2 2777 clog << _("Inverting the condition of if statement ")
bea72737
JS
2778 << *s->tok << endl;
2779 unary_expression *ue = new unary_expression;
2780 ue->operand = s->condition;
2781 ue->tok = ue->operand->tok;
2782 ue->op = "!";
2783 s->condition = ue;
2784 s->thenblock = s->elseblock;
2785 s->elseblock = 0;
ba6f838d
FCE
2786 }
2787 }
1cd151d5 2788 provide (s);
739a3e81
FCE
2789}
2790
2791void
2792dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s)
2793{
8b095b45 2794 replace (s->block, true);
ba6f838d
FCE
2795
2796 if (s->block == 0)
2797 {
10328bcf 2798 // XXX what if s->limit has side effects?
c261711d 2799 // XXX what about s->indexes or s->value used outside the loop?
bad814e8 2800 if(session.verbose > 2)
4af765b2 2801 clog << _("Eliding side-effect-free foreach statement ") << *s->tok << endl;
1cd151d5 2802 s = 0; // yeah, baby
ba6f838d 2803 }
1cd151d5 2804 provide (s);
739a3e81
FCE
2805}
2806
2807void
2808dead_stmtexpr_remover::visit_for_loop (for_loop *s)
2809{
8b095b45 2810 replace (s->block, true);
ba6f838d
FCE
2811
2812 if (s->block == 0)
2813 {
2814 // We may be able to elide this statement, if the condition
2815 // expression is side-effect-free.
313db8e6 2816 varuse_collecting_visitor vct(session);
ba6f838d
FCE
2817 if (s->init) s->init->visit(& vct);
2818 s->cond->visit(& vct);
2819 if (s->incr) s->incr->visit(& vct);
2820 if (vct.side_effect_free ())
2821 {
2822 if (session.verbose>2)
4af765b2 2823 clog << _("Eliding side-effect-free for statement ") << *s->tok << endl;
1cd151d5
JS
2824 s = 0; // yeah, baby
2825 }
2826 else
2827 {
2828 // Can't elide this whole statement; put a null in there.
f946b10f 2829 s->block = new null_statement(s->tok);
ba6f838d 2830 }
ba6f838d 2831 }
1cd151d5 2832 provide (s);
739a3e81
FCE
2833}
2834
2835
cbfbbf69
FCE
2836
2837void
2838dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
2839{
2840 // Run a varuse query against the operand expression. If it has no
2841 // side-effects, replace the entire statement expression by a null
1cd151d5 2842 // statement with the provide() call.
cbfbbf69
FCE
2843 //
2844 // Unlike many other visitors, we do *not* traverse this outermost
2845 // one into the expression subtrees. There is no need - no
2846 // expr_statement nodes will be found there. (Function bodies
2847 // need to be visited explicitly by our caller.)
2848 //
2849 // NB. While we don't share nodes in the parse tree, let's not
2850 // deallocate *s anyway, just in case...
2851
313db8e6 2852 varuse_collecting_visitor vut(session);
cbfbbf69 2853 s->value->visit (& vut);
57148ee7 2854
1cd151d5 2855 if (vut.side_effect_free_wrt (focal_vars))
cbfbbf69 2856 {
a9e8f7e0
FCE
2857 /* PR 1119: NB: this message is not a good idea here. It can
2858 name some arbitrary RHS expression of an assignment.
bad814e8
CM
2859 if (s->value->tok->location.file->name == session.user_file->name) // not tapset
2860 session.print_warning("eliding never-assigned ", *s->value->tok);
57148ee7 2861 else
a9e8f7e0 2862 */
bad814e8
CM
2863 if (s->value->tok->location.file->name == session.user_file->name) // not tapset
2864 session.print_warning("Eliding side-effect-free expression ", s->tok);
cbfbbf69 2865
ba6f838d
FCE
2866 // NB: this 0 pointer is invalid to leave around for any length of
2867 // time, but the parent parse tree objects above handle it.
1cd151d5 2868 s = 0;
cbfbbf69
FCE
2869 relaxed_p = false;
2870 }
1cd151d5 2871 provide (s);
cbfbbf69
FCE
2872}
2873
2874
2875void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
2876{
2877 // Finally, let's remove some statement-expressions that have no
2878 // side-effect. These should be exactly those whose private varuse
2879 // visitors come back with an empty "written" and "embedded" lists.
57148ee7 2880
cbfbbf69
FCE
2881 dead_stmtexpr_remover duv (s, relaxed_p);
2882 // This instance may be reused for multiple probe/function body trims.
2883
2884 for (unsigned i=0; i<s.probes.size(); i++)
1b07c728 2885 {
e19ebcf7 2886 assert_no_interrupts();
f76427a2 2887
ba6f838d
FCE
2888 derived_probe* p = s.probes[i];
2889
1b07c728
FCE
2890 duv.focal_vars.clear ();
2891 duv.focal_vars.insert (s.globals.begin(),
2892 s.globals.end());
ba6f838d
FCE
2893 duv.focal_vars.insert (p->locals.begin(),
2894 p->locals.end());
2895
8b095b45 2896 duv.replace (p->body, true);
ba6f838d
FCE
2897 if (p->body == 0)
2898 {
bad814e8 2899 if (! s.timing) // PR10070
4af765b2 2900 s.print_warning (_F("side-effect-free probe '%s'", p->name.c_str()), p->tok);
ba6f838d 2901
f946b10f 2902 p->body = new null_statement(p->tok);
27d24ae2
FCE
2903
2904 // XXX: possible duplicate warnings; see below
ba6f838d 2905 }
1b07c728 2906 }
f76427a2 2907 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
1b07c728 2908 {
e19ebcf7 2909 assert_no_interrupts();
f76427a2
FCE
2910
2911 functiondecl* fn = it->second;
1b07c728 2912 duv.focal_vars.clear ();
ba6f838d
FCE
2913 duv.focal_vars.insert (fn->locals.begin(),
2914 fn->locals.end());
2915 duv.focal_vars.insert (fn->formal_args.begin(),
2916 fn->formal_args.end());
1b07c728
FCE
2917 duv.focal_vars.insert (s.globals.begin(),
2918 s.globals.end());
ba6f838d 2919
8b095b45 2920 duv.replace (fn->body, true);
ba6f838d
FCE
2921 if (fn->body == 0)
2922 {
bad814e8 2923 s.print_warning (_F("side-effect-free function '%s'", fn->name.c_str()), fn->tok);
ba6f838d 2924
f946b10f 2925 fn->body = new null_statement(fn->tok);
27d24ae2
FCE
2926
2927 // XXX: the next iteration of the outer optimization loop may
2928 // take this new null_statement away again, and thus give us a
2929 // fresh warning. It would be better if this fixup was performed
2930 // only after the relaxation iterations.
2931 // XXX: or else see bug #6469.
ba6f838d 2932 }
1b07c728 2933 }
cbfbbf69
FCE
2934}
2935
bea72737
JS
2936
2937// ------------------------------------------------------------------------
2938
2939// The goal of this visitor is to reduce top-level expressions in void context
2940// into separate statements that evaluate each subcomponent of the expression.
2941// The dead-statement-remover can later remove some parts if they have no side
2942// effects.
9f9873df
JS
2943//
2944// All expressions must be overridden here so we never visit their subexpressions
2945// accidentally. Thus, the only visited expressions should be value of an
2946// expr_statement.
2947//
2948// For an expression to replace its expr_statement with something else, it will
2949// let the new statement provide(), and then provide(0) for itself. The
2950// expr_statement will take this as a sign that it's been replaced.
2951struct void_statement_reducer: public update_visitor
bea72737
JS
2952{
2953 systemtap_session& session;
2954 bool& relaxed_p;
bea72737
JS
2955 set<vardecl*> focal_vars; // vars considered subject to side-effects
2956
2957 void_statement_reducer(systemtap_session& s, bool& r):
9f9873df 2958 session(s), relaxed_p(r) {}
bea72737 2959
133c7b1d 2960 void visit_expr_statement (expr_statement* s);
9f9873df
JS
2961
2962 // expressions in conditional / loop controls are definitely a side effect,
2963 // but still recurse into the child statements
bea72737
JS
2964 void visit_if_statement (if_statement* s);
2965 void visit_for_loop (for_loop* s);
2966 void visit_foreach_loop (foreach_loop* s);
2967
2968 // these expressions get rewritten into their statement equivalents
2969 void visit_logical_or_expr (logical_or_expr* e);
2970 void visit_logical_and_expr (logical_and_expr* e);
2971 void visit_ternary_expression (ternary_expression* e);
2972
93daaca8 2973 // all of these can (usually) be reduced into simpler statements
bea72737
JS
2974 void visit_binary_expression (binary_expression* e);
2975 void visit_unary_expression (unary_expression* e);
ac01386b 2976 void visit_regex_query (regex_query* e); // XXX depends on subexpr extraction
bea72737
JS
2977 void visit_comparison (comparison* e);
2978 void visit_concatenation (concatenation* e);
2979 void visit_functioncall (functioncall* e);
2980 void visit_print_format (print_format* e);
6fda2dff 2981 void visit_target_symbol (target_symbol* e);
bd1fcbad 2982 void visit_atvar_op (atvar_op* e);
9b5af295 2983 void visit_cast_op (cast_op* e);
30263a73 2984 void visit_defined_op (defined_op* e);
bea72737
JS
2985
2986 // these are a bit hairy to grok due to the intricacies of indexables and
2987 // stats, so I'm chickening out and skipping them...
9f9873df
JS
2988 void visit_array_in (array_in* e) { provide (e); }
2989 void visit_arrayindex (arrayindex* e) { provide (e); }
2990 void visit_stat_op (stat_op* e) { provide (e); }
2991 void visit_hist_op (hist_op* e) { provide (e); }
bea72737
JS
2992
2993 // these can't be reduced because they always have an effect
9f9873df
JS
2994 void visit_return_statement (return_statement* s) { provide (s); }
2995 void visit_delete_statement (delete_statement* s) { provide (s); }
2996 void visit_pre_crement (pre_crement* e) { provide (e); }
2997 void visit_post_crement (post_crement* e) { provide (e); }
2998 void visit_assignment (assignment* e) { provide (e); }
bea72737
JS
2999};
3000
3001
133c7b1d
JS
3002void
3003void_statement_reducer::visit_expr_statement (expr_statement* s)
3004{
8b095b45 3005 replace (s->value, true);
133c7b1d 3006
9f9873df
JS
3007 // if the expression provides 0, that's our signal that a new
3008 // statement has been provided, so we shouldn't provide this one.
3009 if (s->value != 0)
3010 provide(s);
bea72737
JS
3011}
3012
3013void
3014void_statement_reducer::visit_if_statement (if_statement* s)
3015{
9f9873df 3016 // s->condition is never void
8b095b45
JS
3017 replace (s->thenblock);
3018 replace (s->elseblock);
9f9873df 3019 provide (s);
bea72737
JS
3020}
3021
3022void
3023void_statement_reducer::visit_for_loop (for_loop* s)
3024{
9f9873df 3025 // s->init/cond/incr are never void
8b095b45 3026 replace (s->block);
9f9873df 3027 provide (s);
bea72737
JS
3028}
3029
3030void
3031void_statement_reducer::visit_foreach_loop (foreach_loop* s)
3032{
c261711d 3033 // s->indexes/base/value/limit are never void
8b095b45 3034 replace (s->block);
9f9873df 3035 provide (s);
bea72737
JS
3036}
3037
3038void
3039void_statement_reducer::visit_logical_or_expr (logical_or_expr* e)
3040{
3041 // In void context, the evaluation of "a || b" is exactly like
3042 // "if (!a) b", so let's do that instead.
3043
bea72737 3044 if (session.verbose>2)
4af765b2 3045 clog << _("Creating if statement from unused logical-or ")
bea72737
JS
3046 << *e->tok << endl;
3047
3048 if_statement *is = new if_statement;
3049 is->tok = e->tok;
3050 is->elseblock = 0;
bea72737
JS
3051
3052 unary_expression *ue = new unary_expression;
3053 ue->operand = e->left;
3054 ue->tok = e->tok;
3055 ue->op = "!";
3056 is->condition = ue;
3057
133c7b1d 3058 expr_statement *es = new expr_statement;
bea72737
JS
3059 es->value = e->right;
3060 es->tok = es->value->tok;
3061 is->thenblock = es;
3062
3063 is->visit(this);
3064 relaxed_p = false;
9f9873df
JS
3065 e = 0;
3066 provide (e);
bea72737
JS
3067}
3068
3069void
3070void_statement_reducer::visit_logical_and_expr (logical_and_expr* e)
3071{
3072 // In void context, the evaluation of "a && b" is exactly like
3073 // "if (a) b", so let's do that instead.
3074
bea72737 3075 if (session.verbose>2)
4af765b2 3076 clog << _("Creating if statement from unused logical-and ")
bea72737
JS
3077 << *e->tok << endl;
3078
3079 if_statement *is = new if_statement;
3080 is->tok = e->tok;
3081 is->elseblock = 0;
3082 is->condition = e->left;
bea72737 3083
133c7b1d 3084 expr_statement *es = new expr_statement;
bea72737
JS
3085 es->value = e->right;
3086 es->tok = es->value->tok;
3087 is->thenblock = es;
3088
3089 is->visit(this);
3090 relaxed_p = false;
9f9873df
JS
3091 e = 0;
3092 provide (e);
bea72737
JS
3093}
3094
3095void
3096void_statement_reducer::visit_ternary_expression (ternary_expression* e)
3097{
3098 // In void context, the evaluation of "a ? b : c" is exactly like
3099 // "if (a) b else c", so let's do that instead.
3100
bea72737 3101 if (session.verbose>2)
4af765b2 3102 clog << _("Creating if statement from unused ternary expression ")
bea72737
JS
3103 << *e->tok << endl;
3104
3105 if_statement *is = new if_statement;
3106 is->tok = e->tok;
3107 is->condition = e->cond;
bea72737 3108
133c7b1d 3109 expr_statement *es = new expr_statement;
bea72737
JS
3110 es->value = e->truevalue;
3111 es->tok = es->value->tok;
3112 is->thenblock = es;
3113
3114 es = new expr_statement;
3115 es->value = e->falsevalue;
3116 es->tok = es->value->tok;
3117 is->elseblock = es;
3118
3119 is->visit(this);
3120 relaxed_p = false;
9f9873df
JS
3121 e = 0;
3122 provide (e);
bea72737
JS
3123}
3124
3125void
3126void_statement_reducer::visit_binary_expression (binary_expression* e)
3127{
3128 // When the result of a binary operation isn't needed, it's just as good to
3129 // evaluate the operands as sequential statements in a block.
3130
bea72737 3131 if (session.verbose>2)
4af765b2 3132 clog << _("Eliding unused binary ") << *e->tok << endl;
bea72737
JS
3133
3134 block *b = new block;
9f9873df 3135 b->tok = e->tok;
bea72737 3136
133c7b1d 3137 expr_statement *es = new expr_statement;
bea72737
JS
3138 es->value = e->left;
3139 es->tok = es->value->tok;
3140 b->statements.push_back(es);
3141
3142 es = new expr_statement;
3143 es->value = e->right;
3144 es->tok = es->value->tok;
3145 b->statements.push_back(es);
3146
3147 b->visit(this);
3148 relaxed_p = false;
9f9873df
JS
3149 e = 0;
3150 provide (e);
bea72737
JS
3151}
3152
3153void
3154void_statement_reducer::visit_unary_expression (unary_expression* e)
3155{
3156 // When the result of a unary operation isn't needed, it's just as good to
3157 // evaluate the operand directly
3158
bea72737 3159 if (session.verbose>2)
4af765b2 3160 clog << _("Eliding unused unary ") << *e->tok << endl;
bea72737 3161
bea72737 3162 relaxed_p = false;
9f9873df 3163 e->operand->visit(this);
bea72737
JS
3164}
3165
93daaca8
SM
3166void
3167void_statement_reducer::visit_regex_query (regex_query* e)
3168{
ac01386b
SM
3169 // TODOXXX After subexpression extraction is implemented,
3170 // regular expression matches *may* have side-effects in
3171 // terms of producing matched subexpressions, e.g.:
93daaca8 3172 //
ac01386b
SM
3173 // str =~ "pat"; println(matched(0));
3174 //
3175 // It's debatable if we want to actually allow this, though.
93daaca8 3176
ac01386b
SM
3177 // Treat e as a unary expression on the left operand -- since the
3178 // right hand side must be a literal (as verified by the parser),
93daaca8
SM
3179 // evaluating it never has side effects.
3180
3181 if (session.verbose>2)
3182 clog << _("Eliding regex query ") << *e->tok << endl;
3183
3184 relaxed_p = false;
3185 e->left->visit(this);
3186}
3187
bea72737
JS
3188void
3189void_statement_reducer::visit_comparison (comparison* e)
3190{
3191 visit_binary_expression(e);
3192}
3193
3194void
3195void_statement_reducer::visit_concatenation (concatenation* e)
3196{
3197 visit_binary_expression(e);
3198}
3199
3200void
3201void_statement_reducer::visit_functioncall (functioncall* e)
3202{
3203 // If a function call is pure and its result ignored, we can elide the call
c7d47935 3204 // and just evaluate the arguments in sequence
bea72737
JS
3205
3206 if (!e->args.size())
9f9873df
JS
3207 {
3208 provide (e);
3209 return;
3210 }
bea72737 3211
313db8e6 3212 varuse_collecting_visitor vut(session);
bea72737
JS
3213 vut.traversed.insert (e->referent);
3214 vut.current_function = e->referent;
3215 e->referent->body->visit (& vut);
3216 if (!vut.side_effect_free_wrt (focal_vars))
9f9873df
JS
3217 {
3218 provide (e);
3219 return;
3220 }
bea72737
JS
3221
3222 if (session.verbose>2)
4af765b2 3223 clog << _("Eliding side-effect-free function call ") << *e->tok << endl;
bea72737 3224
133c7b1d
JS
3225 block *b = new block;
3226 b->tok = e->tok;
bea72737 3227
133c7b1d 3228 for (unsigned i=0; i<e->args.size(); i++ )
bea72737 3229 {
133c7b1d
JS
3230 expr_statement *es = new expr_statement;
3231 es->value = e->args[i];
3232 es->tok = es->value->tok;
bea72737 3233 b->statements.push_back(es);
bea72737
JS
3234 }
3235
133c7b1d 3236 b->visit(this);
bea72737 3237 relaxed_p = false;
9f9873df
JS
3238 e = 0;
3239 provide (e);
bea72737
JS
3240}
3241
3242void
3243void_statement_reducer::visit_print_format (print_format* e)
3244{
3245 // When an sprint's return value is ignored, we can simply evaluate the
3246 // arguments in sequence
3247
3248 if (e->print_to_stream || !e->args.size())
9f9873df
JS
3249 {
3250 provide (e);
3251 return;
3252 }
bea72737
JS
3253
3254 if (session.verbose>2)
4af765b2 3255 clog << _("Eliding unused print ") << *e->tok << endl;
bea72737 3256
133c7b1d
JS
3257 block *b = new block;
3258 b->tok = e->tok;
bea72737 3259
133c7b1d 3260 for (unsigned i=0; i<e->args.size(); i++ )
bea72737 3261 {
133c7b1d
JS
3262 expr_statement *es = new expr_statement;
3263 es->value = e->args[i];
3264 es->tok = es->value->tok;
bea72737 3265 b->statements.push_back(es);
bea72737
JS
3266 }
3267
133c7b1d 3268 b->visit(this);
bea72737 3269 relaxed_p = false;
9f9873df
JS
3270 e = 0;
3271 provide (e);
bea72737
JS
3272}
3273
bd1fcbad
YZ
3274void
3275void_statement_reducer::visit_atvar_op (atvar_op* e)
3276{
3277 visit_target_symbol (e);
3278}
3279
6fda2dff
JS
3280void
3281void_statement_reducer::visit_target_symbol (target_symbol* e)
3282{
3283 // When target_symbol isn't needed, it's just as good to
3284 // evaluate any array indexes directly
3285
3286 block *b = new block;
3287 b->tok = e->tok;
3288
3289 for (unsigned i=0; i<e->components.size(); i++ )
3290 {
3291 if (e->components[i].type != target_symbol::comp_expression_array_index)
3292 continue;
3293
3294 expr_statement *es = new expr_statement;
3295 es->value = e->components[i].expr_index;
3296 es->tok = es->value->tok;
3297 b->statements.push_back(es);
3298 }
3299
3300 if (b->statements.empty())
3301 {
3302 delete b;
3303 provide (e);
3304 return;
3305 }
3306
3307 if (session.verbose>2)
4af765b2 3308 clog << _("Eliding unused target symbol ") << *e->tok << endl;
6fda2dff
JS
3309
3310 b->visit(this);
3311 relaxed_p = false;
3312 e = 0;
3313 provide (e);
3314}
3315
9b5af295
JS
3316void
3317void_statement_reducer::visit_cast_op (cast_op* e)
3318{
3319 // When the result of a cast operation isn't needed, it's just as good to
6fda2dff
JS
3320 // evaluate the operand and any array indexes directly
3321
3322 block *b = new block;
3323 b->tok = e->tok;
3324
3325 expr_statement *es = new expr_statement;
3326 es->value = e->operand;
3327 es->tok = es->value->tok;
3328 b->statements.push_back(es);
3329
3330 for (unsigned i=0; i<e->components.size(); i++ )
3331 {
3332 if (e->components[i].type != target_symbol::comp_expression_array_index)
3333 continue;
3334
3335 es = new expr_statement;
3336 es->value = e->components[i].expr_index;
3337 es->tok = es->value->tok;
3338 b->statements.push_back(es);
3339 }
9b5af295
JS
3340
3341 if (session.verbose>2)
4af765b2 3342 clog << _("Eliding unused typecast ") << *e->tok << endl;
9b5af295 3343
6fda2dff 3344 b->visit(this);
9b5af295 3345 relaxed_p = false;
6fda2dff
JS
3346 e = 0;
3347 provide (e);
9b5af295
JS
3348}
3349
bea72737 3350
30263a73
FCE
3351void
3352void_statement_reducer::visit_defined_op (defined_op* e)
3353{
3354 // When the result of a @defined operation isn't needed, just elide
3355 // it entirely. Its operand $expression must already be
3356 // side-effect-free.
3357
3358 if (session.verbose>2)
4af765b2 3359 clog << _("Eliding unused check ") << *e->tok << endl;
30263a73
FCE
3360
3361 relaxed_p = false;
3362 e = 0;
3363 provide (e);
3364}
3365
3366
3367
bea72737
JS
3368void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p)
3369{
3370 // Let's simplify statements with unused computed values.
3371
3372 void_statement_reducer vuv (s, relaxed_p);
3373 // This instance may be reused for multiple probe/function body trims.
3374
3375 vuv.focal_vars.insert (s.globals.begin(), s.globals.end());
3376
3377 for (unsigned i=0; i<s.probes.size(); i++)
8b095b45 3378 vuv.replace (s.probes[i]->body);
9f9873df
JS
3379 for (map<string,functiondecl*>::iterator it = s.functions.begin();
3380 it != s.functions.end(); it++)
8b095b45 3381 vuv.replace (it->second->body);
bea72737
JS
3382}
3383
3384
10328bcf
JS
3385struct const_folder: public update_visitor
3386{
3387 systemtap_session& session;
3388 bool& relaxed_p;
3389
3390 const_folder(systemtap_session& s, bool& r):
3391 session(s), relaxed_p(r), last_number(0), last_string(0) {}
3392
3393 literal_number* last_number;
3394 literal_number* get_number(expression*& e);
3395 void visit_literal_number (literal_number* e);
3396
3397 literal_string* last_string;
3398 literal_string* get_string(expression*& e);
3399 void visit_literal_string (literal_string* e);
3400
f4869658
JS
3401 void get_literal(expression*& e, literal_number*& n, literal_string*& s);
3402
10328bcf
JS
3403 void visit_if_statement (if_statement* s);
3404 void visit_for_loop (for_loop* s);
3405 void visit_foreach_loop (foreach_loop* s);
3406 void visit_binary_expression (binary_expression* e);
3407 void visit_unary_expression (unary_expression* e);
3408 void visit_logical_or_expr (logical_or_expr* e);
3409 void visit_logical_and_expr (logical_and_expr* e);
7a6ae283 3410 // void visit_regex_query (regex_query* e); // XXX: would require executing dfa at compile-time
10328bcf
JS
3411 void visit_comparison (comparison* e);
3412 void visit_concatenation (concatenation* e);
3413 void visit_ternary_expression (ternary_expression* e);
b7aedf26 3414 void visit_defined_op (defined_op* e);
9fab2262 3415 void visit_target_symbol (target_symbol* e);
10328bcf
JS
3416};
3417
f4869658
JS
3418void
3419const_folder::get_literal(expression*& e,
3420 literal_number*& n,
3421 literal_string*& s)
3422{
3423 replace (e);
3424 n = (e == last_number) ? last_number : NULL;
3425 s = (e == last_string) ? last_string : NULL;
3426}
3427
10328bcf
JS
3428literal_number*
3429const_folder::get_number(expression*& e)
3430{
3431 replace (e);
3432 return (e == last_number) ? last_number : NULL;
3433}
3434
3435void
3436const_folder::visit_literal_number (literal_number* e)
3437{
3438 last_number = e;
3439 provide (e);
3440}
3441
3442literal_string*
3443const_folder::get_string(expression*& e)
3444{
3445 replace (e);
3446 return (e == last_string) ? last_string : NULL;
3447}
3448
3449void
3450const_folder::visit_literal_string (literal_string* e)
3451{
3452 last_string = e;
3453 provide (e);
3454}
3455
3456void
3457const_folder::visit_if_statement (if_statement* s)
3458{
3459 literal_number* cond = get_number (s->condition);
3460 if (!cond)
3461 {
3462 replace (s->thenblock);
3463 replace (s->elseblock);
3464 provide (s);
3465 }
3466 else
3467 {
3468 if (session.verbose>2)
4af765b2
LB
3469 clog << _F("Collapsing constant-%" PRIi64 " if-statement %s",
3470 cond->value, lex_cast(*s->tok).c_str()) << endl;
10328bcf
JS
3471 relaxed_p = false;
3472
3473 statement* n = cond->value ? s->thenblock : s->elseblock;
3474 if (n)
3475 n->visit (this);
3476 else
3477 provide (new null_statement (s->tok));
3478 }
3479}
3480
3481void
3482const_folder::visit_for_loop (for_loop* s)
3483{
3484 literal_number* cond = get_number (s->cond);
3485 if (!cond || cond->value)
3486 {
3487 replace (s->init);
3488 replace (s->incr);
3489 replace (s->block);
3490 provide (s);
3491 }
3492 else
3493 {
3494 if (session.verbose>2)
4af765b2 3495 clog << _("Collapsing constantly-false for-loop ") << *s->tok << endl;
10328bcf
JS
3496 relaxed_p = false;
3497
3498 if (s->init)
3499 s->init->visit (this);
3500 else
3501 provide (new null_statement (s->tok));
3502 }
3503}
3504
3505void
3506const_folder::visit_foreach_loop (foreach_loop* s)
3507{
3508 literal_number* limit = get_number (s->limit);
3509 if (!limit || limit->value > 0)
3510 {
3511 for (unsigned i = 0; i < s->indexes.size(); ++i)
3512 replace (s->indexes[i]);
3513 replace (s->base);
c261711d 3514 replace (s->value);
10328bcf
JS
3515 replace (s->block);
3516 provide (s);
3517 }
3518 else
3519 {
3520 if (session.verbose>2)
4af765b2 3521 clog << _("Collapsing constantly-limited foreach-loop ") << *s->tok << endl;
10328bcf
JS
3522 relaxed_p = false;
3523
3524 provide (new null_statement (s->tok));
3525 }
3526}
3527
3528void
3529const_folder::visit_binary_expression (binary_expression* e)
3530{
e7227e90
JS
3531 int64_t value;
3532 literal_number* left = get_number (e->left);
3533 literal_number* right = get_number (e->right);
3534
3535 if (right && !right->value && (e->op == "/" || e->op == "%"))
3536 {
3537 // Give divide-by-zero a chance to be optimized out elsewhere,
3538 // and if not it will be a runtime error anyway...
3539 provide (e);
3540 return;
3541 }
3542
3543 if (left && right)
3544 {
3545 if (e->op == "+")
3546 value = left->value + right->value;
3547 else if (e->op == "-")
3548 value = left->value - right->value;
3549 else if (e->op == "*")
3550 value = left->value * right->value;
3551 else if (e->op == "&")
3552 value = left->value & right->value;
3553 else if (e->op == "|")
3554 value = left->value | right->value;
3555 else if (e->op == "^")
3556 value = left->value ^ right->value;
3557 else if (e->op == ">>")
3558 value = left->value >> max(min(right->value, (int64_t)64), (int64_t)0);
3559 else if (e->op == "<<")
3560 value = left->value << max(min(right->value, (int64_t)64), (int64_t)0);
3561 else if (e->op == "/")
3562 value = (left->value == LLONG_MIN && right->value == -1) ? LLONG_MIN :
3563 left->value / right->value;
3564 else if (e->op == "%")
3565 value = (left->value == LLONG_MIN && right->value == -1) ? 0 :
3566 left->value % right->value;
3567 else
dc09353a 3568 throw SEMANTIC_ERROR (_("unsupported binary operator ") + e->op);
e7227e90
JS
3569 }
3570
3571 else if ((left && ((left->value == 0 && (e->op == "*" || e->op == "&" ||
3572 e->op == ">>" || e->op == "<<" )) ||
3573 (left->value ==-1 && (e->op == "|" || e->op == ">>"))))
3574 ||
3575 (right && ((right->value == 0 && (e->op == "*" || e->op == "&")) ||
3576 (right->value == 1 && (e->op == "%")) ||
3577 (right->value ==-1 && (e->op == "%" || e->op == "|")))))
3578 {
3579 expression* other = left ? e->right : e->left;
3580 varuse_collecting_visitor vu(session);
3581 other->visit(&vu);
3582 if (!vu.side_effect_free())
3583 {
3584 provide (e);
3585 return;
3586 }
3587
3588 if (left)
3589 value = left->value;
3590 else if (e->op == "%")
3591 value = 0;
3592 else
3593 value = right->value;
3594 }
3595
3596 else if ((left && ((left->value == 0 && (e->op == "+" || e->op == "|" ||
3597 e->op == "^")) ||
3598 (left->value == 1 && (e->op == "*")) ||
3599 (left->value ==-1 && (e->op == "&"))))
3600 ||
3601 (right && ((right->value == 0 && (e->op == "+" || e->op == "-" ||
3602 e->op == "|" || e->op == "^")) ||
3603 (right->value == 1 && (e->op == "*" || e->op == "/")) ||
3604 (right->value ==-1 && (e->op == "&")) ||
3605 (right->value <= 0 && (e->op == ">>" || e->op == "<<")))))
3606 {
3607 if (session.verbose>2)
4af765b2 3608 clog << _("Collapsing constant-identity binary operator ") << *e->tok << endl;
e7227e90
JS
3609 relaxed_p = false;
3610
3611 provide (left ? e->right : e->left);
3612 return;
3613 }
3614
3615 else
3616 {
3617 provide (e);
3618 return;
3619 }
3620
3621 if (session.verbose>2)
4af765b2
LB
3622 clog << _F("Collapsing constant-%" PRIi64 " binary operator %s",
3623 value, lex_cast(*e->tok).c_str()) << endl;
e7227e90
JS
3624 relaxed_p = false;
3625
3626 literal_number* n = new literal_number(value);
3627 n->tok = e->tok;
3628 n->visit (this);
10328bcf
JS
3629}
3630
3631void
3632const_folder::visit_unary_expression (unary_expression* e)
3633{
3634 literal_number* operand = get_number (e->operand);
3635 if (!operand)
3636 provide (e);
3637 else
3638 {
3639 if (session.verbose>2)
4af765b2 3640 clog << _("Collapsing constant unary ") << *e->tok << endl;
10328bcf
JS
3641 relaxed_p = false;
3642
3643 literal_number* n = new literal_number (*operand);
3644 n->tok = e->tok;
3645 if (e->op == "+")
3646 ; // nothing to do
3647 else if (e->op == "-")
3648 n->value = -n->value;
3649 else if (e->op == "!")
3650 n->value = !n->value;
3651 else if (e->op == "~")
3652 n->value = ~n->value;
3653 else
dc09353a 3654 throw SEMANTIC_ERROR (_("unsupported unary operator ") + e->op);
10328bcf
JS
3655 n->visit (this);
3656 }
3657}
3658
3659void
3660const_folder::visit_logical_or_expr (logical_or_expr* e)
3661{
a7e58d4c
JS
3662 int64_t value;
3663 literal_number* left = get_number (e->left);
3664 literal_number* right = get_number (e->right);
3665
3666 if (left && right)
3667 value = left->value || right->value;
3668
3669 else if ((left && left->value) || (right && right->value))
3670 {
3671 // If the const is on the left, we get to short-circuit the right
3672 // immediately. Otherwise, we can only eliminate the LHS if it's pure.
3673 if (right)
3674 {
3675 varuse_collecting_visitor vu(session);
3676 e->left->visit(&vu);
3677 if (!vu.side_effect_free())
3678 {
3679 provide (e);
3680 return;
3681 }
3682 }
3683
3684 value = 1;
3685 }
3686
3687 // We might also get rid of useless "0||x" and "x||0", except it does
3688 // normalize x to 0 or 1. We could change it to "!!x", but it's not clear
3689 // that this would gain us much.
3690
3691 else
3692 {
3693 provide (e);
3694 return;
3695 }
3696
3697 if (session.verbose>2)
4af765b2 3698 clog << _("Collapsing constant logical-OR ") << *e->tok << endl;
a7e58d4c
JS
3699 relaxed_p = false;
3700
3701 literal_number* n = new literal_number(value);
3702 n->tok = e->tok;
3703 n->visit (this);
10328bcf
JS
3704}
3705
3706void
3707const_folder::visit_logical_and_expr (logical_and_expr* e)
3708{
a7e58d4c
JS
3709 int64_t value;
3710 literal_number* left = get_number (e->left);
3711 literal_number* right = get_number (e->right);
3712
3713 if (left && right)
3714 value = left->value && right->value;
3715
3716 else if ((left && !left->value) || (right && !right->value))
3717 {
3718 // If the const is on the left, we get to short-circuit the right
3719 // immediately. Otherwise, we can only eliminate the LHS if it's pure.
3720 if (right)
3721 {
3722 varuse_collecting_visitor vu(session);
3723 e->left->visit(&vu);
3724 if (!vu.side_effect_free())
3725 {
3726 provide (e);
3727 return;
3728 }
3729 }
3730
3731 value = 0;
3732 }
3733
3734 // We might also get rid of useless "1&&x" and "x&&1", except it does
3735 // normalize x to 0 or 1. We could change it to "!!x", but it's not clear
3736 // that this would gain us much.
3737
3738 else
3739 {
3740 provide (e);
3741 return;
3742 }
3743
3744 if (session.verbose>2)
4af765b2 3745 clog << _("Collapsing constant logical-AND ") << *e->tok << endl;
a7e58d4c
JS
3746 relaxed_p = false;
3747
3748 literal_number* n = new literal_number(value);
3749 n->tok = e->tok;
3750 n->visit (this);
10328bcf
JS
3751}
3752
3753void
3754const_folder::visit_comparison (comparison* e)
3755{
f4869658
JS
3756 int comp;
3757
3758 literal_number *left_num, *right_num;
3759 literal_string *left_str, *right_str;
3760 get_literal(e->left, left_num, left_str);
3761 get_literal(e->right, right_num, right_str);
3762
3763 if (left_str && right_str)
3764 comp = left_str->value.compare(right_str->value);
3765
3766 else if (left_num && right_num)
3767 comp = left_num->value < right_num->value ? -1 :
3768 left_num->value > right_num->value ? 1 : 0;
3769
3770 else if ((left_num && ((left_num->value == LLONG_MIN &&
3771 (e->op == "<=" || e->op == ">")) ||
3772 (left_num->value == LLONG_MAX &&
3773 (e->op == ">=" || e->op == "<"))))
3774 ||
3775 (right_num && ((right_num->value == LLONG_MIN &&
3776 (e->op == ">=" || e->op == "<")) ||
3777 (right_num->value == LLONG_MAX &&
3778 (e->op == "<=" || e->op == ">")))))
3779 {
3780 expression* other = left_num ? e->right : e->left;
3781 varuse_collecting_visitor vu(session);
3782 other->visit(&vu);
3783 if (!vu.side_effect_free())
3784 provide (e);
3785 else
3786 {
3787 if (session.verbose>2)
4af765b2 3788 clog << _("Collapsing constant-boundary comparison ") << *e->tok << endl;
f4869658
JS
3789 relaxed_p = false;
3790
3791 // ops <= and >= are true, < and > are false
3792 literal_number* n = new literal_number( e->op.length() == 2 );
3793 n->tok = e->tok;
3794 n->visit (this);
3795 }
3796 return;
3797 }
3798
3799 else
3800 {
3801 provide (e);
3802 return;
3803 }
3804
3805 if (session.verbose>2)
4af765b2 3806 clog << _("Collapsing constant comparison ") << *e->tok << endl;
f4869658
JS
3807 relaxed_p = false;
3808
3809 int64_t value;
3810 if (e->op == "==")
3811 value = comp == 0;
3812 else if (e->op == "!=")
3813 value = comp != 0;
3814 else if (e->op == "<")
3815 value = comp < 0;
3816 else if (e->op == ">")
3817 value = comp > 0;
3818 else if (e->op == "<=")
3819 value = comp <= 0;
3820 else if (e->op == ">=")
3821 value = comp >= 0;
3822 else
dc09353a 3823 throw SEMANTIC_ERROR (_("unsupported comparison operator ") + e->op);
f4869658
JS
3824
3825 literal_number* n = new literal_number(value);
3826 n->tok = e->tok;
3827 n->visit (this);
10328bcf
JS
3828}
3829
3830void
3831const_folder::visit_concatenation (concatenation* e)
3832{
29b1a9b7
JS
3833 literal_string* left = get_string (e->left);
3834 literal_string* right = get_string (e->right);
3835
3836 if (left && right)
3837 {
3838 if (session.verbose>2)
4af765b2 3839 clog << _("Collapsing constant concatenation ") << *e->tok << endl;
29b1a9b7
JS
3840 relaxed_p = false;
3841
3842 literal_string* n = new literal_string (*left);
3843 n->tok = e->tok;
3844 n->value.append(right->value);
3845 n->visit (this);
3846 }
3847 else if ((left && left->value.empty()) ||
3848 (right && right->value.empty()))
3849 {
3850 if (session.verbose>2)
4af765b2 3851 clog << _("Collapsing identity concatenation ") << *e->tok << endl;
29b1a9b7
JS
3852 relaxed_p = false;
3853 provide(left ? e->right : e->left);
3854 }
3855 else
3856 provide (e);
10328bcf
JS
3857}
3858
3859void
3860const_folder::visit_ternary_expression (ternary_expression* e)
3861{
3862 literal_number* cond = get_number (e->cond);
3863 if (!cond)
3864 {
3865 replace (e->truevalue);
3866 replace (e->falsevalue);
3867 provide (e);
3868 }
3869 else
3870 {
3871 if (session.verbose>2)
4af765b2
LB
3872 clog << _F("Collapsing constant-%" PRIi64 " ternary %s",
3873 cond->value, lex_cast(*e->tok).c_str()) << endl;
10328bcf
JS
3874 relaxed_p = false;
3875
3876 expression* n = cond->value ? e->truevalue : e->falsevalue;
3877 n->visit (this);
3878 }
3879}
3880
b7aedf26
JS
3881void
3882const_folder::visit_defined_op (defined_op* e)
3883{
3884 // If a @defined makes it this far, then it is, de facto, undefined.
3885
3886 if (session.verbose>2)
4af765b2 3887 clog << _("Collapsing untouched @defined check ") << *e->tok << endl;
b7aedf26
JS
3888 relaxed_p = false;
3889
3890 literal_number* n = new literal_number (0);
3891 n->tok = e->tok;
3892 n->visit (this);
3893}
3894
9fab2262
JS
3895void
3896const_folder::visit_target_symbol (target_symbol* e)
3897{
a45664f4 3898 if (session.skip_badvars)
9fab2262
JS
3899 {
3900 // Upon user request for ignoring context, the symbol is replaced
3901 // with a literal 0 and a warning message displayed
3902 // XXX this ignores possible side-effects, e.g. in array indexes
3903 literal_number* ln_zero = new literal_number (0);
3904 ln_zero->tok = e->tok;
3905 provide (ln_zero);
bad814e8 3906 session.print_warning (_("Bad $context variable being substituted with literal 0"),
9fab2262 3907 e->tok);
9fab2262
JS
3908 relaxed_p = false;
3909 }
3910 else
3911 update_visitor::visit_target_symbol (e);
3912}
3913
10328bcf
JS
3914static void semantic_pass_const_fold (systemtap_session& s, bool& relaxed_p)
3915{
3916 // Let's simplify statements with constant values.
3917
3918 const_folder cf (s, relaxed_p);
3919 // This instance may be reused for multiple probe/function body trims.
3920
3921 for (unsigned i=0; i<s.probes.size(); i++)
3922 cf.replace (s.probes[i]->body);
3923 for (map<string,functiondecl*>::iterator it = s.functions.begin();
3924 it != s.functions.end(); it++)
3925 cf.replace (it->second->body);
3926}
3927
3928
88bbd60d
DS
3929struct duplicate_function_remover: public functioncall_traversing_visitor
3930{
3931 systemtap_session& s;
88bbd60d
DS
3932 map<functiondecl*, functiondecl*>& duplicate_function_map;
3933
c214bd6a 3934 duplicate_function_remover(systemtap_session& sess,
88bbd60d 3935 map<functiondecl*, functiondecl*>&dfm):
c214bd6a 3936 s(sess), duplicate_function_map(dfm) {};
88bbd60d
DS
3937
3938 void visit_functioncall (functioncall* e);
3939};
3940
3941void
3942duplicate_function_remover::visit_functioncall (functioncall *e)
3943{
3944 functioncall_traversing_visitor::visit_functioncall (e);
3945
3946 // If the current function call reference points to a function that
3947 // is a duplicate, replace it.
3948 if (duplicate_function_map.count(e->referent) != 0)
3949 {
3950 if (s.verbose>2)
4af765b2
LB
3951 clog << _F("Changing %s reference to %s reference\n",
3952 e->referent->name.c_str(), duplicate_function_map[e->referent]->name.c_str());
88bbd60d
DS
3953 e->tok = duplicate_function_map[e->referent]->tok;
3954 e->function = duplicate_function_map[e->referent]->name;
3955 e->referent = duplicate_function_map[e->referent];
88bbd60d
DS
3956 }
3957}
3958
3959static string
3960get_functionsig (functiondecl* f)
3961{
3962 ostringstream s;
3963
3964 // Get the "name:args body" of the function in s. We have to
3965 // include the args since the function 'x1(a, b)' is different than
3966 // the function 'x2(b, a)' even if the bodies of the two functions
3967 // are exactly the same.
3968 f->printsig(s);
3969 f->body->print(s);
3970
3971 // printsig puts f->name + ':' on the front. Remove this
3972 // (otherwise, functions would never compare equal).
3973 string str = s.str().erase(0, f->name.size() + 1);
3974
3975 // Return the function signature.
3976 return str;
3977}
3978
bea72737 3979void semantic_pass_opt6 (systemtap_session& s, bool& relaxed_p)
88bbd60d
DS
3980{
3981 // Walk through all the functions, looking for duplicates.
3982 map<string, functiondecl*> functionsig_map;
3983 map<functiondecl*, functiondecl*> duplicate_function_map;
f76427a2
FCE
3984
3985
3986 vector<functiondecl*> newly_zapped_functions;
3987 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
88bbd60d 3988 {
f76427a2
FCE
3989 functiondecl *fd = it->second;
3990 string functionsig = get_functionsig(fd);
88bbd60d
DS
3991
3992 if (functionsig_map.count(functionsig) == 0)
c214bd6a
DS
3993 {
3994 // This function is unique. Remember it.
f76427a2 3995 functionsig_map[functionsig] = fd;
c214bd6a 3996 }
88bbd60d 3997 else
c214bd6a
DS
3998 {
3999 // This function is a duplicate.
f76427a2
FCE
4000 duplicate_function_map[fd] = functionsig_map[functionsig];
4001 newly_zapped_functions.push_back (fd);
c214bd6a 4002 relaxed_p = false;
c214bd6a 4003 }
88bbd60d 4004 }
f76427a2
FCE
4005 for (unsigned i=0; i<newly_zapped_functions.size(); i++)
4006 {
4007 map<string,functiondecl*>::iterator where = s.functions.find (newly_zapped_functions[i]->name);
4008 assert (where != s.functions.end());
4009 s.functions.erase (where);
4010 }
4011
88bbd60d
DS
4012
4013 // If we have duplicate functions, traverse down the tree, replacing
4014 // the appropriate function calls.
4015 // duplicate_function_remover::visit_functioncall() handles the
c214bd6a 4016 // details of replacing the function calls.
88bbd60d
DS
4017 if (duplicate_function_map.size() != 0)
4018 {
c214bd6a 4019 duplicate_function_remover dfr (s, duplicate_function_map);
88bbd60d
DS
4020
4021 for (unsigned i=0; i < s.probes.size(); i++)
4022 s.probes[i]->body->visit(&dfr);
4023 }
4024}
4025
cbfbbf69
FCE
4026
4027static int
c214bd6a 4028semantic_pass_optimize1 (systemtap_session& s)
cbfbbf69
FCE
4029{
4030 // In this pass, we attempt to rewrite probe/function bodies to
4031 // eliminate some blatantly unnecessary code. This is run before
4032 // type inference, but after symbol resolution and derived_probe
4033 // creation. We run an outer "relaxation" loop that repeats the
4034 // optimizations until none of them find anything to remove.
4035
4036 int rc = 0;
4037
bad814e8
CM
4038 // Save the old value of suppress_warnings, as we will be changing
4039 // it below.
4040 save_and_restore<bool> suppress_warnings(& s.suppress_warnings);
4041
cbfbbf69 4042 bool relaxed_p = false;
cfd621bc 4043 unsigned iterations = 0;
cbfbbf69
FCE
4044 while (! relaxed_p)
4045 {
e19ebcf7 4046 assert_no_interrupts();
49abf162 4047
cbfbbf69
FCE
4048 relaxed_p = true; // until proven otherwise
4049
bad814e8
CM
4050 // If the verbosity is high enough, always print warnings (overrides -w),
4051 // or if not, always suppress warnings for every itteration after the first.
4052 if(s.verbose > 2)
4053 s.suppress_warnings = false;
4054 else if (iterations > 0)
4055 s.suppress_warnings = true;
4056
c0f56268
JS
4057 if (!s.unoptimized)
4058 {
4059 semantic_pass_opt1 (s, relaxed_p);
4060 semantic_pass_opt2 (s, relaxed_p, iterations); // produce some warnings only on iteration=0
4061 semantic_pass_opt3 (s, relaxed_p);
4062 semantic_pass_opt4 (s, relaxed_p);
4063 semantic_pass_opt5 (s, relaxed_p);
4064 }
4065
4066 // For listing mode, we need const-folding regardless of optimization so
4067 // that @defined expressions can be properly resolved. PR11360
ad12c592
MW
4068 // We also want it in case variables are used in if/case expressions,
4069 // so enable always. PR11366
4070 semantic_pass_const_fold (s, relaxed_p);
cfd621bc
FCE
4071
4072 iterations ++;
c214bd6a
DS
4073 }
4074
c214bd6a
DS
4075 return rc;
4076}
4077
4078
4079static int
4080semantic_pass_optimize2 (systemtap_session& s)
4081{
4082 // This is run after type inference. We run an outer "relaxation"
4083 // loop that repeats the optimizations until none of them find
4084 // anything to remove.
4085
4086 int rc = 0;
4087
bad814e8
CM
4088 // Save the old value of suppress_warnings, as we will be changing
4089 // it below.
4090 save_and_restore<bool> suppress_warnings(& s.suppress_warnings);
4091
c214bd6a 4092 bool relaxed_p = false;
bad814e8 4093 unsigned iterations = 0;
c214bd6a
DS
4094 while (! relaxed_p)
4095 {
e19ebcf7 4096 assert_no_interrupts();
c214bd6a
DS
4097 relaxed_p = true; // until proven otherwise
4098
bad814e8
CM
4099 // If the verbosity is high enough, always print warnings (overrides -w),
4100 // or if not, always suppress warnings for every itteration after the first.
4101 if(s.verbose > 2)
4102 s.suppress_warnings = false;
4103 else if (iterations > 0)
4104 s.suppress_warnings = true;
4105
c0f56268
JS
4106 if (!s.unoptimized)
4107 semantic_pass_opt6 (s, relaxed_p);
bad814e8
CM
4108
4109 iterations++;
cbfbbf69
FCE
4110 }
4111
cbfbbf69
FCE
4112 return rc;
4113}
4114
4115
4116
2b066ec1
FCE
4117// ------------------------------------------------------------------------
4118// type resolution
4119
4120
4121static int
4122semantic_pass_types (systemtap_session& s)
4123{
4124 int rc = 0;
4125
4126 // next pass: type inference
4127 unsigned iterations = 0;
4128 typeresolution_info ti (s);
57148ee7 4129
2b066ec1
FCE
4130 ti.assert_resolvability = false;
4131 // XXX: maybe convert to exception-based error signalling
4132 while (1)
4133 {
e19ebcf7 4134 assert_no_interrupts();
49abf162 4135
2b066ec1 4136 iterations ++;
2b066ec1
FCE
4137 ti.num_newly_resolved = 0;
4138 ti.num_still_unresolved = 0;
4139
f76427a2 4140 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2b066ec1 4141 {
e19ebcf7 4142 assert_no_interrupts();
49abf162 4143
f76427a2 4144 functiondecl* fd = it->second;
bdef2583 4145 ti.current_probe = 0;
f76427a2 4146 ti.current_function = fd;
8a43522c 4147 ti.t = pe_unknown;
f76427a2 4148 fd->body->visit (& ti);
8a43522c
GH
4149 // NB: we don't have to assert a known type for
4150 // functions here, to permit a "void" function.
4151 // The translator phase will omit the "retvalue".
4152 //
f76427a2
FCE
4153 // if (fd->type == pe_unknown)
4154 // ti.unresolved (fd->tok);
5abd364d
JS
4155 for (unsigned i=0; i < fd->locals.size(); ++i)
4156 ti.check_local (fd->locals[i]);
57148ee7 4157 }
2b066ec1
FCE
4158
4159 for (unsigned j=0; j<s.probes.size(); j++)
4160 {
e19ebcf7 4161 assert_no_interrupts();
49abf162 4162
2b066ec1
FCE
4163 derived_probe* pn = s.probes[j];
4164 ti.current_function = 0;
bdef2583 4165 ti.current_probe = pn;
2b066ec1
FCE
4166 ti.t = pe_unknown;
4167 pn->body->visit (& ti);
5abd364d
JS
4168 for (unsigned i=0; i < pn->locals.size(); ++i)
4169 ti.check_local (pn->locals[i]);
5d23847d
FCE
4170
4171 probe_point* pp = pn->sole_location();
4172 if (pp->condition)
4173 {
4174 ti.current_function = 0;
4175 ti.current_probe = 0;
4176 ti.t = pe_long; // NB: expected type
4177 pp->condition->visit (& ti);
4178 }
2b066ec1
FCE
4179 }
4180
4181 for (unsigned j=0; j<s.globals.size(); j++)
4182 {
4183 vardecl* gd = s.globals[j];
4184 if (gd->type == pe_unknown)
4185 ti.unresolved (gd->tok);
bc889c8d
CM
4186 if(gd->arity == 0 && gd->wrap == true)
4187 {
dc09353a 4188 throw SEMANTIC_ERROR (_("wrapping not supported for scalars"), gd->tok);
bc889c8d 4189 }
2b066ec1 4190 }
57148ee7 4191
2b066ec1 4192 if (ti.num_newly_resolved == 0) // converged
78f6bba6
FCE
4193 {
4194 if (ti.num_still_unresolved == 0)
4195 break; // successfully
4196 else if (! ti.assert_resolvability)
4197 ti.assert_resolvability = true; // last pass, with error msgs
4198 else
4199 { // unsuccessful conclusion
4200 rc ++;
4201 break;
4202 }
4203 }
2b066ec1 4204 }
57148ee7 4205
7e41d3dc 4206 return rc + s.num_errors();
2b066ec1
FCE
4207}
4208
4209
bdef2583
FCE
4210
4211typeresolution_info::typeresolution_info (systemtap_session& s):
74fe61bc
LB
4212 session(s), num_newly_resolved(0), num_still_unresolved(0),
4213 assert_resolvability(false), current_function(0), current_probe(0),
4214 t(pe_unknown)
bdef2583
FCE
4215{
4216}
4217
4218
2b066ec1
FCE
4219void
4220typeresolution_info::visit_literal_number (literal_number* e)
4221{
4222 assert (e->type == pe_long);
4223 if ((t == e->type) || (t == pe_unknown))
4224 return;
4225
4226 mismatch (e->tok, e->type, t);
4227}
4228
4229
4230void
4231typeresolution_info::visit_literal_string (literal_string* e)
4232{
4233 assert (e->type == pe_string);
4234 if ((t == e->type) || (t == pe_unknown))
4235 return;
4236
4237 mismatch (e->tok, e->type, t);
4238}
4239
4240
4241void
4242typeresolution_info::visit_logical_or_expr (logical_or_expr *e)
4243{
4244 visit_binary_expression (e);
4245}
4246
4247
4248void
4249typeresolution_info::visit_logical_and_expr (logical_and_expr *e)
4250{
4251 visit_binary_expression (e);
4252}
4253
93daaca8
SM
4254void
4255typeresolution_info::visit_regex_query (regex_query *e)
4256{
4257 // NB: result of regex query is an integer!
4258 if (t == pe_stats || t == pe_string)
4259 invalid (e->tok, t);
4260
4261 t = pe_string;
4262 e->left->visit (this);
4263 t = pe_string;
4264 e->right->visit (this); // parser ensures this is a literal known at compile time
4265
4266 if (e->type == pe_unknown)
4267 {
4268 e->type = pe_long;
4269 resolved (e->tok, e->type);
4270 }
4271}
4272
2b066ec1
FCE
4273
4274void
4275typeresolution_info::visit_comparison (comparison *e)
4276{
d5d7c2cc 4277 // NB: result of any comparison is an integer!
553d27a5
FCE
4278 if (t == pe_stats || t == pe_string)
4279 invalid (e->tok, t);
4280
4281 t = (e->right->type != pe_unknown) ? e->right->type : pe_unknown;
4282 e->left->visit (this);
4283 t = (e->left->type != pe_unknown) ? e->left->type : pe_unknown;
4284 e->right->visit (this);
57148ee7 4285
553d27a5
FCE
4286 if (e->left->type != pe_unknown &&
4287 e->right->type != pe_unknown &&
4288 e->left->type != e->right->type)
4289 mismatch (e->tok, e->left->type, e->right->type);
57148ee7 4290
553d27a5
FCE
4291 if (e->type == pe_unknown)
4292 {
4293 e->type = pe_long;
4294 resolved (e->tok, e->type);
4295 }
2b066ec1
FCE
4296}
4297
4298
4299void
4300typeresolution_info::visit_concatenation (concatenation *e)
4301{
553d27a5
FCE
4302 if (t != pe_unknown && t != pe_string)
4303 invalid (e->tok, t);
4304
4305 t = pe_string;
4306 e->left->visit (this);
4307 t = pe_string;
4308 e->right->visit (this);
4309
4310 if (e->type == pe_unknown)
4311 {
4312 e->type = pe_string;
4313 resolved (e->tok, e->type);
4314 }
2b066ec1
FCE
4315}
4316
4317
2b066ec1
FCE
4318void
4319typeresolution_info::visit_assignment (assignment *e)
4320{
553d27a5
FCE
4321 if (t == pe_stats)
4322 invalid (e->tok, t);
2b066ec1 4323
2b066ec1
FCE
4324 if (e->op == "<<<") // stats aggregation
4325 {
553d27a5
FCE
4326 if (t == pe_string)
4327 invalid (e->tok, t);
4328
2b066ec1
FCE
4329 t = pe_stats;
4330 e->left->visit (this);
4331 t = pe_long;
4332 e->right->visit (this);
57b73400
GH
4333 if (e->type == pe_unknown ||
4334 e->type == pe_stats)
2b066ec1
FCE
4335 {
4336 e->type = pe_long;
4337 resolved (e->tok, e->type);
4338 }
4339 }
57b73400
GH
4340
4341 else if (e->left->type == pe_stats)
4342 invalid (e->left->tok, e->left->type);
4343
4344 else if (e->right->type == pe_stats)
4345 invalid (e->right->tok, e->right->type);
4346
553d27a5 4347 else if (e->op == "+=" || // numeric only
d5d7c2cc
FCE
4348 e->op == "-=" ||
4349 e->op == "*=" ||
4350 e->op == "/=" ||
4351 e->op == "%=" ||
4352 e->op == "&=" ||
4353 e->op == "^=" ||
4354 e->op == "|=" ||
4355 e->op == "<<=" ||
4356 e->op == ">>=" ||
553d27a5 4357 false)
2b066ec1 4358 {
553d27a5 4359 visit_binary_expression (e);
2b066ec1 4360 }
d5d7c2cc
FCE
4361 else if (e->op == ".=" || // string only
4362 false)
4363 {
4364 if (t == pe_long || t == pe_stats)
4365 invalid (e->tok, t);
4366
4367 t = pe_string;
4368 e->left->visit (this);
4369 t = pe_string;
4370 e->right->visit (this);
4371 if (e->type == pe_unknown)
4372 {
4373 e->type = pe_string;
4374 resolved (e->tok, e->type);
4375 }
4376 }
4377 else if (e->op == "=") // overloaded = for string & numeric operands
2b066ec1 4378 {
553d27a5 4379 // logic similar to ternary_expression
2b066ec1 4380 exp_type sub_type = t;
553d27a5
FCE
4381
4382 // Infer types across the l/r values
4383 if (sub_type == pe_unknown && e->type != pe_unknown)
2b066ec1 4384 sub_type = e->type;
553d27a5
FCE
4385
4386 t = (sub_type != pe_unknown) ? sub_type :
4387 (e->right->type != pe_unknown) ? e->right->type :
4388 pe_unknown;
2b066ec1 4389 e->left->visit (this);
553d27a5
FCE
4390 t = (sub_type != pe_unknown) ? sub_type :
4391 (e->left->type != pe_unknown) ? e->left->type :
4392 pe_unknown;
2b066ec1 4393 e->right->visit (this);
57148ee7 4394
553d27a5 4395 if ((sub_type != pe_unknown) && (e->type == pe_unknown))
2b066ec1
FCE
4396 {
4397 e->type = sub_type;
4398 resolved (e->tok, e->type);
4399 }
553d27a5 4400 if ((sub_type == pe_unknown) && (e->left->type != pe_unknown))
2b066ec1
FCE
4401 {
4402 e->type = e->left->type;
4403 resolved (e->tok, e->type);
4404 }
553d27a5
FCE
4405
4406 if (e->left->type != pe_unknown &&
4407 e->right->type != pe_unknown &&
4408 e->left->type != e->right->type)
4409 mismatch (e->tok, e->left->type, e->right->type);
d02548c0 4410
553d27a5 4411 }
d5d7c2cc 4412 else
dc09353a 4413 throw SEMANTIC_ERROR (_("unsupported assignment operator ") + e->op);
553d27a5
FCE
4414}
4415
4416
7d902887
FCE
4417void
4418typeresolution_info::visit_embedded_expr (embedded_expr *e)
4419{
4420 if (e->type == pe_unknown)
4421 {
4422 if (e->code.find ("/* string */") != string::npos)
4423 e->type = pe_string;
4424 else // if (e->code.find ("/* long */") != string::npos)
4425 e->type = pe_long;
4426
4427 resolved (e->tok, e->type);
4428 }
4429}
4430
4431
553d27a5
FCE
4432void
4433typeresolution_info::visit_binary_expression (binary_expression* e)
4434{
4435 if (t == pe_stats || t == pe_string)
4436 invalid (e->tok, t);
4437
4438 t = pe_long;
4439 e->left->visit (this);
4440 t = pe_long;
4441 e->right->visit (this);
4442
4443 if (e->left->type != pe_unknown &&
4444 e->right->type != pe_unknown &&
4445 e->left->type != e->right->type)
4446 mismatch (e->tok, e->left->type, e->right->type);
57148ee7 4447
553d27a5
FCE
4448 if (e->type == pe_unknown)
4449 {
4450 e->type = pe_long;
4451 resolved (e->tok, e->type);
2b066ec1
FCE
4452 }
4453}
4454
4455
4456void
4457typeresolution_info::visit_pre_crement (pre_crement *e)
4458{
4459 visit_unary_expression (e);
4460}
4461
4462
4463void
4464typeresolution_info::visit_post_crement (post_crement *e)
4465{
4466 visit_unary_expression (e);
4467}
4468
4469
4470void
4471typeresolution_info::visit_unary_expression (unary_expression* e)
4472{
553d27a5
FCE
4473 if (t == pe_stats || t == pe_string)
4474 invalid (e->tok, t);
4475
2b066ec1
FCE
4476 t = pe_long;
4477 e->operand->visit (this);
4478
553d27a5 4479 if (e->type == pe_unknown)
2b066ec1
FCE
4480 {
4481 e->type = pe_long;
4482 resolved (e->tok, e->type);
4483 }
4484}
4485
4486
2b066ec1
FCE
4487void
4488typeresolution_info::visit_ternary_expression (ternary_expression* e)
4489{
4490 exp_type sub_type = t;
4491
4492 t = pe_long;
4493 e->cond->visit (this);
4494
553d27a5 4495 // Infer types across the true/false arms of the ternary expression.
2b066ec1
FCE
4496
4497 if (sub_type == pe_unknown && e->type != pe_unknown)
4498 sub_type = e->type;
4499 t = sub_type;
4500 e->truevalue->visit (this);
4501 t = sub_type;
4502 e->falsevalue->visit (this);
4503
4504 if ((sub_type == pe_unknown) && (e->type != pe_unknown))
4505 ; // already resolved
4506 else if ((sub_type != pe_unknown) && (e->type == pe_unknown))
4507 {
4508 e->type = sub_type;
4509 resolved (e->tok, e->type);
4510 }
4511 else if ((sub_type == pe_unknown) && (e->truevalue->type != pe_unknown))
4512 {
4513 e->type = e->truevalue->type;
4514 resolved (e->tok, e->type);
4515 }
4516 else if ((sub_type == pe_unknown) && (e->falsevalue->type != pe_unknown))
4517 {
4518 e->type = e->falsevalue->type;
4519 resolved (e->tok, e->type);
4520 }
4521 else if (e->type != sub_type)
4522 mismatch (e->tok, sub_type, e->type);
4523}
4524
4525
4526template <class Referrer, class Referent>
4527void resolve_2types (Referrer* referrer, Referent* referent,
31966088 4528 typeresolution_info* r, exp_type t, bool accept_unknown = false)
2b066ec1
FCE
4529{
4530 exp_type& re_type = referrer->type;
4531 const token* re_tok = referrer->tok;
4532 exp_type& te_type = referent->type;
4533 const token* te_tok = referent->tok;
4534
4535 if (t != pe_unknown && re_type == t && re_type == te_type)
4536 ; // do nothing: all three e->types in agreement
4537 else if (t == pe_unknown && re_type != pe_unknown && re_type == te_type)
4538 ; // do nothing: two known e->types in agreement
4539 else if (re_type != pe_unknown && te_type != pe_unknown && re_type != te_type)
4540 r->mismatch (re_tok, re_type, te_type);
4541 else if (re_type != pe_unknown && t != pe_unknown && re_type != t)
4542 r->mismatch (re_tok, re_type, t);
4543 else if (te_type != pe_unknown && t != pe_unknown && te_type != t)
4544 r->mismatch (te_tok, te_type, t);
4545 else if (re_type == pe_unknown && t != pe_unknown)
4546 {
4547 // propagate from upstream
4548 re_type = t;
4549 r->resolved (re_tok, re_type);
4550 // catch re_type/te_type mismatch later
4551 }
4552 else if (re_type == pe_unknown && te_type != pe_unknown)
4553 {
4554 // propagate from referent
4555 re_type = te_type;
4556 r->resolved (re_tok, re_type);
4557 // catch re_type/t mismatch later
4558 }
4559 else if (re_type != pe_unknown && te_type == pe_unknown)
4560 {
4561 // propagate to referent
4562 te_type = re_type;
4563 r->resolved (te_tok, te_type);
4564 // catch re_type/t mismatch later
4565 }
31966088 4566 else if (! accept_unknown)
2b066ec1
FCE
4567 r->unresolved (re_tok);
4568}
4569
4570
4571void
4572typeresolution_info::visit_symbol (symbol* e)
4573{
4574 assert (e->referent != 0);
d02548c0 4575 resolve_2types (e, e->referent, this, t);
2b066ec1
FCE
4576}
4577
4578
d7f3e0c5
GH
4579void
4580typeresolution_info::visit_target_symbol (target_symbol* e)
4581{
cbfbbf69
FCE
4582 // This occurs only if a target symbol was not resolved over in
4583 // tapset.cxx land, that error was properly suppressed, and the
4584 // later unused-expression-elimination pass didn't get rid of it
4585 // either. So we have a target symbol that is believed to be of
4586 // genuine use, yet unresolved by the provider.
ba6f838d
FCE
4587
4588 if (session.verbose > 2)
4589 {
4af765b2 4590 clog << _("Resolution problem with ");
ba6f838d
FCE
4591 if (current_function)
4592 {
4593 clog << "function " << current_function->name << endl;
4594 current_function->body->print (clog);
4595 clog << endl;
4596 }
4597 else if (current_probe)
4598 {
da2df842 4599 clog << "probe " << *current_probe->sole_location() << endl;
ba6f838d
FCE
4600 current_probe->body->print (clog);
4601 clog << endl;
4602 }
57148ee7 4603 else
4af765b2
LB
4604 //TRANSLATORS: simply saying not an issue with a probe or function
4605 clog << _("other") << endl;
ba6f838d
FCE
4606 }
4607
9b48ce88
FCE
4608 if (e->saved_conversion_error)
4609 throw (* (e->saved_conversion_error));
4610 else
dc09353a 4611 throw SEMANTIC_ERROR(_("unresolved target-symbol expression"), e->tok);
d7f3e0c5
GH
4612}
4613
4614
bd1fcbad
YZ
4615void
4616typeresolution_info::visit_atvar_op (atvar_op* e)
4617{
4618 // This occurs only if an @var() was not resolved over in
4619 // tapset.cxx land, that error was properly suppressed, and the
4620 // later unused-expression-elimination pass didn't get rid of it
4621 // either. So we have an @var() that is believed to be of
4622 // genuine use, yet unresolved by the provider.
4623
4624 if (session.verbose > 2)
4625 {
4626 clog << _("Resolution problem with ");
4627 if (current_function)
4628 {
4629 clog << "function " << current_function->name << endl;
4630 current_function->body->print (clog);
4631 clog << endl;
4632 }
4633 else if (current_probe)
4634 {
4635 clog << "probe " << *current_probe->sole_location() << endl;
4636 current_probe->body->print (clog);
4637 clog << endl;
4638 }
4639 else
4640 //TRANSLATORS: simply saying not an issue with a probe or function
4641 clog << _("other") << endl;
4642 }
4643
4644 if (e->saved_conversion_error)
4645 throw (* (e->saved_conversion_error));
4646 else
dc09353a 4647 throw SEMANTIC_ERROR(_("unresolved @var() expression"), e->tok);
bd1fcbad
YZ
4648}
4649
4650
30263a73
FCE
4651void
4652typeresolution_info::visit_defined_op (defined_op* e)
4653{
dc09353a 4654 throw SEMANTIC_ERROR(_("unexpected @defined"), e->tok);
30263a73
FCE
4655}
4656
4657
8cc799a5
JS
4658void
4659typeresolution_info::visit_entry_op (entry_op* e)
4660{
dc09353a 4661 throw SEMANTIC_ERROR(_("@entry is only valid in .return probes"), e->tok);
8cc799a5
JS
4662}
4663
4664
9b5af295
JS
4665void
4666typeresolution_info::visit_cast_op (cast_op* e)
4667{
4668 // Like target_symbol, a cast_op shouldn't survive this far
4669 // unless it was not resolved and its value is really needed.
4670 if (e->saved_conversion_error)
4671 throw (* (e->saved_conversion_error));
4672 else
dc09353a 4673 throw SEMANTIC_ERROR(_F("type definition '%s' not found in '%s'",
4583161b 4674 e->type_name.c_str(), e->module.c_str()), e->tok);
9b5af295
JS
4675}
4676
4677
3689db05
SC
4678void
4679typeresolution_info::visit_perf_op (perf_op* e)
4680{
4681 // A perf_op should already be resolved
4682 if (t == pe_stats || t == pe_string)
4683 invalid (e->tok, t);
4684
ad583484
FCE
4685 e->type = pe_long;
4686
4687 // (There is no real need to visit our operand - by parser
4688 // construction, it's always a string literal, with its type already
4689 // set.)
4690 t = pe_string;
3689db05
SC
4691 e->operand->visit (this);
4692}
4693
4694
2b066ec1
FCE
4695void
4696typeresolution_info::visit_arrayindex (arrayindex* e)
4697{
2b066ec1 4698
d02548c0
GH
4699 symbol *array = NULL;
4700 hist_op *hist = NULL;
4701 classify_indexable(e->base, array, hist);
57148ee7 4702
d02548c0
GH
4703 // Every hist_op has type [int]:int, that is to say, every hist_op
4704 // is a pseudo-one-dimensional integer array type indexed by
4705 // integers (bucket numbers).
4706
4707 if (hist)
4708 {
4709 if (e->indexes.size() != 1)
4710 unresolved (e->tok);
4711 t = pe_long;
4712 e->indexes[0]->visit (this);
4713 if (e->indexes[0]->type != pe_long)
4714 unresolved (e->tok);
a4636912 4715 hist->visit (this);
1bbeef03
GH
4716 if (e->type != pe_long)
4717 {
4718 e->type = pe_long;
4719 resolved (e->tok, pe_long);
4720 }
d02548c0
GH
4721 return;
4722 }
4723
4724 // Now we are left with "normal" map inference and index checking.
4725
4726 assert (array);
4727 assert (array->referent != 0);
4728 resolve_2types (e, array->referent, this, t);
2b066ec1
FCE
4729
4730 // now resolve the array indexes
69c68955
FCE
4731
4732 // if (e->referent->index_types.size() == 0)
4733 // // redesignate referent as array
4734 // e->referent->set_arity (e->indexes.size ());
2b066ec1 4735
d02548c0 4736 if (e->indexes.size() != array->referent->index_types.size())
2b066ec1
FCE
4737 unresolved (e->tok); // symbol resolution should prevent this
4738 else for (unsigned i=0; i<e->indexes.size(); i++)
4739 {
4740 expression* ee = e->indexes[i];
d02548c0 4741 exp_type& ft = array->referent->index_types [i];
2b066ec1
FCE
4742 t = ft;
4743 ee->visit (this);
4744 exp_type at = ee->type;
4745
4746 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
4747 {
4748 // propagate to formal type
4749 ft = at;
d02548c0 4750 resolved (array->referent->tok, ft);
2b066ec1
FCE
4751 // uses array decl as there is no token for "formal type"
4752 }
4753 if (at == pe_stats)
4754 invalid (ee->tok, at);
4755 if (ft == pe_stats)
4756 invalid (ee->tok, ft);
4757 if (at != pe_unknown && ft != pe_unknown && ft != at)
4758 mismatch (e->tok, at, ft);
4759 if (at == pe_unknown)
313b2f74 4760 unresolved (ee->tok);
2b066ec1
FCE
4761 }
4762}
4763
4764
4765void
4766typeresolution_info::visit_functioncall (functioncall* e)
4767{
4768 assert (e->referent != 0);
4769
57148ee7 4770 resolve_2types (e, e->referent, this, t, true); // accept unknown type
2b066ec1
FCE
4771
4772 if (e->type == pe_stats)
4773 invalid (e->tok, e->type);
4774
2b066ec1
FCE
4775 // now resolve the function parameters
4776 if (e->args.size() != e->referent->formal_args.size())
4777 unresolved (e->tok); // symbol resolution should prevent this
4778 else for (unsigned i=0; i<e->args.size(); i++)
4779 {
4780 expression* ee = e->args[i];
4781 exp_type& ft = e->referent->formal_args[i]->type;
4782 const token* fe_tok = e->referent->formal_args[i]->tok;
4783 t = ft;
4784 ee->visit (this);
4785 exp_type at = ee->type;
57148ee7 4786
2b066ec1
FCE
4787 if (((at == pe_string) || (at == pe_long)) && ft == pe_unknown)
4788 {
4789 // propagate to formal arg
4790 ft = at;
4791 resolved (e->referent->formal_args[i]->tok, ft);
4792 }
4793 if (at == pe_stats)
4794 invalid (e->tok, at);
4795 if (ft == pe_stats)
4796 invalid (fe_tok, ft);
4797 if (at != pe_unknown && ft != pe_unknown && ft != at)
4798 mismatch (e->tok, at, ft);
4799 if (at == pe_unknown)
4800 unresolved (e->tok);
4801 }
4802}
4803
4804
4805void
4806typeresolution_info::visit_block (block* e)
4807{
4808 for (unsigned i=0; i<e->statements.size(); i++)
4809 {
57148ee7 4810 try
2b066ec1
FCE
4811 {
4812 t = pe_unknown;
4813 e->statements[i]->visit (this);
4814 }
4815 catch (const semantic_error& e)
4816 {
4817 session.print_error (e);
4818 }
4819 }
4820}
4821
4822
f4fe2e93
FCE
4823void
4824typeresolution_info::visit_try_block (try_block* e)
4825{
4826 if (e->try_block)
4827 e->try_block->visit (this);
4828 if (e->catch_error_var)
4829 {
4830 t = pe_string;
4831 e->catch_error_var->visit (this);
4832 }
4833 if (e->catch_block)
4834 e->catch_block->visit (this);
4835}
4836
4837
54dfabe9 4838void
6a80494e 4839typeresolution_info::visit_embeddedcode (embeddedcode* s)
54dfabe9 4840{
6a80494e
FCE
4841 // PR11573. If we have survived thus far with a piece of embedded
4842 // code that requires uprobes, we need to track this.
4843 //
4844 // This is an odd place for this check, as opposed
4845 // to a separate 'optimization' pass, or c_unparser::visit_embeddedcode
4846 // over yonder in pass 3. However, we want to do it during pass 2 so
4847 // that cached sessions also get the uprobes treatment.
26c2e4c2
SM
4848 if (! session.need_uprobes
4849 && s->code.find("/* pragma:uprobes */") != string::npos)
6a80494e
FCE
4850 {
4851 if (session.verbose > 2)
4af765b2 4852 clog << _("Activating uprobes support because /* pragma:uprobes */ seen.") << endl;
6a80494e
FCE
4853 session.need_uprobes = true;
4854 }
26c2e4c2
SM
4855
4856 // PR15065. Likewise, we need to detect /* pragma:tagged_dfa */
4857 // before the gen_dfa_table pass. Again, the typechecking part of
4858 // pass 2 is a good place for this.
4859 if (! session.need_tagged_dfa
4860 && s->code.find("/* pragma:tagged_dfa */") != string::npos)
4861 {
112e9e2b
SM
4862 // if (session.verbose > 2)
4863 // clog << _F("Turning on DFA subexpressions, pragma:tagged_dfa found in %s",
4864 // current_function->name.c_str()) << endl;
4865 // session.need_tagged_dfa = true;
dc09353a 4866 throw SEMANTIC_ERROR (_("Tagged DFA support is not yet available"), s->tok);
26c2e4c2 4867 }
54dfabe9
FCE
4868}
4869
4870
2b066ec1
FCE
4871void
4872typeresolution_info::visit_if_statement (if_statement* e)
4873{
4874 t = pe_long;
4875 e->condition->visit (this);
4876
4877 t = pe_unknown;
4878 e->thenblock->visit (this);
4879
4880 if (e->elseblock)
4881 {
4882 t = pe_unknown;
4883 e->elseblock->visit (this);
4884 }
4885}
4886
4887
4888void
4889typeresolution_info::visit_for_loop (for_loop* e)
4890{
4891 t = pe_unknown;
cbfbbf69 4892 if (e->init) e->init->visit (this);
2b066ec1
FCE
4893 t = pe_long;
4894 e->cond->visit (this);
4895 t = pe_unknown;
57148ee7 4896 if (e->incr) e->incr->visit (this);
2b066ec1 4897 t = pe_unknown;
57148ee7 4898 e->block->visit (this);
2b066ec1
FCE
4899}
4900
4901
69c68955
FCE
4902void
4903typeresolution_info::visit_foreach_loop (foreach_loop* e)
4904{
4905 // See also visit_arrayindex.
4906 // This is different in that, being a statement, we can't assign
4907 // a type to the outer array, only propagate to/from the indexes
4908
4909 // if (e->referent->index_types.size() == 0)
4910 // // redesignate referent as array
4911 // e->referent->set_arity (e->indexes.size ());
4912
c261711d 4913 exp_type wanted_value = pe_unknown;
d02548c0
GH
4914 symbol *array = NULL;
4915 hist_op *hist = NULL;
4916 classify_indexable(e->base, array, hist);
69c68955 4917
d02548c0 4918 if (hist)
57148ee7 4919 {
d02548c0
GH
4920 if (e->indexes.size() != 1)
4921 unresolved (e->tok);
4922 t = pe_long;
4923 e->indexes[0]->visit (this);
4924 if (e->indexes[0]->type != pe_long)
4925 unresolved (e->tok);
a4636912 4926 hist->visit (this);
c261711d 4927 wanted_value = pe_long;
d02548c0
GH
4928 }
4929 else
4930 {
57148ee7 4931 assert (array);
d02548c0
GH
4932 if (e->indexes.size() != array->referent->index_types.size())
4933 unresolved (e->tok); // symbol resolution should prevent this
4934 else for (unsigned i=0; i<e->indexes.size(); i++)
4935 {
4936 expression* ee = e->indexes[i];
4937 exp_type& ft = array->referent->index_types [i];
4938 t = ft;
4939 ee->visit (this);
4940 exp_type at = ee->type;
57148ee7 4941
d02548c0
GH
4942 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
4943 {
4944 // propagate to formal type
4945 ft = at;
4946 resolved (array->referent->tok, ft);
4947 // uses array decl as there is no token for "formal type"
4948 }
4949 if (at == pe_stats)
4950 invalid (ee->tok, at);
4951 if (ft == pe_stats)
4952 invalid (ee->tok, ft);
4953 if (at != pe_unknown && ft != pe_unknown && ft != at)
4954 mismatch (e->tok, at, ft);
4955 if (at == pe_unknown)
4956 unresolved (ee->tok);
4957 }
c261711d
JS
4958 t = pe_unknown;
4959 array->visit (this);
4960 wanted_value = array->type;
4961 }
4962
4963 if (e->value)
4964 {
4965 if (wanted_value == pe_stats)
4966 invalid(e->value->tok, wanted_value);
4967 else if (wanted_value != pe_unknown)
4968 check_arg_type(wanted_value, e->value);
4969 else
4970 {
4971 t = pe_unknown;
4972 e->value->visit (this);
4973 }
69c68955
FCE
4974 }
4975
fd5689dc
FCE
4976 /* Prevent @sum etc. aggregate sorting on non-statistics arrays. */
4977 if (wanted_value != pe_unknown)
4978 if (e->sort_aggr != sc_none && wanted_value != pe_stats)
4979 invalid (array->tok, wanted_value);
4980
27f21e8c
DS
4981 if (e->limit)
4982 {
4983 t = pe_long;
4984 e->limit->visit (this);
4985 }
4986
69c68955 4987 t = pe_unknown;
57148ee7 4988 e->block->visit (this);
69c68955
FCE
4989}
4990
4991
2b066ec1 4992void
78f6bba6 4993typeresolution_info::visit_null_statement (null_statement*)
2b066ec1
FCE
4994{
4995}
4996
4997
4998void
4999typeresolution_info::visit_expr_statement (expr_statement* e)
5000{
5001 t = pe_unknown;
5002 e->value->visit (this);
5003}
5004
5005
57148ee7 5006struct delete_statement_typeresolution_info:
d98d459c
GH
5007 public throwing_visitor
5008{
5009 typeresolution_info *parent;
5010 delete_statement_typeresolution_info (typeresolution_info *p):
4af765b2 5011 throwing_visitor (_("invalid operand of delete expression")),
d98d459c
GH
5012 parent (p)
5013 {}
5014
5015 void visit_arrayindex (arrayindex* e)
5016 {
5017 parent->visit_arrayindex (e);
5018 }
57148ee7 5019
d98d459c
GH
5020 void visit_symbol (symbol* e)
5021 {
5022 exp_type ignored = pe_unknown;
57148ee7 5023 assert (e->referent != 0);
d98d459c
GH
5024 resolve_2types (e, e->referent, parent, ignored);
5025 }
5026};
5027
5028
2b066ec1
FCE
5029void
5030typeresolution_info::visit_delete_statement (delete_statement* e)
5031{
d98d459c
GH
5032 delete_statement_typeresolution_info di (this);
5033 t = pe_unknown;
5034 e->value->visit (&di);
2b066ec1
FCE
5035}
5036
5037
f3c26ea5 5038void
78f6bba6 5039typeresolution_info::visit_next_statement (next_statement*)
f3c26ea5
FCE
5040{
5041}
5042
5043
5044void
78f6bba6 5045typeresolution_info::visit_break_statement (break_statement*)
f3c26ea5
FCE
5046{
5047}
5048
5049
5050void
78f6bba6 5051typeresolution_info::visit_continue_statement (continue_statement*)
f3c26ea5
FCE
5052{
5053}
5054
5055
2b066ec1
FCE
5056void
5057typeresolution_info::visit_array_in (array_in* e)
5058{
ce10591c
FCE
5059 // all unary operators only work on numerics
5060 exp_type t1 = t;
5061 t = pe_unknown; // array value can be anything
5062 e->operand->visit (this);
5063
5064 if (t1 == pe_unknown && e->type != pe_unknown)
5065 ; // already resolved
5066 else if (t1 == pe_string || t1 == pe_stats)
5067 mismatch (e->tok, t1, pe_long);
5068 else if (e->type == pe_unknown)
5069 {
5070 e->type = pe_long;
5071 resolved (e->tok, e->type);
5072 }
2b066ec1
FCE
5073}
5074
5075
5076void
5077typeresolution_info::visit_return_statement (return_statement* e)
5078{
5079 // This is like symbol, where the referent is
5080 // the return value of the function.
5081
57148ee7 5082 // translation pass will print error
2b066ec1 5083 if (current_function == 0)
22f46231 5084 return;
2b066ec1
FCE
5085
5086 exp_type& e_type = current_function->type;
5087 t = current_function->type;
5088 e->value->visit (this);
5089
5090 if (e_type != pe_unknown && e->value->type != pe_unknown
5091 && e_type != e->value->type)
5092 mismatch (current_function->tok, e_type, e->value->type);
57148ee7 5093 if (e_type == pe_unknown &&
2b066ec1
FCE
5094 (e->value->type == pe_long || e->value->type == pe_string))
5095 {
5096 // propagate non-statistics from value
5097 e_type = e->value->type;
5098 resolved (current_function->tok, e->value->type);
5099 }
5100 if (e->value->type == pe_stats)
5101 invalid (e->value->tok, e->value->type);
5102}
5103
57148ee7 5104void
d02548c0
GH
5105typeresolution_info::visit_print_format (print_format* e)
5106{
5107 size_t unresolved_args = 0;
5108
1bbeef03
GH
5109 if (e->hist)
5110 {
5111 e->hist->visit(this);
5112 }
5113
5114 else if (e->print_with_format)
d02548c0
GH
5115 {
5116 // If there's a format string, we can do both inference *and*
5117 // checking.
5118
5119 // First we extract the subsequence of formatting components
5120 // which are conversions (not just literal string components)
5121
34201621 5122 unsigned expected_num_args = 0;
d02548c0
GH
5123 std::vector<print_format::format_component> components;
5124 for (size_t i = 0; i < e->components.size(); ++i)
5125 {
5126 if (e->components[i].type == print_format::conv_unspecified)
dc09353a 5127 throw SEMANTIC_ERROR (_("Unspecified conversion in print operator format string"),
d02548c0 5128 e->tok);
b5852334 5129 else if (e->components[i].type == print_format::conv_literal)
d02548c0
GH
5130 continue;
5131 components.push_back(e->components[i]);
34201621
DB
5132 ++expected_num_args;
5133 if (e->components[i].widthtype == print_format::width_dynamic)
5134 ++expected_num_args;
5135 if (e->components[i].prectype == print_format::prec_dynamic)
5136 ++expected_num_args;
d02548c0
GH
5137 }
5138
5139 // Then we check that the number of conversions and the number
5140 // of args agree.
5141
34201621 5142 if (expected_num_args != e->args.size())
dc09353a 5143 throw SEMANTIC_ERROR (_("Wrong number of args to formatted print operator"),
d02548c0
GH
5144 e->tok);
5145
5146 // Then we check that the types of the conversions match the types
5147 // of the args.
34201621 5148 unsigned argno = 0;
d02548c0
GH
5149 for (size_t i = 0; i < components.size(); ++i)
5150 {
34201621
DB
5151 // Check the dynamic width, if specified
5152 if (components[i].widthtype == print_format::width_dynamic)
5153 {
5154 check_arg_type (pe_long, e->args[argno]);
5155 ++argno;
5156 }
5157
5158 // Check the dynamic precision, if specified
5159 if (components[i].prectype == print_format::prec_dynamic)
5160 {
5161 check_arg_type (pe_long, e->args[argno]);
5162 ++argno;
5163 }
5164
d02548c0
GH
5165 exp_type wanted = pe_unknown;
5166
5167 switch (components[i].type)
5168 {
d02548c0
GH
5169 case print_format::conv_unspecified:
5170 case print_format::conv_literal:
5171 assert (false);
5172 break;
5173
929eb962
JS
5174 case print_format::conv_pointer:
5175 case print_format::conv_number:
dc0b623a 5176 case print_format::conv_binary:
fecccf83 5177 case print_format::conv_char:
ec03bd4b 5178 case print_format::conv_memory:
30c94a80 5179 case print_format::conv_memory_hex:
d02548c0
GH
5180 wanted = pe_long;
5181 break;
5182
5183 case print_format::conv_string:
5184 wanted = pe_string;
5185 break;
5186 }
5187
5188 assert (wanted != pe_unknown);
34201621
DB
5189 check_arg_type (wanted, e->args[argno]);
5190 ++argno;
d02548c0
GH
5191 }
5192 }
5193 else
5194 {
5195 // Without a format string, the best we can do is require that
5196 // each argument resolve to a concrete type.
5197 for (size_t i = 0; i < e->args.size(); ++i)
5198 {
5199 t = pe_unknown;
5200 e->args[i]->visit (this);
5201 if (e->args[i]->type == pe_unknown)
5202 {
5203 unresolved (e->args[i]->tok);
5204 ++unresolved_args;
5205 }
5206 }
5207 }
57148ee7 5208
d02548c0
GH
5209 if (unresolved_args == 0)
5210 {
5211 if (e->type == pe_unknown)
5212 {
5213 if (e->print_to_stream)
5214 e->type = pe_long;
5215 else
57148ee7 5216 e->type = pe_string;
d02548c0
GH
5217 resolved (e->tok, e->type);
5218 }
5219 }
5220 else
5221 {
5222 e->type = pe_unknown;
5223 unresolved (e->tok);
5224 }
5225}
5226
5227
57148ee7 5228void
d02548c0
GH
5229typeresolution_info::visit_stat_op (stat_op* e)
5230{
5231 t = pe_stats;
5232 e->stat->visit (this);
5233 if (e->type == pe_unknown)
5234 {
5235 e->type = pe_long;
5236 resolved (e->tok, e->type);
5237 }
07c17d67 5238 else if (e->type != pe_long)
d02548c0
GH
5239 mismatch (e->tok, e->type, pe_long);
5240}
5241
57148ee7 5242void
d02548c0
GH
5243typeresolution_info::visit_hist_op (hist_op* e)
5244{
5245 t = pe_stats;
5246 e->stat->visit (this);
5247}
5248
2b066ec1 5249
34201621
DB
5250void
5251typeresolution_info::check_arg_type (exp_type wanted, expression* arg)
5252{
5253 t = wanted;
5254 arg->visit (this);
5255
5256 if (arg->type == pe_unknown)
5257 {
5258 arg->type = wanted;
5259 resolved (arg->tok, wanted);
5260 }
5261 else if (arg->type != wanted)
5262 {
5263 mismatch (arg->tok, arg->type, wanted);
5264 }
5265}
5266
5267
5abd364d
JS
5268void
5269typeresolution_info::check_local (vardecl* v)
5270{
5271 if (v->arity != 0)
5272 {
5273 num_still_unresolved ++;
5274 if (assert_resolvability)
5275 session.print_error
dc09353a 5276 (SEMANTIC_ERROR (_("array locals not supported, missing global declaration? "), v->tok));
5abd364d
JS
5277 }
5278
5279 if (v->type == pe_unknown)
5280 unresolved (v->tok);
5281 else if (v->type == pe_stats)
5282 {
5283 num_still_unresolved ++;
5284 if (assert_resolvability)
5285 session.print_error
dc09353a 5286 (SEMANTIC_ERROR (_("stat locals not supported, missing global declaration? "), v->tok));
5abd364d
JS
5287 }
5288 else if (!(v->type == pe_long || v->type == pe_string))
5289 invalid (v->tok, v->type);
5290}
5291
5292
2b066ec1
FCE
5293void
5294typeresolution_info::unresolved (const token* tok)
5295{
5296 num_still_unresolved ++;
5297
5298 if (assert_resolvability)
5299 {
6c543717 5300 stringstream msg;
4af765b2 5301 msg << _("unresolved type ");
dc09353a 5302 session.print_error (SEMANTIC_ERROR (msg.str(), tok));
2b066ec1
FCE
5303 }
5304}
5305
5306
5307void
5308typeresolution_info::invalid (const token* tok, exp_type pe)
5309{
5310 num_still_unresolved ++;
5311
5312 if (assert_resolvability)
5313 {
6c543717 5314 stringstream msg;
022b623f 5315 if (tok && tok->type == tok_operator)
4af765b2 5316 msg << _("invalid operator");
2b066ec1 5317 else
4af765b2 5318 msg << _("invalid type ") << pe;
dc09353a 5319 session.print_error (SEMANTIC_ERROR (msg.str(), tok));
2b066ec1
FCE
5320 }
5321}
5322
5323
5324void
5325typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2)
5326{
d784c94d 5327 bool tok_resolved = false;
d5f0c423
RA
5328 size_t i;
5329 semantic_error* err1 = 0;
2b066ec1
FCE
5330 num_still_unresolved ++;
5331
d5f0c423
RA
5332 //BZ 9719: for improving type mismatch messages, a semantic error is
5333 //generated with the token where type was first resolved. All such
5334 //resolved tokens, stored in a vector, are matched against their
5335 //content. If an error for the matching token hasn't been printed out
5336 //already, it is and the token pushed in another printed_toks vector
5337
2b066ec1
FCE
5338 if (assert_resolvability)
5339 {
6c543717 5340 stringstream msg;
d5f0c423
RA
5341 for (i=0; i<resolved_toks.size(); i++)
5342 {
5343 if (resolved_toks[i]->content == tok->content)
5344 {
5345 tok_resolved = true;
5346 break;
5347 }
5348 }
5349 if (!tok_resolved)
5350 {
3c5dc934 5351 msg << _F("type mismatch (%s vs. %s)",
4af765b2 5352 lex_cast(t1).c_str(), lex_cast(t2).c_str());
d5f0c423
RA
5353 }
5354 else
5355 {
d784c94d 5356 bool tok_printed = false;
d5f0c423
RA
5357 for (size_t j=0; j<printed_toks.size(); j++)
5358 {
5359 if (printed_toks[j] == resolved_toks[i])
5360 {
5361 tok_printed = true;
5362 break;
5363 }
5364 }
3c5dc934 5365 msg << _F("type mismatch (%s vs. %s)",
4af765b2 5366 lex_cast(t1).c_str(), lex_cast(t2).c_str());
d5f0c423
RA
5367 if (!tok_printed)
5368 {
5369 //error for possible mismatch in the earlier resolved token
5370 printed_toks.push_back (resolved_toks[i]);
5371 stringstream type_msg;
3c5dc934 5372 type_msg << _F("type was first inferred here (%s)", lex_cast(t2).c_str());
dc09353a 5373 err1 = new SEMANTIC_ERROR (type_msg.str(), resolved_toks[i]);
d5f0c423
RA
5374 }
5375 }
dc09353a 5376 semantic_error err (ERR_SRC, msg.str(), tok);
d5f0c423
RA
5377 err.chain = err1;
5378 session.print_error (err);
2b066ec1
FCE
5379 }
5380}
5381
5382
5383void
d5f0c423 5384typeresolution_info::resolved (const token* tok, exp_type)
2b066ec1 5385{
d5f0c423 5386 resolved_toks.push_back (tok);
2b066ec1 5387 num_newly_resolved ++;
2b066ec1
FCE
5388}
5389
73267b89 5390/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.861881 seconds and 5 git commands to generate.