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