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