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