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