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