// -*- C++ -*- // Copyright (C) 2005-2010 Red Hat Inc. // Copyright (C) 2006 Intel Corporation. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General // Public License (GPL); either version 2, or (at your option) any // later version. #ifndef STAPTREE_H #define STAPTREE_H #include #include #include #include #include #include #include #include extern "C" { #include } struct token; // parse.h struct systemtap_session; // session.h struct semantic_error: public std::runtime_error { const token* tok1; std::string msg2; const token* tok2; semantic_error *chain; ~semantic_error () throw () {} semantic_error (const std::string& msg): runtime_error (msg), tok1 (0), tok2 (0), chain (0) {} semantic_error (const std::string& msg, const token* t1): runtime_error (msg), tok1 (t1), tok2 (0), chain (0) {} semantic_error (const std::string& msg, const token* t1, const std::string& m2, const token* t2): runtime_error (msg), tok1 (t1), msg2 (m2), tok2 (t2), chain (0) {} }; // ------------------------------------------------------------------------ /* struct statistic_decl moved to session.h */ // ------------------------------------------------------------------------ enum exp_type { pe_unknown, pe_long, // int64_t pe_string, // std::string pe_stats }; std::ostream& operator << (std::ostream& o, const exp_type& e); struct token; struct visitor; struct update_visitor; struct expression { exp_type type; const token* tok; expression (); virtual ~expression (); virtual void print (std::ostream& o) const = 0; virtual void visit (visitor* u) = 0; }; std::ostream& operator << (std::ostream& o, const expression& k); struct literal: public expression { }; struct literal_string: public literal { std::string value; literal_string (const std::string& v); void print (std::ostream& o) const; void visit (visitor* u); }; struct literal_number: public literal { int64_t value; bool print_hex; literal_number (int64_t v, bool hex=false); void print (std::ostream& o) const; void visit (visitor* u); }; struct binary_expression: public expression { expression* left; std::string op; expression* right; void print (std::ostream& o) const; void visit (visitor* u); }; struct unary_expression: public expression { std::string op; expression* operand; void print (std::ostream& o) const; void visit (visitor* u); }; struct pre_crement: public unary_expression { void visit (visitor* u); }; struct post_crement: public unary_expression { void print (std::ostream& o) const; void visit (visitor* u); }; struct logical_or_expr: public binary_expression { void visit (visitor* u); }; struct logical_and_expr: public binary_expression { void visit (visitor* u); }; struct arrayindex; struct array_in: public expression { arrayindex* operand; void print (std::ostream& o) const; void visit (visitor* u); }; struct comparison: public binary_expression { void visit (visitor* u); }; struct concatenation: public binary_expression { void visit (visitor* u); }; struct ternary_expression: public expression { expression* cond; expression* truevalue; expression* falsevalue; void print (std::ostream& o) const; void visit (visitor* u); }; struct assignment: public binary_expression { void visit (visitor* u); }; struct symbol; struct hist_op; struct indexable { // This is a helper class which, type-wise, acts as a disjoint union // of symbols and histograms. You can ask it whether it's a // histogram or a symbol, and downcast accordingly. void print_indexable (std::ostream& o) const; void visit_indexable (visitor* u); virtual bool is_symbol(symbol *& sym_out); virtual bool is_hist_op(hist_op *& hist_out); virtual bool is_const_symbol(const symbol *& sym_out) const; virtual bool is_const_hist_op(const hist_op *& hist_out) const; virtual const token *get_tok() const = 0; virtual ~indexable() {} }; // Perform a downcast to one out-value and NULL the other, throwing an // exception if neither downcast succeeds. This is (sadly) about the // best we can accomplish in C++. void classify_indexable(indexable* ix, symbol *& array_out, hist_op *& hist_out); void classify_const_indexable(const indexable* ix, symbol const *& array_out, hist_op const *& hist_out); class vardecl; struct symbol: public expression, public indexable { std::string name; vardecl *referent; symbol (); void print (std::ostream& o) const; void visit (visitor* u); // overrides of type 'indexable' const token *get_tok() const; bool is_const_symbol(const symbol *& sym_out) const; bool is_symbol(symbol *& sym_out); }; struct target_symbol: public symbol { enum component_type { comp_struct_member, comp_literal_array_index, comp_expression_array_index, }; struct component { const token* tok; component_type type; std::string member; // comp_struct_member int64_t num_index; // comp_literal_array_index expression* expr_index; // comp_expression_array_index component(const token* t, const std::string& m): tok(t), type(comp_struct_member), member(m) {} component(const token* t, int64_t n): tok(t), type(comp_literal_array_index), num_index(n) {} component(const token* t, expression* e): tok(t), type(comp_expression_array_index), expr_index(e) {} void print (std::ostream& o) const; }; bool addressof; std::string base_name; std::vector components; std::string probe_context_var; // NB: this being set implies that target_symbol is *resolved* semantic_error* saved_conversion_error; // hand-made linked list target_symbol(): addressof(false), saved_conversion_error (0) {} void chain (semantic_error* e); void print (std::ostream& o) const; void visit (visitor* u); void visit_components (visitor* u); void visit_components (update_visitor* u); void assert_no_components(const std::string& tapset); }; std::ostream& operator << (std::ostream& o, const target_symbol::component& c); struct cast_op: public target_symbol { expression *operand; std::string type, module; void print (std::ostream& o) const; void visit (visitor* u); }; struct defined_op: public expression { target_symbol *operand; void print (std::ostream& o) const; void visit (visitor* u); }; struct arrayindex: public expression { std::vector indexes; indexable *base; arrayindex (); void print (std::ostream& o) const; void visit (visitor* u); }; class functiondecl; struct functioncall: public expression { std::string function; std::vector args; functiondecl *referent; functioncall (); void print (std::ostream& o) const; void visit (visitor* u); }; struct print_format: public expression { bool print_to_stream; bool print_with_format; bool print_with_delim; bool print_with_newline; bool print_char; enum format_flag { fmt_flag_zeropad = 1, fmt_flag_plus = 2, fmt_flag_space = 4, fmt_flag_left = 8, fmt_flag_special = 16 }; enum conversion_type { conv_unspecified, conv_signed_decimal, conv_unsigned_decimal, conv_unsigned_octal, conv_unsigned_ptr, conv_unsigned_uppercase_hex, conv_unsigned_lowercase_hex, conv_string, conv_char, conv_memory, conv_memory_hex, conv_literal, conv_binary }; enum width_type { width_unspecified, width_static, width_dynamic }; enum precision_type { prec_unspecified, prec_static, prec_dynamic }; struct format_component { unsigned long flags; unsigned width; unsigned precision; width_type widthtype; precision_type prectype; conversion_type type; std::string literal_string; bool is_empty() const { return flags == 0 && widthtype == width_unspecified && prectype == prec_unspecified && type == conv_unspecified && literal_string.empty(); } void clear() { flags = 0; widthtype = width_unspecified; prectype = prec_unspecified; type = conv_unspecified; literal_string.clear(); } }; std::string raw_components; std::vector components; format_component delimiter; std::vector args; hist_op *hist; static std::string components_to_string(std::vector const & components); static std::vector string_to_components(std::string const & str); static print_format* create(const token *t); void print (std::ostream& o) const; void visit (visitor* u); private: print_format(bool stream, bool format, bool delim, bool newline, bool _char): print_to_stream(stream), print_with_format(format), print_with_delim(delim), print_with_newline(newline), print_char(_char), hist(NULL) {} }; enum stat_component_type { sc_average, sc_count, sc_sum, sc_min, sc_max, }; struct stat_op: public expression { stat_component_type ctype; expression* stat; void print (std::ostream& o) const; void visit (visitor* u); }; enum histogram_type { hist_linear, hist_log }; struct hist_op: public indexable { const token* tok; histogram_type htype; expression* stat; std::vector params; void print (std::ostream& o) const; void visit (visitor* u); // overrides of type 'indexable' const token *get_tok() const; bool is_const_hist_op(const hist_op *& hist_out) const; bool is_hist_op(hist_op *& hist_out); }; // ------------------------------------------------------------------------ struct symboldecl // unique object per (possibly implicit) // symbol declaration { const token* tok; std::string name; exp_type type; symboldecl (); virtual ~symboldecl (); virtual void print (std::ostream &o) const = 0; virtual void printsig (std::ostream &o) const = 0; }; std::ostream& operator << (std::ostream& o, const symboldecl& k); struct vardecl: public symboldecl { void print (std::ostream& o) const; void printsig (std::ostream& o) const; vardecl (); void set_arity (int arity); bool compatible_arity (int a); int arity; // -1: unknown; 0: scalar; >0: array int maxsize; // upperbound on size for arrays std::vector index_types; // for arrays only literal *init; // for global scalars only }; struct vardecl_builtin: public vardecl { }; struct statement; struct functiondecl: public symboldecl { std::vector formal_args; std::vector locals; std::vector unused_locals; statement* body; bool synthetic; functiondecl (); void print (std::ostream& o) const; void printsig (std::ostream& o) const; }; // ------------------------------------------------------------------------ struct statement { virtual void print (std::ostream& o) const = 0; virtual void visit (visitor* u) = 0; const token* tok; statement (); statement (const token* tok); virtual ~statement (); }; std::ostream& operator << (std::ostream& o, const statement& k); struct embeddedcode: public statement { std::string code; void print (std::ostream& o) const; void visit (visitor* u); }; struct block: public statement { std::vector statements; void print (std::ostream& o) const; void visit (visitor* u); block () {} block (statement* car, statement* cdr); }; struct try_block: public statement { statement* try_block; // may be 0 statement* catch_block; // may be 0 symbol* catch_error_var; // may be 0 void print (std::ostream& o) const; void visit (visitor* u); }; struct expr_statement; struct for_loop: public statement { expr_statement* init; // may be 0 expression* cond; expr_statement* incr; // may be 0 statement* block; void print (std::ostream& o) const; void visit (visitor* u); }; struct foreach_loop: public statement { // this part is a specialization of arrayindex std::vector indexes; indexable *base; int sort_direction; // -1: decreasing, 0: none, 1: increasing unsigned sort_column; // 0: value, 1..N: index expression* limit; // optional iteration limit statement* block; void print (std::ostream& o) const; void visit (visitor* u); }; struct null_statement: public statement { void print (std::ostream& o) const; void visit (visitor* u); null_statement (const token* tok); }; struct expr_statement: public statement { expression* value; // executed for side-effects void print (std::ostream& o) const; void visit (visitor* u); }; struct if_statement: public statement { expression* condition; statement* thenblock; statement* elseblock; // may be 0 void print (std::ostream& o) const; void visit (visitor* u); }; struct return_statement: public expr_statement { void print (std::ostream& o) const; void visit (visitor* u); }; struct delete_statement: public expr_statement { void print (std::ostream& o) const; void visit (visitor* u); }; struct break_statement: public statement { void print (std::ostream& o) const; void visit (visitor* u); }; struct continue_statement: public statement { void print (std::ostream& o) const; void visit (visitor* u); }; struct next_statement: public statement { void print (std::ostream& o) const; void visit (visitor* u); }; struct probe; struct derived_probe; struct probe_alias; struct embeddedcode; struct stapfile { std::string name; std::vector probes; std::vector aliases; std::vector functions; std::vector globals; std::vector embeds; std::string file_contents; bool privileged; stapfile (): file_contents (""), privileged (false) {} void print (std::ostream& o) const; }; struct probe_point { struct component // XXX: sort of a restricted functioncall { std::string functor; literal* arg; // optional component (); const token* tok; // points to component's functor component(std::string const & f, literal * a = NULL); }; std::vector components; bool optional; bool sufficient; expression* condition; void print (std::ostream& o) const; probe_point (); probe_point(const probe_point& pp); probe_point(std::vector const & comps); std::string str(); }; std::ostream& operator << (std::ostream& o, const probe_point& k); struct probe { std::vector locations; statement* body; const token* tok; std::vector locals; std::vector unused_locals; probe (); void print (std::ostream& o) const; virtual void printsig (std::ostream &o) const; virtual void collect_derivation_chain (std::vector &probes_list); virtual const probe_alias *get_alias () const { return 0; } virtual probe* create_alias(probe_point* l, probe_point* a); virtual probe* basest () { return this; } virtual ~probe() {} bool privileged; std::string name; }; struct probe_alias: public probe { probe_alias(std::vector const & aliases); std::vector alias_names; virtual void printsig (std::ostream &o) const; bool epilogue_style; }; // A derived visitor instance is used to visit the entire // statement/expression tree. struct visitor { // Machinery for differentiating lvalue visits from non-lvalue. std::vector active_lvalues; bool is_active_lvalue(expression *e); void push_active_lvalue(expression *e); void pop_active_lvalue(); virtual ~visitor () {} virtual void visit_block (block *s) = 0; virtual void visit_try_block (try_block *s) = 0; virtual void visit_embeddedcode (embeddedcode *s) = 0; virtual void visit_null_statement (null_statement *s) = 0; virtual void visit_expr_statement (expr_statement *s) = 0; virtual void visit_if_statement (if_statement* s) = 0; virtual void visit_for_loop (for_loop* s) = 0; virtual void visit_foreach_loop (foreach_loop* s) = 0; virtual void visit_return_statement (return_statement* s) = 0; virtual void visit_delete_statement (delete_statement* s) = 0; virtual void visit_next_statement (next_statement* s) = 0; virtual void visit_break_statement (break_statement* s) = 0; virtual void visit_continue_statement (continue_statement* s) = 0; virtual void visit_literal_string (literal_string* e) = 0; virtual void visit_literal_number (literal_number* e) = 0; virtual void visit_binary_expression (binary_expression* e) = 0; virtual void visit_unary_expression (unary_expression* e) = 0; virtual void visit_pre_crement (pre_crement* e) = 0; virtual void visit_post_crement (post_crement* e) = 0; virtual void visit_logical_or_expr (logical_or_expr* e) = 0; virtual void visit_logical_and_expr (logical_and_expr* e) = 0; virtual void visit_array_in (array_in* e) = 0; virtual void visit_comparison (comparison* e) = 0; virtual void visit_concatenation (concatenation* e) = 0; virtual void visit_ternary_expression (ternary_expression* e) = 0; virtual void visit_assignment (assignment* e) = 0; virtual void visit_symbol (symbol* e) = 0; virtual void visit_target_symbol (target_symbol* e) = 0; virtual void visit_arrayindex (arrayindex* e) = 0; virtual void visit_functioncall (functioncall* e) = 0; virtual void visit_print_format (print_format* e) = 0; virtual void visit_stat_op (stat_op* e) = 0; virtual void visit_hist_op (hist_op* e) = 0; virtual void visit_cast_op (cast_op* e) = 0; virtual void visit_defined_op (defined_op* e) = 0; }; // A simple kind of visitor, which travels down to the leaves of the // statement/expression tree, up to but excluding following vardecls // and functioncalls. struct traversing_visitor: public visitor { void visit_block (block *s); void visit_try_block (try_block *s); void visit_embeddedcode (embeddedcode *s); void visit_null_statement (null_statement *s); void visit_expr_statement (expr_statement *s); void visit_if_statement (if_statement* s); void visit_for_loop (for_loop* s); void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); void visit_next_statement (next_statement* s); void visit_break_statement (break_statement* s); void visit_continue_statement (continue_statement* s); void visit_literal_string (literal_string* e); void visit_literal_number (literal_number* e); void visit_binary_expression (binary_expression* e); void visit_unary_expression (unary_expression* e); void visit_pre_crement (pre_crement* e); void visit_post_crement (post_crement* e); void visit_logical_or_expr (logical_or_expr* e); void visit_logical_and_expr (logical_and_expr* e); void visit_array_in (array_in* e); void visit_comparison (comparison* e); void visit_concatenation (concatenation* e); void visit_ternary_expression (ternary_expression* e); void visit_assignment (assignment* e); void visit_symbol (symbol* e); void visit_target_symbol (target_symbol* e); void visit_arrayindex (arrayindex* e); void visit_functioncall (functioncall* e); void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); void visit_cast_op (cast_op* e); void visit_defined_op (defined_op* e); }; // A kind of traversing visitor, which also follows function calls. // It uses an internal set object to prevent infinite recursion. struct functioncall_traversing_visitor: public traversing_visitor { std::set traversed; functiondecl* current_function; functioncall_traversing_visitor(): current_function(0) {} void visit_functioncall (functioncall* e); }; // A kind of traversing visitor, which also follows function calls, // and stores the vardecl* referent of each variable read and/or // written and other such sundry side-effect data. It's used by // the elaboration-time optimizer pass. struct varuse_collecting_visitor: public functioncall_traversing_visitor { systemtap_session& session; std::set read; std::set written; bool embedded_seen; expression* current_lvalue; expression* current_lrvalue; varuse_collecting_visitor(systemtap_session& s): session (s), embedded_seen (false), current_lvalue(0), current_lrvalue(0) {} void visit_embeddedcode (embeddedcode *s); void visit_try_block (try_block *s); void visit_delete_statement (delete_statement *s); void visit_print_format (print_format *e); void visit_assignment (assignment *e); void visit_arrayindex (arrayindex *e); void visit_target_symbol (target_symbol *e); void visit_symbol (symbol *e); void visit_pre_crement (pre_crement *e); void visit_post_crement (post_crement *e); void visit_foreach_loop (foreach_loop *s); void visit_cast_op (cast_op* e); void visit_defined_op (defined_op* e); bool side_effect_free (); bool side_effect_free_wrt (const std::set& vars); }; // A kind of visitor that throws an semantic_error exception // whenever a non-overridden method is called. struct throwing_visitor: public visitor { std::string msg; throwing_visitor (const std::string& m); throwing_visitor (); virtual void throwone (const token* t); void visit_block (block *s); void visit_try_block (try_block *s); void visit_embeddedcode (embeddedcode *s); void visit_null_statement (null_statement *s); void visit_expr_statement (expr_statement *s); void visit_if_statement (if_statement* s); void visit_for_loop (for_loop* s); void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); void visit_next_statement (next_statement* s); void visit_break_statement (break_statement* s); void visit_continue_statement (continue_statement* s); void visit_literal_string (literal_string* e); void visit_literal_number (literal_number* e); void visit_binary_expression (binary_expression* e); void visit_unary_expression (unary_expression* e); void visit_pre_crement (pre_crement* e); void visit_post_crement (post_crement* e); void visit_logical_or_expr (logical_or_expr* e); void visit_logical_and_expr (logical_and_expr* e); void visit_array_in (array_in* e); void visit_comparison (comparison* e); void visit_concatenation (concatenation* e); void visit_ternary_expression (ternary_expression* e); void visit_assignment (assignment* e); void visit_symbol (symbol* e); void visit_target_symbol (target_symbol* e); void visit_arrayindex (arrayindex* e); void visit_functioncall (functioncall* e); void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); void visit_cast_op (cast_op* e); void visit_defined_op (defined_op* e); }; // A visitor similar to a traversing_visitor, but with the ability to rewrite // parts of the tree through require/provide. struct update_visitor: public visitor { template T* require (T* src, bool clearok=false) { T* dst = NULL; if (src != NULL) { src->visit(this); assert(!targets.empty()); dst = static_cast(targets.top()); // XXX: danger will robinson: not typesafe! targets.pop(); assert(clearok || dst); } return dst; } template void provide (T* src) { targets.push(static_cast(src)); // XXX: not typesafe! } template void replace (T*& src, bool clearok=false) { src = require(src, clearok); } virtual ~update_visitor() { assert(targets.empty()); } virtual void visit_block (block *s); virtual void visit_try_block (try_block *s); virtual void visit_embeddedcode (embeddedcode *s); virtual void visit_null_statement (null_statement *s); virtual void visit_expr_statement (expr_statement *s); virtual void visit_if_statement (if_statement* s); virtual void visit_for_loop (for_loop* s); virtual void visit_foreach_loop (foreach_loop* s); virtual void visit_return_statement (return_statement* s); virtual void visit_delete_statement (delete_statement* s); virtual void visit_next_statement (next_statement* s); virtual void visit_break_statement (break_statement* s); virtual void visit_continue_statement (continue_statement* s); virtual void visit_literal_string (literal_string* e); virtual void visit_literal_number (literal_number* e); virtual void visit_binary_expression (binary_expression* e); virtual void visit_unary_expression (unary_expression* e); virtual void visit_pre_crement (pre_crement* e); virtual void visit_post_crement (post_crement* e); virtual void visit_logical_or_expr (logical_or_expr* e); virtual void visit_logical_and_expr (logical_and_expr* e); virtual void visit_array_in (array_in* e); virtual void visit_comparison (comparison* e); virtual void visit_concatenation (concatenation* e); virtual void visit_ternary_expression (ternary_expression* e); virtual void visit_assignment (assignment* e); virtual void visit_symbol (symbol* e); virtual void visit_target_symbol (target_symbol* e); virtual void visit_arrayindex (arrayindex* e); virtual void visit_functioncall (functioncall* e); virtual void visit_print_format (print_format* e); virtual void visit_stat_op (stat_op* e); virtual void visit_hist_op (hist_op* e); virtual void visit_cast_op (cast_op* e); virtual void visit_defined_op (defined_op* e); private: std::stack targets; }; template <> indexable* update_visitor::require (indexable* src, bool clearok); // A visitor which performs a deep copy of the root node it's applied // to. NB: It does not copy any of the variable or function // declarations; those fields are set to NULL, assuming you want to // re-infer the declarations in a new context (the one you're copying // to). struct deep_copy_visitor: public update_visitor { template static T* deep_copy (T* e) { deep_copy_visitor v; return v.require (e); } virtual void visit_block (block *s); virtual void visit_try_block (try_block *s); virtual void visit_embeddedcode (embeddedcode *s); virtual void visit_null_statement (null_statement *s); virtual void visit_expr_statement (expr_statement *s); virtual void visit_if_statement (if_statement* s); virtual void visit_for_loop (for_loop* s); virtual void visit_foreach_loop (foreach_loop* s); virtual void visit_return_statement (return_statement* s); virtual void visit_delete_statement (delete_statement* s); virtual void visit_next_statement (next_statement* s); virtual void visit_break_statement (break_statement* s); virtual void visit_continue_statement (continue_statement* s); virtual void visit_literal_string (literal_string* e); virtual void visit_literal_number (literal_number* e); virtual void visit_binary_expression (binary_expression* e); virtual void visit_unary_expression (unary_expression* e); virtual void visit_pre_crement (pre_crement* e); virtual void visit_post_crement (post_crement* e); virtual void visit_logical_or_expr (logical_or_expr* e); virtual void visit_logical_and_expr (logical_and_expr* e); virtual void visit_array_in (array_in* e); virtual void visit_comparison (comparison* e); virtual void visit_concatenation (concatenation* e); virtual void visit_ternary_expression (ternary_expression* e); virtual void visit_assignment (assignment* e); virtual void visit_symbol (symbol* e); virtual void visit_target_symbol (target_symbol* e); virtual void visit_arrayindex (arrayindex* e); virtual void visit_functioncall (functioncall* e); virtual void visit_print_format (print_format* e); virtual void visit_stat_op (stat_op* e); virtual void visit_hist_op (hist_op* e); virtual void visit_cast_op (cast_op* e); virtual void visit_defined_op (defined_op* e); }; #endif // STAPTREE_H /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */