tapsets.cxx - systemtap
 Global variables defined
 
 Data types defined
 
 Functions defined
 
 Macros defined
 
 Source code
  
#include "config.h"
#include "staptree.h"
#include "elaborate.h"
#include "tapsets.h"
#include "task_finder.h"
#include "tapset-dynprobe.h"
#include "translate.h"
#include "session.h"
#include "util.h"
#include "buildrun.h"
#include "dwarf_wrappers.h"
#include "auto_free.h"
#include "hash.h"
#include "dwflpp.h"
#include "setupdwfl.h"
#include <gelf.h>
#include "sdt_types.h"
#include <cstdlib>
#include <algorithm>
#include <deque>
#include <iostream>
#include <fstream>
#include <map>
#include <set>
#include <sstream>
#include <stdexcept>
#include <vector>
#include <stack>
#include <cstdarg>
#include <cassert>
#include <iomanip>
#include <cerrno>
extern "C" {
#include <fcntl.h>
#include <elfutils/libdwfl.h>
#include <elfutils/libdw.h>
#include <dwarf.h>
#include <elf.h>
#include <obstack.h>
#include <glob.h>
#include <fnmatch.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <math.h>
#include <regex.h>
#include <unistd.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
}
#ifndef EM_AARCH64
#define EM_AARCH64 183
#endif
using namespace std;
using namespace __gnu_cxx;
string
common_probe_init (derived_probe* p)
{
  assert(p->session_index != (unsigned)-1);
  return "(&stap_probes[" + lex_cast(p->session_index) + "])";
}
void
common_probe_entryfn_prologue (systemtap_session& s,
                   string statestr, string probe,
                   string probe_type, bool overload_processing)
{
  if (s.runtime_usermode_p())
    {
                        s.op->newline() << "if (likely(session_state())) {";
      s.op->indent(1);
    }
  s.op->newline() << "#ifdef STP_ALIBI";
  s.op->newline() << "atomic_inc(probe_alibi(" << probe << "->index));";
  s.op->newline() << "#else";
  if (s.runtime_usermode_p())
    s.op->newline() << "int _stp_saved_errno = errno;";
  s.op->newline() << "struct context* __restrict__ c = NULL;";
  s.op->newline() << "#if !INTERRUPTIBLE";
  s.op->newline() << "unsigned long flags;";
  s.op->newline() << "#endif";
  s.op->newline() << "#ifdef STP_TIMING";
  s.op->newline() << "Stat stat = probe_timing(" << probe << "->index);";
  s.op->newline() << "#endif";
  if (overload_processing && !s.runtime_usermode_p())
    s.op->newline() << "#if defined(STP_TIMING) || defined(STP_OVERLOAD)";
  else
    s.op->newline() << "#ifdef STP_TIMING";
  if (! s.runtime_usermode_p())
    s.op->newline() << "cycles_t cycles_atstart = get_cycles ();";
  else
    {
    s.op->newline() << "struct timespec timespec_atstart;";
    s.op->newline() << "(void)clock_gettime(CLOCK_MONOTONIC, ×pec_atstart);";
    }
  s.op->newline() << "#endif";
  s.op->newline() << "#if !INTERRUPTIBLE";
  s.op->newline() << "local_irq_save (flags);";
  s.op->newline() << "#endif";
  if (! s.runtime_usermode_p())
    {
            s.op->newline() << "if (unlikely ((((unsigned long) (& c)) & (THREAD_SIZE-1))";       s.op->newline(1) << "< (MINSTACKSPACE + sizeof (struct thread_info)))) {";       XXX                  s.op->newline() << "atomic_inc (skipped_count());";
      s.op->newline() << "#ifdef STP_TIMING";
      s.op->newline() << "atomic_inc (skipped_count_lowstack());";
      s.op->newline() << "#endif";
      s.op->newline() << "goto probe_epilogue;";
      s.op->newline(-1) << "}";
    }
  s.op->newline() << "if (atomic_read (session_state()) != " << statestr << ")";
  s.op->newline(1) << "goto probe_epilogue;";
  s.op->indent(-1);
  s.op->newline() << "c = _stp_runtime_entryfn_get_context();";
  s.op->newline() << "if (!c) {";
  s.op->newline(1) << "#if !INTERRUPTIBLE";
  s.op->newline() << "atomic_inc (skipped_count());";
  s.op->newline() << "#endif";
  s.op->newline() << "#ifdef STP_TIMING";
  s.op->newline() << "atomic_inc (skipped_count_reentrant());";
  s.op->newline() << "#endif";
  s.op->newline() << "goto probe_epilogue;";
  s.op->newline(-1) << "}";
  s.op->newline();
  s.op->newline() << "c->last_stmt = 0;";
  s.op->newline() << "c->last_error = 0;";
  s.op->newline() << "c->nesting = -1;";   s.op->newline() << "c->uregs = 0;";
  s.op->newline() << "c->kregs = 0;";
  s.op->newline() << "#if defined __ia64__";
  s.op->newline() << "c->unwaddr = 0;";
  s.op->newline() << "#endif";
  if (s.runtime_usermode_p())
    s.op->newline() << "c->probe_index = " << probe << "->index;";
  s.op->newline() << "c->probe_point = " << probe << "->pp;";
  s.op->newline() << "#ifdef STP_NEED_PROBE_NAME";
  s.op->newline() << "c->probe_name = " << probe << "->pn;";
  s.op->newline() << "#endif";
  s.op->newline() << "c->probe_type = " << probe_type << ";";
    s.op->newline() << "memset(&c->ips, 0, sizeof(c->ips));";
  s.op->newline() << "c->user_mode_p = 0; c->full_uregs_p = 0;";
  s.op->newline() << "#ifdef STAP_NEED_REGPARM";   s.op->newline() << "c->regparm = 0;";
  s.op->newline() << "#endif";
  if(!s.suppress_time_limits){
    s.op->newline() << "#if INTERRUPTIBLE";
    s.op->newline() << "c->actionremaining = MAXACTION_INTERRUPTIBLE;";
    s.op->newline() << "#else";
    s.op->newline() << "c->actionremaining = MAXACTION;";
    s.op->newline() << "#endif";
  }
          
  s.op->newline() << "#if defined(STP_NEED_UNWIND_DATA)";
  s.op->newline() << "c->uwcache_user.state = uwcache_uninitialized;";
  s.op->newline() << "c->uwcache_kernel.state = uwcache_uninitialized;";
  s.op->newline() << "#endif";
}
void
common_probe_entryfn_epilogue (systemtap_session& s,
                               bool overload_processing,
                               bool schedule_work_safe)
{
  if (!s.runtime_usermode_p()
      && schedule_work_safe)
    {
            s.op->newline( 0) <<  "if (atomic_cmpxchg(&need_module_refresh, 1, 0) == 1)";
      s.op->newline(+1) <<    "schedule_work(&module_refresher_work);";
      s.op->indent(-1);
    }
  if (overload_processing && !s.runtime_usermode_p())
    s.op->newline() << "#if defined(STP_TIMING) || defined(STP_OVERLOAD)";
  else
    s.op->newline() << "#ifdef STP_TIMING";
  s.op->newline() << "{";
  s.op->indent(1);
  if (! s.runtime_usermode_p())
    {
      s.op->newline() << "cycles_t cycles_atend = get_cycles ();";
                        s.op->newline() << "int32_t cycles_elapsed = ((int32_t)cycles_atend > (int32_t)cycles_atstart)";
      s.op->newline(1) << "? ((int32_t)cycles_atend - (int32_t)cycles_atstart)";
      s.op->newline() << ": (~(int32_t)0) - (int32_t)cycles_atstart + (int32_t)cycles_atend + 1;";
      s.op->indent(-1);
    }
  else
    {
      s.op->newline() << "struct timespec timespec_atend, timespec_elapsed;";
      s.op->newline() << "long cycles_elapsed;";
      s.op->newline() << "(void)clock_gettime(CLOCK_MONOTONIC, ×pec_atend);";
      s.op->newline() << "_stp_timespec_sub(×pec_atend, ×pec_atstart, ×pec_elapsed);";
            s.op->newline() << "cycles_elapsed = (timespec_elapsed.tv_sec * NSEC_PER_SEC) + timespec_elapsed.tv_nsec;";
    }
  s.op->newline() << "#ifdef STP_TIMING";
  s.op->newline() << "if (likely (stat)) _stp_stat_add(stat, cycles_elapsed);";
  s.op->newline() << "#endif";
  if (overload_processing && !s.runtime_usermode_p())
    {
      s.op->newline() << "#ifdef STP_OVERLOAD";
      s.op->newline() << "{";
                        s.op->newline(1) << "cycles_t interval = (cycles_atend > c->cycles_base)";
      s.op->newline(1) << "? (cycles_atend - c->cycles_base)";
      s.op->newline() << ": (STP_OVERLOAD_INTERVAL + 1);";
      s.op->newline(-1) << "c->cycles_sum += cycles_elapsed;";
                                          s.op->newline() << "if (interval > STP_OVERLOAD_INTERVAL) {";
      s.op->newline(1) << "if (c->cycles_sum > STP_OVERLOAD_THRESHOLD) {";
      s.op->newline(1) << "_stp_error (\"probe overhead exceeded threshold\");";
      s.op->newline() << "atomic_set (session_state(), STAP_SESSION_ERROR);";
      s.op->newline() << "atomic_inc (error_count());";
      s.op->newline(-1) << "}";
      s.op->newline() << "c->cycles_base = cycles_atend;";
      s.op->newline() << "c->cycles_sum = 0;";
      s.op->newline(-1) << "}";
      s.op->newline(-1) << "}";
      s.op->newline() << "#endif";
    }
  s.op->newline(-1) << "}";
  s.op->newline() << "#endif";
  s.op->newline() << "c->probe_point = 0;";   s.op->newline() << "#ifdef STP_NEED_PROBE_NAME";
  s.op->newline() << "c->probe_name = 0;";
  s.op->newline() << "#endif";
  s.op->newline() << "c->probe_type = 0;";
  s.op->newline() << "if (unlikely (c->last_error && c->last_error[0])) {";
  s.op->indent(1);
  if (s.suppress_handler_errors)     {
      s.op->newline() << "atomic_inc (error_count());";
    }
  else
    {
      s.op->newline() << "if (c->last_stmt != NULL)";
      s.op->newline(1) << "_stp_softerror (\"%s near %s\", c->last_error, c->last_stmt);";
      s.op->newline(-1) << "else";
      s.op->newline(1) << "_stp_softerror (\"%s\", c->last_error);";
      s.op->indent(-1);
      s.op->newline() << "atomic_inc (error_count());";
      s.op->newline() << "if (atomic_read (error_count()) > MAXERRORS) {";
      s.op->newline(1) << "atomic_set (session_state(), STAP_SESSION_ERROR);";
      s.op->newline() << "_stp_exit ();";
      s.op->newline(-1) << "}";
    }
  s.op->newline(-1) << "}";
  s.op->newline(-1) << "probe_epilogue:";   s.op->indent(1);
  if (! s.suppress_handler_errors)     {
            s.op->newline() << "if (unlikely (atomic_read (skipped_count()) > MAXSKIPPED)) {";
      s.op->newline(1) << "if (unlikely (pseudo_atomic_cmpxchg(session_state(), STAP_SESSION_RUNNING, STAP_SESSION_ERROR) == STAP_SESSION_RUNNING))";
      s.op->newline() << "_stp_error (\"Skipped too many probes, check MAXSKIPPED or try again with stap -t for more details.\");";
      s.op->newline(-1) << "}";
    }
      s.op->newline() << "_stp_runtime_entryfn_put_context(c);";
  s.op->newline() << "#if !INTERRUPTIBLE";
  s.op->newline() << "local_irq_restore (flags);";
  s.op->newline() << "#endif";
  if (s.runtime_usermode_p())
    {
      s.op->newline() << "errno = _stp_saved_errno;";
    }
  s.op->newline() << "#endif // STP_ALIBI";
  if (s.runtime_usermode_p())
    s.op->newline(-1) << "}";
}
static const string TOK_KERNEL("kernel");
static const string TOK_MODULE("module");
static const string TOK_FUNCTION("function");
static const string TOK_INLINE("inline");
static const string TOK_CALL("call");
static const string TOK_EXPORTED("exported");
static const string TOK_RETURN("return");
static const string TOK_MAXACTIVE("maxactive");
static const string TOK_STATEMENT("statement");
static const string TOK_ABSOLUTE("absolute");
static const string TOK_PROCESS("process");
static const string TOK_PROVIDER("provider");
static const string TOK_MARK("mark");
static const string TOK_TRACE("trace");
static const string TOK_LABEL("label");
static const string TOK_LIBRARY("library");
static const string TOK_PLT("plt");
static const string TOK_METHOD("method");
static const string TOK_CLASS("class");;
static const string TOK_CALLEE("callee");;
static const string TOK_CALLEES("callees");;
static const string TOK_NEAREST("nearest");;
enum dbinfo_reqt
{
  dbr_unknown,
  dbr_none,          dbr_need_symtab,      dbr_need_dwarf
};
struct dwarf_query; 
static int query_cu (Dwarf_Die * cudie, dwarf_query *q);
static void query_addr(Dwarf_Addr addr, dwarf_query *q);
static void query_plt_statement(dwarf_query *q);
struct
symbol_table
{
  module_info *mod_info;      map<string, func_info*> map_by_name;
  multimap<Dwarf_Addr, func_info*> map_by_addr;
  map<string, Dwarf_Addr> globals;
  map<string, Dwarf_Addr> locals;
  typedef multimap<Dwarf_Addr, func_info*>::iterator iterator_t;
  typedef pair<iterator_t, iterator_t> range_t;
#ifdef __powerpc__
  GElf_Word opd_section;
#endif
  void add_symbol(const char *name, bool weak, bool descriptor,
                  Dwarf_Addr addr, Dwarf_Addr *high_addr);
  enum info_status get_from_elf();
  void prepare_section_rejection(Dwfl_Module *mod);
  bool reject_section(GElf_Word section);
  void purge_syscall_stubs();
  func_info *lookup_symbol(const string& name);
  Dwarf_Addr lookup_symbol_address(const string& name);
  func_info *get_func_containing_address(Dwarf_Addr addr);
  func_info *get_first_func();
  symbol_table(module_info *mi) : mod_info(mi) {}
  ~symbol_table();
};
static bool null_die(Dwarf_Die *die)
{
  static Dwarf_Die null;
  return (!die || !memcmp(die, &null, sizeof(null)));
}
struct exp_type_dwarf : public exp_type_details
{
        dwflpp* dw;
  Dwarf_Die die;
  bool userspace_p;
  bool is_pointer;
  exp_type_dwarf(dwflpp* dw, Dwarf_Die* die, bool userspace_p, bool addressof);
  uintptr_t id () const { return reinterpret_cast<uintptr_t>(die.addr); }
  bool expandable() const { return true; }
  functioncall *expand(autocast_op* e, bool lvalue);
};
enum
function_spec_type
  {
    function_alone,
    function_and_file,
    function_file_and_line
  };
struct dwarf_builder;
struct dwarf_var_expanding_visitor;
XXX
struct dwarf_derived_probe: public derived_probe
{
  dwarf_derived_probe (const string& function,
                       const string& filename,
                       int line,
                       const string& module,
                       const string& section,
               Dwarf_Addr dwfl_addr,
               Dwarf_Addr addr,
               dwarf_query & q,
                       Dwarf_Die* scope_die);
  string module;
  string section;
  Dwarf_Addr addr;
  string path;
  bool has_process;
  bool has_return;
  bool has_maxactive;
  bool has_library;
  long maxactive_val;
    string user_path;
  string user_lib;
  bool access_vars;
  unsigned saved_longs, saved_strings;
  dwarf_derived_probe* entry_handler;
  void printsig (std::ostream &o) const;
  virtual void join_group (systemtap_session& s);
  void emit_probe_local_init(systemtap_session& s, translator_output * o);
  void getargs(std::list<std::string> &arg_set) const;
  void emit_privilege_assertion (translator_output*);
  void print_dupe_stamp(ostream& o);
    static void register_statement_variants(match_node * root,
                      dwarf_builder * dw,
                      privilege_t privilege);
  static void register_function_variants(match_node * root,
                     dwarf_builder * dw,
                     privilege_t privilege);
  static void register_function_and_statement_variants(systemtap_session& s,
                               match_node * root,
                               dwarf_builder * dw,
                               privilege_t privilege);
  static void register_sdt_variants(systemtap_session& s,
                    match_node * root,
                    dwarf_builder * dw);
  static void register_plt_variants(systemtap_session& s,
                    match_node * root,
                    dwarf_builder * dw);
  static void register_patterns(systemtap_session& s);
protected:
  dwarf_derived_probe(probe *base,
                      probe_point *location,
                      Dwarf_Addr addr,
                      bool has_return):
    derived_probe(base, location), addr(addr), has_process(0),
    has_return(has_return), has_maxactive(0), has_library(0),
    maxactive_val(0), access_vars(false), saved_longs(0),
    saved_strings(0), entry_handler(0)
  {}
private:
  list<string> args;
  void saveargs(dwarf_query& q, Dwarf_Die* scope_die, Dwarf_Addr dwfl_addr);
};
struct uprobe_derived_probe: public dwarf_derived_probe
{
  int pid; 
  uprobe_derived_probe (const string& function,
                        const string& filename,
                        int line,
                        const string& module,
                        const string& section,
                        Dwarf_Addr dwfl_addr,
                        Dwarf_Addr addr,
                        dwarf_query & q,
                        Dwarf_Die* scope_die);
    uprobe_derived_probe (probe *base,
                        probe_point *location,
                        int pid,
                        Dwarf_Addr addr,
                        bool has_return):
    dwarf_derived_probe(base, location, addr, has_return), pid(pid)
  {}
  void join_group (systemtap_session& s);
  void emit_privilege_assertion (translator_output*);
  void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged_process_owner (o); }
  void getargs(std::list<std::string> &arg_set) const;
  void saveargs(int nargs);
private:
  list<string> args;
};
struct dwarf_derived_probe_group: public derived_probe_group
{
private:
  multimap<string,dwarf_derived_probe*> probes_by_module;
  typedef multimap<string,dwarf_derived_probe*>::iterator p_b_m_iterator;
public:
  dwarf_derived_probe_group() {}
  void enroll (dwarf_derived_probe* probe);
  void emit_module_decls (systemtap_session& s);
  void emit_module_init (systemtap_session& s);
  void emit_module_refresh (systemtap_session& s);
  void emit_module_exit (systemtap_session& s);
  bool otf_supported (systemtap_session& s) { return true; }
    bool otf_safe_context (systemtap_session& s) { return false; }
};
struct base_query
{
  base_query(dwflpp & dw, literal_map_t const & params);
  base_query(dwflpp & dw, const string & module_val);
  virtual ~base_query() {}
  systemtap_session & sess;
  dwflpp & dw;
      set<string> visited_modules;
    static bool has_null_param(literal_map_t const & params,
                             string const & k);
  static bool get_string_param(literal_map_t const & params,
                   string const & k, string & v);
  static bool get_number_param(literal_map_t const & params,
                   string const & k, long & v);
  static bool get_number_param(literal_map_t const & params,
                   string const & k, long long & v);
  static bool get_number_param(literal_map_t const & params,
                   string const & k, Dwarf_Addr & v);
  static void query_library_callback (base_query *me, const char *data);
  static void query_plt_callback (base_query *me, const char *link, size_t addr);
  virtual void query_library (const char *data) = 0;
  virtual void query_plt (const char *link, size_t addr) = 0;
    bool has_kernel;
  bool has_module;
  bool has_process;
  bool has_library;
  bool has_plt;
  bool has_statement;
  string module_val;   string path;           string plt_val;      int64_t pid_val;
  virtual void handle_query_module() = 0;
};
base_query::base_query(dwflpp & dw, literal_map_t const & params):
  sess(dw.sess), dw(dw), has_library(false), has_plt(false), has_statement(false),
  pid_val(0)
{
  has_kernel = has_null_param (params, TOK_KERNEL);
  if (has_kernel)
    module_val = "kernel";
  has_module = get_string_param (params, TOK_MODULE, module_val);
  if (has_module)
    has_process = false;
  else
    {
      string library_name;
      long statement_num_val;
      has_process =  derived_probe_builder::has_param(params, TOK_PROCESS);
      has_library = get_string_param (params, TOK_LIBRARY, library_name);
      if ((has_plt = has_null_param (params, TOK_PLT)))
        plt_val = "*";
      else has_plt = get_string_param (params, TOK_PLT, plt_val);
      has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val);
      if (has_process)
        {
          if (get_number_param(params, TOK_PROCESS, pid_val))
            {
                            string pid_err_msg;
              if (!is_valid_pid(pid_val, pid_err_msg))
                throw SEMANTIC_ERROR(pid_err_msg);
              string pid_path = string("/proc/") + lex_cast(pid_val) + "/exe";
              module_val = sess.sysroot + pid_path;
            }
          else
            {
                            pid_val = 0;
              get_string_param(params, TOK_PROCESS, module_val);
            }
          module_val = find_executable (module_val, sess.sysroot, sess.sysenv);
          if (!is_fully_resolved(module_val, sess.sysroot, sess.sysenv))
            throw SEMANTIC_ERROR(_F("cannot find executable '%s'",
                                    module_val.c_str()));
        }
                        if (has_library && is_fully_resolved(library_name, sess.sysroot, sess.sysenv,
                                           "LD_LIBRARY_PATH"))
        {
          path = path_remove_sysroot(sess, module_val);
          module_val = library_name;
        }
    }
  assert (has_kernel || has_process || has_module);
}
base_query::base_query(dwflpp & dw, const string & module_val)
  : sess(dw.sess), dw(dw), has_library(false), has_plt(false), has_statement(false),
    module_val(module_val), pid_val(0)
{
      if (module_val.find('/') == string::npos)
    {
      has_kernel = (module_val == TOK_KERNEL);
      has_module = !has_kernel;
      has_process = false;
    }
  else
    {
      has_kernel = has_module = false;
      has_process = true;
    }
}
bool
base_query::has_null_param(literal_map_t const & params,
               string const & k)
{
  return derived_probe_builder::has_null_param(params, k);
}
bool
base_query::get_string_param(literal_map_t const & params,
                 string const & k, string & v)
{
  return derived_probe_builder::get_param (params, k, v);
}
bool
base_query::get_number_param(literal_map_t const & params,
                 string const & k, long & v)
{
  int64_t value;
  bool present = derived_probe_builder::get_param (params, k, value);
  v = (long) value;
  return present;
}
bool
base_query::get_number_param(literal_map_t const & params,
                 string const & k, long long & v)
{
  int64_t value;
  bool present = derived_probe_builder::get_param (params, k, value);
  v = (long) value;
  return present;
}
bool
base_query::get_number_param(literal_map_t const & params,
                 string const & k, Dwarf_Addr & v)
{
  int64_t value;
  bool present = derived_probe_builder::get_param (params, k, value);
  v = (Dwarf_Addr) value;
  return present;
}
struct dwarf_query : public base_query
{
  dwarf_query(probe * base_probe,
          probe_point * base_loc,
          dwflpp & dw,
          literal_map_t const & params,
          vector<derived_probe *> & results,
          const string user_path,
          const string user_lib);
  vector<derived_probe *> & results;
  set<string> inlined_non_returnable;   probe * base_probe;
  probe_point * base_loc;
  string user_path;
  string user_lib;
  set<string> visited_libraries;
  bool resolved_library;
  virtual void handle_query_module();
  void query_module_dwarf();
  void query_module_symtab();
  void query_library (const char *data);
  void query_plt (const char *entry, size_t addr);
  void add_probe_point(string const & funcname,
               char const * filename,
               int line,
               Dwarf_Die *scope_die,
               Dwarf_Addr addr);
  void mount_well_formed_probe_point();
  void unmount_well_formed_probe_point();
  stack<pair<probe_point*, probe*> > previous_bases;
  void replace_probe_point_component_arg(const string& functor,
                                         const string& new_functor,
                                         int64_t new_arg,
                                         bool hex = false);
  void replace_probe_point_component_arg(const string& functor,
                                         int64_t new_arg,
                                         bool hex = false);
  void replace_probe_point_component_arg(const string& functor,
                                         const string& new_functor,
                                         const string& new_arg);
  void replace_probe_point_component_arg(const string& functor,
                                         const string& new_arg);
  void remove_probe_point_component(const string& functor);
    set<Dwarf_Addr> alias_dupes;
      set<inline_instance_info> inline_dupes;
            stack<Dwarf_Addr> *callers;
  bool has_function_str;
  bool has_statement_str;
  bool has_function_num;
  bool has_statement_num;
  string statement_str_val;
  string function_str_val;
  Dwarf_Addr statement_num_val;
  Dwarf_Addr function_num_val;
  bool has_call;
  bool has_exported;
  bool has_inline;
  bool has_return;
  bool has_nearest;
  bool has_maxactive;
  long maxactive_val;
  bool has_label;
  string label_val;
  bool has_callee;
  string callee_val;
  bool has_callees_num;
  long callees_num_val;
  bool has_relative;
  long relative_val;
  bool has_absolute;
  bool has_mark;
  enum dbinfo_reqt dbinfo_reqt;
  enum dbinfo_reqt assess_dbinfo_reqt();
  void parse_function_spec(const string & spec);
  function_spec_type spec_type;
  vector<string> scopes;
  string function;
  string file;
  lineno_t lineno_type;
  vector<int> linenos;
  bool query_done;    
    Dwarf_Addr prologue_end;
  set<string> filtered_srcfiles;
    inline_instance_map_t filtered_inlines;
  func_info_map_t filtered_functions;
    base_func_info_map_t filtered_all();
  void query_module_functions ();
  string final_function_name(const string& final_func,
                             const char* final_file,
                             int final_line);
  bool is_fully_specified_function();
};
uprobe_derived_probe::uprobe_derived_probe (const string& function,
                        const string& filename,
                        int line,
                        const string& module,
                        const string& section,
                        Dwarf_Addr dwfl_addr,
                        Dwarf_Addr addr,
                        dwarf_query & q,
                        Dwarf_Die* scope_die):
    dwarf_derived_probe(function, filename, line, module, section,
                        dwfl_addr, addr, q, scope_die), pid(q.pid_val)
  {}
static void delete_session_module_cache (systemtap_session& s); 
struct dwarf_builder: public derived_probe_builder
{
  map <string,dwflpp*> kern_dw;   map <string,dwflpp*> user_dw;
  string user_path;
  string user_lib;
      set <string> modules_seen;
  dwarf_builder() {}
  dwflpp *get_kern_dw(systemtap_session& sess, const string& module)
  {
    if (kern_dw[module] == 0)
      kern_dw[module] = new dwflpp(sess, module, true);     return kern_dw[module];
  }
  dwflpp *get_user_dw(systemtap_session& sess, const string& module)
  {
    if (user_dw[module] == 0)
      user_dw[module] = new dwflpp(sess, module, false);     return user_dw[module];
  }
    void dwarf_build_no_more (bool)
  {
    delete_map(kern_dw);
    delete_map(user_dw);
  }
  void build_no_more (systemtap_session &s)
  {
    dwarf_build_no_more (s.verbose > 3);
    delete_session_module_cache (s);
  }
  ~dwarf_builder()
  {
    dwarf_build_no_more (false);
  }
  virtual void build(systemtap_session & sess,
             probe * base,
             probe_point * location,
             literal_map_t const & parameters,
             vector<derived_probe *> & finished_results);
};
dwarf_query::dwarf_query(probe * base_probe,
             probe_point * base_loc,
             dwflpp & dw,
             literal_map_t const & params,
             vector<derived_probe *> & results,
             const string user_path,
             const string user_lib)
  : base_query(dw, params), results(results), base_probe(base_probe),
    base_loc(base_loc), user_path(user_path), user_lib(user_lib),
    resolved_library(false), callers(NULL), has_relative(false),
    relative_val(0), prologue_end(0)
{
      has_function_str = get_string_param(params, TOK_FUNCTION, function_str_val);
  has_function_num = get_number_param(params, TOK_FUNCTION, function_num_val);
  has_statement_str = get_string_param(params, TOK_STATEMENT, statement_str_val);
  has_statement_num = get_number_param(params, TOK_STATEMENT, statement_num_val);
  has_label = get_string_param(params, TOK_LABEL, label_val);
  has_callee = get_string_param(params, TOK_CALLEE, callee_val);
  if (has_null_param(params, TOK_CALLEES))
    {       has_callees_num = true;
      callees_num_val = 1;
    }
  else
    {
      has_callees_num = get_number_param(params, TOK_CALLEES, callees_num_val);
      if (has_callees_num && callees_num_val < 1)
        throw SEMANTIC_ERROR(_(".callees(N) only acceptable for N >= 1"),
                             base_probe->tok);
    }
  has_call = has_null_param(params, TOK_CALL);
  has_exported = has_null_param(params, TOK_EXPORTED);
  has_inline = has_null_param(params, TOK_INLINE);
  has_return = has_null_param(params, TOK_RETURN);
  has_nearest = has_null_param(params, TOK_NEAREST);
  has_maxactive = get_number_param(params, TOK_MAXACTIVE, maxactive_val);
  has_absolute = has_null_param(params, TOK_ABSOLUTE);
  has_mark = false;
  if (has_function_str)
    parse_function_spec(function_str_val);
  else if (has_statement_str)
    parse_function_spec(statement_str_val);
  dbinfo_reqt = assess_dbinfo_reqt();
  query_done = false;
}
void
dwarf_query::query_module_dwarf()
{
  if (has_function_num || has_statement_num)
    {
                              Dwarf_Addr addr = has_function_num ?
        function_num_val : statement_num_val;
                  Dwarf_Addr elf_bias;
      Elf *elf = dwfl_module_getelf (dw.module, &elf_bias);
      assert(elf);
      addr += elf_bias;
      query_addr(addr, this);
    }
  else
    {
                        assert(has_function_str || has_statement_str);
                  if (spec_type == function_alone &&
          !dw.name_has_wildcard(function) &&
          !startswith(function, "_Z"))
        query_module_functions();
      else
        dw.iterate_over_cus(&query_cu, this, false);
    }
}
static void query_func_info (Dwarf_Addr entrypc, func_info & fi,
                            dwarf_query * q);
static void
query_symtab_func_info (func_info & fi, dwarf_query * q)
{
  assert(null_die(&fi.die));
  Dwarf_Addr addr = fi.addr;
      q->dw.get_module_dwarf(false, false);
  addr -= q->dw.module_bias;
          if (q->alias_dupes.insert(addr).second)
    query_func_info(addr, fi, q);
}
void
dwarf_query::query_module_symtab()
{
    if (dbinfo_reqt == dbr_need_dwarf)
    return;
  module_info *mi = dw.mod_info;
  if (dbinfo_reqt == dbr_need_symtab)
    {
      if (mi->symtab_status == info_unknown)
        mi->get_symtab();
      if (mi->symtab_status == info_absent)
        return;
    }
  func_info *fi = NULL;
  symbol_table *sym_table = mi->sym_table;
  if (has_function_str)
    {
            assert(spec_type == function_alone);
      if (dw.name_has_wildcard(function_str_val))
        {
          symbol_table::iterator_t iter;
          for (iter = sym_table->map_by_addr.begin();
               iter != sym_table->map_by_addr.end();
               ++iter)
            {
              fi = iter->second;
              if (!null_die(&fi->die)                   || fi->descriptor)                 continue;
              if (dw.function_name_matches_pattern(fi->name, function_str_val))
                query_symtab_func_info(*fi, this);
            }
        }
      else
        {
          fi = sym_table->lookup_symbol(function_str_val);
          if (fi && !fi->descriptor && null_die(&fi->die))
         query_symtab_func_info(*fi, this);
        }
    }
}
void
dwarf_query::handle_query_module()
{
  if (has_plt && has_statement_num)
    {
      query_plt_statement (this);
      return;
    }
  bool report = dbinfo_reqt == dbr_need_dwarf;
  dw.get_module_dwarf(false, report);
    dw.mod_info->get_symtab();
    alias_dupes.clear();
  inline_dupes.clear();
  if (dw.mod_info->dwarf_status == info_present)
    query_module_dwarf();
          if (!query_done && !pending_interrupts)
    query_module_symtab();
}
void
dwarf_query::parse_function_spec(const string & spec)
{
  lineno_type = ABSOLUTE;
  size_t src_pos, line_pos, scope_pos;
    scope_pos = spec.rfind("::");
  if (scope_pos != string::npos)
    {
      tokenize_cxx(spec.substr(0, scope_pos), scopes);
      scope_pos += 2;
    }
  else
    scope_pos = 0;
    src_pos = spec.find('@', scope_pos);
  if (src_pos == string::npos)
    {
      function = spec.substr(scope_pos);
      spec_type = function_alone;
    }
  else
    {
      function = spec.substr(scope_pos, src_pos - scope_pos);
            line_pos = spec.find_first_of(":+", src_pos);
      if (line_pos == string::npos)
        {
          file = spec.substr(src_pos + 1);
          spec_type = function_and_file;
        }
      else
        {
          file = spec.substr(src_pos + 1, line_pos - src_pos - 1);
                    spec_type = function_file_and_line;
          if (spec[line_pos] == '+')
            lineno_type = RELATIVE;
          else if (spec[line_pos + 1] == '*' &&
                   spec.length() == line_pos + 2)
            lineno_type = WILDCARD;
          else
            lineno_type = ABSOLUTE;
          if (lineno_type != WILDCARD)
            try
              {
                                if (spec.find_first_of(",-", line_pos + 1) != string::npos)
                  {
                    lineno_type = ENUMERATED;
                    vector<string> sub_specs;
                    tokenize(spec.substr(line_pos + 1), sub_specs, ",");
                    vector<string>::const_iterator line_spec;
                    for (line_spec = sub_specs.begin(); line_spec != sub_specs.end(); ++line_spec)
                      {
                        vector<string> ranges;
                        tokenize(*line_spec, ranges, "-");
                        if (ranges.size() > 1)
                            for (int i = lex_cast<int>(ranges.front()); i <= lex_cast<int>(ranges.back()); i++)
                                linenos.push_back(i);
                        else
                            linenos.push_back(lex_cast<int>(ranges.at(0)));
                      }
                    sort(linenos.begin(), linenos.end());
                  }
                else
                  {
                    linenos.push_back(lex_cast<int>(spec.substr(line_pos + 1)));
                    linenos.push_back(lex_cast<int>(spec.substr(line_pos + 1)));
                  }
              }
            catch (runtime_error & exn)
              {
                goto bad;
              }
                        if (has_nearest && lineno_type != ABSOLUTE
                            && lineno_type != RELATIVE)
              throw SEMANTIC_ERROR(_(".nearest is only valid with absolute or relative line numbers"));
        }
    }
  if (function.empty() ||
      (spec_type != function_alone && file.empty()))
    goto bad;
  if (sess.verbose > 2)
    {
            clog << _F("parse '%s'", spec.c_str());
      if (!scopes.empty())
        clog << ", scope '" << scopes[0] << "'";
      for (unsigned i = 1; i < scopes.size(); ++i)
        clog << "::'" << scopes[i] << "'";
      clog << ", func '" << function << "'";
      if (spec_type != function_alone)
        clog << ", file '" << file << "'";
      if (spec_type == function_file_and_line)
        {
          clog << ", line ";
          switch (lineno_type)
            {
            case ABSOLUTE:
              clog << linenos[0];
              break;
            case RELATIVE:
              clog << "+" << linenos[0];
              break;
            case ENUMERATED:
              {
                vector<int>::const_iterator linenos_it;
                for (linenos_it = linenos.begin(); linenos_it != linenos.end(); ++linenos_it)
                  {
                    vector<int>::const_iterator range_it(linenos_it);
                    while ((range_it+1) != linenos.end() && *range_it + 1 == *(range_it+1))
                        ++range_it;
                    if (linenos_it == range_it)
                        clog << *linenos_it;
                    else
                        clog << *linenos_it << "-" << *range_it;
                    if (range_it + 1 != linenos.end())
                      clog << ",";
                    linenos_it = range_it;
                  }
                }
              break;
            case WILDCARD:
              clog << "*";
              break;
            }
        }
      clog << endl;
    }
  return;
bad:
  throw SEMANTIC_ERROR(_F("malformed specification '%s'", spec.c_str()),
                       base_probe->tok);
}
string path_remove_sysroot(const systemtap_session& sess, const string& path)
{
  size_t pos;
  string retval = path;
  if (!sess.sysroot.empty() &&
      (pos = retval.find(sess.sysroot)) != string::npos)
    retval.replace(pos, sess.sysroot.length(), "/");
  return retval;
}
void
dwarf_query::add_probe_point(const string& dw_funcname,
                 const char* filename,
                 int line,
                 Dwarf_Die* scope_die,
                 Dwarf_Addr addr)
{
  string reloc_section;   Dwarf_Addr reloc_addr;   const string& module = dw.module_name;   string funcname = dw_funcname;
  assert (! has_absolute); 
  reloc_addr = dw.relocate_address(addr, reloc_section);
    const char* linkage_name;
  if (!null_die(scope_die) && startswith (this->function, "_Z")
      && (linkage_name = dwarf_linkage_name (scope_die)))
    funcname = linkage_name;
  if (sess.verbose > 1)
    {
      clog << _("probe ") << funcname << "@" << filename << ":" << line;
      if (string(module) == TOK_KERNEL)
        clog << _(" kernel");
      else if (has_module)
        clog << _(" module=") << module;
      else if (has_process)
        clog << _(" process=") << module;
      if (reloc_section != "") clog << " reloc=" << reloc_section;
      clog << " pc=0x" << hex << addr << dec;
    }
  dwflpp::blacklisted_type blacklisted = dw.blacklisted_p (funcname, filename,
                                                           line, module, addr,
                                                           has_return);
  if (sess.verbose > 1)
    clog << endl;
  if (module == TOK_KERNEL)
    {
            reloc_addr = addr - sess.sym_stext;
      reloc_section = "_stext";     }
  if (!blacklisted)
    {
      sess.unwindsym_modules.insert (module);
      if (has_process)
        {
          string module_tgt = path_remove_sysroot(sess, module);
          results.push_back (new uprobe_derived_probe(funcname, filename, line,
                                                      module_tgt, reloc_section, addr, reloc_addr,
                                                      *this, scope_die));
        }
      else
        {
          assert (has_kernel || has_module);
          results.push_back (new dwarf_derived_probe(funcname, filename, line,
                                                     module, reloc_section, addr, reloc_addr,
                                                     *this, scope_die));
        }
    }
  else
    {
      switch (blacklisted)
        {
        case dwflpp::blacklisted_section:
          sess.print_warning(_F("function %s is in blacklisted section",
                                funcname.c_str()), base_probe->tok);
          break;
        case dwflpp::blacklisted_kprobes:
          sess.print_warning(_F("kprobes function %s is blacklisted",
                                funcname.c_str()), base_probe->tok);
          break;
        case dwflpp::blacklisted_function_return:
          sess.print_warning(_F("function %s return probe is blacklisted",
                                funcname.c_str()), base_probe->tok);
          break;
        case dwflpp::blacklisted_file:
          sess.print_warning(_F("function %s is in blacklisted file",
                                funcname.c_str()), base_probe->tok);
          break;
        case dwflpp::blacklisted_function:
        default:
          sess.print_warning(_F("function %s is blacklisted",
                                funcname.c_str()), base_probe->tok);
          break;
        }
    }
}
void
dwarf_query::mount_well_formed_probe_point()
{
  string module = dw.module_name;
  if (has_process)
    module = path_remove_sysroot(sess, module);
  vector<probe_point::component*> comps;
  vector<probe_point::component*>::iterator it;
  for (it  = base_loc->components.begin();
       it != base_loc->components.end(); ++it)
    {
      if ((*it)->functor == TOK_PROCESS || (*it)->functor == TOK_MODULE)
        comps.push_back(new probe_point::component((*it)->functor,
          new literal_string(has_library ? path : module)));
      else
        comps.push_back(*it);
    }
  probe_point *pp = new probe_point(*base_loc);
  pp->well_formed = true;
  pp->components = comps;
  previous_bases.push(make_pair(base_loc, base_probe));
  base_loc = pp;
  base_probe = new probe(base_probe, pp);
}
void
dwarf_query::unmount_well_formed_probe_point()
{
  assert(!previous_bases.empty());
  base_loc = previous_bases.top().first;
  base_probe = previous_bases.top().second;
  previous_bases.pop();
}
void
dwarf_query::replace_probe_point_component_arg(const string& functor,
                                               const string& new_functor,
                                               int64_t new_arg,
                                               bool hex)
{
    assert(!previous_bases.empty());
  vector<probe_point::component*>::iterator it;
  for (it  = base_loc->components.begin();
       it != base_loc->components.end(); ++it)
    if ((*it)->functor == functor)
      *it = new probe_point::component(new_functor,
              new literal_number(new_arg, hex));
}
void
dwarf_query::replace_probe_point_component_arg(const string& functor,
                                               int64_t new_arg,
                                               bool hex)
{
  replace_probe_point_component_arg(functor, functor, new_arg, hex);
}
void
dwarf_query::replace_probe_point_component_arg(const string& functor,
                                               const string& new_functor,
                                               const string& new_arg)
{
    assert(!previous_bases.empty());
  vector<probe_point::component*>::iterator it;
  for (it  = base_loc->components.begin();
       it != base_loc->components.end(); ++it)
    if ((*it)->functor == functor)
      *it = new probe_point::component(new_functor,
              new literal_string(new_arg));
}
void
dwarf_query::replace_probe_point_component_arg(const string& functor,
                                               const string& new_arg)
{
  replace_probe_point_component_arg(functor, functor, new_arg);
}
void
dwarf_query::remove_probe_point_component(const string& functor)
{
    assert(!previous_bases.empty());
  vector<probe_point::component*> new_comps;
  vector<probe_point::component*>::iterator it;
  for (it  = base_loc->components.begin();
       it != base_loc->components.end(); ++it)
    if ((*it)->functor != functor)
      new_comps.push_back(*it);
  base_loc->components = new_comps;
}
enum dbinfo_reqt
dwarf_query::assess_dbinfo_reqt()
{
  if (has_absolute)
    {
            return dbr_none;
    }
  if (has_inline || has_label || has_callee || has_callees_num)
    {
            return dbr_need_dwarf;
    }
  if (has_function_str && spec_type == function_alone)
    {
            return dbr_need_symtab;
    }
  if (has_statement_num)
    {
                                          return dbr_need_symtab;
    }
  if (has_function_num)
    {
                        return dbr_need_symtab;
    }
    return dbr_need_dwarf;
}
string
dwarf_query::final_function_name(const string& final_func,
                                 const char* final_file,
                                 int final_line)
{
  string final_name = final_func;
  if (final_file && *final_file != '\0')
    {
      final_name += ("@" + string(final_file));
      if (final_line > 0)
        final_name += (":" + lex_cast(final_line));
    }
  return final_name;
}
bool
dwarf_query::is_fully_specified_function()
{
      return (has_function_str
          && spec_type == function_file_and_line
          && !dw.name_has_wildcard(function)
          && filtered_srcfiles.size() == 1
          && !filtered_functions.empty()
          && lineno_type == ABSOLUTE
          && filtered_functions[0].decl_line == linenos[0]);
}
base_func_info_map_t
dwarf_query::filtered_all(void)
{
  base_func_info_map_t r;
  func_info_map_t::const_iterator f;
  for (f  = filtered_functions.begin();
       f != filtered_functions.end(); ++f)
    r.push_back(*f);
  inline_instance_map_t::const_iterator i;
  for (i  = filtered_inlines.begin();
       i != filtered_inlines.end(); ++i)
    r.push_back(*i);
  return r;
}
static void
query_statement (string const & func,
         char const * file,
         int line,
         Dwarf_Die *scope_die,
         Dwarf_Addr stmt_addr,
         dwarf_query * q)
{
  try
    {
      q->add_probe_point(func, file ? file : "",
                         line, scope_die, stmt_addr);
    }
  catch (const semantic_error& e)
    {
      q->sess.print_error (e);
    }
}
static void
query_addr(Dwarf_Addr addr, dwarf_query *q)
{
  assert(q->has_function_num || q->has_statement_num);
  dwflpp &dw = q->dw;
  if (q->sess.verbose > 2)
    clog << "query_addr 0x" << hex << addr << dec << endl;
    Dwarf_Die* cudie = dw.query_cu_containing_address(addr);
  if (!cudie)     return;
  dw.focus_on_cu(cudie);
    addr -= dw.module_bias;
      
    vector<Dwarf_Die> scopes = dw.getscopes(addr);
  if (scopes.empty())
    return;
    Dwarf_Die *fnscope = NULL;
  for (size_t i = 0; i < scopes.size(); ++i)
    {
      int tag = dwarf_tag(&scopes[i]);
      if ((tag == DW_TAG_subprogram && !q->has_inline) ||
          (tag == DW_TAG_inlined_subroutine &&
           !q->has_call && !q->has_return && !q->has_exported))
        {
          fnscope = &scopes[i];
          break;
        }
    }
  if (!fnscope)
    return;
  dw.focus_on_function(fnscope);
  Dwarf_Die *scope = q->has_function_num ? fnscope : &scopes[0];
  const char *file = dwarf_decl_file(fnscope);
  int line;
  dwarf_decl_line(fnscope, &line);
      if (q->has_function_num)
    {
      if (!dw.die_entrypc(fnscope, &addr))
        return;
      if (dwarf_tag(fnscope) == DW_TAG_subprogram &&
          (q->sess.prologue_searching ||
           (q->has_process && !q->dw.has_valid_locs())))         {
          func_info func;
          func.die = *fnscope;
          func.name = dw.function_name;
          func.decl_file = file;
          func.decl_line = line;
          func.entrypc = addr;
          func_info_map_t funcs(1, func);
          dw.resolve_prologue_endings (funcs);
          q->prologue_end = funcs[0].prologue_end;
                                                  if (!q->has_return)
            addr = funcs[0].prologue_end;
        }
    }
  else
    {
      Dwarf_Line *address_line = dwarf_getsrc_die(cudie, addr);
      Dwarf_Addr address_line_addr = addr;
      if (address_line)
        {
          file = DWARF_LINESRC(address_line);
          line = DWARF_LINENO(address_line);
          address_line_addr = DWARF_LINEADDR(address_line);
        }
                                    if (!q->has_mark && (!address_line || address_line_addr != addr))
        {
          stringstream msg;
          msg << _F("address %#" PRIx64 " does not match the beginning of a statement",
                    addr);
          if (address_line)
            msg << _F(" (try %#" PRIx64 ")", address_line_addr);
          else
            msg << _F(" (no line info found for '%s', in module '%s')",
                      dw.cu_name().c_str(), dw.module_name.c_str());
          if (! q->sess.guru_mode)
            throw SEMANTIC_ERROR(msg.str());
          else
           q->sess.print_warning(msg.str());
        }
    }
      q->mount_well_formed_probe_point();
  q->replace_probe_point_component_arg(TOK_FUNCTION, addr, true  );
  q->replace_probe_point_component_arg(TOK_STATEMENT, addr, true  );
    query_statement(dw.function_name, file, line, scope, addr, q);
  q->unmount_well_formed_probe_point();
}
static void
query_plt_statement(dwarf_query *q)
{
  assert (q->has_plt && q->has_statement_num);
  Dwarf_Addr addr = q->statement_num_val;
  if (q->sess.verbose > 2)
    clog << "query_plt_statement 0x" << hex << addr << dec << endl;
    Dwarf_Addr elf_bias;
  Elf *elf = dwfl_module_getelf (q->dw.module, &elf_bias);
  assert(elf);
  addr += elf_bias;
    q->dw.get_module_dwarf(false, false);
  addr -= q->dw.module_bias;
    q->mount_well_formed_probe_point();
  q->replace_probe_point_component_arg(TOK_STATEMENT, q->statement_num_val, true  );
          q->remove_probe_point_component(TOK_PLT);
    query_statement(q->plt_val, NULL, -1, NULL, addr, q);
  q->unmount_well_formed_probe_point();
}
static void
query_label (const base_func_info& func,
             char const * label,
             char const * file,
             int line,
             Dwarf_Die *scope_die,
             Dwarf_Addr stmt_addr,
             dwarf_query * q)
{
  assert (q->has_statement_str || q->has_function_str);
      if (q->spec_type != function_alone &&
      q->filtered_srcfiles.count(file) == 0)
    return;
    string canon_func = q->final_function_name(func.name, file, line);
  q->mount_well_formed_probe_point();
  q->replace_probe_point_component_arg(TOK_FUNCTION, canon_func);
  q->replace_probe_point_component_arg(TOK_LABEL, label);
  query_statement(func.name, file, line, scope_die, stmt_addr, q);
  q->unmount_well_formed_probe_point();
}
static void
query_callee (base_func_info& callee,
              base_func_info& caller,
              stack<Dwarf_Addr> *callers,
              dwarf_query * q)
{
  assert (q->has_function_str);
  assert (q->has_callee || q->has_callees_num);
    
  string canon_caller = q->final_function_name(caller.name, caller.decl_file,
                                               caller.decl_line);
  string canon_callee = q->final_function_name(callee.name, callee.decl_file,
                                               callee.decl_line);
  q->mount_well_formed_probe_point();
  q->replace_probe_point_component_arg(TOK_FUNCTION, canon_caller);
  q->replace_probe_point_component_arg(TOK_CALLEES, TOK_CALLEE, canon_callee);
  q->replace_probe_point_component_arg(TOK_CALLEE, canon_callee);
    q->callers = callers;
  query_statement(callee.name, callee.decl_file, callee.decl_line,
                  &callee.die, callee.entrypc, q);
  q->unmount_well_formed_probe_point();
}
static void
query_inline_instance_info (inline_instance_info & ii,
                dwarf_query * q)
{
  try
    {
      assert (! q->has_return);       assert (q->has_function_str || q->has_statement_str);
      if (q->sess.verbose>2)
        clog << _F("querying entrypc %#" PRIx64 " of instance of inline '%s'\n",
                   ii.entrypc, ii.name.c_str());
      string canon_func = q->final_function_name(ii.name, ii.decl_file,
                                                 ii.decl_line);
      q->mount_well_formed_probe_point();
      q->replace_probe_point_component_arg(TOK_FUNCTION, canon_func);
      q->replace_probe_point_component_arg(TOK_STATEMENT, canon_func);
      query_statement (ii.name, ii.decl_file, ii.decl_line,
                       &ii.die, ii.entrypc, q);
      q->unmount_well_formed_probe_point();
    }
  catch (semantic_error &e)
    {
      q->sess.print_error (e);
    }
}
static void
query_func_info (Dwarf_Addr entrypc,
         func_info & fi,
         dwarf_query * q)
{
  assert(q->has_function_str || q->has_statement_str);
  try
    {
      string canon_func = q->final_function_name(fi.name, fi.decl_file,
                                                 fi.decl_line);
      q->mount_well_formed_probe_point();
      q->replace_probe_point_component_arg(TOK_FUNCTION, canon_func);
      q->replace_probe_point_component_arg(TOK_STATEMENT, canon_func);
                              if (fi.prologue_end == 0 || q->has_return)
        {
          q->prologue_end = fi.prologue_end;
          query_statement (fi.name, fi.decl_file, fi.decl_line,
                           &fi.die, entrypc, q);
        }
      else
        {
          query_statement (fi.name, fi.decl_file, fi.decl_line,
                           &fi.die, fi.prologue_end, q);
        }
      q->unmount_well_formed_probe_point();
    }
  catch (semantic_error &e)
    {
      q->sess.print_error (e);
    }
}
static void
query_srcfile_line (Dwarf_Addr addr, int lineno, dwarf_query * q)
{
  assert (q->has_statement_str || q->has_function_str);
  assert (q->spec_type == function_file_and_line);
  base_func_info_map_t bfis = q->filtered_all();
  base_func_info_map_t::iterator i;
  for (i = bfis.begin(); i != bfis.end(); ++i)
    {
      if (q->dw.die_has_pc (i->die, addr))
        {
          if (q->sess.verbose>3)
            clog << _("filtered DIE lands on srcfile\n");
          Dwarf_Die scope;
          q->dw.inner_die_containing_pc(i->die, addr, scope);
          string canon_func = q->final_function_name(i->name, i->decl_file,
                                                     lineno  );
          if (q->has_nearest)
            {
              int lineno_nearest = q->linenos[0];
              if (q->lineno_type == RELATIVE)
                lineno_nearest += i->decl_line;
              string canon_func_nearest = q->final_function_name(i->name, i->decl_file,
                                                                 lineno_nearest);
              q->mount_well_formed_probe_point();
              q->replace_probe_point_component_arg(TOK_STATEMENT, canon_func_nearest);
            }
          q->mount_well_formed_probe_point();
          q->replace_probe_point_component_arg(TOK_FUNCTION, canon_func);
          q->replace_probe_point_component_arg(TOK_STATEMENT, canon_func);
          query_statement (i->name, i->decl_file,
                           lineno,                            &scope, addr, q);
          q->unmount_well_formed_probe_point();
          if (q->has_nearest)
            q->unmount_well_formed_probe_point();
        }
    }
}
bool
inline_instance_info::operator<(const inline_instance_info& other) const
{
  if (entrypc != other.entrypc)
    return entrypc < other.entrypc;
  if (decl_line != other.decl_line)
    return decl_line < other.decl_line;
  int cmp = name.compare(other.name);
  if (!cmp)
    {
      assert (decl_file);
      assert (other.decl_file);
      cmp = strcmp(decl_file, other.decl_file);
    }
  return cmp < 0;
}
static int
query_dwarf_inline_instance (Dwarf_Die * die, dwarf_query * q)
{
  assert (q->has_statement_str || q->has_function_str);
  assert (!q->has_call && !q->has_return && !q->has_exported);
  try
    {
      if (q->sess.verbose>2)
        clog << _F("selected inline instance of %s\n", q->dw.function_name.c_str());
      Dwarf_Addr entrypc;
      if (q->dw.die_entrypc (die, &entrypc))
        {
          inline_instance_info inl;
          inl.die = *die;
          inl.name = q->dw.function_name;
          inl.entrypc = entrypc;
          q->dw.function_file (&inl.decl_file);
          q->dw.function_line (&inl.decl_line);
                              if (q->inline_dupes.insert(inl).second)
            q->filtered_inlines.push_back(inl);
        }
      return DWARF_CB_OK;
    }
  catch (const semantic_error& e)
    {
      q->sess.print_error (e);
      return DWARF_CB_ABORT;
    }
}
static int
query_dwarf_func (Dwarf_Die * func, dwarf_query * q)
{
  assert (q->has_statement_str || q->has_function_str);
      if (q->spec_type != function_alone &&
      q->filtered_srcfiles.count(dwarf_decl_file(func)?:"") == 0)
    return DWARF_CB_OK;
  try
    {
      q->dw.focus_on_function (func);
      if (!q->dw.function_scope_matches(q->scopes))
        return DWARF_CB_OK;
                  Dwarf_Addr addr;
      if (!q->dw.func_is_inline() &&
          dwarf_entrypc(func, &addr) == 0 &&
          !q->alias_dupes.insert(addr).second)
        return DWARF_CB_OK;
      if (q->dw.func_is_inline () && (! q->has_call) && (! q->has_return) && (! q->has_exported))
    {
          if (q->sess.verbose>3)
            clog << _F("checking instances of inline %s\n", q->dw.function_name.c_str());
          q->dw.iterate_over_inline_instances (query_dwarf_inline_instance, q);
    }
      else if (q->dw.func_is_inline () && (q->has_return))     {
          q->inlined_non_returnable.insert (q->dw.function_name);
    }
      else if (!q->dw.func_is_inline () && (! q->has_inline))
    {
          if (q->has_exported && !q->dw.func_is_exported ())
            return DWARF_CB_OK;
          if (q->sess.verbose>2)
            clog << _F("selected function %s\n", q->dw.function_name.c_str());
          func_info func;
          q->dw.function_die (&func.die);
          func.name = q->dw.function_name;
          q->dw.function_file (&func.decl_file);
          q->dw.function_line (&func.decl_line);
          Dwarf_Addr entrypc;
          if (q->dw.function_entrypc (&entrypc))
            {
              func.entrypc = entrypc;
              q->filtered_functions.push_back (func);
            }
              }
      return DWARF_CB_OK;
    }
  catch (const semantic_error& e)
    {
      q->sess.print_error (e);
      return DWARF_CB_ABORT;
    }
}
static int
query_cu (Dwarf_Die * cudie, dwarf_query * q)
{
  assert (q->has_statement_str || q->has_function_str);
  if (pending_interrupts) return DWARF_CB_ABORT;
  try
    {
      q->dw.focus_on_cu (cudie);
      if (false && q->sess.verbose>2)
        clog << _F("focused on CU '%s', in module '%s'\n",
                   q->dw.cu_name().c_str(), q->dw.module_name.c_str());
      q->filtered_srcfiles.clear();
      q->filtered_functions.clear();
      q->filtered_inlines.clear();
                              
      if (q->spec_type != function_alone)
        {
                              q->dw.collect_srcfiles_matching (q->file, q->filtered_srcfiles);
                              if (q->filtered_srcfiles.empty())
            return DWARF_CB_OK;
        }
                        int rc = q->dw.iterate_over_functions (query_dwarf_func, q, q->function);
      if (rc != DWARF_CB_OK)
        q->query_done = true;
      if (!q->filtered_functions.empty() &&
          !q->has_statement_str &&            (q->sess.prologue_searching ||
            (q->has_process && !q->dw.has_valid_locs())))         q->dw.resolve_prologue_endings (q->filtered_functions);
      if (q->has_label)
        {
          enum lineno_t lineno_type = WILDCARD;
          if (q->spec_type == function_file_and_line)
            lineno_type = q->lineno_type;
          base_func_info_map_t bfis = q->filtered_all();
          base_func_info_map_t::iterator i;
          for (i = bfis.begin(); i != bfis.end(); ++i)
            q->dw.iterate_over_labels (&i->die, q->label_val, *i, q->linenos,
                                       lineno_type, q, query_label);
        }
      else if (q->has_callee || q->has_callees_num)
        {
                    string callee_val = q->has_callee ? q->callee_val : "*";
          long callees_num_val = q->has_callees_num ? q->callees_num_val : 1;
                                                  base_func_info_map_t bfis = q->filtered_all();
          base_func_info_map_t::iterator i;
          for (i = bfis.begin(); i != bfis.end(); ++i)
            {
              if (q->spec_type != function_alone &&
                  q->filtered_srcfiles.count(i->decl_file) == 0)
                continue;
              q->dw.iterate_over_callees (&i->die, callee_val,
                                          callees_num_val,
                                          q, query_callee, *i);
            }
        }
      else if (q->spec_type == function_file_and_line
                                                                                     && !q->is_fully_specified_function())
        {
                    if (q->has_function_str)
            q->sess.print_warning (_("For probing a particular line, use a "
                                   ".statement() probe, not .function()"),
                                   q->base_probe->tok);
          base_func_info_map_t bfis = q->filtered_all();
          set<string>::const_iterator srcfile;
          for (srcfile  = q->filtered_srcfiles.begin();
               srcfile != q->filtered_srcfiles.end(); ++srcfile)
            q->dw.iterate_over_srcfile_lines(srcfile->c_str(), q->linenos,
                                             q->lineno_type, bfis,
                                             query_srcfile_line,
                                             q->has_nearest, q);
        }
      else
        {
                    for (func_info_map_t::iterator i = q->filtered_functions.begin();
               i != q->filtered_functions.end(); ++i)
            query_func_info (i->entrypc, *i, q);
                    if (! q->has_call)
            for (inline_instance_map_t::iterator i
                   = q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i)
              query_inline_instance_info (*i, q);
        }
      return DWARF_CB_OK;
    }
  catch (const semantic_error& e)
    {
      q->sess.print_error (e);
      return DWARF_CB_ABORT;
    }
}
void
dwarf_query::query_module_functions ()
{
  try
    {
      filtered_srcfiles.clear();
      filtered_functions.clear();
      filtered_inlines.clear();
            int rc = dw.iterate_single_function(query_dwarf_func, this, function);
      if (rc != DWARF_CB_OK)
        {
          query_done = true;
          return;
        }
      set<void*> used_cus;       vector<Dwarf_Die> cus;
      Dwarf_Die cu_mem;
      base_func_info_map_t bfis = filtered_all();
      base_func_info_map_t::iterator i;
      for (i = bfis.begin(); i != bfis.end(); ++i)
        if (dwarf_diecu(&i->die, &cu_mem, NULL, NULL) &&
            used_cus.insert(cu_mem.addr).second)
          cus.push_back(cu_mem);
            alias_dupes.clear();
      inline_dupes.clear();
            for (vector<Dwarf_Die>::iterator i = cus.begin(); i != cus.end(); ++i){
        rc = query_cu(&*i, this);
    if (rc != DWARF_CB_OK)
      {
        query_done = true;
        return;
      }
      }
    }
  catch (const semantic_error& e)
    {
      sess.print_error (e);
    }
}
static void
validate_module_elf (Dwfl_Module *mod, const char *name,  base_query *q)
{
          
  Dwarf_Addr bias;
        Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias))
          ?: dwfl_module_getelf (mod, &bias));
  GElf_Ehdr ehdr_mem;
  GElf_Ehdr* em = gelf_getehdr (elf, &ehdr_mem);
  if (em == 0) { DWFL_ASSERT ("dwfl_getehdr", dwfl_errno()); }
  assert(em);
  int elf_machine = em->e_machine;
  const char* debug_filename = "";
  const char* main_filename = "";
  (void) dwfl_module_info (mod, NULL, NULL,
                               NULL, NULL, NULL,
                               & main_filename,
                               & debug_filename);
  const string& sess_machine = q->sess.architecture;
  string expect_machine;   string expect_machine2;
    switch (elf_machine)
    {
                case EM_386:
      expect_machine = "i?86";
      if (! q->has_process) break;           case EM_X86_64:
      expect_machine2 = "x86_64";
      break;
    case EM_PPC:
    case EM_PPC64:
      expect_machine = "powerpc";
      break;
    case EM_S390: expect_machine = "s390"; break;
    case EM_IA_64: expect_machine = "ia64"; break;
    case EM_ARM: expect_machine = "arm*"; break;
    case EM_AARCH64: expect_machine = "arm64"; break;
      XXX    default: expect_machine = "?"; break;
    }
  if (! debug_filename) debug_filename = main_filename;
  if (! debug_filename) debug_filename = name;
  if (fnmatch (expect_machine.c_str(), sess_machine.c_str(), 0) != 0 &&
      fnmatch (expect_machine2.c_str(), sess_machine.c_str(), 0) != 0)
    {
      stringstream msg;
      msg << _F("ELF machine %s|%s (code %d) mismatch with target %s in '%s'",
                expect_machine.c_str(), expect_machine2.c_str(), elf_machine,
                sess_machine.c_str(), debug_filename);
      throw SEMANTIC_ERROR(msg.str ());
    }
  if (q->sess.verbose>1)
    clog << _F("focused on module '%s' = [%#" PRIx64 "-%#" PRIx64 ", bias %#" PRIx64
               " file %s ELF machine %s|%s (code %d)\n",
               q->dw.module_name.c_str(), q->dw.module_start, q->dw.module_end,
               q->dw.module_bias, debug_filename, expect_machine.c_str(),
               expect_machine2.c_str(), elf_machine);
}
static Dwarf_Addr
lookup_symbol_address (Dwfl_Module *m, const char* wanted)
{
  int syments = dwfl_module_getsymtab(m);
  assert(syments);
  for (int i = 1; i < syments; ++i)
    {
      GElf_Sym sym;
      const char *name = dwfl_module_getsym(m, i, &sym, NULL);
      if (name != NULL && strcmp(name, wanted) == 0)
        return sym.st_value;
    }
  return 0;
}
static int
query_module (Dwfl_Module *mod,
              void **,
          const char *name,
              Dwarf_Addr addr,
          base_query *q)
{
  try
    {
      module_info* mi = q->sess.module_cache->cache[name];
      if (mi == 0)
        {
          mi = q->sess.module_cache->cache[name] = new module_info(name);
          mi->mod = mod;
          mi->addr = addr;
          const char* debug_filename = "";
          const char* main_filename = "";
          (void) dwfl_module_info (mod, NULL, NULL,
                                   NULL, NULL, NULL,
                                   & main_filename,
                                   & debug_filename);
          if (debug_filename || main_filename)
            {
              mi->elf_path = debug_filename ?: main_filename;
            }
          else if (name == TOK_KERNEL)
            {
              mi->dwarf_status = info_absent;
            }
        }
      
      q->dw.focus_on_module(mod, mi);
                  if (!q->dw.module_name_matches(q->module_val))
        return pending_interrupts ? DWARF_CB_ABORT : DWARF_CB_OK;
                        if (q->dw.module_name == TOK_KERNEL && ! q->has_kernel)
        return pending_interrupts ? DWARF_CB_ABORT : DWARF_CB_OK;
      if (mod)
        validate_module_elf(mod, name, q);
      else
        assert(q->has_kernel);   
      if (q->sess.verbose>2)
        cerr << _F("focused on module '%s'\n", q->dw.module_name.c_str());
      XXX            if (q->dw.module_name == TOK_KERNEL)
        {
          if (! q->sess.sym_kprobes_text_start)
            q->sess.sym_kprobes_text_start = lookup_symbol_address (mod, "__kprobes_text_start");
          if (! q->sess.sym_kprobes_text_end)
            q->sess.sym_kprobes_text_end = lookup_symbol_address (mod, "__kprobes_text_end");
          if (! q->sess.sym_stext)
            q->sess.sym_stext = lookup_symbol_address (mod, "_stext");
        }
                        if (q->has_library && q->path.empty())
        q->dw.iterate_over_libraries (&q->query_library_callback, q);
                  else if (q->has_plt && ! q->has_statement)
        {
          q->dw.iterate_over_plt (q, &q->query_plt_callback);
          q->visited_modules.insert(name);
        }
      else
        {
                    q->handle_query_module();
          q->visited_modules.insert(name);
        }
            if (q->dw.module_name_final_match(q->module_val) || pending_interrupts)
        return DWARF_CB_ABORT;
      else
        return DWARF_CB_OK;
    }
  catch (const semantic_error& e)
    {
      q->sess.print_error (e);
      return DWARF_CB_ABORT;
    }
}
void
base_query::query_library_callback (base_query *me, const char *data)
{
  me->query_library (data);
}
probe*
build_library_probe(dwflpp& dw,
                    const string& library,
                    probe *base_probe,
                    probe_point *base_loc)
{
  probe_point* specific_loc = new probe_point(*base_loc);
  specific_loc->from_glob = true;
  vector<probe_point::component*> derived_comps;
        vector<probe_point::component*>::iterator it;
  for (it = specific_loc->components.begin();
      it != specific_loc->components.end(); ++it)
    if ((*it)->functor == TOK_PROCESS)
      derived_comps.push_back(new probe_point::component(TOK_PROCESS,
          new literal_string(path_remove_sysroot(dw.sess, dw.module_name))));
    else if ((*it)->functor == TOK_LIBRARY)
      derived_comps.push_back(new probe_point::component(TOK_LIBRARY,
          new literal_string(path_remove_sysroot(dw.sess, library))));
    else
      derived_comps.push_back(*it);
  probe_point* derived_loc = new probe_point(*specific_loc);
  derived_loc->components = derived_comps;
  return new probe (new probe (base_probe, specific_loc), derived_loc);
}
bool
query_one_library (const char *library, dwflpp & dw,
    const string user_lib, probe * base_probe, probe_point *base_loc,
    vector<derived_probe *> & results)
{
  if (dw.function_name_matches_pattern(library, "*" + user_lib))
    {
      string library_path = find_executable (library, "", dw.sess.sysenv,
                                             "LD_LIBRARY_PATH");
      probe *new_base = build_library_probe(dw, library_path,
                                            base_probe, base_loc);
                                    derive_probes(dw.sess, new_base, results, true  );
      if (dw.sess.verbose > 2)
        clog << _("module=") << library_path << endl;
      return true;
    }
  return false;
}
void
dwarf_query::query_library (const char *library)
{
  visited_libraries.insert(library);
  if (query_one_library (library, dw, user_lib, base_probe, base_loc, results))
    resolved_library = true;
}
struct plt_expanding_visitor: public var_expanding_visitor
{
  plt_expanding_visitor(const string & entry):
    entry (entry)
  {
  }
  const string & entry;
  void visit_target_symbol (target_symbol* e);
};
void
base_query::query_plt_callback (base_query *me, const char *entry, size_t address)
{
  if (me->dw.function_name_matches_pattern (entry, me->plt_val))
    me->query_plt (entry, address);
  me->dw.mod_info->plt_funcs.insert(entry);
}
void
query_one_plt (const char *entry, long addr, dwflpp & dw,
    probe * base_probe, probe_point *base_loc,
    vector<derived_probe *> & results, base_query *q)
{
      string module = dw.module_name;
      if (q->has_process)
        module = path_remove_sysroot(dw.sess, module);
      probe_point* specific_loc = new probe_point(*base_loc);
      specific_loc->well_formed = true;
      vector<probe_point::component*> derived_comps;
      if (dw.sess.verbose > 2)
        clog << _F("plt entry=%s\n", entry);
      vector<probe_point::component*>::iterator it;
      for (it = specific_loc->components.begin();
          it != specific_loc->components.end(); ++it)
        if ((*it)->functor == TOK_PROCESS)
          {
                        *it = new probe_point::component(TOK_PROCESS,
                    new literal_string(q->has_library ? q->path : module));
            derived_comps.push_back(*it);
          }
        else if ((*it)->functor == TOK_PLT)
          {
                        *it = new probe_point::component(TOK_PLT,
                                             new literal_string(entry));
            derived_comps.push_back(*it);
            derived_comps.push_back(new probe_point::component(TOK_STATEMENT,
                                                               new literal_number(addr, true)));
          }
        else
          derived_comps.push_back(*it);
      probe_point* derived_loc = new probe_point(*specific_loc);
      derived_loc->components = derived_comps;
      probe *new_base = new probe (new probe (base_probe, specific_loc),
                                   derived_loc);
      string e = string(entry);
      plt_expanding_visitor pltv (e);
      pltv.replace (new_base->body);
      literal_map_t params;
      for (unsigned i = 0; i < derived_loc->components.size(); ++i)
       {
          probe_point::component *c = derived_loc->components[i];
          params[c->functor] = c->arg;
       }
      dwarf_query derived_q(new_base, derived_loc, dw, params, results, "", "");
      dw.iterate_over_modules<base_query>(&query_module, &derived_q);
}
void
dwarf_query::query_plt (const char *entry, size_t address)
{
  query_one_plt (entry, address, dw, base_probe, base_loc, results, this);
}
static void
delete_session_module_cache (systemtap_session& s)
{
  if (s.module_cache) {
    if (s.verbose > 3)
      clog << _("deleting module_cache") << endl;
    delete s.module_cache;
    s.module_cache = 0;
  }
}
struct dwarf_var_expanding_visitor: public var_expanding_visitor
{
  dwarf_query & q;
  Dwarf_Die *scope_die;
  Dwarf_Addr addr;
  block *add_block;
  block *add_call_probe;         bool add_block_tid, add_call_probe_tid;
  unsigned saved_longs, saved_strings;   map<std::string, expression *> return_ts_map;
  vector<Dwarf_Die> scopes;
    std::set<std::string> perf_counter_refs;
  bool visited;
  dwarf_var_expanding_visitor(dwarf_query & q, Dwarf_Die *sd, Dwarf_Addr a):
    q(q), scope_die(sd), addr(a), add_block(NULL), add_call_probe(NULL),
    add_block_tid(false), add_call_probe_tid(false),
    saved_longs(0), saved_strings(0), visited(false) {}
  expression* gen_mapped_saved_return(expression* e, const string& name);
  expression* gen_kretprobe_saved_return(expression* e);
  void visit_target_symbol_saved_return (target_symbol* e);
  void visit_target_symbol_context (target_symbol* e);
  void visit_target_symbol (target_symbol* e);
  void visit_atvar_op (atvar_op* e);
  void visit_cast_op (cast_op* e);
  void visit_entry_op (entry_op* e);
  void visit_perf_op (perf_op* e);
private:
  vector<Dwarf_Die>& getscopes(target_symbol *e);
};
unsigned var_expanding_visitor::tick = 0;
var_expanding_visitor::var_expanding_visitor (): op()
{
  FIXME            valid_ops.insert ("=");
}
void
var_expanding_visitor::provide_lvalue_call(functioncall* fcall)
{
      assert(!target_symbol_setter_functioncalls.empty());
  *(target_symbol_setter_functioncalls.top()) = fcall;
}
bool
var_expanding_visitor::rewrite_lvalue(const token* tok, const std::string& eop,
                                      expression*& lvalue, expression*& rvalue)
{
                      
  functioncall *fcall = NULL;
    const string* old_op = op;
  op = &eop;
  target_symbol_setter_functioncalls.push (&fcall);
  replace (lvalue);
  target_symbol_setter_functioncalls.pop ();
  replace (rvalue);
  op = old_op;
  if (fcall != NULL)
    {
                              
      if (valid_ops.find (eop) == valid_ops.end ())
        {
            string ops;
      std::set<string>::iterator i;
          int valid_ops_size = 0;
      for (i = valid_ops.begin(); i != valid_ops.end(); i++)
          {
        ops += " " + *i + ",";
            valid_ops_size++;
          }
      ops.resize(ops.size() - 1);    
            throw SEMANTIC_ERROR (_NF("Only the following assign operator is implemented on target variables: %s",
                                            "Only the following assign operators are implemented on target variables: %s",
                                           valid_ops_size, ops.c_str()), tok);
    }
      assert (lvalue == fcall);
      if (rvalue)
        fcall->args.push_back (rvalue);
      provide (fcall);
      return true;
    }
  else
    return false;
}
void
var_expanding_visitor::visit_assignment (assignment* e)
{
  if (!rewrite_lvalue (e->tok, e->op, e->left, e->right))
    provide (e);
}
void
var_expanding_visitor::visit_pre_crement (pre_crement* e)
{
  expression *dummy = NULL;
  if (!rewrite_lvalue (e->tok, e->op, e->operand, dummy))
    provide (e);
}
void
var_expanding_visitor::visit_post_crement (post_crement* e)
{
  expression *dummy = NULL;
  if (!rewrite_lvalue (e->tok, e->op, e->operand, dummy))
    provide (e);
}
void
var_expanding_visitor::visit_delete_statement (delete_statement* s)
{
  string fakeop = "delete";
  expression *dummy = NULL;
  if (!rewrite_lvalue (s->tok, fakeop, s->value, dummy))
    provide (s);
}
void
var_expanding_visitor::visit_defined_op (defined_op* e)
{
  bool resolved = true;
  defined_ops.push (e);
  try {
    replace (e->operand);
                                                
                                                
    target_symbol* tsym = dynamic_cast<target_symbol*> (e->operand);
    if (tsym && tsym->saved_conversion_error)       resolved = false;
    else if (tsym)       {
                                provide (e);
        return;
      }
    else       resolved = true;
  } catch (const semantic_error& e) {
    assert (0);   }
  defined_ops.pop ();
  literal_number* ln = new literal_number (resolved ? 1 : 0);
  ln->tok = e->tok;
  provide (ln);
}
struct dwarf_pretty_print
{
  dwarf_pretty_print (dwflpp& dw, vector<Dwarf_Die>& scopes, Dwarf_Addr pc,
                      const string& local, bool userspace_p,
                      const target_symbol& e):
    dw(dw), local(local), scopes(scopes), pc(pc), pointer(NULL),
    userspace_p(userspace_p), deref_p(true)
  {
    init_ts (e);
    dw.type_die_for_local (scopes, pc, local, ts, &base_type);
  }
  dwarf_pretty_print (dwflpp& dw, Dwarf_Die *scope_die, Dwarf_Addr pc,
                      bool userspace_p, const target_symbol& e):
    dw(dw), scopes(1, *scope_die), pc(pc), pointer(NULL),
    userspace_p(userspace_p), deref_p(true)
  {
    init_ts (e);
    dw.type_die_for_return (&scopes[0], pc, ts, &base_type);
  }
  dwarf_pretty_print (dwflpp& dw, Dwarf_Die *type_die, expression* pointer,
                      bool deref_p, bool userspace_p, const target_symbol& e):
    dw(dw), pc(0), pointer(pointer), pointer_type(*type_die),
    userspace_p(userspace_p), deref_p(deref_p)
  {
    init_ts (e);
    dw.type_die_for_pointer (type_die, ts, &base_type);
  }
  functioncall* expand ();
  ~dwarf_pretty_print () { delete ts; }
private:
  dwflpp& dw;
  target_symbol* ts;
  bool print_full;
  Dwarf_Die base_type;
  string local;
  vector<Dwarf_Die> scopes;
  Dwarf_Addr pc;
  expression* pointer;
  Dwarf_Die pointer_type;
  const bool userspace_p, deref_p;
  void recurse (Dwarf_Die* type, target_symbol* e,
                print_format* pf, bool top=false);
  void recurse_bitfield (Dwarf_Die* type, target_symbol* e,
                         print_format* pf);
  void recurse_base (Dwarf_Die* type, target_symbol* e,
                     print_format* pf);
  void recurse_array (Dwarf_Die* type, target_symbol* e,
                      print_format* pf, bool top);
  void recurse_pointer (Dwarf_Die* type, target_symbol* e,
                        print_format* pf, bool top);
  void recurse_struct (Dwarf_Die* type, target_symbol* e,
                       print_format* pf, bool top);
  void recurse_struct_members (Dwarf_Die* type, target_symbol* e,
                               print_format* pf, int& count);
  bool print_chars (Dwarf_Die* type, target_symbol* e, print_format* pf);
  void init_ts (const target_symbol& e);
  expression* deref (target_symbol* e);
  bool push_deref (print_format* pf, const string& fmt, target_symbol* e);
};
void
dwarf_pretty_print::init_ts (const target_symbol& e)
{
    ts = new target_symbol (e);
  if (ts->addressof)
    throw SEMANTIC_ERROR(_("cannot take address of pretty-printed variable"), ts->tok);
  size_t depth = ts->pretty_print_depth ();
  if (depth == 0)
    throw SEMANTIC_ERROR(_("invalid target_symbol for pretty-print"), ts->tok);
  print_full = depth > 1;
  ts->components.pop_back();
}
functioncall*
dwarf_pretty_print::expand ()
{
  static unsigned tick = 0;
              
  
  functiondecl *fdecl = new functiondecl;
  fdecl->tok = ts->tok;
  fdecl->synthetic = true;
  fdecl->name = "_dwarf_pretty_print_" + lex_cast(tick++);
  fdecl->type = pe_string;
  functioncall* fcall = new functioncall;
  fcall->referent = fdecl;
  fcall->tok = ts->tok;
  fcall->function = fdecl->name;
  fcall->type = pe_string;
      if (pointer)
    {
      vardecl *v = new vardecl;
      v->type = pe_long;
      v->name = "pointer";
      v->tok = ts->tok;
      fdecl->formal_args.push_back (v);
      fcall->args.push_back (pointer);
      symbol* sym = new symbol;
      sym->tok = ts->tok;
      sym->name = v->name;
      pointer = sym;
    }
    for (unsigned i = 0; i < ts->components.size(); ++i)
    if (ts->components[i].type == target_symbol::comp_expression_array_index)
      {
        vardecl *v = new vardecl;
        v->type = pe_long;
        v->name = "index" + lex_cast(i);
        v->tok = ts->tok;
        fdecl->formal_args.push_back (v);
        fcall->args.push_back (ts->components[i].expr_index);
        symbol* sym = new symbol;
        sym->tok = ts->tok;
        sym->name = v->name;
        ts->components[i].expr_index = sym;
      }
    print_format* pf = print_format::create(ts->tok, "sprintf");
  return_statement* rs = new return_statement;
  rs->tok = ts->tok;
  rs->value = pf;
    recurse (&base_type, ts, pf, true);
  pf->components = print_format::string_to_components(pf->raw_components);
    try_block* tb = new try_block;
  tb->tok = ts->tok;
  tb->try_block = rs;
  tb->catch_error_var = 0;
  return_statement* rs2 = new return_statement;
  rs2->tok = ts->tok;
  rs2->value = new literal_string ("ERROR");
  rs2->value->tok = ts->tok;
  tb->catch_block = rs2;
  fdecl->body = tb;
  fdecl->join (dw.sess);
  return fcall;
}
void
dwarf_pretty_print::recurse (Dwarf_Die* start_type, target_symbol* e,
                             print_format* pf, bool top)
{
    if (!deref_p && null_die(start_type))
    {
      push_deref (pf, "%p", e);
      return;
    }
  Dwarf_Die type;
  dw.resolve_unqualified_inner_typedie (start_type, &type, e);
  switch (dwarf_tag(&type))
    {
    default:
      XXX                  pf->raw_components.append("?");
      break;
    case DW_TAG_enumeration_type:
    case DW_TAG_base_type:
      recurse_base (&type, e, pf);
      break;
    case DW_TAG_array_type:
      recurse_array (&type, e, pf, top);
      break;
    case DW_TAG_pointer_type:
    case DW_TAG_reference_type:
    case DW_TAG_rvalue_reference_type:
      recurse_pointer (&type, e, pf, top);
      break;
    case DW_TAG_subroutine_type:
      push_deref (pf, "<function>:%p", e);
      break;
    case DW_TAG_union_type:
    case DW_TAG_structure_type:
    case DW_TAG_class_type:
      recurse_struct (&type, e, pf, top);
      break;
    }
}
void
dwarf_pretty_print::recurse_bitfield (Dwarf_Die* start_type, target_symbol* e,
                                      print_format* pf)
{
  Dwarf_Die type;
  dw.resolve_unqualified_inner_typedie (start_type, &type, e);
  int tag = dwarf_tag(&type);
  if (tag != DW_TAG_base_type && tag != DW_TAG_enumeration_type)
    {
      XXX                  pf->raw_components.append("?");
      return;
    }
  Dwarf_Attribute attr;
  Dwarf_Word encoding = (Dwarf_Word) -1;
  dwarf_formudata (dwarf_attr_integrate (&type, DW_AT_encoding, &attr),
                   &encoding);
  switch (encoding)
    {
    case DW_ATE_float:
    case DW_ATE_complex_float:
      XXX                  pf->raw_components.append("?");
      break;
    case DW_ATE_unsigned:
    case DW_ATE_unsigned_char:
      push_deref (pf, "%u", e);
      break;
    case DW_ATE_signed:
    case DW_ATE_signed_char:
    default:
      push_deref (pf, "%i", e);
      break;
    }
}
void
dwarf_pretty_print::recurse_base (Dwarf_Die* type, target_symbol* e,
                                  print_format* pf)
{
  Dwarf_Attribute attr;
  Dwarf_Word encoding = (Dwarf_Word) -1;
  dwarf_formudata (dwarf_attr_integrate (type, DW_AT_encoding, &attr),
                   &encoding);
  switch (encoding)
    {
    case DW_ATE_float:
    case DW_ATE_complex_float:
      XXX                  pf->raw_components.append("?");
      break;
    case DW_ATE_UTF: XXX    case DW_ATE_signed_char:
    case DW_ATE_unsigned_char:
                  push_deref (pf, "'%#c'", e);
      break;
    case DW_ATE_unsigned:
      push_deref (pf, "%u", e);
      break;
    case DW_ATE_signed:
    default:
      push_deref (pf, "%i", e);
      break;
    }
}
void
dwarf_pretty_print::recurse_array (Dwarf_Die* type, target_symbol* e,
                                   print_format* pf, bool top)
{
  if (!top && !print_full)
    {
      pf->raw_components.append("[...]");
      return;
    }
  Dwarf_Die childtype;
  dwarf_attr_die (type, DW_AT_type, &childtype);
  if (print_chars (&childtype, e, pf))
    return;
  pf->raw_components.append("[");
    XXX      unsigned i, size = 1;
  for (i=0; i < size && i < 5 && pf->args.size() < 32; ++i)
    {
      if (i > 0)
        pf->raw_components.append(", ");
      target_symbol* e2 = new target_symbol(*e);
      e2->components.push_back (target_symbol::component(e->tok, i));
      recurse (&childtype, e2, pf);
    }
  if (i < size || 1XXX)
    pf->raw_components.append(", ...");
  pf->raw_components.append("]");
}
void
dwarf_pretty_print::recurse_pointer (Dwarf_Die* type, target_symbol* e,
                                     print_format* pf, bool top)
{
    bool void_p = true;
  Dwarf_Die pointee;
  if (dwarf_attr_die (type, DW_AT_type, &pointee))
    {
      try
        {
          dw.resolve_unqualified_inner_typedie (&pointee, &pointee, e);
          void_p = false;
        }
      catch (const semantic_error&) {}
    }
  if (!void_p)
    {
      if (print_chars (&pointee, e, pf))
        return;
      if (top)
        {
          recurse (&pointee, e, pf, top);
          return;
        }
    }
  push_deref (pf, "%p", e);
}
void
dwarf_pretty_print::recurse_struct (Dwarf_Die* type, target_symbol* e,
                                    print_format* pf, bool top)
{
  if (dwarf_hasattr(type, DW_AT_declaration))
    {
      Dwarf_Die *resolved = dw.declaration_resolve(type);
      if (!resolved)
        {
                              pf->raw_components.append("{...}");
          return;
        }
      type = resolved;
    }
  int count = 0;
  pf->raw_components.append("{");
  if (top || print_full)
    recurse_struct_members (type, e, pf, count);
  else
    pf->raw_components.append("...");
  pf->raw_components.append("}");
}
void
dwarf_pretty_print::recurse_struct_members (Dwarf_Die* type, target_symbol* e,
                                            print_format* pf, int& count)
{
    set<string> dupes;
  deque<Dwarf_Die> inheritees(1, *type);
  for (; !inheritees.empty(); inheritees.pop_front())
    {
      Dwarf_Die child, childtype, import;
      if (dwarf_child (&inheritees.front(), &child) == 0)
        do
          {
            target_symbol* e2 = e;
                        if (dwarf_hasattr(&child, DW_AT_declaration))
              continue;
            int tag = dwarf_tag (&child);
                        if (tag == DW_TAG_imported_unit
                && dwarf_attr_die (&child, DW_AT_import, &import))
              recurse_struct_members (&import, e2, pf, count);
            if (tag != DW_TAG_member && tag != DW_TAG_inheritance)
              continue;
            dwarf_attr_die (&child, DW_AT_type, &childtype);
            if (tag == DW_TAG_inheritance)
              {
                inheritees.push_back(childtype);
                continue;
              }
            int childtag = dwarf_tag (&childtype);
            const char *member = dwarf_diename (&child);
                                    if (member && startswith(member, "_vptr."))
              continue;
                        if (member && !dupes.insert(member).second)
              continue;
            if (++count > 1)
              pf->raw_components.append(", ");
                        if (pf->args.size() >= 32)
              {
                pf->raw_components.append("...");
                break;
              }
            if (member)
              {
                pf->raw_components.append(".");
                pf->raw_components.append(member);
                e2 = new target_symbol(*e);
                e2->components.push_back (target_symbol::component(e->tok, member));
              }
            else if (childtag == DW_TAG_union_type)
              pf->raw_components.append("<union>");
            else if (childtag == DW_TAG_structure_type)
              pf->raw_components.append("<class>");
            else if (childtag == DW_TAG_class_type)
              pf->raw_components.append("<struct>");
            pf->raw_components.append("=");
            if (dwarf_hasattr_integrate (&child, DW_AT_bit_offset))
              recurse_bitfield (&childtype, e2, pf);
            else
              recurse (&childtype, e2, pf);
          }
        while (dwarf_siblingof (&child, &child) == 0);
    }
}
bool
dwarf_pretty_print::print_chars (Dwarf_Die* start_type, target_symbol* e,
                                 print_format* pf)
{
  Dwarf_Die type;
  dw.resolve_unqualified_inner_typedie (start_type, &type, e);
  Dwarf_Attribute attr;
  Dwarf_Word encoding = (Dwarf_Word) -1;
  dwarf_formudata (dwarf_attr_integrate (&type, DW_AT_encoding, &attr),
                   &encoding);
  switch (encoding)
    {
    case DW_ATE_UTF:
    case DW_ATE_signed_char:
    case DW_ATE_unsigned_char:
      break;
    default:
      return false;
    }
  string function = userspace_p ? "user_string2" : "kernel_string2";
  Dwarf_Word size = (Dwarf_Word) -1;
  dwarf_formudata (dwarf_attr_integrate (&type, DW_AT_byte_size, &attr), &size);
  switch (size)
    {
    case 1:
      break;
    case 2:
      function += "_utf16";
      break;
    case 4:
      function += "_utf32";
      break;
    default:
      return false;
    }
  if (push_deref (pf, "\"%s\"", e))
    {
            assert (!pf->args.empty());
      functioncall* fcall = new functioncall;
      fcall->tok = e->tok;
      fcall->function = function;
      fcall->args.push_back (pf->args.back());
      expression *err_msg = new literal_string ("<unknown>");
      err_msg->tok = e->tok;
      fcall->args.push_back (err_msg);
      pf->args.back() = fcall;
    }
  return true;
}
static const string EMBEDDED_FETCH_DEREF_KERNEL = string("\n")
  + "#define fetch_register k_fetch_register\n"
  + "#define store_register k_store_register\n"
  + "#define deref kderef\n"
  + "#define store_deref store_kderef\n";
static const string EMBEDDED_FETCH_DEREF_USER = string("\n")
  + "#define fetch_register u_fetch_register\n"
  + "#define store_register u_store_register\n"
  + "#define deref uderef\n"
  + "#define store_deref store_uderef\n";
#define EMBEDDED_FETCH_DEREF(U) \
  (U ? EMBEDDED_FETCH_DEREF_USER : EMBEDDED_FETCH_DEREF_KERNEL)
static const string EMBEDDED_FETCH_DEREF_DONE = string("\n")
  + "#undef fetch_register\n"
  + "#undef store_register\n"
  + "#undef deref\n"
  + "#undef store_deref\n";
static functioncall*
synthetic_embedded_deref_call(dwflpp& dw,
                              Dwarf_Die* function_type,
                              const string& function_name,
                              const string& function_code,
                              bool userspace_p,
                              bool lvalue_p,
                              target_symbol* e,
                              expression* pointer=NULL)
{
    functiondecl *fdecl = new functiondecl;
  fdecl->synthetic = true;
  fdecl->tok = e->tok;
  fdecl->name = function_name;
    fdecl->type = pe_long;
  fdecl->type_details.reset(new exp_type_dwarf(&dw, function_type,
                                               userspace_p, e->addressof));
  embeddedcode *ec = new embeddedcode;
  ec->tok = e->tok;
  ec->code += "/* unprivileged */";
  if (! lvalue_p)
    ec->code += "/* pure */";
  ec->code += EMBEDDED_FETCH_DEREF(userspace_p);
  ec->code += function_code;
  ec->code += EMBEDDED_FETCH_DEREF_DONE;
  fdecl->body = ec;
    functioncall* fcall = new functioncall;
  fcall->tok = e->tok;
  fcall->referent = fdecl;
  fcall->function = fdecl->name;
  fcall->type = fdecl->type;
  fcall->type_details = fdecl->type_details;
      if (pointer)
    {
      vardecl *v = new vardecl;
      v->type = pe_long;
      v->name = "pointer";
      v->tok = e->tok;
      fdecl->formal_args.push_back(v);
      fcall->args.push_back(pointer);
    }
    for (unsigned i = 0; i < e->components.size(); ++i)
    if (e->components[i].type == target_symbol::comp_expression_array_index)
      {
        vardecl *v = new vardecl;
        v->type = pe_long;
        v->name = "index" + lex_cast(i);
        v->tok = e->tok;
        fdecl->formal_args.push_back(v);
        fcall->args.push_back(e->components[i].expr_index);
      }
      if (lvalue_p)
    {
            
      FIXME                  
      vardecl *v = new vardecl;
      v->type = pe_long;
      v->name = "value";
      v->tok = e->tok;
      fdecl->formal_args.push_back(v);
                }
    fdecl->join (dw.sess);
  return fcall;
}
expression*
dwarf_pretty_print::deref (target_symbol* e)
{
  static unsigned tick = 0;
  if (!deref_p)
    {
      assert (pointer && e->components.empty());
      return pointer;
    }
  bool lvalue_p = false;
  string name = "_dwarf_pretty_print_deref_" + lex_cast(tick++);
  string code;
  Dwarf_Die endtype;
  if (pointer)
    code = dw.literal_stmt_for_pointer (&pointer_type, e, false, &endtype);
  else if (!local.empty())
    code = dw.literal_stmt_for_local (scopes, pc, local, e, false, &endtype);
  else
    code = dw.literal_stmt_for_return (&scopes[0], pc, e, false, &endtype);
  return synthetic_embedded_deref_call(dw, &endtype, name, code,
                                       userspace_p, lvalue_p, e, pointer);
}
bool
dwarf_pretty_print::push_deref (print_format* pf, const string& fmt,
                                target_symbol* e)
{
  expression* e2 = NULL;
  try
    {
      e2 = deref (e);
    }
  catch (const semantic_error&)
    {
      pf->raw_components.append ("?");
      return false;
    }
  pf->raw_components.append (fmt);
  pf->args.push_back (e2);
  return true;
}
void
dwarf_var_expanding_visitor::visit_target_symbol_saved_return (target_symbol* e)
{
    stringstream ts_name_stream;
  e->print(ts_name_stream);
  string ts_name = ts_name_stream.str();
        map<string, expression *>::iterator i = return_ts_map.find(ts_name);
  if (i != return_ts_map.end())
    {
      provide (i->second);
      return;
    }
        bool saved_has_return = q.has_return;
  q.has_return = false;
  expression *repl = e;
  replace (repl);
  q.has_return = saved_has_return;
  target_symbol* n = dynamic_cast<target_symbol*>(repl);
  if (n && n->saved_conversion_error)
    {
      provide (repl);
      return;
    }
  expression *exp;
  if (!q.has_process &&
      strverscmp(q.sess.kernel_base_release.c_str(), "2.6.25") >= 0)
    exp = gen_kretprobe_saved_return(repl);
  else
    exp = gen_mapped_saved_return(repl, e->sym_name());
    if (repl->type_details && !exp->type_details)
    exp->type_details = repl->type_details;
      provide (exp);
        return_ts_map[ts_name] = exp;
}
static expression*
gen_mapped_saved_return(systemtap_session &sess, expression* e,
            const string& name,
            block *& add_block, bool& add_block_tid,
            block *& add_call_probe, bool& add_call_probe_tid)
{
  static unsigned tick = 0;
    
              
  string aname = (string("_entry_tvar_")
                  + name
                  + "_" + lex_cast(tick++));
  vardecl* vd = new vardecl;
  vd->name = aname;
  vd->tok = e->tok;
  sess.globals.push_back (vd);
  string ctrname = aname + "_ctr";
  vd = new vardecl;
  vd->name = ctrname;
  vd->tok = e->tok;
  sess.globals.push_back (vd);
                            
          symbol* tidsym = new symbol;
  tidsym->name = string("_entry_tvar_tid");
  tidsym->tok = e->tok;
  if (add_block == NULL)
    {
      add_block = new block;
      add_block->tok = e->tok;
    }
  if (!add_block_tid)
    {
            functioncall* fc = new functioncall;
      fc->tok = e->tok;
      fc->function = string("tid");
            assignment* a = new assignment;
      a->tok = e->tok;
      a->op = "=";
      a->left = tidsym;
      a->right = fc;
      expr_statement* es = new expr_statement;
      es->tok = e->tok;
      es->value = a;
      add_block->statements.push_back (es);
      add_block_tid = true;
    }
              
  arrayindex* ai_tvar_base = new arrayindex;
  ai_tvar_base->tok = e->tok;
  symbol* sym = new symbol;
  sym->name = aname;
  sym->tok = e->tok;
  ai_tvar_base->base = sym;
  ai_tvar_base->indexes.push_back(tidsym);
        arrayindex* ai_tvar = new arrayindex;
  arrayindex* ai_tvar_postdec = new arrayindex;
  *ai_tvar = *ai_tvar_base;
  *ai_tvar_postdec = *ai_tvar_base;
        arrayindex* ai_ctr = new arrayindex;
  ai_ctr->tok = e->tok;
  sym = new symbol;
  sym->name = ctrname;
  sym->tok = e->tok;
  ai_ctr->base = sym;
  ai_ctr->indexes.push_back(tidsym);
  ai_tvar->indexes.push_back(ai_ctr);
  symbol* tmpsym = new symbol;
  tmpsym->name = aname + "_tmp";
  tmpsym->tok = e->tok;
  assignment* a = new assignment;
  a->tok = e->tok;
  a->op = "=";
  a->left = tmpsym;
  a->right = ai_tvar;
  expr_statement* es = new expr_statement;
  es->tok = e->tok;
  es->value = a;
  add_block->statements.push_back (es);
          
  post_crement* pc = new post_crement;
  pc->tok = e->tok;
  pc->op = "--";
  pc->operand = ai_ctr;
  ai_tvar_postdec->indexes.push_back(pc);
  delete_statement* ds = new delete_statement;
  ds->tok = e->tok;
  ds->value = ai_tvar_postdec;
  add_block->statements.push_back (ds);
        
  ds = new delete_statement;
  ds->tok = e->tok;
  ds->value = ai_ctr;
  unary_expression *ue = new unary_expression;
  ue->tok = e->tok;
  ue->op = "!";
  ue->operand = ai_ctr;
  if_statement *ifs = new if_statement;
  ifs->tok = e->tok;
  ifs->condition = ue;
  ifs->thenblock = ds;
  ifs->elseblock = NULL;
  add_block->statements.push_back (ifs);
                    
  if (add_call_probe == NULL)
    {
      add_call_probe = new block;
      add_call_probe->tok = e->tok;
    }
  if (!add_call_probe_tid)
    {
            functioncall* fc = new functioncall;
      fc->tok = e->tok;
      fc->function = string("tid");
            assignment* a = new assignment;
      a->tok = e->tok;
      a->op = "=";
      a->left = tidsym;
      a->right = fc;
      expr_statement* es = new expr_statement;
      es->tok = e->tok;
      es->value = a;
      add_call_probe = new block(add_call_probe, es);
      add_call_probe_tid = true;
    }
          arrayindex* ai_tvar_preinc = new arrayindex;
  *ai_tvar_preinc = *ai_tvar_base;
  pre_crement* preinc = new pre_crement;
  preinc->tok = e->tok;
  preinc->op = "++";
  preinc->operand = ai_ctr;
  ai_tvar_preinc->indexes.push_back(preinc);
  a = new assignment;
  a->tok = e->tok;
  a->op = "=";
  a->left = ai_tvar_preinc;
  a->right = e;
  es = new expr_statement;
  es->tok = e->tok;
  es->value = a;
  add_call_probe = new block(add_call_probe, es);
        delete ai_tvar_base;
  return tmpsym;
}
expression*
dwarf_var_expanding_visitor::gen_mapped_saved_return(expression* e,
                                                     const string& name)
{
    return ::gen_mapped_saved_return(q.sess, e, name, add_block,
                     add_block_tid, add_call_probe,
                     add_call_probe_tid);
}
expression*
dwarf_var_expanding_visitor::gen_kretprobe_saved_return(expression* e)
{
                  
  unsigned index;
  string setfn, getfn;
    switch (e->type)
    {
    case pe_string:
      index = saved_strings++;
      setfn = "_set_kretprobe_string";
      getfn = "_get_kretprobe_string";
      break;
    case pe_long:
      index = saved_longs++;
      setfn = "_set_kretprobe_long";
      getfn = "_get_kretprobe_long";
      break;
    default:
      throw SEMANTIC_ERROR(_("unknown type to save in kretprobe"), e->tok);
    }
    
  if (add_call_probe == NULL)
    {
      add_call_probe = new block;
      add_call_probe->tok = e->tok;
    }
  functioncall* set_fc = new functioncall;
  set_fc->tok = e->tok;
  set_fc->function = setfn;
  set_fc->args.push_back(new literal_number(index));
  set_fc->args.back()->tok = e->tok;
  set_fc->args.push_back(e);
  expr_statement* set_es = new expr_statement;
  set_es->tok = e->tok;
  set_es->value = set_fc;
  add_call_probe->statements.push_back(set_es);
    
  functioncall* get_fc = new functioncall;
  get_fc->tok = e->tok;
  get_fc->function = getfn;
  get_fc->args.push_back(new literal_number(index));
  get_fc->args.back()->tok = e->tok;
  return get_fc;
}
void
dwarf_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
{
  if (null_die(scope_die)) {
    literal_string *empty = new literal_string("");
    empty->tok = e->tok;
    provide(empty);
    return;
  }
  target_symbol *tsym = new target_symbol(*e);
  bool pretty = e->check_pretty_print ();
  string format = pretty ? "=%s" : "=%#x";
    
  print_format* pf = print_format::create(e->tok, "sprintf");
  if (q.has_return && (e->name == "$$return"))
    {
      tsym->name = "$return";
            tsym->saved_conversion_error = 0;
      expression *texp = tsym;
      replace (texp);       if (tsym->saved_conversion_error)         {
        }
      else
        {
          pf->raw_components += "return";
          pf->raw_components += format;
          pf->args.push_back(texp);
        }
    }
  else
    {
            bool first = true;
      Dwarf_Die result;
      vector<Dwarf_Die> scopes = q.dw.getscopes(scope_die);
      for (unsigned i = 0; i < scopes.size(); ++i)
        {
          if (dwarf_tag(&scopes[i]) == DW_TAG_compile_unit)
            break;           if (dwarf_child (&scopes[i], &result) == 0)
            do
              {
                switch (dwarf_tag (&result))
                  {
                  case DW_TAG_variable:
                    if (e->name == "$$parms")
                      continue;
                    break;
                  case DW_TAG_formal_parameter:
                    if (e->name == "$$locals")
                      continue;
                    break;
                  default:
                    continue;
                  }
                const char *diename = dwarf_diename (&result);
                if (! diename) continue;
                if (! first)
                  pf->raw_components += " ";
                pf->raw_components += diename;
                first = false;
                                Dwarf_Die type;
                if (!pretty && dwarf_attr_die(&result, DW_AT_type, &type))
                  {
                    q.dw.resolve_unqualified_inner_typedie(&type, &type, e);
                    switch (dwarf_tag(&type))
                      {
                      case DW_TAG_union_type:
                      case DW_TAG_structure_type:
                      case DW_TAG_class_type:
                        pf->raw_components += "={...}";
                        continue;
                      case DW_TAG_array_type:
                        pf->raw_components += "=[...]";
                        continue;
                      }
                  }
                tsym->name = "$";
                tsym->name += diename;
                                tsym->saved_conversion_error = 0;
                expression *texp = tsym;
                replace (texp);                 if (tsym->saved_conversion_error)                   {
                    if (q.sess.verbose>2)
                      {
                        for (const semantic_error *c = tsym->saved_conversion_error;
                             c != 0;
                             c = c->get_chain()) {
                            clog << _("variable location problem [man error::dwarf]: ") << c->what() << endl;
                        }
                      }
                    pf->raw_components += "=?";
                  }
                else
                  {
                    pf->raw_components += format;
                    pf->args.push_back(texp);
                  }
              }
            while (dwarf_siblingof (&result, &result) == 0);
        }
    }
  pf->components = print_format::string_to_components(pf->raw_components);
  pf->type = pe_string;
  provide (pf);
}
void
dwarf_var_expanding_visitor::visit_atvar_op (atvar_op *e)
{
    if (e->module.empty())
    e->module = q.dw.module_name;
  if (e->module == q.dw.module_name && e->cu_name.empty())
    {
                  visit_target_symbol(e);
      return;
    }
  var_expanding_visitor::visit_atvar_op(e);
}
void
dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
{
  assert(e->name.size() > 0 && (e->name[0] == '$' || e->name == "@var"));
  visited = true;
  bool defined_being_checked = (defined_ops.size() > 0 && (defined_ops.top()->operand == e));
  
  try
    {
      bool lvalue = is_active_lvalue(e);
      if (lvalue && !q.sess.guru_mode)
        throw SEMANTIC_ERROR(_("write to target variable not permitted; need stap -g"), e->tok);
      XXX
                  if (q.has_return
          && !defined_being_checked
          && e->name != "$return"           && e->name != "$$return")         {
          if (lvalue)
            throw SEMANTIC_ERROR(_("write to target variable not permitted in .return probes"), e->tok);
          visit_target_symbol_saved_return(e);
          return;
        }
      if (e->name == "$$vars" || e->name == "$$parms" || e->name == "$$locals"
          || (q.has_return && (e->name == "$$return")))
        {
          if (lvalue)
            throw SEMANTIC_ERROR(_("cannot write to context variable"), e->tok);
          if (e->addressof)
            throw SEMANTIC_ERROR(_("cannot take address of context variable"), e->tok);
          e->assert_no_components("dwarf", true);
          visit_target_symbol_context(e);
          return;
        }
                        if (null_die(scope_die))
        {
          provide(e);
          return;
        }
      if (e->check_pretty_print (lvalue))
        {
          if (q.has_return && (e->name == "$return"))
            {
              dwarf_pretty_print dpp (q.dw, scope_die, addr,
                                      q.has_process, *e);
              dpp.expand()->visit(this);
            }
          else
            {
              dwarf_pretty_print dpp (q.dw, getscopes(e), addr,
                                      e->sym_name(),
                                      q.has_process, *e);
              dpp.expand()->visit(this);
            }
          return;
        }
      bool userspace_p = q.has_process;
      string fname = (string(lvalue ? "_dwarf_tvar_set" : "_dwarf_tvar_get")
                      + "_" + e->sym_name()
                      + "_" + lex_cast(tick++));
      string code;
      Dwarf_Die endtype;
      if (q.has_return && (e->name == "$return"))
        code = q.dw.literal_stmt_for_return (scope_die, addr, e, lvalue, &endtype);
      else
        code = q.dw.literal_stmt_for_local (getscopes(e), addr, e->sym_name(),
                                            e, lvalue, &endtype);
      functioncall* n = synthetic_embedded_deref_call(q.dw, &endtype, fname, code,
                                                      userspace_p, lvalue, e);
      if (lvalue)
    provide_lvalue_call (n);
            n->visit (this);
    }
  catch (const semantic_error& er)
    {
                              e->chain (er);
      provide (e);
    }
}
void
dwarf_var_expanding_visitor::visit_cast_op (cast_op *e)
{
    if (e->module.empty())
    e->module = q.dw.module_name;
  var_expanding_visitor::visit_cast_op(e);
}
void
dwarf_var_expanding_visitor::visit_entry_op (entry_op *e)
{
  expression *repl = e;
  if (q.has_return)
    {
            q.has_return = false;
      replace (e->operand);
      q.has_return = true;
      XXX                  repl = gen_mapped_saved_return (e->operand, "entry");
    }
  provide (repl);
}
void
dwarf_var_expanding_visitor::visit_perf_op (perf_op *e)
{
  string e_lit_val = e->operand->value;
  add_block = new block;
  add_block->tok = e->tok;
  systemtap_session &s = this->q.sess;
  std::vector<std::pair<std::string,std::string> >::iterator it;
    for (it=s.perf_counters.begin();
       it != s.perf_counters.end();
       it++)
    if ((*it).first == e_lit_val)
      {
        if ((*it).second.length() == 0)
      (*it).second = this->q.user_path;
    if ((*it).second == this->q.user_path)
      break;
      }
  if (it != s.perf_counters.end())
    {
      perf_counter_refs.insert((*it).first);
            symbol* sym = new symbol;
      sym->tok = e->tok;
      sym->name = "__perf_read_" + (*it).first;
      provide (sym);
    }
  else
    throw SEMANTIC_ERROR(_F("perf counter '%s' not defined", e_lit_val.c_str()));
}
vector<Dwarf_Die>&
dwarf_var_expanding_visitor::getscopes(target_symbol *e)
{
  if (scopes.empty())
    {
      if(!null_die(scope_die))
        scopes = q.dw.getscopes(scope_die);
      if (scopes.empty())
                        throw SEMANTIC_ERROR ("unable to find any scopes containing "
                              + lex_cast_hex(addr)
                              + (null_die(scope_die) ? ""
                                 : (string (" in ")
                                    + (dwarf_diename(scope_die) ?: "<unknown>")
                                    + "(" + (dwarf_diename(q.dw.cu) ?: "<unknown>")
                                    + ")"))
                              + " while searching for local '"
                              + e->sym_name() + "'",
                              e->tok);
    }
  return scopes;
}
struct dwarf_cast_expanding_visitor: public var_expanding_visitor
{
  systemtap_session& s;
  dwarf_builder& db;
  map<string,string> compiled_headers;
  dwarf_cast_expanding_visitor(systemtap_session& s, dwarf_builder& db):
    s(s), db(db) {}
  void visit_cast_op (cast_op* e);
  void filter_special_modules(string& module);
};
struct dwarf_cast_query : public base_query
{
  cast_op& e;
  const bool lvalue;
  const bool userspace_p;
  functioncall*& result;
  dwarf_cast_query(dwflpp& dw, const string& module, cast_op& e, bool lvalue,
                   const bool userspace_p, functioncall*& result):
    base_query(dw, module), e(e), lvalue(lvalue),
    userspace_p(userspace_p), result(result) {}
  void handle_query_module();
  void query_library (const char *) {}
  void query_plt (const char *entry, size_t addr) {}
};
void
dwarf_cast_query::handle_query_module()
{
  static unsigned tick = 0;
  if (result)
    return;
    Dwarf_Die* type_die = NULL;
  if (startswith(e.type_name, "class "))
    {
            string struct_name = "struct " + e.type_name.substr(6);
      type_die = dw.declaration_resolve_other_cus(struct_name);
    }
  else
    type_die = dw.declaration_resolve_other_cus(e.type_name);
          if (!type_die &&
      !startswith(e.type_name, "class ") &&
      !startswith(e.type_name, "struct ") &&
      !startswith(e.type_name, "union ") &&
      !startswith(e.type_name, "enum "))
    {
      type_die = dw.declaration_resolve_other_cus("struct " + e.type_name);
      if (!type_die)
        type_die = dw.declaration_resolve_other_cus("union " + e.type_name);
      if (!type_die)
        type_die = dw.declaration_resolve_other_cus("enum " + e.type_name);
    }
  if (!type_die)
    return;
  string code;
  Dwarf_Die endtype;
  try
    {
      Dwarf_Die cu_mem;
      dw.focus_on_cu(dwarf_diecu(type_die, &cu_mem, NULL, NULL));
      if (e.check_pretty_print (lvalue))
        {
          dwarf_pretty_print dpp(dw, type_die, e.operand, true, userspace_p, e);
          result = dpp.expand();
          return;
        }
      code = dw.literal_stmt_for_pointer (type_die, &e, lvalue, &endtype);
    }
  catch (const semantic_error& er)
    {
                        e.chain (er);
    }
  if (code.empty())
    return;
  string fname = (string(lvalue ? "_dwarf_cast_set" : "_dwarf_cast_get")
          + "_" + e.sym_name()
          + "_" + lex_cast(tick++));
  result = synthetic_embedded_deref_call(dw, &endtype, fname, code,
                                         userspace_p, lvalue, &e, e.operand);
}
void dwarf_cast_expanding_visitor::filter_special_modules(string& module)
{
      if (module[module.size() - 1] == '>' &&
      (module[0] == '<' || startswith(module, "kernel<")))
    {
      string header = module;
      map<string,string>::const_iterator it = compiled_headers.find(header);
      if (it != compiled_headers.end())
        {
          module = it->second;
          return;
        }
      string cached_module;
      if (s.use_cache)
        {
                    cached_module = find_typequery_hash(s, module);
          if (!cached_module.empty() && !s.poison_cache)
            {
              int fd = open(cached_module.c_str(), O_RDONLY);
              if (fd != -1)
                {
                  if (s.verbose > 2)
                                        clog << _("Pass 2: using cached ") << cached_module << endl;
                  compiled_headers[header] = module = cached_module;
                  close(fd);
                  return;
                }
            }
        }
            if (make_typequery(s, module) == 0)
        {
                    if (s.use_cache)
            copy_file(module, cached_module, s.verbose > 2);
          compiled_headers[header] = module;
        }
    }
}
void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
{
  bool lvalue = is_active_lvalue(e);
  if (lvalue && !s.guru_mode)
    throw SEMANTIC_ERROR(_("write to @cast context variable not permitted; need stap -g"), e->tok);
  if (e->module.empty())
    e->module = "kernel"; 
  functioncall* result = NULL;
    vector<string> modules;
  tokenize(e->module, modules, ":");
  bool userspace_p=false;   for (unsigned i = 0; !result && i < modules.size(); ++i)
    {
      string& module = modules[i];
      filter_special_modules(module);
                  dwflpp* dw;
      try
    {
          userspace_p=is_user_module (module);
      if (! userspace_p)
        {
                    dw = db.get_kern_dw(s, module);
        }
      else
        {
              module = find_executable (module, "", s.sysenv);           dw = db.get_user_dw(s, module);
        }
    }
      catch (const semantic_error& er)
    {
            continue;
    }
      dwarf_cast_query q (*dw, module, *e, lvalue, userspace_p, result);
      dw->iterate_over_modules<base_query>(&query_module, &q);
    }
  if (!result)
    {
                        provide (e);
      return;
    }
  if (lvalue)
    provide_lvalue_call (result);
  result->visit (this);
}
static bool resolve_pointer_type(Dwarf_Die& die, bool& isptr);
exp_type_dwarf::exp_type_dwarf(dwflpp* dw, Dwarf_Die* die,
                               bool userspace_p, bool addressof):
  dw(dw), die(*die), userspace_p(userspace_p), is_pointer(false)
{
      if (addressof)
        is_pointer = true;
  else
        resolve_pointer_type(this->die, is_pointer);
}
functioncall *
exp_type_dwarf::expand(autocast_op* e, bool lvalue)
{
  static unsigned tick = 0;
  try
    {
            bool deref_p = is_pointer && !null_die(&die);
      if (!deref_p)
        e->assert_no_components("autocast", true);
      if (lvalue && !dw->sess.guru_mode)
    throw SEMANTIC_ERROR(_("write not permitted; need stap -g"), e->tok);
      if (e->components.empty())
        {
          if (e->addressof)
            throw SEMANTIC_ERROR(_("cannot take address of tracepoint variable"), e->tok);
                    throw SEMANTIC_ERROR(_("internal error: no-op autocast encountered"), e->tok);
        }
      Dwarf_Die cu_mem;
      if (!null_die(&die))
        dw->focus_on_cu(dwarf_diecu(&die, &cu_mem, NULL, NULL));
      if (e->check_pretty_print (lvalue))
    {
      dwarf_pretty_print dpp(*dw, &die, e->operand, deref_p, userspace_p, *e);
      return dpp.expand();
    }
      Dwarf_Die endtype;
      string code = dw->literal_stmt_for_pointer (&die, e, lvalue, &endtype);
      string fname = (string(lvalue ? "_dwarf_autocast_set" : "_dwarf_autocast_get")
              + "_" + lex_cast(tick++));
      return synthetic_embedded_deref_call(*dw, &endtype, fname, code,
                      userspace_p, lvalue, e, e->operand);
    }
  catch (const semantic_error &er)
    {
      e->chain (er);
      return NULL;
    }
}
struct dwarf_atvar_expanding_visitor: public var_expanding_visitor
{
  systemtap_session& s;
  dwarf_builder& db;
  dwarf_atvar_expanding_visitor(systemtap_session& s, dwarf_builder& db):
    s(s), db(db) {}
  void visit_atvar_op (atvar_op* e);
};
struct dwarf_atvar_query: public base_query
{
  atvar_op& e;
  const bool userspace_p, lvalue;
  functioncall*& result;
  unsigned& tick;
  const string cu_name_pattern;
  dwarf_atvar_query(dwflpp& dw, const string& module, atvar_op& e,
                    const bool userspace_p, const bool lvalue,
                    functioncall*& result,
                    unsigned& tick):
    base_query(dw, module), e(e),
    userspace_p(userspace_p), lvalue(lvalue), result(result),
    tick(tick), cu_name_pattern(string("*/") + e.cu_name) {}
  void handle_query_module ();
  void query_library (const char *) {}
  void query_plt (const char *entry, size_t addr) {}
  static int atvar_query_cu (Dwarf_Die *cudie, dwarf_atvar_query *q);
};
int
dwarf_atvar_query::atvar_query_cu (Dwarf_Die * cudie, dwarf_atvar_query *q)
{
  if (! q->e.cu_name.empty())
    {
      const char *die_name = dwarf_diename(cudie) ?: "";
      if (strcmp(die_name, q->e.cu_name.c_str()) != 0           && fnmatch(q->cu_name_pattern.c_str(), die_name, 0) != 0)
        {
          return DWARF_CB_OK;
        }
    }
  try
    {
      vector<Dwarf_Die>  scopes(1, *cudie);
      q->dw.focus_on_cu (cudie);
      if (q->e.check_pretty_print (q->lvalue))
        {
          dwarf_pretty_print dpp (q->dw, scopes, 0, q->e.sym_name(),
                                  q->userspace_p, q->e);
          q->result = dpp.expand();
          return DWARF_CB_ABORT;
        }
      Dwarf_Die endtype;
      string code = q->dw.literal_stmt_for_local (scopes, 0, q->e.sym_name(),
                                                  &q->e, q->lvalue, &endtype);
      if (code.empty())
        return DWARF_CB_OK;
      string fname = (string(q->lvalue ? "_dwarf_tvar_set"
                                       : "_dwarf_tvar_get")
                      + "_" + q->e.sym_name()
                      + "_" + lex_cast(q->tick++));
      q->result = synthetic_embedded_deref_call (q->dw, &endtype, fname, code,
                                                 q->userspace_p, q->lvalue,
                                                 &q->e);
    }
  catch (const semantic_error& er)
    {
                  return DWARF_CB_OK;
    }
  if (q->result) {
      return DWARF_CB_ABORT;
  }
  return DWARF_CB_OK;
}
void
dwarf_atvar_query::handle_query_module ()
{
  dw.iterate_over_cus(atvar_query_cu, this, false);
}
void
dwarf_atvar_expanding_visitor::visit_atvar_op (atvar_op* e)
{
  const bool lvalue = is_active_lvalue(e);
  if (lvalue && !s.guru_mode)
    throw SEMANTIC_ERROR(_("write to @var variable not permitted; "
                           "need stap -g"), e->tok);
  if (e->module.empty())
    e->module = "kernel";
  functioncall* result = NULL;
    vector<string> modules;
  tokenize(e->module, modules, ":");
  bool userspace_p = false;
  for (unsigned i = 0; !result && i < modules.size(); ++i)
    {
      string& module = modules[i];
      dwflpp* dw;
      try
        {
          userspace_p = is_user_module(module);
          if (!userspace_p)
            {
                            dw = db.get_kern_dw(s, module);
            }
          else
            {
              module = find_executable(module, "", s.sysenv);
              dw = db.get_user_dw(s, module);
            }
        }
      catch (const semantic_error& er)
        {
                    continue;
        }
      dwarf_atvar_query q (*dw, module, *e, userspace_p, lvalue, result, tick);
      dw->iterate_over_modules<base_query>(&query_module, &q);
      if (result)
        {
          s.unwindsym_modules.insert(module);
          if (lvalue)
        provide_lvalue_call (result);
          result->visit(this);
          return;
        }
            semantic_error  er(ERR_SRC, _F("unable to find global '%s' in %s%s%s",
                            e->sym_name().c_str(), module.c_str(),
                            e->cu_name.empty() ? "" : _(", in "),
                            e->cu_name.c_str()));
      e->chain (er);
    }
  provide(e);
}
void
dwarf_derived_probe::printsig (ostream& o) const
{
          sole_location()->print (o);
  o << " /* pc=" << section << "+0x" << hex << addr << dec << " */";
  printsig_nested (o);
}
void
dwarf_derived_probe::join_group (systemtap_session& s)
{
    if (!has_return && (saved_longs || saved_strings))
    return;
  if (! s.dwarf_derived_probes)
    s.dwarf_derived_probes = new dwarf_derived_probe_group ();
  s.dwarf_derived_probes->enroll (this);
  this->group = s.dwarf_derived_probes;
  if (has_return && entry_handler)
    entry_handler->group = s.dwarf_derived_probes;
}
static bool
kernel_supports_inode_uprobes(systemtap_session& s)
{
        return (s.kernel_config["CONFIG_ARCH_SUPPORTS_UPROBES"] == "y"
          && s.kernel_config["CONFIG_UPROBES"] == "y");
}
static bool
kernel_supports_inode_uretprobes(systemtap_session& s)
{
      return kernel_supports_inode_uprobes(s) &&
    (s.kernel_functions.count("arch_uretprobe_hijack_return_addr") > 0);
}
void
check_process_probe_kernel_support(systemtap_session& s)
{
    if (s.kernel_config["CONFIG_UTRACE"] == "y")
    return;
                if (! s.need_uprobes && s.kernel_config["CONFIG_TRACEPOINTS"] == "y")
    return;
      if (s.need_uprobes
      && s.kernel_config["CONFIG_TRACEPOINTS"] == "y"
      && kernel_supports_inode_uprobes(s))
    return;
  throw SEMANTIC_ERROR (_("process probes not available without kernel CONFIG_UTRACE or CONFIG_TRACEPOINTS/CONFIG_ARCH_SUPPORTS_UPROBES/CONFIG_UPROBES"));
}
dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
                                         const string& filename,
                                         int line,
                                                                                                                                                                                                                                                                                               const string& module,
                                         const string& section,
                                                                                                                           Dwarf_Addr dwfl_addr,
                                                                                                                           Dwarf_Addr addr,
                                         dwarf_query& q,
                                         Dwarf_Die* scope_die )
  : derived_probe (q.base_probe, q.base_loc, true  ),
    module (module), section (section), addr (addr),
    path (q.path),
    has_process (q.has_process),
    has_return (q.has_return),
    has_maxactive (q.has_maxactive),
    has_library (q.has_library),
    maxactive_val (q.maxactive_val),
    user_path (q.user_path),
    user_lib (q.user_lib),
    access_vars(false),
    saved_longs(0), saved_strings(0),
    entry_handler(0)
{
    if (q.has_module && is_fully_resolved(module, q.dw.sess.sysroot, q.dw.sess.sysenv))
    this->module = modname_from_path(module);
  if (user_lib.size() != 0)
    has_library = true;
  if (q.has_process)
    {
                              XXX
                  if ((kernel_supports_inode_uprobes(q.dw.sess) || q.dw.sess.runtime_usermode_p()) &&
          section == ".absolute" && addr == dwfl_addr &&
          addr >= q.dw.module_start && addr < q.dw.module_end)
        this->addr = addr - q.dw.module_start;
    }
  else
    {
            if (section == "" && dwfl_addr != addr)         throw SEMANTIC_ERROR (_("missing relocation basis"), tok);
      if (section != "" && dwfl_addr == addr)         throw SEMANTIC_ERROR (_("inconsistent relocation address"), tok);
    }
  XXX#ifndef USHRT_MAX
#define USHRT_MAX 32767
#endif
    if (has_maxactive && (maxactive_val < 0 || maxactive_val > USHRT_MAX))
    throw SEMANTIC_ERROR (_F("maxactive value out of range [0,%s]",
                          lex_cast(USHRT_MAX).c_str()), q.base_loc->components.front()->tok);
            {
      XXX
                                    Dwarf_Addr handler_dwfl_addr = dwfl_addr;
      if (q.prologue_end != 0 && q.has_return)
        {
          handler_dwfl_addr = q.prologue_end;
          if (q.sess.verbose > 2)
            clog << _F("expanding .return vars at prologue_end (0x%s) "
                       "rather than entrypc (0x%s)\n",
                       lex_cast_hex(handler_dwfl_addr).c_str(),
                       lex_cast_hex(dwfl_addr).c_str());
        }
      dwarf_var_expanding_visitor v (q, scope_die, handler_dwfl_addr);
      v.replace (this->body);
            this->perf_counter_refs = v.perf_counter_refs;
            std::set<string>::iterator pcii;
      for (pcii = v.perf_counter_refs.begin();
       pcii != v.perf_counter_refs.end(); pcii++)
    {
      std::vector<std::pair<std::string,std::string> >::iterator it;
            for (it=q.sess.perf_counters.begin() ;
           it != q.sess.perf_counters.end();
           it++)
        if ((*it).first == (*pcii))
          break;
      vardecl* vd = new vardecl;
      vd->name = "__perf_read_" + (*it).first;
      vd->tok = this->tok;
      vd->set_arity(0, this->tok);
      vd->type = pe_long;
      vd->synthetic = true;
      this->locals.push_back (vd);
    }
      if (!q.has_process)
        access_vars = v.visited;
                  if (v.add_block)
        this->body = new block(v.add_block, this->body);
                              if (v.add_call_probe)
        {
          assert (q.has_return && !q.has_call);
                    statement* old_body = q.base_probe->body;
          q.base_probe->body = v.add_call_probe;
          q.has_return = false;
          q.has_call = true;
          if (q.has_process)
            {
                                                        Dwarf_Addr handler_addr = addr;
              if (handler_dwfl_addr != dwfl_addr)
                                handler_addr += handler_dwfl_addr - dwfl_addr;
              entry_handler = new uprobe_derived_probe (funcname, filename,
                                                        line, module, section,
                                                        handler_dwfl_addr,
                                                        handler_addr, q,
                                                        scope_die);
            }
          else
            entry_handler = new dwarf_derived_probe (funcname, filename, line,
                                                     module, section, dwfl_addr,
                                                     addr, q, scope_die);
          saved_longs = entry_handler->saved_longs = v.saved_longs;
          saved_strings = entry_handler->saved_strings = v.saved_strings;
          q.results.push_back (entry_handler);
          q.has_return = true;
          q.has_call = false;
          q.base_probe->body = old_body;
        }
                  if (!null_die(scope_die) &&
          q.sess.dump_mode == systemtap_session::dump_matched_probes_vars)
        saveargs(q, scope_die, dwfl_addr);
    }
        
  vector<probe_point::component*> comps;
  if (q.has_kernel)
    comps.push_back (new probe_point::component(TOK_KERNEL));
  else if(q.has_module)
    comps.push_back (new probe_point::component(TOK_MODULE, new literal_string(module)));
  else if(q.has_process)
    comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(module)));
  else
    assert (0);
  string fn_or_stmt;
  if (q.has_function_str || q.has_function_num)
    fn_or_stmt = TOK_FUNCTION;
  else
    fn_or_stmt = TOK_STATEMENT;
  if (q.has_function_str || q.has_statement_str)
      {
        string retro_name = q.final_function_name(funcname, filename.c_str(), line);
        comps.push_back
          (new probe_point::component
           (fn_or_stmt, new literal_string (retro_name)));
      }
  else if (q.has_function_num || q.has_statement_num)
    {
      Dwarf_Addr retro_addr;
      if (q.has_function_num)
        retro_addr = q.function_num_val;
      else
        retro_addr = q.statement_num_val;
      comps.push_back (new probe_point::component
                       (fn_or_stmt,
                        new literal_number(retro_addr, true)));
      if (q.has_absolute)
        comps.push_back (new probe_point::component (TOK_ABSOLUTE));
    }
  if (q.has_call)
      comps.push_back (new probe_point::component(TOK_CALL));
  if (q.has_exported)
      comps.push_back (new probe_point::component(TOK_EXPORTED));
  if (q.has_inline)
      comps.push_back (new probe_point::component(TOK_INLINE));
  if (has_return)
    comps.push_back (new probe_point::component(TOK_RETURN));
  if (has_maxactive)
    comps.push_back (new probe_point::component
                     (TOK_MAXACTIVE, new literal_number(maxactive_val)));
    this->sole_location()->components = comps;
          if ((q.has_callee || q.has_callees_num) && q.callers && !q.callers->empty())
    {
      if (q.sess.verbose > 2)
        clog << _F("adding caller checks for callee %s\n", funcname.c_str());
            stack<Dwarf_Addr> callers(*q.callers);
      for (unsigned level = 1; !callers.empty(); level++,
                                                 callers.pop())
        {
          Dwarf_Addr caller = callers.top();
                    string caller_section;
          Dwarf_Addr caller_reloc;
          if (module == TOK_KERNEL)
            {               caller_reloc = caller - q.sess.sym_stext;
              caller_section = "_stext";
            }
          else
            caller_reloc = q.dw.relocate_address(caller,
                                                 caller_section);
          if (q.sess.verbose > 2)
            clog << _F("adding caller check [u]stack(%d) == reloc(0x%s)\n",
                       level, lex_cast_hex(caller_reloc).c_str());
                              
          functioncall* check = new functioncall();
          check->tok = this->tok;
          check->function = "_caller_match";
          check->args.push_back(new literal_number(q.has_process));
          check->args[0]->tok = this->tok;
          check->args.push_back(new literal_number(level));
          check->args[1]->tok = this->tok;
          check->args.push_back(new literal_string(this->module));
          check->args[2]->tok = this->tok;
          check->args.push_back(new literal_string(caller_section));
          check->args[3]->tok = this->tok;
          check->args.push_back(new literal_number(caller_reloc, true ));
          check->args[4]->tok = this->tok;
          unary_expression* notexp = new unary_expression();
          notexp->tok = this->tok;
          notexp->op = "!";
          notexp->operand = check;
          if_statement* ifs = new if_statement();
          ifs->tok = this->tok;
          ifs->thenblock = new next_statement();
          ifs->thenblock->tok = this->tok;
          ifs->elseblock = NULL;
          ifs->condition = notexp;
          this->body = new block(ifs, this->body);
        }
    }
}
void
dwarf_derived_probe::saveargs(dwarf_query& q, Dwarf_Die* scope_die,
                              Dwarf_Addr dwfl_addr)
{
  if (null_die(scope_die))
    return;
  bool verbose = q.sess.verbose > 2;
  if (verbose)
    clog << _F("saveargs: examining '%s' (dieoffset: %#" PRIx64 ")\n", (dwarf_diename(scope_die)?: "unknown"), dwarf_dieoffset(scope_die));
  if (has_return)
    {
            string type_name;
      Dwarf_Die type_die;
      if (dwarf_attr_die (scope_die, DW_AT_type, &type_die) &&
          dwarf_type_name(&type_die, type_name))
        args.push_back("$return:"+type_name);
      else if (verbose)
        clog << _F("saveargs: failed to retrieve type name for return value (dieoffset: %s)\n",
                   lex_cast_hex(dwarf_dieoffset(scope_die)).c_str());
    }
  Dwarf_Die arg;
  vector<Dwarf_Die> scopes = q.dw.getscopes(scope_die);
  for (unsigned i = 0; i < scopes.size(); ++i)
    {
      if (dwarf_tag(&scopes[i]) == DW_TAG_compile_unit)
        break;       if (dwarf_child (&scopes[i], &arg) == 0)
        do
          {
            switch (dwarf_tag (&arg))
              {
              case DW_TAG_variable:
              case DW_TAG_formal_parameter:
                break;
              default:
                continue;
              }
                        const char *arg_name = dwarf_diename (&arg);
            if (!arg_name)
              {
                if (verbose)
                  clog << _F("saveargs: failed to retrieve name for local (dieoffset: %s)\n",
                             lex_cast_hex(dwarf_dieoffset(&arg)).c_str());
                continue;
              }
            if (verbose)
              clog << _F("saveargs: finding location for local '%s' (dieoffset: %s)\n",
                         arg_name, lex_cast_hex(dwarf_dieoffset(&arg)).c_str());
                        
            XXX
            Dwarf_Attribute attr_mem;
            if (!dwarf_attr_integrate (&arg, DW_AT_const_value, &attr_mem))
              {
                Dwarf_Op *expr;
                size_t len;
                if (!dwarf_attr_integrate (&arg, DW_AT_location, &attr_mem))
                  {
                    if (verbose)
                      clog << _F("saveargs: failed to resolve the location for local '%s' (dieoffset: %s)\n",
                                  arg_name, lex_cast_hex(dwarf_dieoffset(&arg)).c_str());
                    continue;
                  }
                else if (!(dwarf_getlocation_addr(&attr_mem, dwfl_addr, &expr,
                                                  &len, 1) == 1 && len > 0))
                  {
                    Dwarf_Addr dwfl_addr2 = q.dw.pr15123_retry_addr (dwfl_addr, & arg);
                    if (!dwfl_addr2 || (!(dwarf_getlocation_addr(&attr_mem, dwfl_addr2, &expr,
                                                                 &len, 1) == 1 && len > 0))) {
                      if (verbose)
                        clog << _F("saveargs: local '%s' (dieoffset: %s) is not available at this address (%s)\n",
                                   arg_name, lex_cast_hex(dwarf_dieoffset(&arg)).c_str(), lex_cast_hex(dwfl_addr).c_str());
                      continue;
                    }
                  }
              }
                        string type_name;
            Dwarf_Die type_die;
            if (!dwarf_attr_die (&arg, DW_AT_type, &type_die) ||
                !dwarf_type_name(&type_die, type_name))
              {
                if (verbose)
                  clog << _F("saveargs: failed to retrieve type name for local '%s' (dieoffset: %s)\n",
                             arg_name, lex_cast_hex(dwarf_dieoffset(&arg)).c_str());
                continue;
              }
                        args.push_back("$"+string(arg_name)+":"+type_name);
          }
        while (dwarf_siblingof (&arg, &arg) == 0);
    }
}
void
dwarf_derived_probe::getargs(std::list<std::string> &arg_set) const
{
  arg_set.insert(arg_set.end(), args.begin(), args.end());
}
void
dwarf_derived_probe::emit_privilege_assertion (translator_output* o)
{
  if (has_process)
    {
                  emit_process_owner_assertion (o);
      return;
    }
      derived_probe::emit_privilege_assertion (o);
}
void
dwarf_derived_probe::print_dupe_stamp(ostream& o)
{
  if (has_process)
    {
                  print_dupe_stamp_unprivileged_process_owner (o);
      return;
    }
    derived_probe::print_dupe_stamp (o);
}
void
dwarf_derived_probe::register_statement_variants(match_node * root,
                         dwarf_builder * dw,
                         privilege_t privilege)
{
  root
    ->bind_privilege(privilege)
    ->bind(dw);
  root->bind(TOK_NEAREST)
    ->bind_privilege(privilege)
    ->bind(dw);
}
void
dwarf_derived_probe::register_function_variants(match_node * root,
                        dwarf_builder * dw,
                        privilege_t privilege)
{
  root
    ->bind_privilege(privilege)
    ->bind(dw);
  root->bind(TOK_CALL)
    ->bind_privilege(privilege)
    ->bind(dw);
  root->bind(TOK_EXPORTED)
    ->bind_privilege(privilege)
    ->bind(dw);
  root->bind(TOK_RETURN)
    ->bind_privilege(privilege)
    ->bind(dw);
    if (! pr_contains (privilege, pr_stapusr))
    {
      root->bind(TOK_RETURN)
        ->bind_num(TOK_MAXACTIVE)->bind(dw);
    }
}
void
dwarf_derived_probe::register_function_and_statement_variants(
  systemtap_session& s,
  match_node * root,
  dwarf_builder * dw,
  privilege_t privilege
)
{
            
  match_node *fv_root = root->bind_str(TOK_FUNCTION);
  register_function_variants(fv_root, dw, privilege);
    fv_root->bind(TOK_INLINE)
    ->bind_privilege(privilege)
    ->bind(dw);
  fv_root->bind_str(TOK_LABEL)
    ->bind_privilege(privilege)
    ->bind(dw);
  fv_root->bind_str(TOK_CALLEE)
    ->bind_privilege(privilege)
    ->bind(dw);
  fv_root->bind(TOK_CALLEES)
    ->bind_privilege(privilege)
    ->bind(dw);
  fv_root->bind_num(TOK_CALLEES)
    ->bind_privilege(privilege)
    ->bind(dw);
  fv_root = root->bind_num(TOK_FUNCTION);
  register_function_variants(fv_root, dw, privilege);
    if (strverscmp(s.compatible.c_str(), "1.7") <= 0)
    {
      fv_root->bind(TOK_INLINE)
    ->bind_privilege(privilege)
    ->bind(dw);
    }
  register_statement_variants(root->bind_str(TOK_STATEMENT), dw, privilege);
  register_statement_variants(root->bind_num(TOK_STATEMENT), dw, privilege);
}
void
dwarf_derived_probe::register_sdt_variants(systemtap_session& s,
                       match_node * root,
                       dwarf_builder * dw)
{
  root->bind_str(TOK_MARK)
    ->bind_privilege(pr_all)
    ->bind(dw);
  root->bind_str(TOK_PROVIDER)->bind_str(TOK_MARK)
    ->bind_privilege(pr_all)
    ->bind(dw);
}
void
dwarf_derived_probe::register_plt_variants(systemtap_session& s,
                       match_node * root,
                       dwarf_builder * dw)
{
  root->bind(TOK_PLT)
    ->bind_privilege(pr_all)
    ->bind(dw);
  root->bind_str(TOK_PLT)
    ->bind_privilege(pr_all)
    ->bind(dw);
  root->bind(TOK_PLT)
    ->bind(TOK_RETURN)
    ->bind_privilege(pr_all)
    ->bind(dw);
  root->bind_str(TOK_PLT)
    ->bind(TOK_RETURN)
    ->bind_privilege(pr_all)
    ->bind(dw);
}
void
dwarf_derived_probe::register_patterns(systemtap_session& s)
{
  match_node* root = s.pattern_root;
  dwarf_builder *dw = new dwarf_builder();
  update_visitor *filter = new dwarf_cast_expanding_visitor(s, *dw);
  s.code_filters.push_back(filter);
  filter = new dwarf_atvar_expanding_visitor(s, *dw);
  s.code_filters.push_back(filter);
  register_function_and_statement_variants(s, root->bind(TOK_KERNEL), dw, pr_privileged);
  register_function_and_statement_variants(s, root->bind_str(TOK_MODULE), dw, pr_privileged);
  root->bind(TOK_KERNEL)->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)
    ->bind(dw);
  match_node* uprobes[] = {
      root->bind(TOK_PROCESS),
      root->bind_str(TOK_PROCESS),
      root->bind_num(TOK_PROCESS),
      root->bind(TOK_PROCESS)->bind_str(TOK_LIBRARY),
      root->bind_str(TOK_PROCESS)->bind_str(TOK_LIBRARY),
  };
  for (size_t i = 0; i < sizeof(uprobes) / sizeof(*uprobes); ++i)
    {
      register_function_and_statement_variants(s, uprobes[i], dw, pr_all);
      register_sdt_variants(s, uprobes[i], dw);
      register_plt_variants(s, uprobes[i], dw);
    }
}
void
dwarf_derived_probe::emit_probe_local_init(systemtap_session& s, translator_output * o)
{
  std::set<string>::iterator pcii;
  for (pcii = perf_counter_refs.begin();
       pcii != perf_counter_refs.end();
       pcii++)
    {
      std::vector<std::pair<std::string,std::string> >::iterator it;
            unsigned i = 0;
      for (it=s.perf_counters.begin() ;
       it != s.perf_counters.end();
       it++, i++)
    if ((*it).first == (*pcii))
      break;
            o->newline() << "l->l___perf_read_" + (*it).first
    + " = (((int64_t) (_stp_perf_read(smp_processor_id(),"
    + lex_cast(i) + "))));";
    }
  if (access_vars)
    {
            o->newline() << "#if defined __ia64__";
      o->newline() << "bspcache(c->unwaddr, c->kregs);";
      o->newline() << "#endif";
    }
}
void
dwarf_derived_probe_group::enroll (dwarf_derived_probe* p)
{
  probes_by_module.insert (make_pair (p->module, p));
  XXX    }
void
dwarf_derived_probe_group::emit_module_decls (systemtap_session& s)
{
  if (probes_by_module.empty()) return;
  s.op->newline() << "/* ---- dwarf probes ---- */";
        size_t module_name_max = 0, section_name_max = 0;
  size_t module_name_tot = 0, section_name_tot = 0;
  size_t all_name_cnt = probes_by_module.size();   for (p_b_m_iterator it = probes_by_module.begin(); it != probes_by_module.end(); it++)
    {
      dwarf_derived_probe* p = it->second;
#define DOIT(var,expr) do {                             \
        size_t var##_size = (expr) + 1;                 \
        var##_max = max (var##_max, var##_size);        \
        var##_tot += var##_size; } while (0)
      DOIT(module_name, p->module.size());
      DOIT(section_name, p->section.size());
#undef DOIT
    }
      #define CALCIT(var)                                                     \
  if ((var##_name_max-(var##_name_tot/all_name_cnt)) < (3 * sizeof(void*))) \
    {                                                                   \
      s.op->newline() << "#define STAP_DWARF_PROBE_STR_" << #var << " " \
                      << "const char " << #var                          \
                      << "[" << var##_name_max << "]";                 \
      if (s.verbose > 2) clog << "stap_dwarf_probe " << #var            \
                              << "[" << var##_name_max << "]" << endl;  \
    }                                                                   \
  else                                                                  \
    {                                                                   \
      s.op->newline() << "#define STAP_DWARF_PROBE_STR_" << #var << " " \
                      << "const char * const " << #var << "";          \
      if (s.verbose > 2) clog << "stap_dwarf_probe *" << #var << endl;  \
    }
  CALCIT(module);
  CALCIT(section);
#undef CALCIT
  s.op->newline() << "#include \"linux/kprobes.c\"";
#define UNDEFIT(var) s.op->newline() << "#undef STAP_DWARF_PROBE_STR_" << #var
  UNDEFIT(module);
  UNDEFIT(section);
#undef UNDEFIT
    s.op->newline() << "#if defined(STAPCONF_UNREGISTER_KPROBES)";
  s.op->newline() << "static void * stap_unreg_kprobes[" << probes_by_module.size() << "];";
  s.op->newline() << "#endif";
  
        s.op->newline() << "static struct stap_dwarf_kprobe stap_dwarf_kprobes[" << probes_by_module.size() << "];";
  
  s.op->newline() << "static struct stap_dwarf_probe stap_dwarf_probes[] = {";
  s.op->indent(1);
  size_t stap_dwarf_kprobe_idx = 0;
  for (p_b_m_iterator it = probes_by_module.begin(); it != probes_by_module.end(); it++)
    {
      dwarf_derived_probe* p = it->second;
      s.op->newline() << "{";
      if (p->has_return)
        s.op->line() << " .return_p=1,";
      if (p->has_maxactive)
        {
          s.op->line() << " .maxactive_p=1,";
          assert (p->maxactive_val >= 0 && p->maxactive_val <= USHRT_MAX);
          s.op->line() << " .maxactive_val=" << p->maxactive_val << ",";
        }
      if (p->saved_longs || p->saved_strings)
        {
          if (p->saved_longs)
            s.op->line() << " .saved_longs=" << p->saved_longs << ",";
          if (p->saved_strings)
            s.op->line() << " .saved_strings=" << p->saved_strings << ",";
          if (p->entry_handler)
            s.op->line() << " .entry_probe=" << common_probe_init (p->entry_handler) << ",";
        }
      if (p->locations[0]->optional)
        s.op->line() << " .optional_p=1,";
      s.op->line() << " .address=(unsigned long)0x" << hex << p->addr << dec << "ULL,";
      s.op->line() << " .module=\"" << p->module << "\",";
      s.op->line() << " .section=\"" << p->section << "\",";
      s.op->line() << " .probe=" << common_probe_init (p) << ",";
      s.op->line() << " .kprobe=&stap_dwarf_kprobes[" << stap_dwarf_kprobe_idx++ << "],";
      s.op->line() << " },";
    }
  s.op->newline(-1) << "};";
    s.op->newline();
  s.op->newline() << "static int enter_kprobe_probe (struct kprobe *inst,";
  s.op->line() << " struct pt_regs *regs) {";
    s.op->newline(1) << "int kprobe_idx = ((uintptr_t)inst-(uintptr_t)stap_dwarf_kprobes)/sizeof(struct stap_dwarf_kprobe);";
    s.op->newline() << "struct stap_dwarf_probe *sdp = &stap_dwarf_probes[";
  s.op->line() << "((kprobe_idx >= 0 && kprobe_idx < " << probes_by_module.size() << ")?";
  s.op->line() << "kprobe_idx:0)";   XXX  s.op->line() << "];";
  common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sdp->probe",
                 "stp_probe_type_kprobe");
  s.op->newline() << "c->kregs = regs;";
        s.op->newline() << "{";
  s.op->indent(1);
  s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->kregs);";
  s.op->newline() << "SET_REG_IP(regs, (unsigned long) inst->addr);";
  s.op->newline() << "(*sdp->probe->ph) (c);";
  s.op->newline() << "SET_REG_IP(regs, kprobes_ip);";
  s.op->newline(-1) << "}";
  common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
  s.op->newline() << "return 0;";
  s.op->newline(-1) << "}";
    s.op->newline();
  s.op->newline() << "static int enter_kretprobe_common (struct kretprobe_instance *inst,";
  s.op->line() << " struct pt_regs *regs, int entry) {";
  s.op->newline(1) << "struct kretprobe *krp = inst->rp;";
    s.op->newline() << "int kprobe_idx = ((uintptr_t)krp-(uintptr_t)stap_dwarf_kprobes)/sizeof(struct stap_dwarf_kprobe);";
    s.op->newline() << "struct stap_dwarf_probe *sdp = &stap_dwarf_probes[";
  s.op->line() << "((kprobe_idx >= 0 && kprobe_idx < " << probes_by_module.size() << ")?";
  s.op->line() << "kprobe_idx:0)";   XXX  s.op->line() << "];";
  s.op->newline() << "const struct stap_probe *sp = entry ? sdp->entry_probe : sdp->probe;";
  s.op->newline() << "if (sp) {";
  s.op->indent(1);
  common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sp",
                 "stp_probe_type_kretprobe");
  s.op->newline() << "c->kregs = regs;";
    s.op->newline() << "c->ips.krp.pi = inst;";
  s.op->newline() << "c->ips.krp.pi_longs = sdp->saved_longs;";
        s.op->newline() << "{";
  s.op->newline(1) << "unsigned long kprobes_ip = REG_IP(c->kregs);";
  s.op->newline() << "if (entry)";
  s.op->newline(1) << "SET_REG_IP(regs, (unsigned long) inst->rp->kp.addr);";
  s.op->newline(-1) << "else";
  s.op->newline(1) << "SET_REG_IP(regs, (unsigned long)inst->ret_addr);";
  s.op->newline(-1) << "(sp->ph) (c);";
  s.op->newline() << "SET_REG_IP(regs, kprobes_ip);";
  s.op->newline(-1) << "}";
  common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
  s.op->newline(-1) << "}";
  s.op->newline() << "return 0;";
  s.op->newline(-1) << "}";
  s.op->newline();
}
void
dwarf_derived_probe_group::emit_module_init (systemtap_session& s)
{
  if (probes_by_module.empty()) return;
  s.op->newline() << "/* ---- dwarf probes ---- */";
      s.op->newline() << "probe_point = NULL;";
  s.op->newline() << "rc = stapkp_init( "
                                     << "stap_dwarf_probes, "
                                     << "ARRAY_SIZE(stap_dwarf_probes));";
}
void
dwarf_derived_probe_group::emit_module_refresh (systemtap_session& s)
{
  if (probes_by_module.empty()) return;
  s.op->newline() << "/* ---- dwarf probes ---- */";
  s.op->newline() << "stapkp_refresh( "
                                   << "modname, "
                                   << "stap_dwarf_probes, "
                                   << "ARRAY_SIZE(stap_dwarf_probes));";
}
void
dwarf_derived_probe_group::emit_module_exit (systemtap_session& s)
{
  if (probes_by_module.empty()) return;
  s.op->newline() << "/* ---- dwarf probes ---- */";
  s.op->newline() << "stapkp_exit( "
                                << "stap_dwarf_probes, "
                                << "ARRAY_SIZE(stap_dwarf_probes));";
}
static void sdt_v3_tokenize(const string& str, vector<string>& tokens)
{
  string::size_type pos;
  string::size_type lastPos = str.find_first_not_of(" ", 0);
  string::size_type nextAt = str.find("@", lastPos);
  if (nextAt == string::npos)
    {
                              tokenize(str, tokens, " ");
      return;
    }
  while (lastPos != string::npos)
   {
     pos = nextAt + 1;
     nextAt = str.find("@", pos);
     if (nextAt == string::npos)
       pos = string::npos;
     else
       pos = str.rfind(" ", nextAt);
     tokens.push_back(str.substr(lastPos, pos - lastPos));
     lastPos = str.find_first_not_of(" ", pos);
   }
}
struct sdt_uprobe_var_expanding_visitor: public var_expanding_visitor
{
  enum regwidths {QI, QIh, HI, SI, DI};
  sdt_uprobe_var_expanding_visitor(systemtap_session& s,
                                   dwflpp& dw,
                                   int elf_machine,
                                   const string & process_name,
                   const string & provider_name,
                   const string & probe_name,
                   stap_sdt_probe_type probe_type,
                   const string & arg_string,
                   int ac):
    session (s), dw (dw), elf_machine (elf_machine),
    process_name (process_name), provider_name (provider_name),
    probe_name (probe_name), probe_type (probe_type), arg_count ((unsigned) ac)
  {
        assert(is_user_module(process_name));
    build_dwarf_registers();
    need_debug_info = false;
    if (probe_type == uprobe3_type)
      {
        sdt_v3_tokenize(arg_string, arg_tokens);
        assert(arg_count <= 12);
      }
    else
      {
        tokenize(arg_string, arg_tokens, " ");
        assert(arg_count <= 10);
      }
  }
  systemtap_session& session;
  dwflpp& dw;
  int elf_machine;
  const string & process_name;
  const string & provider_name;
  const string & probe_name;
  stap_sdt_probe_type probe_type;
  unsigned arg_count;
  vector<string> arg_tokens;
  map<string, pair<unsigned,int> > dwarf_regs;
  string regnames;
  string percent_regnames;
  bool need_debug_info;
  void build_dwarf_registers();
  void visit_target_symbol (target_symbol* e);
  unsigned get_target_symbol_argno_and_validate (target_symbol* e);
  long parse_out_arg_precision(string& asmarg);
  expression* try_parse_arg_literal (target_symbol *e,
                                     const string& asmarg,
                                     long precision);
  expression* try_parse_arg_register (target_symbol *e,
                                      const string& asmarg,
                                      long precision);
  expression* try_parse_arg_offset_register (target_symbol *e,
                                             const string& asmarg,
                                             long precision);
  expression* try_parse_arg_effective_addr (target_symbol *e,
                                            const string& asmarg,
                                            long precision);
  expression* try_parse_arg_varname (target_symbol *e,
                                     const string& asmarg,
                                     long precision);
  void visit_target_symbol_arg (target_symbol* e);
  void visit_target_symbol_context (target_symbol* e);
  void visit_atvar_op (atvar_op* e);
  void visit_cast_op (cast_op* e);
};
void
sdt_uprobe_var_expanding_visitor::build_dwarf_registers ()
{
  
#define DRI(name,num,width)  dwarf_regs[name]=make_pair(num,width)
  if (elf_machine == EM_X86_64) {
    DRI ("%rax", 0, DI); DRI ("%eax", 0, SI); DRI ("%ax", 0, HI);
       DRI ("%al", 0, QI); DRI ("%ah", 0, QIh);
    DRI ("%rdx", 1, DI); DRI ("%edx", 1, SI); DRI ("%dx", 1, HI);
       DRI ("%dl", 1, QI); DRI ("%dh", 1, QIh);
    DRI ("%rcx", 2, DI); DRI ("%ecx", 2, SI); DRI ("%cx", 2, HI);
       DRI ("%cl", 2, QI); DRI ("%ch", 2, QIh);
    DRI ("%rbx", 3, DI); DRI ("%ebx", 3, SI); DRI ("%bx", 3, HI);
       DRI ("%bl", 3, QI); DRI ("%bh", 3, QIh);
    DRI ("%rsi", 4, DI); DRI ("%esi", 4, SI); DRI ("%si", 4, HI);
       DRI ("%sil", 4, QI);
    DRI ("%rdi", 5, DI); DRI ("%edi", 5, SI); DRI ("%di", 5, HI);
       DRI ("%dil", 5, QI);
    DRI ("%rbp", 6, DI); DRI ("%ebp", 6, SI); DRI ("%bp", 6, HI);
       DRI ("%bpl", 6, QI);
    DRI ("%rsp", 7, DI); DRI ("%esp", 7, SI); DRI ("%sp", 7, HI);
       DRI ("%spl", 7, QI);
    DRI ("%r8", 8, DI); DRI ("%r8d", 8, SI); DRI ("%r8w", 8, HI);
       DRI ("%r8b", 8, QI);
    DRI ("%r9", 9, DI); DRI ("%r9d", 9, SI); DRI ("%r9w", 9, HI);
       DRI ("%r9b", 9, QI);
    DRI ("%r10", 10, DI); DRI ("%r10d", 10, SI); DRI ("%r10w", 10, HI);
       DRI ("%r10b", 10, QI);
    DRI ("%r11", 11, DI); DRI ("%r11d", 11, SI); DRI ("%r11w", 11, HI);
       DRI ("%r11b", 11, QI);
    DRI ("%r12", 12, DI); DRI ("%r12d", 12, SI); DRI ("%r12w", 12, HI);
       DRI ("%r12b", 12, QI);
    DRI ("%r13", 13, DI); DRI ("%r13d", 13, SI); DRI ("%r13w", 13, HI);
       DRI ("%r13b", 13, QI);
    DRI ("%r14", 14, DI); DRI ("%r14d", 14, SI); DRI ("%r14w", 14, HI);
       DRI ("%r14b", 14, QI);
    DRI ("%r15", 15, DI); DRI ("%r15d", 15, SI); DRI ("%r15w", 15, HI);
       DRI ("%r15b", 15, QI);
    DRI ("%rip", 16, DI); DRI ("%eip", 16, SI); DRI ("%ip", 16, HI);
  } else if (elf_machine == EM_386) {
    DRI ("%eax", 0, SI); DRI ("%ax", 0, HI); DRI ("%al", 0, QI);
       DRI ("%ah", 0, QIh);
    DRI ("%ecx", 1, SI); DRI ("%cx", 1, HI); DRI ("%cl", 1, QI);
       DRI ("%ch", 1, QIh);
    DRI ("%edx", 2, SI); DRI ("%dx", 2, HI); DRI ("%dl", 2, QI);
       DRI ("%dh", 2, QIh);
    DRI ("%ebx", 3, SI); DRI ("%bx", 3, HI); DRI ("%bl", 3, QI);
       DRI ("%bh", 3, QIh);
    DRI ("%esp", 4, SI); DRI ("%sp", 4, HI);
    DRI ("%ebp", 5, SI); DRI ("%bp", 5, HI);
    DRI ("%esi", 6, SI); DRI ("%si", 6, HI); DRI ("%sil", 6, QI);
    DRI ("%edi", 7, SI); DRI ("%di", 7, HI); DRI ("%dil", 7, QI);
  } else if (elf_machine == EM_PPC || elf_machine == EM_PPC64) {
    DRI ("%r0", 0, DI);
    DRI ("%r1", 1, DI);
    DRI ("%r2", 2, DI);
    DRI ("%r3", 3, DI);
    DRI ("%r4", 4, DI);
    DRI ("%r5", 5, DI);
    DRI ("%r6", 6, DI);
    DRI ("%r7", 7, DI);
    DRI ("%r8", 8, DI);
    DRI ("%r9", 9, DI);
    DRI ("%r10", 10, DI);
    DRI ("%r11", 11, DI);
    DRI ("%r12", 12, DI);
    DRI ("%r13", 13, DI);
    DRI ("%r14", 14, DI);
    DRI ("%r15", 15, DI);
    DRI ("%r16", 16, DI);
    DRI ("%r17", 17, DI);
    DRI ("%r18", 18, DI);
    DRI ("%r19", 19, DI);
    DRI ("%r20", 20, DI);
    DRI ("%r21", 21, DI);
    DRI ("%r22", 22, DI);
    DRI ("%r23", 23, DI);
    DRI ("%r24", 24, DI);
    DRI ("%r25", 25, DI);
    DRI ("%r26", 26, DI);
    DRI ("%r27", 27, DI);
    DRI ("%r28", 28, DI);
    DRI ("%r29", 29, DI);
    DRI ("%r30", 30, DI);
    DRI ("%r31", 31, DI);
        DRI ("0", 0, DI);
    DRI ("1", 1, DI);
    DRI ("2", 2, DI);
    DRI ("3", 3, DI);
    DRI ("4", 4, DI);
    DRI ("5", 5, DI);
    DRI ("6", 6, DI);
    DRI ("7", 7, DI);
    DRI ("8", 8, DI);
    DRI ("9", 9, DI);
    DRI ("10", 10, DI);
    DRI ("11", 11, DI);
    DRI ("12", 12, DI);
    DRI ("13", 13, DI);
    DRI ("14", 14, DI);
    DRI ("15", 15, DI);
    DRI ("16", 16, DI);
    DRI ("17", 17, DI);
    DRI ("18", 18, DI);
    DRI ("19", 19, DI);
    DRI ("20", 20, DI);
    DRI ("21", 21, DI);
    DRI ("22", 22, DI);
    DRI ("23", 23, DI);
    DRI ("24", 24, DI);
    DRI ("25", 25, DI);
    DRI ("26", 26, DI);
    DRI ("27", 27, DI);
    DRI ("28", 28, DI);
    DRI ("29", 29, DI);
    DRI ("30", 30, DI);
    DRI ("31", 31, DI);
  } else if (elf_machine == EM_S390) {
    DRI ("%r0", 0, DI);
    DRI ("%r1", 1, DI);
    DRI ("%r2", 2, DI);
    DRI ("%r3", 3, DI);
    DRI ("%r4", 4, DI);
    DRI ("%r5", 5, DI);
    DRI ("%r6", 6, DI);
    DRI ("%r7", 7, DI);
    DRI ("%r8", 8, DI);
    DRI ("%r9", 9, DI);
    DRI ("%r10", 10, DI);
    DRI ("%r11", 11, DI);
    DRI ("%r12", 12, DI);
    DRI ("%r13", 13, DI);
    DRI ("%r14", 14, DI);
    DRI ("%r15", 15, DI);
  } else if (elf_machine == EM_ARM) {
    DRI ("r0", 0, SI);
    DRI ("r1", 1, SI);
    DRI ("r2", 2, SI);
    DRI ("r3", 3, SI);
    DRI ("r4", 4, SI);
    DRI ("r5", 5, SI);
    DRI ("r6", 6, SI);
    DRI ("r7", 7, SI);
    DRI ("r8", 8, SI);
    DRI ("r9", 9, SI);
    DRI ("r10", 10, SI); DRI ("sl", 10, SI);
    DRI ("fp", 11, SI);
    DRI ("ip", 12, SI);
    DRI ("sp", 13, SI);
    DRI ("lr", 14, SI);
    DRI ("pc", 15, SI);
  } else if (elf_machine == EM_AARCH64) {
    DRI ("x0", 0, DI); DRI ("w0", 0, SI);
    DRI ("x1", 1, DI); DRI ("w1", 1, SI);
    DRI ("x2", 2, DI); DRI ("w2", 2, SI);
    DRI ("x3", 3, DI); DRI ("w3", 3, SI);
    DRI ("x4", 4, DI); DRI ("w4", 4, SI);
    DRI ("x5", 5, DI); DRI ("w5", 5, SI);
    DRI ("x6", 6, DI); DRI ("w6", 6, SI);
    DRI ("x7", 7, DI); DRI ("w7", 7, SI);
    DRI ("x8", 8, DI); DRI ("w8", 8, SI);
    DRI ("x9", 9, DI); DRI ("w9", 9, SI);
    DRI ("x10", 10, DI); DRI ("w10", 10, SI);
    DRI ("x11", 11, DI); DRI ("w11", 11, SI);
    DRI ("x12", 12, DI); DRI ("w12", 12, SI);
    DRI ("x13", 13, DI); DRI ("w13", 13, SI);
    DRI ("x14", 14, DI); DRI ("w14", 14, SI);
    DRI ("x15", 15, DI); DRI ("w15", 15, SI);
    DRI ("x16", 16, DI); DRI ("w16", 16, SI);
    DRI ("x17", 17, DI); DRI ("w17", 17, SI);
    DRI ("x18", 18, DI); DRI ("w18", 18, SI);
    DRI ("x19", 19, DI); DRI ("w19", 19, SI);
    DRI ("x20", 20, DI); DRI ("w20", 20, SI);
    DRI ("x21", 21, DI); DRI ("w21", 21, SI);
    DRI ("x22", 22, DI); DRI ("w22", 22, SI);
    DRI ("x23", 23, DI); DRI ("w23", 23, SI);
    DRI ("x24", 24, DI); DRI ("w24", 24, SI);
    DRI ("x25", 25, DI); DRI ("w25", 25, SI);
    DRI ("x26", 26, DI); DRI ("w26", 26, SI);
    DRI ("x27", 27, DI); DRI ("w27", 27, SI);
    DRI ("x28", 28, DI); DRI ("w28", 28, SI);
    DRI ("x29", 29, DI); DRI ("w29", 29, SI);
    DRI ("x30", 30, DI); DRI ("w30", 30, SI);
    DRI ("sp", 31, DI);
  } else if (arg_count) {
      }
#undef DRI
        map<string,pair<unsigned,int> >::const_iterator ri;
  for (ri = dwarf_regs.begin(); ri != dwarf_regs.end(); ri++)
    {
      string regname = ri->first;
      assert (regname != "");
      regnames += string("|")+regname;
      if (regname[0]=='%')
        percent_regnames += string("|")+regname;
    }
    if (regnames != "")
    regnames = regnames.substr(1);
  if (percent_regnames != "")
    percent_regnames = percent_regnames.substr(1);
}
void
sdt_uprobe_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
{
  if (e->addressof)
    throw SEMANTIC_ERROR(_("cannot take address of context variable"), e->tok);
  if (e->name == "$$name")
    {
      literal_string *myname = new literal_string (probe_name);
      myname->tok = e->tok;
      provide(myname);
      return;
    }
  else if (e->name == "$$provider")
    {
      literal_string *myname = new literal_string (provider_name);
      myname->tok = e->tok;
      provide(myname);
      return;
    }
  else if (e->name == "$$vars" || e->name == "$$parms")
    {
      e->assert_no_components("sdt", true);
      
      print_format* pf = print_format::create(e->tok, "sprintf");
      for (unsigned i = 1; i <= arg_count; ++i)
        {
          if (i > 1)
            pf->raw_components += " ";
          target_symbol *tsym = new target_symbol;
          tsym->tok = e->tok;
          tsym->name = "$arg" + lex_cast(i);
          pf->raw_components += tsym->name;
          tsym->components = e->components;
          expression *texp = require<expression> (tsym);
          if (e->check_pretty_print ())
            pf->raw_components += "=%s";
          else
            pf->raw_components += "=%#x";
          pf->args.push_back(texp);
        }
      pf->components = print_format::string_to_components(pf->raw_components);
      provide (pf);
    }
  else
    assert(0); }
unsigned
sdt_uprobe_var_expanding_visitor::get_target_symbol_argno_and_validate (target_symbol *e)
{
    unsigned argno = 0;
  if (startswith(e->name, "$arg"))
    {
      try
        {
          argno = lex_cast<unsigned>(e->name.substr(4));
        }
      catch (const runtime_error& f)
        {
                    argno = 0;
        }
    }
    if (arg_count == 0 ||       argno < 1 || argno > arg_count)     {
                                    need_debug_info = true;
      throw SEMANTIC_ERROR(_("target-symbol requires debuginfo"), e->tok);
    }
  assert (arg_tokens.size() >= argno);
  return argno;
}
long
sdt_uprobe_var_expanding_visitor::parse_out_arg_precision(string& asmarg)
{
  long precision;
  if (asmarg.find('@') != string::npos)
    {
      precision = lex_cast<int>(asmarg.substr(0, asmarg.find('@')));
      asmarg = asmarg.substr(asmarg.find('@')+1);
    }
  else
    {
                  if (probe_type == uprobe3_type)
        precision = sizeof(long);       else
        precision = -sizeof(long);
    }
  return precision;
}
expression*
sdt_uprobe_var_expanding_visitor::try_parse_arg_literal (target_symbol *e,
                                                         const string& asmarg,
                                                         long precision)
{
  expression *argexpr = NULL;
    XXX
              vector<string> matches;
  if (!regexp_match (asmarg, "^[i\\$#][-]?[0-9][0-9]*$", matches))
    {
      string sn = matches[0].substr(1);
      int64_t n;
                              switch (precision)
        {
        case -1: n = lex_cast<  int8_t>(sn); break;
        case  1: n = lex_cast< uint8_t>(sn); break;
        case -2: n = lex_cast< int16_t>(sn); break;
        case  2: n = lex_cast<uint16_t>(sn); break;
        case -4: n = lex_cast< int32_t>(sn); break;
        case  4: n = lex_cast<uint32_t>(sn); break;
        default:
        case -8: n = lex_cast< int64_t>(sn); break;
        case  8: n = lex_cast<uint64_t>(sn); break;
        }
      literal_number* ln = new literal_number(n);
      ln->tok = e->tok;
      argexpr = ln;
    }
  return argexpr;
}
expression*
sdt_uprobe_var_expanding_visitor::try_parse_arg_register (target_symbol *e,
                                                          const string& asmarg,
                                                          long precision)
{
  expression *argexpr = NULL;
      string regexp;
  if (elf_machine == EM_PPC || elf_machine == EM_PPC64
     || elf_machine == EM_ARM || elf_machine == EM_AARCH64)
    regexp = "^(" + regnames + ")$";
  else
    regexp = "^(" + percent_regnames + ")$";
  vector<string> matches;
  if (!regexp_match(asmarg, regexp, matches))
    {
      string regname = matches[1];
      map<string,pair<unsigned,int> >::iterator ri = dwarf_regs.find (regname);
      if (ri != dwarf_regs.end())         {
          embedded_expr *get_arg1 = new embedded_expr;
          string width_adjust;
          switch (ri->second.second)
            {
            case QI: width_adjust = ") & 0xff)"; break;
            case QIh: width_adjust = ">>8) & 0xff)"; break;
            case HI:
                            width_adjust = ") & 0xffff)";
              if (precision < 0)
                width_adjust += " << 48 >> 48";
              break;
            case SI:
                            width_adjust = ") & 0xffffffff)";
              if (precision < 0)
                width_adjust += " << 32 >> 32";
              break;
            default: width_adjust = "))";
            }
          string type = "";
          if (probe_type == uprobe3_type)
            type = (precision < 0
                    ? "(int" : "(uint") + lex_cast(abs(precision) * 8) + "_t)";
          type = type + "((";
          get_arg1->tok = e->tok;
          get_arg1->code = string("/* unprivileged */ /* pure */")
            + string(" ((int64_t)") + type
            + string("u_fetch_register(")
            + lex_cast(dwarf_regs[regname].first) + string("))")
            + width_adjust;
          argexpr = get_arg1;
        }
    }
  return argexpr;
}
static string
precision_to_function(long precision)
{
  switch (precision)
    {
    case 1: case -1:
      return "user_int8";
    case 2:
      return "user_uint16";
    case -2:
      return "user_int16";
    case 4:
      return "user_uint32";
    case -4:
      return "user_int32";
    case 8: case -8:
      return "user_int64";
    default:
      return "user_long";
    }
}
expression*
sdt_uprobe_var_expanding_visitor::try_parse_arg_offset_register (target_symbol *e,
                                                                 const string& asmarg,
                                                                 long precision)
{
  expression *argexpr = NULL;
        
  string regexp;
  int reg, offset1;
  if (elf_machine == EM_ARM || elf_machine == EM_AARCH64)
    {
      regexp = "^\\[(" + regnames + ")(,[ ]*[#]?([+-]?[0-9]+)([+-][0-9]*)?([+-][0-9]*)?)?\\]$";
      reg = 1;
      offset1 = 3;
    }
  else
    {
      regexp = "^([+-]?[0-9]*)([+-][0-9]*)?([+-][0-9]*)?[(](" + regnames + ")[)]$";
      reg = 4;
      offset1 = 1;
    }
  vector<string> matches;
  if (!regexp_match(asmarg, regexp, matches))
    {
      string regname;
      int64_t disp = 0;
      if (matches[reg].length())
        regname = matches[reg];
      if (dwarf_regs.find (regname) == dwarf_regs.end())
        throw SEMANTIC_ERROR(_F("unrecognized register '%s'", regname.c_str()));
      for (int i=offset1; i <= (offset1 + 2); i++)
        if (matches[i].length())
                              disp += lex_cast<int64_t>(matches[i]);
            embedded_expr *get_arg1 = new embedded_expr;
      get_arg1->tok = e->tok;
      get_arg1->code = string("/* unprivileged */ /* pure */")
        + string("u_fetch_register(")
        + lex_cast(dwarf_regs[regname].first) + string(")");
      XXX
      literal_number* inc = new literal_number(disp);
      inc->tok = e->tok;
      binary_expression *be = new binary_expression;
      be->tok = e->tok;
      be->left = get_arg1;
      be->op = "+";
      be->right = inc;
      functioncall *fc = new functioncall;
      fc->function = precision_to_function(precision);
      fc->tok = e->tok;
      fc->args.push_back(be);
      argexpr = fc;
    }
  return argexpr;
}
expression*
sdt_uprobe_var_expanding_visitor::try_parse_arg_effective_addr (target_symbol *e,
                                                                const string& asmarg,
                                                                long precision)
{
  expression *argexpr = NULL;
        string regexp = "^([+-]?[0-9]*)([+-][0-9]*)?([+-][0-9]*)?[(](" + regnames + "),(" +
                                                                   regnames + ")(,[1248])?[)]$";
  vector<string> matches;
  if (!regexp_match(asmarg, regexp, matches))
    {
      string baseregname;
      string indexregname;
      int64_t disp = 0;
      short scale = 1;
      if (matches[6].length())
                scale = lex_cast<short>(matches[6].substr(1)); 
      if (matches[4].length())
        baseregname = matches[4];
      if (dwarf_regs.find (baseregname) == dwarf_regs.end())
        throw SEMANTIC_ERROR(_F("unrecognized base register '%s'", baseregname.c_str()));
      if (matches[5].length())
        indexregname = matches[5];
      if (dwarf_regs.find (indexregname) == dwarf_regs.end())
        throw SEMANTIC_ERROR(_F("unrecognized index register '%s'", indexregname.c_str()));
      for (int i = 1; i <= 3; i++)         if (matches[i].length())
                              disp += lex_cast<int64_t>(matches[i]);
      
      embedded_expr *get_arg1 = new embedded_expr;
      string regfn = "u_fetch_register";
      get_arg1->tok = e->tok;
      get_arg1->code = string("/* unprivileged */ /* pure */")
        + regfn + string("(")+lex_cast(dwarf_regs[baseregname].first)+string(")")
        + string("+(")
        + regfn + string("(")+lex_cast(dwarf_regs[indexregname].first)+string(")")
        + string("*")
        + lex_cast(scale)
        + string(")");
            literal_number* inc = new literal_number(disp);
      inc->tok = e->tok;
      binary_expression *be = new binary_expression;
      be->tok = e->tok;
      be->left = get_arg1;
      be->op = "+";
      be->right = inc;
      functioncall *fc = new functioncall;
      fc->function = precision_to_function(precision);
      fc->tok = e->tok;
      fc->args.push_back(be);
      argexpr = fc;
    }
  return argexpr;
}
expression*
sdt_uprobe_var_expanding_visitor::try_parse_arg_varname (target_symbol *e,
                                                         const string& asmarg,
                                                         long precision)
{
  static unsigned tick = 0;
  expression *argexpr = NULL;
        string regex = "^(([0-9]+)[+])?([a-zA-Z_][a-zA-Z0-9_]*)([+][0-9]+)?([(]("
                 + regnames + ")[)])?$";
  vector<string> matches;
  if (!regexp_match(asmarg, regex, matches))
    {
      assert(matches.size() >= 4);
      string varname = matches[3];
                        int64_t offset = 0;
      if (!matches[2].empty())
        offset += lex_cast<int64_t>(matches[2]);
      if (matches.size() >= 5 && !matches[4].empty())
        offset += lex_cast<int64_t>(matches[4]);
      string regname;
      if (matches.size() >= 7)
        regname = matches[6];
                  if (regname.empty() || (regname == "%rip" && elf_machine == EM_X86_64))
        {
          dw.mod_info->get_symtab();
          if (dw.mod_info->symtab_status != info_present)
            throw SEMANTIC_ERROR(_("can't retrieve symbol table"));
          assert(dw.mod_info->sym_table);
          map<string, Dwarf_Addr>& globals = dw.mod_info->sym_table->globals;
          map<string, Dwarf_Addr>& locals = dw.mod_info->sym_table->locals;
          Dwarf_Addr addr = 0;
                    if (locals.count(varname))
            addr = locals[varname];
          if (globals.count(varname))
            addr = globals[varname];
          if (addr)
            {
                            addr += offset;
                                          dw.get_module_dwarf(false, false);
              addr -= dw.module_bias;
              string reloc_section;
              Dwarf_Addr reloc_addr = dw.relocate_address(addr, reloc_section);
                                          
              functioncall *user_int_call = new functioncall;
              user_int_call->function = precision_to_function(precision);
              user_int_call->tok = e->tok;
              functiondecl *get_addr_decl = new functiondecl;
              get_addr_decl->tok = e->tok;
              get_addr_decl->synthetic = true;
              get_addr_decl->name = "_sdt_arg_get_addr_" + lex_cast(tick++);
              get_addr_decl->type = pe_long;
                            stringstream ss;
              ss << " /* unprivileged */ /* pure */ /* pragma:vma */" << endl;
              ss << "STAP_RETURN(_stp_umodule_relocate(";
                ss << "\"" << path_remove_sysroot(session, process_name) << "\", ";
                ss << "0x" << hex << reloc_addr << dec << ", ";
                ss << "current";
              ss << "));" << endl;
              embeddedcode *ec = new embeddedcode;
              ec->tok = e->tok;
              ec->code = ss.str();
              get_addr_decl->body = ec;
              get_addr_decl->join(session);
              functioncall *get_addr_call = new functioncall;
              get_addr_call->tok = e->tok;
              get_addr_call->function = get_addr_decl->name;
              user_int_call->args.push_back(get_addr_call);
              argexpr = user_int_call;
            }
        }
    }
  return argexpr;
}
void
sdt_uprobe_var_expanding_visitor::visit_target_symbol_arg (target_symbol *e)
{
  try
    {
      unsigned argno = get_target_symbol_argno_and_validate(e);       string asmarg = arg_tokens[argno-1];   
                                                                              
      expression* argexpr = 0; 
            long precision = parse_out_arg_precision(asmarg);
      try
        {
          if ((argexpr = try_parse_arg_literal(e, asmarg, precision)) != NULL)
            goto matched;
                    if (regnames == "")
            throw SEMANTIC_ERROR("no registers to use for parsing");
          if ((argexpr = try_parse_arg_register(e, asmarg, precision)) != NULL)
            goto matched;
          if ((argexpr = try_parse_arg_offset_register(e, asmarg, precision)) != NULL)
            goto matched;
          if ((argexpr = try_parse_arg_effective_addr(e, asmarg, precision)) != NULL)
            goto matched;
          if ((argexpr = try_parse_arg_varname(e, asmarg, precision)) != NULL)
            goto matched;
        }
      catch (const semantic_error& err)
        {
          e->chain(err);
        }
            if (! session.suppress_warnings)
        {
          if (probe_type == UPROBE3_TYPE)
            session.print_warning (_F("Can't parse SDT_V3 operand '%s' "
                                      "[man error::sdt]", asmarg.c_str()),
                                   e->tok);
          else             session.print_warning (_F("Downgrading SDT_V2 probe argument to "
                                      "dwarf, can't parse '%s' [man error::sdt]",
                                      asmarg.c_str()),
                                   e->tok);
        }
      need_debug_info = true;
      throw SEMANTIC_ERROR(_("SDT asm not understood, requires debuginfo "
                             "[man error::sdt]"), e->tok);
      
    matched:
      assert (argexpr != 0);
      if (session.verbose > 2)
                clog << _F("mapped asm operand %s to ", asmarg.c_str()) << *argexpr << endl;
      if (e->components.empty())         {
          if (e->addressof)
            throw SEMANTIC_ERROR(_("cannot take address of sdt variable"), e->tok);
          provide (argexpr);
        }
      else          {
          cast_op *cast = new cast_op;
          cast->name = "@cast";
          cast->tok = e->tok;
          cast->operand = argexpr;
          cast->components = e->components;
          cast->type_name = probe_name + "_arg" + lex_cast(argno);
          cast->module = process_name;
          cast->visit(this);
        }
    }
  catch (const semantic_error &er)
    {
      e->chain (er);
      provide (e);
    }
}
void
sdt_uprobe_var_expanding_visitor::visit_target_symbol (target_symbol* e)
{
  try
    {
      assert(e->name.size() > 0
             && (e->name[0] == '$' || e->name == "@var"));
      if (e->name == "$$name" || e->name == "$$provider" || e->name == "$$parms" || e->name == "$$vars")
        visit_target_symbol_context (e);
      else
        visit_target_symbol_arg (e);
    }
  catch (const semantic_error &er)
    {
      e->chain (er);
      provide (e);
    }
}
void
sdt_uprobe_var_expanding_visitor::visit_atvar_op (atvar_op* e)
{
  need_debug_info = true;
    if (e->module.empty())
    e->module = process_name;
  var_expanding_visitor::visit_atvar_op(e);
}
void
sdt_uprobe_var_expanding_visitor::visit_cast_op (cast_op* e)
{
    if (e->module.empty())
    e->module = process_name;
  var_expanding_visitor::visit_cast_op(e);
}
void
plt_expanding_visitor::visit_target_symbol (target_symbol *e)
{
  try
    {
      if (e->name == "$$name")
    {
      literal_string *myname = new literal_string (entry);
      myname->tok = e->tok;
      provide(myname);
      return;
    }
                  string alternatives = "$$name";
      throw SEMANTIC_ERROR(_F("unable to find plt variable '%s' (alternatives: %s)",
                              e->name.c_str(), alternatives.c_str()), e->tok);
    }
  catch (const semantic_error &er)
    {
      e->chain (er);
      provide (e);
    }
}
struct sdt_query : public base_query
{
  sdt_query(probe * base_probe, probe_point * base_loc,
            dwflpp & dw, literal_map_t const & params,
            vector<derived_probe *> & results, const string user_lib);
  void query_library (const char *data);
  set<string> visited_libraries;
  bool resolved_library;
  void query_plt (const char *entry, size_t addr) {}
  void handle_query_module();
private:
  stap_sdt_probe_type probe_type;
  enum { probe_section=0, note_section=1, unknown_section=-1 } probe_loc;
  probe * base_probe;
  probe_point * base_loc;
  literal_map_t const & params;
  vector<derived_probe *> & results;
  string pp_mark;
  string pp_provider;
  string user_lib;
  set<string> probes_handled;
  Elf_Data *pdata;
  size_t probe_scn_offset;
  size_t probe_scn_addr;
  uint64_t arg_count;
  GElf_Addr base;
  GElf_Addr pc;
  string arg_string;
  string probe_name;
  string provider_name;
  GElf_Addr semaphore_load_offset;
  Dwarf_Addr semaphore;
  bool init_probe_scn();
  bool get_next_probe();
  void iterate_over_probe_entries();
  void handle_probe_entry();
  static void setup_note_probe_entry_callback (sdt_query *me,
                                               const string& scn_name,
                                               const string& note_name,
                                               int type,
                                               const char *data,
                                               size_t len);
  void setup_note_probe_entry (const string& scn_name,
                               const string& note_name, int type,
                               const char *data, size_t len);
  void convert_probe(probe *base);
  void record_semaphore(vector<derived_probe *> & results, unsigned start);
  probe* convert_location();
  bool have_uprobe() {return probe_type == uprobe1_type || probe_type == uprobe2_type || probe_type == uprobe3_type;}
  bool have_debuginfo_uprobe(bool need_debug_info)
  {return probe_type == uprobe1_type
      || ((probe_type == uprobe2_type || probe_type == uprobe3_type)
      && need_debug_info);}
  bool have_debuginfoless_uprobe() {return probe_type == uprobe2_type || probe_type == uprobe3_type;}
};
sdt_query::sdt_query(probe * base_probe, probe_point * base_loc,
                     dwflpp & dw, literal_map_t const & params,
                     vector<derived_probe *> & results, const string user_lib):
  base_query(dw, params), resolved_library(false),
  probe_type(unknown_probe_type), probe_loc(unknown_section),
  base_probe(base_probe), base_loc(base_loc), params(params), results(results),
  user_lib(user_lib), probe_scn_offset(0), probe_scn_addr(0), arg_count(0),
  base(0), pc(0), semaphore_load_offset(0), semaphore(0)
{
  assert(get_string_param(params, TOK_MARK, pp_mark));
  get_string_param(params, TOK_PROVIDER, pp_provider); 
      size_t pos = 0;
  while (1)     {
      size_t i = pp_mark.find("-", pos);
      if (i == string::npos) break;
      pp_mark.replace (i, 1, "__");
      pos = i+1;     }
  XXX}
void
sdt_query::handle_probe_entry()
{
  if (! have_uprobe()
      && !probes_handled.insert(probe_name).second)
    return;
  if (sess.verbose > 3)
    {
                  clog << _F("matched probe_name %s probe type ", probe_name.c_str());
      switch (probe_type)
    {
    case uprobe1_type:
      clog << "uprobe1 at 0x" << hex << pc << dec << endl;
      break;
    case uprobe2_type:
      clog << "uprobe2 at 0x" << hex << pc << dec << endl;
      break;
    case uprobe3_type:
      clog << "uprobe3 at 0x" << hex << pc << dec << endl;
      break;
    default:
      clog << "unknown!" << endl;
      break;
    }
    }
    probe *new_base = convert_location();
  probe_point *new_location = new_base->locations[0];
  bool need_debug_info = false;
          Dwarf_Addr bias;
  Elf* elf = dwfl_module_getelf (dw.mod_info->mod, &bias);
    GElf_Ehdr ehdr_mem;
  GElf_Ehdr* em = gelf_getehdr (elf, &ehdr_mem);
  if (em == 0) { DWFL_ASSERT ("dwfl_getehdr", dwfl_errno()); }
  assert(em);
  int elf_machine = em->e_machine;
  sdt_uprobe_var_expanding_visitor svv (sess, dw, elf_machine, module_val,
                                        provider_name, probe_name, probe_type,
                                        arg_string, arg_count);
  svv.replace (new_base->body);
  need_debug_info = svv.need_debug_info;
  XXX  literal_map_t params;
  for (unsigned i = 0; i < new_location->components.size(); ++i)
   {
      probe_point::component *c = new_location->components[i];
      params[c->functor] = c->arg;
   }
  unsigned prior_results_size = results.size();
  dwarf_query q(new_base, new_location, dw, params, results, "", "");
  q.has_mark = true; 
      if (have_debuginfo_uprobe(need_debug_info))
    dw.iterate_over_modules<base_query>(&query_module, &q);
        if (have_debuginfoless_uprobe() && results.size() == prior_results_size)
    {
      string section;
      Dwarf_Addr reloc_addr = q.statement_num_val + bias;
      if (dwfl_module_relocations (q.dw.mod_info->mod) > 0)
        {
      dwfl_module_relocate_address (q.dw.mod_info->mod, &reloc_addr);
      section = ".dynamic";
        }
      else
    section = ".absolute";
      uprobe_derived_probe* p =
    new uprobe_derived_probe ("", "", 0,
                  path_remove_sysroot(sess,q.module_val),
                  section,
                  q.statement_num_val, reloc_addr, q, 0);
      p->saveargs (arg_count);
      results.push_back (p);
    }
  sess.unwindsym_modules.insert (dw.module_name);
  record_semaphore(results, prior_results_size);
}
void
sdt_query::handle_query_module()
{
  if (!init_probe_scn())
    return;
  if (sess.verbose > 3)
    clog << "TOK_MARK: " << pp_mark << " TOK_PROVIDER: " << pp_provider << endl;
  if (probe_loc == note_section)
    {
      GElf_Shdr shdr_mem;
      GElf_Shdr *shdr = dw.get_section (".stapsdt.base", &shdr_mem);
                              if (shdr)
    {
      base = shdr->sh_addr;
      GElf_Addr base_offset = shdr->sh_offset;
      shdr = dw.get_section (".probes", &shdr_mem);
      if (shdr)
        semaphore_load_offset =
          (shdr->sh_addr - shdr->sh_offset) - (base - base_offset);
    }
      else
    base = semaphore_load_offset = 0;
      dw.iterate_over_notes (this, &sdt_query::setup_note_probe_entry_callback);
    }
  else if (probe_loc == probe_section)
    iterate_over_probe_entries ();
}
bool
sdt_query::init_probe_scn()
{
  Elf* elf;
  GElf_Shdr shdr_mem;
  GElf_Shdr *shdr = dw.get_section (".note.stapsdt", &shdr_mem);
  if (shdr)
    {
      probe_loc = note_section;
      return true;
    }
  shdr = dw.get_section (".probes", &shdr_mem, &elf);
  if (shdr)
    {
      pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE);
      probe_scn_offset = 0;
      probe_scn_addr = shdr->sh_addr;
      assert (pdata != NULL);
      if (sess.verbose > 4)
        clog << "got .probes elf scn_addr@0x" << probe_scn_addr << ", size: "
             << pdata->d_size << endl;
      probe_loc = probe_section;
      return true;
    }
  else
    return false;
}
void
sdt_query::setup_note_probe_entry_callback (sdt_query *me,
                                            const string& scn_name,
                                            const string& note_name, int type,
                                            const char *data, size_t len)
{
  me->setup_note_probe_entry (scn_name, note_name, type, data, len);
}
void
sdt_query::setup_note_probe_entry (const string& scn_name,
                                   const string& note_name, int type,
                                   const char *data, size_t len)
{
  if (scn_name.compare(".note.stapsdt"))
    return;
#define _SDT_NOTE_NAME "stapsdt"
  if (note_name.compare(_SDT_NOTE_NAME))
    return;
#define _SDT_NOTE_TYPE 3
  if (type != _SDT_NOTE_TYPE)
    return;
    union
  {
    Elf64_Addr a64[3];
    Elf32_Addr a32[3];
  } buf;
  Dwarf_Addr bias;
  Elf* elf = (dwfl_module_getelf (dw.mod_info->mod, &bias));
  Elf_Data dst =
    {
      &buf, ELF_T_ADDR, EV_CURRENT,
      gelf_fsize (elf, ELF_T_ADDR, 3, EV_CURRENT), 0, 0
    };
  assert (dst.d_size <= sizeof buf);
  if (len < dst.d_size + 3)
    return;
  Elf_Data src =
    {
      (void *) data, ELF_T_ADDR, EV_CURRENT,
      dst.d_size, 0, 0
    };
  if (gelf_xlatetom (elf, &dst, &src,
              elf_getident (elf, NULL)[EI_DATA]) == NULL)
    printf ("gelf_xlatetom: %s", elf_errmsg (-1));
  probe_type = uprobe3_type;
  const char * provider = data + dst.d_size;
  const char *name = (const char*)memchr (provider, '\0', data + len - provider);
  if(name++ == NULL)
    return;
  const char *args = (const char*)memchr (name, '\0', data + len - name);
  if (args++ == NULL || memchr (args, '\0', data + len - name) != data + len - 1)
    return;
  provider_name = provider;
  probe_name = name;
  arg_string = args;
  dw.mod_info->marks.insert(make_pair(provider, name));
    if (! (dw.function_name_matches_pattern (probe_name, pp_mark)
     && ((pp_provider == "")
         || dw.function_name_matches_pattern (provider_name, pp_provider))))
    return;
      arg_count = count(arg_string.begin(), arg_string.end(), '@');
  if (!arg_count && !arg_string.empty())
    arg_count = 1 + count(arg_string.begin(), arg_string.end(), ' ');
  GElf_Addr base_ref;
  if (gelf_getclass (elf) == ELFCLASS32)
    {
      pc = buf.a32[0];
      base_ref = buf.a32[1];
      semaphore = buf.a32[2];
    }
  else
    {
      pc = buf.a64[0];
      base_ref = buf.a64[1];
      semaphore = buf.a64[2];
    }
  semaphore += base - base_ref;
  pc += base - base_ref;
      semaphore += bias;
  if (sess.verbose > 4)
    clog << _F(" saw .note.stapsdt %s%s ", probe_name.c_str(), (provider_name != "" ? _(" (provider ")+provider_name+") " : "").c_str()) << "@0x" << hex << pc << dec << endl;
  handle_probe_entry();
}
void
sdt_query::iterate_over_probe_entries()
{
    while (probe_scn_offset < pdata->d_size)
    {
      stap_sdt_probe_entry_v1 *pbe_v1 = (stap_sdt_probe_entry_v1 *) ((char*)pdata->d_buf + probe_scn_offset);
      stap_sdt_probe_entry_v2 *pbe_v2 = (stap_sdt_probe_entry_v2 *) ((char*)pdata->d_buf + probe_scn_offset);
      probe_type = (stap_sdt_probe_type)(pbe_v1->type_a);
      if (! have_uprobe())
    {
                        if (sess.verbose > 5)
            clog << _F("got unknown probe_type : 0x%x", probe_type) << endl;
      probe_scn_offset += sizeof(__uint32_t);
      continue;
    }
      if ((long)pbe_v1 % sizeof(__uint64_t))     {
      pbe_v1 = (stap_sdt_probe_entry_v1*)((char*)pbe_v1 - sizeof(__uint32_t));
      if (pbe_v1->type_b != uprobe1_type)
        continue;
    }
      if (probe_type == uprobe1_type)
    {
      if (pbe_v1->name == 0)         return;
      semaphore = 0;
      probe_name = (char*)((char*)pdata->d_buf + pbe_v1->name - (char*)probe_scn_addr);
          provider_name = "";       pc = pbe_v1->arg;
      arg_count = 0;
      probe_scn_offset += sizeof (stap_sdt_probe_entry_v1);
    }
      else if (probe_type == uprobe2_type)
    {
      if (pbe_v2->name == 0)         return;
      semaphore = pbe_v2->semaphore;
      probe_name = (char*)((char*)pdata->d_buf + pbe_v2->name - (char*)probe_scn_addr);
      provider_name = (char*)((char*)pdata->d_buf + pbe_v2->provider - (char*)probe_scn_addr);
      arg_count = pbe_v2->arg_count;
      pc = pbe_v2->pc;
      if (pbe_v2->arg_string)
        arg_string = (char*)((char*)pdata->d_buf + pbe_v2->arg_string - (char*)probe_scn_addr);
            probe_scn_offset = ((long)(pbe_v2->name) - (long)(probe_scn_addr)) + probe_name.length();
      probe_scn_offset += sizeof (__uint32_t) - probe_scn_offset % sizeof (__uint32_t);
    }
      if (sess.verbose > 4)
    clog << _("saw .probes ") << probe_name << (provider_name != "" ? _(" (provider ")+provider_name+") " : "")
         << "@0x" << hex << pc << dec << endl;
      dw.mod_info->marks.insert(make_pair(provider_name, probe_name));
      if (dw.function_name_matches_pattern (probe_name, pp_mark)
          && ((pp_provider == "") || dw.function_name_matches_pattern (provider_name, pp_provider)))
    handle_probe_entry ();
    }
}
void
sdt_query::record_semaphore (vector<derived_probe *> & results, unsigned start)
{
  for (unsigned i=0; i<2; i++) {
        string semaphore = (i==0 ? (provider_name+"_") : "") + probe_name + "_semaphore";
    XXX    if (sess.verbose > 2)
      clog << _F("looking for semaphore symbol %s ", semaphore.c_str());
    Dwarf_Addr addr;
    if (this->semaphore)
      addr = this->semaphore;
    else
      addr  = lookup_symbol_address(dw.module, semaphore.c_str());
    if (addr)
      {
        if (dwfl_module_relocations (dw.module) > 0)
          dwfl_module_relocate_address (dw.module, &addr);
        XXX
                        if (dw.sess.runtime_usermode_p())
          addr -= semaphore_load_offset;
        for (unsigned i = start; i < results.size(); ++i)
          results[i]->sdt_semaphore_addr = addr;
        if (sess.verbose > 2)
          clog << _(", found at 0x") << hex << addr << dec << endl;
        return;
      }
    else
      if (sess.verbose > 2)
        clog << _(", not found") << endl;
  }
}
void
sdt_query::convert_probe (probe *base)
{
  block *b = new block;
  b->tok = base->body->tok;
    functioncall *fc = new functioncall;
  fc->function = "ulong_arg";
  fc->tok = b->tok;
  literal_number* num = new literal_number(1);
  num->tok = b->tok;
  fc->args.push_back(num);
  functioncall *fcus = new functioncall;
  fcus->function = "user_string";
  fcus->type = pe_string;
  fcus->tok = b->tok;
  fcus->args.push_back(fc);
  if_statement *is = new if_statement;
  is->thenblock = new next_statement;
  is->elseblock = NULL;
  is->tok = b->tok;
  is->thenblock->tok = b->tok;
  comparison *be = new comparison;
  be->op = "!=";
  be->tok = b->tok;
  be->left = fcus;
  be->right = new literal_string(probe_name);
  be->right->tok = b->tok;
  is->condition = be;
  b->statements.push_back(is);
    b->statements.push_back(base->body);
  base->body = b;
}
probe*
sdt_query::convert_location ()
{
  string module = dw.module_name;
  if (has_process)
    module = path_remove_sysroot(sess, module);
  probe_point* specific_loc = new probe_point(*base_loc);
  specific_loc->well_formed = true;
  vector<probe_point::component*> derived_comps;
  vector<probe_point::component*>::iterator it;
  for (it = specific_loc->components.begin();
       it != specific_loc->components.end(); ++it)
    if ((*it)->functor == TOK_PROCESS)
      {
                *it = new probe_point::component(TOK_PROCESS,
                new literal_string(has_library ? path : module));
                derived_comps.push_back(*it);
      }
    else if ((*it)->functor == TOK_LIBRARY)
      {
                derived_comps.push_back(*it);
      }
    else if ((*it)->functor == TOK_PROVIDER)
      {
                *it = new probe_point::component(TOK_PROVIDER,
                                         new literal_string(provider_name));
      }
    else if ((*it)->functor == TOK_MARK)
      {
                *it = new probe_point::component(TOK_MARK,
                                         new literal_string(probe_name));
    if (sess.verbose > 3)
      switch (probe_type)
        {
        case uprobe1_type:
              clog << _("probe_type == uprobe1, use statement addr: 0x")
           << hex << pc << dec << endl;
          break;
        case uprobe2_type:
              clog << _("probe_type == uprobe2, use statement addr: 0x")
           << hex << pc << dec << endl;
            break;
        case uprobe3_type:
              clog << _("probe_type == uprobe3, use statement addr: 0x")
           << hex << pc << dec << endl;
          break;
        default:
              clog << _F("probe_type == use_uprobe_no_dwarf, use label name: _stapprobe1_%s",
                         pp_mark.c_str()) << endl;
          }
        switch (probe_type)
          {
          case uprobe1_type:
          case uprobe2_type:
          case uprobe3_type:
                        derived_comps.push_back
              (new probe_point::component(TOK_STATEMENT,
                                          new literal_number(pc, true)));
            break;
          default:                         derived_comps.push_back
              (new probe_point::component(TOK_FUNCTION,
                                          new literal_string("*")));
            derived_comps.push_back
              (new probe_point::component(TOK_LABEL,
                                          new literal_string("_stapprobe1_" + pp_mark)));
            break;
          }
      }
  probe_point* derived_loc = new probe_point(*specific_loc);
  derived_loc->components = derived_comps;
  return new probe (new probe (base_probe, specific_loc), derived_loc);
}
void
sdt_query::query_library (const char *library)
{
  visited_libraries.insert(library);
  if (query_one_library (library, dw, user_lib, base_probe, base_loc, results))
    resolved_library = true;
}
string
suggest_marks(systemtap_session& sess,
              const set<string>& modules,
              const string& mark,
              const string& provider)
{
  if (mark.empty() || modules.empty() || sess.module_cache == NULL)
    return "";
  set<string> marks;
  const map<string, module_info*> &cache = sess.module_cache->cache;
  bool dash_suggestions = (mark.find("-") != string::npos);
  for (set<string>::iterator itmod = modules.begin();
       itmod != modules.end(); ++itmod)
    {
      map<string, module_info*>::const_iterator itcache;
      if ((itcache = cache.find(*itmod)) != cache.end())
        {
          set<pair<string,string> >::const_iterator itmarks;
          for (itmarks = itcache->second->marks.begin();
               itmarks != itcache->second->marks.end(); ++itmarks)
            {
              if (provider.empty()
                                    || (fnmatch(provider.c_str(), itmarks->first.c_str(), 0) == 0))
                {
                  string marksug = itmarks->second;
                  if (dash_suggestions)
                    {
                      size_t pos = 0;
                      while (1)                         {
                          size_t i = marksug.find("__", pos);
                          if (i == string::npos) break;
                          marksug.replace (i, 2, "-");
                          pos = i+1;                         }
                    }
                  marks.insert(marksug);
                }
            }
        }
    }
  if (sess.verbose > 2)
    {
      clog << "suggesting " << marks.size() << " marks "
           << "from modules:" << endl;
      for (set<string>::iterator itmod = modules.begin();
          itmod != modules.end(); ++itmod)
        clog << *itmod << endl;
    }
  if (marks.empty())
    return "";
  return levenshtein_suggest(mark, marks, 5); }
string
suggest_plt_functions(systemtap_session& sess,
                      const set<string>& modules,
                      const string& func)
{
  if (func.empty() || modules.empty() || sess.module_cache == NULL)
    return "";
  set<string> funcs;
  const map<string, module_info*> &cache = sess.module_cache->cache;
  for (set<string>::iterator itmod = modules.begin();
       itmod != modules.end(); ++itmod)
    {
      map<string, module_info*>::const_iterator itcache;
      if ((itcache = cache.find(*itmod)) != cache.end())
        funcs.insert(itcache->second->plt_funcs.begin(),
                     itcache->second->plt_funcs.end());
    }
  if (sess.verbose > 2)
    {
      clog << "suggesting " << funcs.size() << " plt functions "
           << "from modules:" << endl;
      for (set<string>::iterator itmod = modules.begin();
          itmod != modules.end(); ++itmod)
        clog << *itmod << endl;
    }
  if (funcs.empty())
    return "";
  return levenshtein_suggest(func, funcs, 5); }
string
suggest_dwarf_functions(systemtap_session& sess,
                        const set<string>& modules,
                        string func)
{
    size_t pos = func.find('@');
  if (pos != string::npos)
    func.erase(pos);
  if (func.empty() || modules.empty() || sess.module_cache == NULL)
    return "";
    set<string> funcs;
  const map<string, module_info*> &cache = sess.module_cache->cache;
  for (set<string>::iterator itmod = modules.begin();
      itmod != modules.end(); ++itmod)
    {
      module_info *module;
            map<string, module_info*>::const_iterator itcache;
      if ((itcache = cache.find(*itmod)) != cache.end())
        module = itcache->second;
      else         continue;
            funcs.insert(module->inlined_funcs.begin(),
                   module->inlined_funcs.end());
            if (module->symtab_status != info_present || module->sym_table == NULL)
        continue;
      map<string, func_info*>& modfuncs = module->sym_table->map_by_name;
      for (map<string, func_info*>::const_iterator itfuncs = modfuncs.begin();
           itfuncs != modfuncs.end(); ++itfuncs)
        funcs.insert(itfuncs->first);
    }
  if (sess.verbose > 2)
    {
      clog << "suggesting " << funcs.size() << " dwarf functions "
           << "from modules:" << endl;
      for (set<string>::iterator itmod = modules.begin();
          itmod != modules.end(); ++itmod)
        clog << *itmod << endl;
    }
  if (funcs.empty())
    return "";
  return levenshtein_suggest(func, funcs, 5); }
void
dwarf_builder::build(systemtap_session & sess,
             probe * base,
             probe_point * location,
             literal_map_t const & parameters,
             vector<derived_probe *> & finished_results)
{
    XXX  
  dwflpp* dw = 0;
  literal_map_t filled_parameters = parameters;
  string module_name;
  int64_t proc_pid;
  if (has_null_param (parameters, TOK_KERNEL))
    {
      dw = get_kern_dw(sess, "kernel");
    }
  else if (get_param (parameters, TOK_MODULE, module_name))
    {
                  if (!is_fully_resolved(module_name, sess.sysroot, sess.sysenv))
        {
          size_t dash_pos = 0;
          while((dash_pos=module_name.find('-'))!=string::npos)
            module_name.replace(int(dash_pos),1,"_");
          filled_parameters[TOK_MODULE] = new literal_string(module_name);
        }
                  dw = get_kern_dw(sess, module_name);
    }
  else if (has_param(filled_parameters, TOK_PROCESS))
      {
        
      if(has_null_param(filled_parameters, TOK_PROCESS))
        {
          string file;
          try
            {
              file = sess.cmd_file();
            }
          catch (const semantic_error& e)
            {
              if(sess.target_pid)
                throw SEMANTIC_ERROR(_("invalid -x pid for unspecified process"
                                       " probe [man stapprobes]"), NULL, NULL, &e);
              else
                throw SEMANTIC_ERROR(_("invalid -c command for unspecified process"
                                     " probe [man stapprobes]"), NULL, NULL, &e);
            }
          if(file.empty())
            throw SEMANTIC_ERROR(_("unspecified process probe is invalid without"
                                   " a -c COMMAND or -x PID [man stapprobes]"));
          module_name = sess.sysroot + file;
          filled_parameters[TOK_PROCESS] = new literal_string(module_name);          XXX          if(location->components[0]->functor==TOK_PROCESS &&
             location->components[0]->arg == 0)
            {
              if (sess.target_pid)
                location->components[0]->arg = new literal_number(sess.target_pid);
              else
                location->components[0]->arg = new literal_string(module_name);
            }
        }
                  else if (get_param (parameters, TOK_PROCESS, module_name))
        {
          module_name = sess.sysroot + module_name;
          filled_parameters[TOK_PROCESS] = new literal_string(module_name);
        }
      else if (get_param (parameters, TOK_PROCESS, proc_pid))
        {
                    string pid_err_msg;
          if (!is_valid_pid(proc_pid, pid_err_msg))
            throw SEMANTIC_ERROR(pid_err_msg);
          string pid_path = string("/proc/") + lex_cast(proc_pid) + "/exe";
          module_name = sess.sysroot + pid_path;
          XXX          if(location->components[0]->functor==TOK_PROCESS &&
             location->components[0]->arg == 0)
            location->components[0]->arg = new literal_number(sess.target_pid);
        }
            if (contains_glob_chars (module_name))
        {
                    
          assert (location->components.size() > 0);
          assert (location->components[0]->functor == TOK_PROCESS);
          assert (location->components[0]->arg);
          literal_string* lit = dynamic_cast<literal_string*>(location->components[0]->arg);
          assert (lit);
                    glob_t the_blob;
          set<string> dupes;
          int rc = glob (module_name.c_str(), 0, NULL, & the_blob);
          if (rc)
            throw SEMANTIC_ERROR (_F("glob %s error (%s)", module_name.c_str(), lex_cast(rc).c_str() ));
          unsigned results_pre = finished_results.size();
          for (unsigned i = 0; i < the_blob.gl_pathc; ++i)
            {
              assert_no_interrupts();
              const char* globbed = the_blob.gl_pathv[i];
              struct stat st;
              if (access (globbed, X_OK) == 0
                  && stat (globbed, &st) == 0
                  && S_ISREG (st.st_mode))                 {
                                                                                          string canononicalized = resolve_path (globbed);
                  globbed = canononicalized.c_str();
                                                                        if (!dupes.insert(canononicalized).second)
                    continue;
                                    probe_point *pp = new probe_point (*location);
                  pp->from_glob = true;
                                    string eglobbed = escape_glob_chars (globbed);
                  if (sess.verbose > 1)
                    clog << _F("Expanded process(\"%s\") to process(\"%s\")",
                               module_name.c_str(), eglobbed.c_str()) << endl;
                  string eglobbed_tgt = path_remove_sysroot(sess, eglobbed);
                  probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
                                                    new literal_string (eglobbed_tgt));
                  ppc->tok = location->components[0]->tok;                   pp->components[0] = ppc;
                  probe* new_probe = new probe (base, pp);
                                    
                                                                                          
                  derive_probes (sess, new_probe, finished_results,
                                 true  );
                }
            }
          globfree (& the_blob);
          unsigned results_post = finished_results.size();
                              string func;
          if (results_pre == results_post
              && get_param(filled_parameters, TOK_FUNCTION, func)
              && !func.empty())
            {
              string sugs = suggest_dwarf_functions(sess, modules_seen, func);
              modules_seen.clear();
              if (!sugs.empty())
                throw SEMANTIC_ERROR (_NF("no match (similar function: %s)",
                                          "no match (similar functions: %s)",
                                          sugs.find(',') == string::npos,
                                          sugs.c_str()));
            }
          else if (results_pre == results_post
                   && get_param(filled_parameters, TOK_PLT, func)
                   && !func.empty())
            {
              string sugs = suggest_plt_functions(sess, modules_seen, func);
              modules_seen.clear();
              if (!sugs.empty())
                throw SEMANTIC_ERROR (_NF("no match (similar function: %s)",
                                          "no match (similar functions: %s)",
                                          sugs.find(',') == string::npos,
                                          sugs.c_str()));
            }
          else if (results_pre == results_post
                   && get_param(filled_parameters, TOK_MARK, func)
                   && !func.empty())
            {
              string provider;
              get_param(filled_parameters, TOK_PROVIDER, provider);
              string sugs = suggest_marks(sess, modules_seen, func, provider);
              modules_seen.clear();
              if (!sugs.empty())
                throw SEMANTIC_ERROR (_NF("no match (similar mark: %s)",
                                          "no match (similar marks: %s)",
                                          sugs.find(',') == string::npos,
                                          sugs.c_str()));
            }
          return;         }
            module_name = unescape_glob_chars (module_name);
      user_path = find_executable (module_name, "", sess.sysenv);       if (!is_fully_resolved(user_path, "", sess.sysenv))
        throw SEMANTIC_ERROR(_F("cannot find executable '%s'",
                                user_path.c_str()));
            {
         ifstream script_file (user_path.c_str () );
         if (script_file.good ())
         {
           string line;
           getline (script_file, line);
           if (line.compare (0, 2, "#!") == 0)
           {
              string path_head = line.substr(2);
                            size_t p2 = path_head.find_first_not_of(" \t");
              if (p2 != string::npos)
              {
                string path = path_head.substr(p2);
                                p2 = path.find_last_not_of(" \t\n");
                if (string::npos != p2)
                  path.erase(p2+1);
                                size_t offset = 0;
                if (path.compare(0, sizeof("/bin/env")-1, "/bin/env") == 0)
                {
                  offset = sizeof("/bin/env")-1;
                }
                else if (path.compare(0, sizeof("/usr/bin/env")-1, "/usr/bin/env") == 0)
                {
                  offset = sizeof("/usr/bin/env")-1;
                }
                if (offset != 0)
                {
                    size_t p3 = path.find_first_not_of(" \t", offset);
                    if (p3 != string::npos)
                    {
                       string env_path = path.substr(p3);
                       user_path = find_executable (env_path, sess.sysroot,
                                                    sess.sysenv);
                    }
                }
                else
                {
                  user_path = find_executable (path, sess.sysroot, sess.sysenv);
                }
                struct stat st;
                if (access (user_path.c_str(), X_OK) == 0
                  && stat (user_path.c_str(), &st) == 0
                  && S_ISREG (st.st_mode))                 {
                  if (sess.verbose > 1)
                    clog << _F("Expanded process(\"%s\") to process(\"%s\")",
                               module_name.c_str(), user_path.c_str()) << endl;
                  assert (location->components.size() > 0);
                  assert (location->components[0]->functor == TOK_PROCESS);
                  assert (location->components[0]->arg);
                  literal_string* lit = dynamic_cast<literal_string*>(location->components[0]->arg);
                  assert (lit);
                                    probe_point *pp = new probe_point (*location);
                  string user_path_tgt = path_remove_sysroot(sess, user_path);
                  probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
                                                                            new literal_string (user_path_tgt.c_str()));
                  ppc->tok = location->components[0]->tok;                   pp->components[0] = ppc;
                  probe* new_probe = new probe (base, pp);
                  derive_probes (sess, new_probe, finished_results);
                  script_file.close();
                  return;
                }
              }
           }
         }
         script_file.close();
      }
                              if (get_param (parameters, TOK_LIBRARY, user_lib) && !user_lib.empty()
          && is_fully_resolved(user_lib, sess.sysroot, sess.sysenv, "LD_LIBRARY_PATH"))
        module_name = user_lib;
      else
        module_name = user_path; 
            if (has_null_param(parameters, TOK_RETURN) && !sess.runtime_usermode_p())
        {
          if (kernel_supports_inode_uprobes(sess) &&
              !kernel_supports_inode_uretprobes(sess))
            throw SEMANTIC_ERROR
              (_("process return probes not available [man error::inode-uprobes]"));
        }
                              if (!sess.runtime_usermode_p())
        check_process_probe_kernel_support(sess);
                  dw = get_user_dw(sess, module_name);
    }
  assert(dw);
  unsigned results_pre = finished_results.size();
  if (sess.verbose > 3)
    clog << _F("dwarf_builder::build for %s", module_name.c_str()) << endl;
  string dummy_mark_name;   if (get_param(parameters, TOK_MARK, dummy_mark_name))
    {
      sdt_query sdtq(base, location, *dw, filled_parameters, finished_results, user_lib);
      dw->iterate_over_modules<base_query>(&query_module, &sdtq);
            modules_seen.insert(sdtq.visited_modules.begin(),
                          sdtq.visited_modules.end());
      string lib;
      if (results_pre == finished_results.size() && !sdtq.resolved_library
          && get_param(filled_parameters, TOK_LIBRARY, lib)
          && !lib.empty() && !sdtq.visited_libraries.empty())
        {
                              string resolved_lib = find_executable(lib, sess.sysroot, sess.sysenv,
                                                "LD_LIBRARY_PATH");
          if (resolved_lib.find('/') != string::npos)
            {
              probe *new_base = build_library_probe(*dw, resolved_lib,
                                                    base, location);
              derive_probes(sess, new_base, finished_results);
              sess.print_warning(_F("'%s' is not a needed library of '%s'. "
                                    "Specify the full path to squelch this warning.",
                                    resolved_lib.c_str(), dw->module_name.c_str()));
              return;
            }
                    string sugs = levenshtein_suggest(lib, sdtq.visited_libraries, 5);
          if (!sugs.empty())
            throw SEMANTIC_ERROR (_NF("no match (similar library: %s)",
                                      "no match (similar libraries: %s)",
                                      sugs.find(',') == string::npos,
                                      sugs.c_str()));
        }
            if (results_pre == finished_results.size() && !location->from_glob)
        {
          string provider;
          get_param(filled_parameters, TOK_PROVIDER, provider);
          string sugs = suggest_marks(sess, modules_seen, dummy_mark_name, provider);
          modules_seen.clear();
          if (!sugs.empty())
            throw SEMANTIC_ERROR (_NF("no match (similar mark: %s)",
                                      "no match (similar marks: %s)",
                                      sugs.find(',') == string::npos,
                                      sugs.c_str()));
        }
      return;
    }
  dwarf_query q(base, location, *dw, filled_parameters, finished_results, user_path, user_lib);
  XXX    if (q.has_kernel && q.has_absolute)
    {
            if (! q.base_probe->privileged)
        {
          throw SEMANTIC_ERROR (_("absolute statement probe in unprivileged script; need stap -g"),
                                q.base_probe->tok);
        }
                        dwarf_derived_probe* p =
        new dwarf_derived_probe ("", "", 0, "kernel", "",
                                 q.statement_num_val, q.statement_num_val,
                                 q, 0);
      finished_results.push_back (p);
      sess.unwindsym_modules.insert ("kernel");
      return;
    }
  dw->iterate_over_modules<base_query>(&query_module, &q);
    modules_seen.insert(q.visited_modules.begin(),
                      q.visited_modules.end());
      unsigned i_n_r = q.inlined_non_returnable.size();
  unsigned results_post = finished_results.size();
  if (i_n_r > 0)
    {
      if ((results_pre == results_post) && (! sess.suppress_warnings))         {
          string quicklist;
          for (set<string>::iterator it = q.inlined_non_returnable.begin();
               it != q.inlined_non_returnable.end();
               it++)
            {
              quicklist += " " + (*it);
              if (quicklist.size() > 80)                 {
                  quicklist += " ...";
                  break;
                }
            }
          sess.print_warning (_NF("cannot probe .return of %u inlined function %s",
                                          "cannot probe .return of %u inlined functions %s",
                                           quicklist.size(), i_n_r, quicklist.c_str()));
                  }
      if (sess.verbose > 1)
        clog << _NF("skipped .return probe of %u inlined function",
                            "skipped .return probe of %u inlined functions", i_n_r, i_n_r) << endl;
      if ((sess.verbose > 3) || (sess.verbose > 2 && results_pre == results_post))         {
          for (set<string>::iterator it = q.inlined_non_returnable.begin();
               it != q.inlined_non_returnable.end();
               it++)
            clog << (*it) << " ";
          clog << endl;
        }
    } 
  string lib;
  if (results_pre == results_post && !q.resolved_library
      && get_param(filled_parameters, TOK_LIBRARY, lib)
      && !lib.empty() && !q.visited_libraries.empty())
    {
                  string resolved_lib = find_executable(lib, sess.sysroot, sess.sysenv,
                                            "LD_LIBRARY_PATH");
      if (resolved_lib.find('/') != string::npos)
        {
          probe *new_base = build_library_probe(*dw, resolved_lib,
                                                base, location);
          derive_probes(sess, new_base, finished_results);
          sess.print_warning(_F("'%s' is not a needed library of '%s'. "
                                "Specify the full path to squelch this warning.",
                                resolved_lib.c_str(), dw->module_name.c_str()));
          return;
        }
            string sugs = levenshtein_suggest(lib, q.visited_libraries, 5);
      if (!sugs.empty())
        throw SEMANTIC_ERROR (_NF("no match (similar library: %s)",
                                  "no match (similar libraries: %s)",
                                  sugs.find(',') == string::npos,
                                  sugs.c_str()));
    }
            string func;
  if (results_pre == results_post && !location->from_glob
      && get_param(filled_parameters, TOK_FUNCTION, func)
      && !func.empty())
    {
      string sugs = suggest_dwarf_functions(sess, modules_seen, func);
      modules_seen.clear();
      if (!sugs.empty())
        throw SEMANTIC_ERROR (_NF("no match (similar function: %s)",
                                  "no match (similar functions: %s)",
                                  sugs.find(',') == string::npos,
                                  sugs.c_str()));
    }
  else if (results_pre == results_post && !location->from_glob
           && get_param(filled_parameters, TOK_PLT, func)
           && !func.empty())
    {
      string sugs = suggest_plt_functions(sess, modules_seen, func);
      modules_seen.clear();
      if (!sugs.empty())
        throw SEMANTIC_ERROR (_NF("no match (similar function: %s)",
                                  "no match (similar functions: %s)",
                                  sugs.find(',') == string::npos,
                                  sugs.c_str()));
    }
  else if (results_pre != results_post)
        modules_seen.clear();
}
symbol_table::~symbol_table()
{
  delete_map(map_by_addr);
}
void
symbol_table::add_symbol(const char *name, bool weak, bool descriptor,
                         Dwarf_Addr addr, Dwarf_Addr* )
{
#ifdef __powerpc__
    if (name[0] == '.')
    name++;
#endif
  func_info *fi = new func_info();
  fi->addr = addr;
  fi->name = name;
  fi->weak = weak;
  fi->descriptor = descriptor;
  map_by_name[fi->name] = fi;
  TODO    map_by_addr.insert(make_pair(addr, fi));
}
void
symbol_table::prepare_section_rejection(Dwfl_Module *mod __attribute__ ((unused)))
{
#ifdef __powerpc__
    opd_section = SHN_UNDEF;
  Dwarf_Addr bias;
  Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias))
                                    ?: dwfl_module_getelf (mod, &bias));
  Elf_Scn* scn = 0;
  size_t shstrndx;
  if (!elf)
    return;
  if (elf_getshdrstrndx (elf, &shstrndx) != 0)
    return;
  while ((scn = elf_nextscn(elf, scn)) != NULL)
    {
      GElf_Shdr shdr_mem;
      GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
      if (!shdr)
        continue;
      const char *name = elf_strptr(elf, shstrndx, shdr->sh_name);
      if (!strcmp(name, ".opd"))
        {
          opd_section = elf_ndxscn(scn);
          return;
        }
    }
#endif
}
bool
symbol_table::reject_section(GElf_Word section)
{
  if (section == SHN_UNDEF)
    return true;
#ifdef __powerpc__
  if (section == opd_section)
    return true;
#endif
  return false;
}
enum info_status
symbol_table::get_from_elf()
{
  Dwarf_Addr high_addr = 0;
  Dwfl_Module *mod = mod_info->mod;
  int syments = dwfl_module_getsymtab(mod);
  assert(syments);
  prepare_section_rejection(mod);
  for (int i = 1; i < syments; ++i)
    {
      GElf_Sym sym;
      GElf_Word section;
      const char *name;
      GElf_Addr addr;
      bool reject;
#if _ELFUTILS_PREREQ (0, 158)
      name = dwfl_module_getsym_info (mod, i, &sym, &addr, §ion,
                      NULL, NULL);
      reject = section == SHN_UNDEF;
#else
      name = dwfl_module_getsym (mod, i, &sym, §ion);
      addr = sym.st_value;
      reject = reject_section(section);
#endif
      if (name && GELF_ST_TYPE(sym.st_info) == STT_FUNC)
        add_symbol(name, (GELF_ST_BIND(sym.st_info) == STB_WEAK),
                   reject, addr, &high_addr);
      if (name && GELF_ST_TYPE(sym.st_info) == STT_OBJECT
               && GELF_ST_BIND(sym.st_info) == STB_GLOBAL)
        globals[name] = addr;
      if (name && GELF_ST_TYPE(sym.st_info) == STT_OBJECT
               && GELF_ST_BIND(sym.st_info) == STB_LOCAL)
        locals[name] = addr;
    }
  return info_present;
}
func_info *
symbol_table::get_func_containing_address(Dwarf_Addr addr)
{
  iterator_t iter = map_by_addr.upper_bound(addr);
  if (iter == map_by_addr.begin())
    return NULL;
  else
    return (--iter)->second;
}
func_info *
symbol_table::get_first_func()
{
  iterator_t iter = map_by_addr.begin();
  return (iter)->second;
}
func_info *
symbol_table::lookup_symbol(const string& name)
{
  map<string, func_info*>::iterator i = map_by_name.find(name);
  if (i == map_by_name.end())
    return NULL;
  return i->second;
}
Dwarf_Addr
symbol_table::lookup_symbol_address(const string& name)
{
  func_info *fi = lookup_symbol(name);
  if (fi)
    return fi->addr;
  return 0;
}
TODOvoid
symbol_table::purge_syscall_stubs()
{
  Dwarf_Addr stub_addr = lookup_symbol_address("sys_ni_syscall");
  if (stub_addr == 0)
    return;
  range_t purge_range = map_by_addr.equal_range(stub_addr);
  for (iterator_t iter = purge_range.first;
       iter != purge_range.second;
       )
    {
      func_info *fi = iter->second;
      if (fi->weak && fi->name != "sys_ni_syscall")
        {
          map_by_name.erase(fi->name);
          map_by_addr.erase(iter++);
          delete fi;
        }
      else
        iter++;
    }
}
void
module_info::get_symtab()
{
  if (symtab_status != info_unknown)
    return;
  sym_table = new symbol_table(this);
  if (!elf_path.empty())
    {
      symtab_status = sym_table->get_from_elf();
    }
  else
    {
      assert(name == TOK_KERNEL);
      symtab_status = info_absent;
      cerr << _("Error: Cannot find vmlinux.") << endl;;
    }
  if (symtab_status == info_absent)
    {
      delete sym_table;
      sym_table = NULL;
      return;
    }
  if (name == TOK_KERNEL)
    sym_table->purge_syscall_stubs();
}
void
module_info::update_symtab(cu_function_cache_t *funcs)
{
  if (!sym_table)
    return;
  cu_function_cache_t new_funcs;
  for (cu_function_cache_t::iterator func = funcs->begin();
       func != funcs->end(); func++)
    {
            if (dwarf_func_inline(&func->second) != 0)
        {
          inlined_funcs.insert(func->first);
          continue;
        }
      XXX                  
      func_info *fi = sym_table->lookup_symbol(func->first);
      if (!fi)
        continue;
            symbol_table::range_t er = sym_table->map_by_addr.equal_range(fi->addr);
      for (symbol_table::iterator_t it = er.first; it != er.second; ++it)
        {
                    it->second->die = func->second;
                              if (it->second != fi)
            new_funcs.insert(make_pair(it->second->name, it->second->die));
        }
    }
      funcs->insert(new_funcs.begin(), new_funcs.end());
}
module_info::~module_info()
{
  if (sym_table)
    delete sym_table;
}
struct uprobe_derived_probe_group: public generic_dpg<uprobe_derived_probe>
{
private:
  string make_pbm_key (uprobe_derived_probe* p) {
    return p->path + "|" + p->module + "|" + p->section + "|" + lex_cast(p->pid);
  }
  void emit_module_maxuprobes (systemtap_session& s);
    void emit_module_utrace_decls (systemtap_session& s);
  void emit_module_utrace_init (systemtap_session& s);
  void emit_module_utrace_exit (systemtap_session& s);
    void emit_module_inode_decls (systemtap_session& s);
  void emit_module_inode_init (systemtap_session& s);
  void emit_module_inode_refresh (systemtap_session& s);
  void emit_module_inode_exit (systemtap_session& s);
    void emit_module_dyninst_decls (systemtap_session& s);
  void emit_module_dyninst_init (systemtap_session& s);
  void emit_module_dyninst_exit (systemtap_session& s);
public:
  void emit_module_decls (systemtap_session& s);
  void emit_module_init (systemtap_session& s);
  void emit_module_refresh (systemtap_session& s);
  void emit_module_exit (systemtap_session& s);
    bool otf_supported (systemtap_session& s)
    { return !s.runtime_usermode_p()
             && kernel_supports_inode_uprobes(s); }
    bool otf_safe_context (systemtap_session& s)
    { return otf_supported(s); }
};
void
uprobe_derived_probe::join_group (systemtap_session& s)
{
  if (! s.uprobe_derived_probes)
    s.uprobe_derived_probes = new uprobe_derived_probe_group ();
  s.uprobe_derived_probes->enroll (this);
  this->group = s.uprobe_derived_probes;
  if (s.runtime_usermode_p())
    enable_dynprobes(s);
  else
    enable_task_finder(s);
        s.need_uprobes = true;
}
void
uprobe_derived_probe::getargs(std::list<std::string> &arg_set) const
{
  dwarf_derived_probe::getargs(arg_set);
  arg_set.insert(arg_set.end(), args.begin(), args.end());
}
void
uprobe_derived_probe::saveargs(int nargs)
{
  for (int i = 1; i <= nargs; i++)
    args.push_back("$arg" + lex_cast (i) + ":long");
}
void
uprobe_derived_probe::emit_privilege_assertion (translator_output* o)
{
      emit_process_owner_assertion (o);
}
struct uprobe_builder: public derived_probe_builder
{
  uprobe_builder() {}
  virtual void build(systemtap_session & sess,
             probe * base,
             probe_point * location,
             literal_map_t const & parameters,
             vector<derived_probe *> & finished_results)
  {
    int64_t process, address;
    if (kernel_supports_inode_uprobes(sess))
      throw SEMANTIC_ERROR (_("absolute process probes not available [man error::inode-uprobes]"));
    bool b1 = get_param (parameters, TOK_PROCESS, process);
    (void) b1;
    bool b2 = get_param (parameters, TOK_STATEMENT, address);
    (void) b2;
    bool rr = has_null_param (parameters, TOK_RETURN);
    assert (b1 && b2); 
    finished_results.push_back(new uprobe_derived_probe(base, location, process, address, rr));
  }
};
void
uprobe_derived_probe_group::emit_module_maxuprobes (systemtap_session& s)
{
    unsigned minuprobes = probes.size();
    unsigned uprobesize = 64;
  unsigned maxuprobesmem = 10*1024*1024;   unsigned maxuprobes = maxuprobesmem / uprobesize;
            unsigned default_maxuprobes = (unsigned)sqrt((double)minuprobes * (double)maxuprobes);
  s.op->newline() << "#ifndef MAXUPROBES";
  s.op->newline() << "#define MAXUPROBES " << default_maxuprobes;
  s.op->newline() << "#endif";
}
void
uprobe_derived_probe_group::emit_module_utrace_decls (systemtap_session& s)
{
  if (probes.empty()) return;
  s.op->newline() << "/* ---- utrace uprobes ---- */";
  
  s.op->newline() << "#if defined(CONFIG_UPROBES) || defined(CONFIG_UPROBES_MODULE)";
  s.op->newline() << "#include <linux/uprobes.h>";
  s.op->newline() << "#else";
  s.op->newline() << "#include \"linux/uprobes/uprobes.h\"";
  s.op->newline() << "#endif";
  s.op->newline() << "#ifndef UPROBES_API_VERSION";
  s.op->newline() << "#define UPROBES_API_VERSION 1";
  s.op->newline() << "#endif";
  emit_module_maxuprobes (s);
    s.op->newline() << "#include \"linux/uprobes-common.h\"";
      XXX  s.op->newline() << "static struct stap_uprobe stap_uprobes [MAXUPROBES];";
  s.op->newline() << "static DEFINE_MUTEX(stap_uprobes_lock);"; 
  s.op->assert_0_indent();
      map <string,unsigned> module_index;
  unsigned module_index_ctr = 0;
    s.op->newline() << "static struct stap_uprobe_tf stap_uprobe_finders[] = {";
  s.op->indent(1);
  for (unsigned i=0; i<probes.size(); i++)
    {
      uprobe_derived_probe *p = probes[i];
      string pbmkey = make_pbm_key (p);
      if (module_index.find (pbmkey) == module_index.end())
        {
          module_index[pbmkey] = module_index_ctr++;
          s.op->newline() << "{";
                              s.op->line() << " .finder={";
          s.op->line() << "  .purpose=\"uprobes\",";
          if (p->pid != 0)
            s.op->line() << " .pid=" << p->pid << ",";
          if (p->section == "")             s.op->line() << " .callback=&stap_uprobe_process_found,";
          else if (p->section == ".absolute")             {
              s.op->line() << " .procname=" << lex_cast_qstring(p->module) << ",";
              s.op->line() << " .callback=&stap_uprobe_process_found,";
            }
      else if (p->section != ".absolute")             {
          if (p->has_library)
            s.op->line() << " .procname=\"" << p->path << "\", ";
              s.op->line() << " .mmap_callback=&stap_uprobe_mmap_found, ";
              s.op->line() << " .munmap_callback=&stap_uprobe_munmap_found, ";
              s.op->line() << " .callback=&stap_uprobe_process_munmap,";
            }
          s.op->line() << " },";
          if (p->module != "")
            s.op->line() << " .pathname=" << lex_cast_qstring(p->module) << ", ";
          s.op->line() << " },";
        }
      else
        { }     }
  s.op->newline(-1) << "};";
  s.op->assert_0_indent();
  unsigned pci;
  for (pci=0; pci<probes.size(); pci++)
    {
                  uprobe_derived_probe *p = probes[pci];
      std::set<string>::iterator pcii;
      s.op->newline() << "long perf_counters_" + lex_cast(pci) + "[] = {";
      for (pcii = p->perf_counter_refs.begin();
       pcii != p->perf_counter_refs.end(); pcii++)
    {
          std::vector<std::pair<std::string,std::string> >::iterator it;
      unsigned i = 0;
            for (it=s.perf_counters.begin() ;
           it != s.perf_counters.end(); it++, i++)
        if ((*it).first == (*pcii))
          break;
      s.op->line() << lex_cast(i) << ", ";
    }
      s.op->newline() << "};";
    }
     s.op->newline() << "static const struct stap_uprobe_spec stap_uprobe_specs [] = {";
  s.op->indent(1);
  for (unsigned i =0; i<probes.size(); i++)
    {
      uprobe_derived_probe* p = probes[i];
      s.op->newline() << "{";
      string key = make_pbm_key (p);
      unsigned value = module_index[key];
      if (value != 0)
        s.op->line() << " .tfi=" << value << ",";
      s.op->line() << " .address=(unsigned long)0x" << hex << p->addr << dec << "ULL,";
      s.op->line() << " .probe=" << common_probe_init (p) << ",";
      if (p->sdt_semaphore_addr != 0)
        s.op->line() << " .sdt_sem_offset=(unsigned long)0x"
                     << hex << p->sdt_semaphore_addr << dec << "ULL,";
      XXX      s.op->line() << " .perf_counters_dim=ARRAY_SIZE(perf_counters_" << lex_cast(i) << "),";
            s.op->line() << " .perf_counters=perf_counters_" + lex_cast(i) + ",";
      if (p->has_return)
        s.op->line() << " .return_p=1,";
      s.op->line() << " },";
    }
  s.op->newline(-1) << "};";
  s.op->assert_0_indent();
  s.op->newline() << "static void enter_uprobe_probe (struct uprobe *inst, struct pt_regs *regs) {";
  s.op->newline(1) << "struct stap_uprobe *sup = container_of(inst, struct stap_uprobe, up);";
  s.op->newline() << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];";
  common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sups->probe",
                 "stp_probe_type_uprobe");
  s.op->newline() << "if (sup->spec_index < 0 || "
                  << "sup->spec_index >= " << probes.size() << ") {";
  s.op->newline(1) << "_stp_error (\"bad spec_index %d (max " << probes.size()
           << "): %s\", sup->spec_index, c->probe_point);";
  s.op->newline() << "goto probe_epilogue;";
  s.op->newline(-1) << "}";
  s.op->newline() << "c->uregs = regs;";
  s.op->newline() << "c->user_mode_p = 1;";
        s.op->newline() << "{";
  s.op->indent(1);
  s.op->newline() << "unsigned long uprobes_ip = REG_IP(c->uregs);";
  s.op->newline() << "SET_REG_IP(regs, inst->vaddr);";
  s.op->newline() << "(*sups->probe->ph) (c);";
  s.op->newline() << "SET_REG_IP(regs, uprobes_ip);";
  s.op->newline(-1) << "}";
  common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
  s.op->newline(-1) << "}";
  s.op->newline() << "static void enter_uretprobe_probe (struct uretprobe_instance *inst, struct pt_regs *regs) {";
  s.op->newline(1) << "struct stap_uprobe *sup = container_of(inst->rp, struct stap_uprobe, urp);";
  s.op->newline() << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];";
  common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sups->probe",
                 "stp_probe_type_uretprobe");
  s.op->newline() << "c->ips.ri = inst;";
  s.op->newline() << "if (sup->spec_index < 0 || "
                  << "sup->spec_index >= " << probes.size() << ") {";
  s.op->newline(1) << "_stp_error (\"bad spec_index %d (max " << probes.size()
           << "): %s\", sup->spec_index, c->probe_point);";
  s.op->newline() << "goto probe_epilogue;";
  s.op->newline(-1) << "}";
  s.op->newline() << "c->uregs = regs;";
  s.op->newline() << "c->user_mode_p = 1;";
        s.op->newline() << "{";
  s.op->indent(1);
  s.op->newline() << "unsigned long uprobes_ip = REG_IP(c->uregs);";
  s.op->newline() << "SET_REG_IP(regs, inst->ret_addr);";
  s.op->newline() << "(*sups->probe->ph) (c);";
  s.op->newline() << "SET_REG_IP(regs, uprobes_ip);";
  s.op->newline(-1) << "}";
  common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
  s.op->newline(-1) << "}";
  s.op->newline();
  s.op->newline() << "#include \"linux/uprobes-common.c\"";
  s.op->newline();
}
void
uprobe_derived_probe_group::emit_module_utrace_init (systemtap_session& s)
{
  if (probes.empty()) return;
  s.op->newline() << "/* ---- utrace uprobes ---- */";
  s.op->newline() << "for (j=0; j<MAXUPROBES; j++) {";
  s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[j];";
  s.op->newline() << "sup->spec_index = -1;";         s.op->newline(-1) << "}";
  s.op->newline() << "mutex_init (& stap_uprobes_lock);";
    s.op->newline() << "for (i=0; i<sizeof(stap_uprobe_finders)/sizeof(stap_uprobe_finders[0]); i++) {";
  s.op->newline(1) << "struct stap_uprobe_tf *stf = & stap_uprobe_finders[i];";
  s.op->newline() << "probe_point = stf->pathname;"; XXX  s.op->newline() << "rc = stap_register_task_finder_target (& stf->finder);";
  XXX          s.op->newline() << "if (rc) break;";
  s.op->newline(-1) << "}";
}
void
uprobe_derived_probe_group::emit_module_utrace_exit (systemtap_session& s)
{
  if (probes.empty()) return;
  s.op->newline() << "/* ---- utrace uprobes ---- */";
                
  s.op->newline() << "for (j=0; j<MAXUPROBES; j++) {";
  s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[j];";
  s.op->newline() << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];";
  s.op->newline() << "if (sup->spec_index < 0) continue;"; 
    s.op->newline() << "if (sup->sdt_sem_address) {";
  s.op->newline(1) << "unsigned short sdt_semaphore;";   s.op->newline() << "pid_t pid = (sups->return_p ? sup->urp.u.pid : sup->up.pid);";
  s.op->newline() << "struct task_struct *tsk;";
  s.op->newline() << "rcu_read_lock();";
        s.op->newline() << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)";
      s.op->newline() << "  tsk = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID);";
  s.op->newline() << "#else";
  s.op->newline() << "  tsk = find_task_by_pid (pid);";
  s.op->newline() << "#endif /* 2.6.24 */";
  s.op->newline() << "if (tsk) {";   s.op->newline(1) << "if (__access_process_vm_noflush(tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof(sdt_semaphore), 0)) {";
  s.op->newline(1) << "sdt_semaphore --;";
  s.op->newline() << "#ifdef DEBUG_UPROBES";
  s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"-semaphore %#x @ %#lx\\n\", sdt_semaphore, sup->sdt_sem_address);";
  s.op->newline() << "#endif";
  s.op->newline() << "__access_process_vm_noflush(tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof(sdt_semaphore), 1);";
  s.op->newline(-1) << "}";
  XXX  s.op->newline(-1) << "}";
  s.op->newline() << "rcu_read_unlock();";
  s.op->newline(-1) << "}";
  s.op->newline() << "if (sups->return_p) {";
  s.op->newline(1) << "#ifdef DEBUG_UPROBES";
  s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"-uretprobe spec %d index %d pid %d addr %p\\n\", sup->spec_index, j, sup->up.pid, (void*) sup->up.vaddr);";
  s.op->newline() << "#endif";
      s.op->newline() << "unregister_uretprobe (& sup->urp);";
  s.op->newline(-1) << "} else {";
  s.op->newline(1) << "#ifdef DEBUG_UPROBES";
  s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"-uprobe spec %d index %d pid %d addr %p\\n\", sup->spec_index, j, sup->up.pid, (void*) sup->up.vaddr);";
  s.op->newline() << "#endif";
  s.op->newline() << "unregister_uprobe (& sup->up);";
  s.op->newline(-1) << "}";
  s.op->newline() << "sup->spec_index = -1;";
  XXX
  s.op->newline(-1) << "}";
  s.op->newline() << "mutex_destroy (& stap_uprobes_lock);";
}
void
uprobe_derived_probe_group::emit_module_inode_decls (systemtap_session& s)
{
  if (probes.empty()) return;
  s.op->newline() << "/* ---- inode uprobes ---- */";
  emit_module_maxuprobes (s);
  s.op->newline() << "#include \"linux/uprobes-inode.c\"";
    s.op->newline() << "static int stapiu_probe_handler "
                  << "(struct stapiu_consumer *sup, struct pt_regs *regs) {";
  s.op->newline(1);
    string probe_type = "(sup->return_p ? stp_probe_type_uretprobe : stp_probe_type_uprobe)";
  common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sup->probe",
                                 probe_type);
  s.op->newline() << "c->uregs = regs;";
  s.op->newline() << "c->user_mode_p = 1;";
    s.op->newline() << "(*sup->probe->ph) (c);";
  common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
  s.op->newline() << "return 0;";
  s.op->newline(-1) << "}";
  s.op->assert_0_indent();
    map<string, unsigned> module_index;
  unsigned module_index_ctr = 0;
    s.op->newline() << "static struct stapiu_target "
                  << "stap_inode_uprobe_targets[] = {";
  s.op->indent(1);
  for (unsigned i=0; i<probes.size(); i++)
    {
      uprobe_derived_probe *p = probes[i];
      const string key = make_pbm_key(p);
      if (module_index.find (key) == module_index.end())
        {
          module_index[key] = module_index_ctr++;
          s.op->newline() << "{";
          s.op->line() << " .finder={";
          s.op->line() << "  .purpose=\"inode-uprobes\",";
          if (p->pid != 0)
            s.op->line() << " .pid=" << p->pid << ",";
          if (p->section == "") XXX            s.op->line() << " .callback=&stapiu_process_found,";
          else if (p->section == ".absolute")             {
              s.op->line() << " .procname=" << lex_cast_qstring(p->module) << ",";
              s.op->line() << " .callback=&stapiu_process_found,";
            }
          else if (p->section != ".absolute")             {
              if (p->has_library)
                s.op->line() << " .procname=\"" << p->path << "\", ";
              s.op->line() << " .mmap_callback=&stapiu_mmap_found, ";
              s.op->line() << " .munmap_callback=&stapiu_munmap_found, ";
              s.op->line() << " .callback=&stapiu_process_munmap,";
            }
          s.op->line() << " },";
          s.op->line() << " .filename=" << lex_cast_qstring(p->module) << ",";
          s.op->line() << " },";
        }
    }
  s.op->newline(-1) << "};";
  s.op->assert_0_indent();
    unsigned pci;
  for (pci=0; pci<probes.size(); pci++)
    {
                  uprobe_derived_probe *p = probes[pci];
      std::set<string>::iterator pcii;
      s.op->newline() << "long perf_counters_" + lex_cast(pci) + "[] = {";
      for (pcii = p->perf_counter_refs.begin();
       pcii != p->perf_counter_refs.end(); pcii++)
    {
          vector<std::pair<string,string> >:: iterator it;
      unsigned i = 0;
            for (it=s.perf_counters.begin() ;
           it != s.perf_counters.end(); it++, i++)
        if ((*it).first == (*pcii))
          break;
      s.op->line() << lex_cast(i) << ", ";
    }
      s.op->newline() << "};";
    }
  s.op->newline() << "static struct stapiu_consumer "
                  << "stap_inode_uprobe_consumers[] = {";
  s.op->indent(1);
  for (unsigned i=0; i<probes.size(); i++)
    {
      uprobe_derived_probe *p = probes[i];
      unsigned index = module_index[make_pbm_key(p)];
      s.op->newline() << "{";
      if (p->has_return)
        s.op->line() << " .return_p=1,";
      s.op->line() << " .target=&stap_inode_uprobe_targets[" << index << "],";
      s.op->line() << " .offset=(loff_t)0x" << hex << p->addr << dec << "ULL,";
      if (p->sdt_semaphore_addr)
        s.op->line() << " .sdt_sem_offset=(loff_t)0x"
                     << hex << p->sdt_semaphore_addr << dec << "ULL,";
      XXX      s.op->line() << " .perf_counters_dim=ARRAY_SIZE(perf_counters_" << lex_cast(i) << "),";
            s.op->line() << " .perf_counters=perf_counters_" + lex_cast(i) + ",";
      s.op->line() << " .probe=" << common_probe_init (p) << ",";
      s.op->line() << " },";
    }
  s.op->newline(-1) << "};";
  s.op->assert_0_indent();
}
void
uprobe_derived_probe_group::emit_module_inode_init (systemtap_session& s)
{
  if (probes.empty()) return;
  s.op->newline() << "/* ---- inode uprobes ---- */";
      s.op->newline() << "probe_point = NULL;";
  s.op->newline() << "rc = stapiu_init ("
                  << "stap_inode_uprobe_targets, "
                  << "ARRAY_SIZE(stap_inode_uprobe_targets), "
                  << "stap_inode_uprobe_consumers, "
                  << "ARRAY_SIZE(stap_inode_uprobe_consumers));";
}
void
uprobe_derived_probe_group::emit_module_inode_refresh (systemtap_session& s)
{
  if (probes.empty()) return;
  s.op->newline() << "/* ---- inode uprobes ---- */";
  s.op->newline() << "stapiu_refresh ("
                  << "stap_inode_uprobe_targets, "
                  << "ARRAY_SIZE(stap_inode_uprobe_targets));";
}
void
uprobe_derived_probe_group::emit_module_inode_exit (systemtap_session& s)
{
  if (probes.empty()) return;
  s.op->newline() << "/* ---- inode uprobes ---- */";
  s.op->newline() << "stapiu_exit ("
                  << "stap_inode_uprobe_targets, "
                  << "ARRAY_SIZE(stap_inode_uprobe_targets), "
                  << "stap_inode_uprobe_consumers, "
                  << "ARRAY_SIZE(stap_inode_uprobe_consumers));";
}
void
uprobe_derived_probe_group::emit_module_dyninst_decls (systemtap_session& s)
{
  if (probes.empty()) return;
  s.op->newline() << "/* ---- dyninst uprobes ---- */";
  emit_module_maxuprobes (s);
  s.op->newline() << "#include \"dyninst/uprobes.h\"";
      s.op->newline() << "static struct stapdu_probe stapdu_probes[];";
  for (unsigned i = 0; i < probes.size(); i++)
    {
      uprobe_derived_probe *p = probes[i];
      dynprobe_add_uprobe(s, p->module, p->addr, p->sdt_semaphore_addr,
              (p->has_return ? "STAPDYN_PROBE_FLAG_RETURN" : "0"),
              common_probe_init(p));
    }
      s.op->newline() << "static struct pt_regs stapdu_dummy_uregs;";
      s.op->newline() << "int enter_dyninst_uprobe "
                  << "(uint64_t index, struct pt_regs *regs) {";
  s.op->newline(1) << "struct stapdu_probe *sup = &stapdu_probes[index];";
    string probe_type = "((sup->flags & STAPDYN_PROBE_FLAG_RETURN) ?"
                      " stp_probe_type_uretprobe : stp_probe_type_uprobe)";
  common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sup->probe",
                                 probe_type);
  s.op->newline() << "c->uregs = regs ?: &stapdu_dummy_uregs;";
  s.op->newline() << "c->user_mode_p = 1;";
  XXX  XXX    s.op->newline() << "(*sup->probe->ph) (c);";
  common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
  s.op->newline() << "return 0;";
  s.op->newline(-1) << "}";
  s.op->newline() << "#include \"dyninst/uprobes-regs.c\"";
  s.op->assert_0_indent();
}
void
uprobe_derived_probe_group::emit_module_dyninst_init (systemtap_session& s)
{
  if (probes.empty()) return;
    s.op->newline() << "/* ---- dyninst uprobes ---- */";
  s.op->newline() << "/* this section left intentionally blank */";
}
void
uprobe_derived_probe_group::emit_module_dyninst_exit (systemtap_session& s)
{
  if (probes.empty()) return;
    s.op->newline() << "/* ---- dyninst uprobes ---- */";
  s.op->newline() << "/* this section left intentionally blank */";
}
void
uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
{
  if (s.runtime_usermode_p())
    emit_module_dyninst_decls (s);
  else if (kernel_supports_inode_uprobes (s))
    emit_module_inode_decls (s);
  else
    emit_module_utrace_decls (s);
}
void
uprobe_derived_probe_group::emit_module_init (systemtap_session& s)
{
  if (s.runtime_usermode_p())
    emit_module_dyninst_init (s);
  else if (kernel_supports_inode_uprobes (s))
    emit_module_inode_init (s);
  else
    emit_module_utrace_init (s);
}
void
uprobe_derived_probe_group::emit_module_refresh (systemtap_session& s)
{
  if (!s.runtime_usermode_p() && kernel_supports_inode_uprobes (s))
    emit_module_inode_refresh (s);
}
void
uprobe_derived_probe_group::emit_module_exit (systemtap_session& s)
{
  if (s.runtime_usermode_p())
    emit_module_dyninst_exit (s);
  else if (kernel_supports_inode_uprobes (s))
    emit_module_inode_exit (s);
  else
    emit_module_utrace_exit (s);
}
static const string TOK_KPROBE("kprobe");
struct kprobe_derived_probe: public derived_probe
{
  kprobe_derived_probe (systemtap_session& sess,
            vector<derived_probe *> & results,
            probe *base,
            probe_point *location,
            const string& name,
            int64_t stmt_addr,
            bool has_call,
            bool has_return,
            bool has_statement,
            bool has_maxactive,
            bool has_path,
            bool has_library,
            long maxactive_val,
            const string& path,
            const string& library
            );
  string symbol_name;
  Dwarf_Addr addr;
  bool has_call;
  bool has_return;
  bool has_statement;
  bool has_maxactive;
  bool has_path;
  bool has_library;
  long maxactive_val;
  string path;
  string library;
  bool access_var;
  void printsig (std::ostream &o) const;
  void join_group (systemtap_session& s);
};
struct kprobe_derived_probe_group: public derived_probe_group
{
private:
  multimap<string,kprobe_derived_probe*> probes_by_module;
  typedef multimap<string,kprobe_derived_probe*>::iterator p_b_m_iterator;
public:
  void enroll (kprobe_derived_probe* probe);
  void emit_module_decls (systemtap_session& s);
  void emit_module_init (systemtap_session& s);
  void emit_module_exit (systemtap_session& s);
};
struct kprobe_var_expanding_visitor: public var_expanding_visitor
{
  systemtap_session& sess;
  block *add_block;
  block *add_call_probe;   bool add_block_tid, add_call_probe_tid;
  bool has_return;
  kprobe_var_expanding_visitor(systemtap_session& sess, bool has_return):
    sess(sess), add_block(NULL), add_call_probe(NULL),
    add_block_tid(false), add_call_probe_tid(false),
    has_return(has_return) {}
  void visit_entry_op (entry_op* e);
};
kprobe_derived_probe::kprobe_derived_probe (systemtap_session& sess,
                        vector<derived_probe *> & results,
                        probe *base,
                        probe_point *location,
                        const string& name,
                        int64_t stmt_addr,
                        bool has_call,
                        bool has_return,
                        bool has_statement,
                        bool has_maxactive,
                        bool has_path,
                        bool has_library,
                        long maxactive_val,
                        const string& path,
                        const string& library
                        ):
  derived_probe (base, location, true  ),
  symbol_name (name), addr (stmt_addr), has_call (has_call),
  has_return (has_return), has_statement (has_statement),
  has_maxactive (has_maxactive), has_path (has_path),
  has_library (has_library),
  maxactive_val (maxactive_val),
  path (path), library (library)
{
  this->tok = base->tok;
  this->access_var = false;
#ifndef USHRT_MAX
#define USHRT_MAX 32767
#endif
    
  vector<probe_point::component*> comps;
  comps.push_back (new probe_point::component(TOK_KPROBE));
  if (has_statement)
    {
      comps.push_back (new probe_point::component(TOK_STATEMENT,
                                                  new literal_number(addr, true)));
      comps.push_back (new probe_point::component(TOK_ABSOLUTE));
    }
  else
    {
      size_t pos = name.find(':');
      if (pos != string::npos)
        {
          string module = name.substr(0, pos);
          string function = name.substr(pos + 1);
          comps.push_back (new probe_point::component(TOK_MODULE, new literal_string(module)));
          comps.push_back (new probe_point::component(TOK_FUNCTION, new literal_string(function)));
        }
      else
        comps.push_back (new probe_point::component(TOK_FUNCTION, new literal_string(name)));
    }
  if (has_call)
    comps.push_back (new probe_point::component(TOK_CALL));
  if (has_return)
    comps.push_back (new probe_point::component(TOK_RETURN));
  if (has_maxactive)
    comps.push_back (new probe_point::component(TOK_MAXACTIVE, new literal_number(maxactive_val)));
  kprobe_var_expanding_visitor v (sess, has_return);
  v.replace (this->body);
      if (v.add_block)
    this->body = new block(v.add_block, this->body);
          if (v.add_call_probe)
    {
      assert (has_return);
            statement* old_body = base->body;
      base->body = v.add_call_probe;
      derived_probe *entry_handler
    = new kprobe_derived_probe (sess, results, base, location, name, 0,
                    true , false ,
                    has_statement, has_maxactive, has_path,
                    has_library, maxactive_val, path, library);
      results.push_back (entry_handler);
      base->body = old_body;
    }
  this->sole_location()->components = comps;
}
void kprobe_derived_probe::printsig (ostream& o) const
{
  sole_location()->print (o);
  o << " /* " << " name = " << symbol_name << "*/";
  printsig_nested (o);
}
void kprobe_derived_probe::join_group (systemtap_session& s)
{
  if (! s.kprobe_derived_probes)
    s.kprobe_derived_probes = new kprobe_derived_probe_group ();
  s.kprobe_derived_probes->enroll (this);
  this->group = s.kprobe_derived_probes;
}
void kprobe_derived_probe_group::enroll (kprobe_derived_probe* p)
{
  probes_by_module.insert (make_pair (p->symbol_name, p));
  }
void
kprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
{
  if (probes_by_module.empty()) return;
  s.op->newline() << "/* ---- kprobe-based probes ---- */";
    s.op->newline() << "#if ! defined(CONFIG_KPROBES)";
  s.op->newline() << "#error \"Need CONFIG_KPROBES!\"";
  s.op->newline() << "#endif";
  s.op->newline();
  s.op->newline() << "#ifndef KRETACTIVE";
  s.op->newline() << "#define KRETACTIVE (max(15,6*(int)num_possible_cpus()))";
  s.op->newline() << "#endif";
    s.op->newline() << "static int enter_kprobe2_probe (struct kprobe *inst,";
  s.op->line() << " struct pt_regs *regs);";
  s.op->newline() << "static int enter_kretprobe2_probe (struct kretprobe_instance *inst,";
  s.op->line() << " struct pt_regs *regs);";
    s.op->newline() << "#if defined(STAPCONF_UNREGISTER_KPROBES)";
  s.op->newline() << "static void * stap_unreg_kprobes2[" << probes_by_module.size() << "];";
  s.op->newline() << "#endif";
  
  s.op->newline() << "static struct stap_dwarfless_kprobe {";
  s.op->newline(1) << "union { struct kprobe kp; struct kretprobe krp; } u;";
  s.op->newline() << "#ifdef __ia64__";
  s.op->newline() << "struct kprobe dummy;";
  s.op->newline() << "#endif";
  s.op->newline(-1) << "} stap_dwarfless_kprobes[" << probes_by_module.size() << "];";
  
  s.op->newline() << "static struct stap_dwarfless_probe {";
  s.op->newline(1) << "const unsigned return_p:1;";
  s.op->newline() << "const unsigned maxactive_p:1;";
  s.op->newline() << "const unsigned optional_p:1;";
  s.op->newline() << "unsigned registered_p:1;";
  s.op->newline() << "const unsigned short maxactive_val;";
    
  size_t symbol_string_name_max = 0;
  size_t symbol_string_name_tot = 0;
  for (p_b_m_iterator it = probes_by_module.begin(); it != probes_by_module.end(); it++)
    {
      kprobe_derived_probe* p = it->second;
#define DOIT(var,expr) do {                             \
        size_t var##_size = (expr) + 1;                 \
        var##_max = max (var##_max, var##_size);        \
        var##_tot += var##_size; } while (0)
      DOIT(symbol_string_name, p->symbol_name.size());
#undef DOIT
    }
#define CALCIT(var)                                                     \
    s.op->newline() << "const char " << #var << "[" << var##_name_max << "] ;";
  CALCIT(symbol_string);
#undef CALCIT
  s.op->newline() << "unsigned long address;";
  s.op->newline() << "const struct stap_probe * const probe;";
  s.op->newline(-1) << "} stap_dwarfless_probes[] = {";
  s.op->indent(1);
  for (p_b_m_iterator it = probes_by_module.begin(); it != probes_by_module.end(); it++)
    {
      kprobe_derived_probe* p = it->second;
      s.op->newline() << "{";
      if (p->has_return)
        s.op->line() << " .return_p=1,";
      if (p->has_maxactive)
        {
          s.op->line() << " .maxactive_p=1,";
          assert (p->maxactive_val >= 0 && p->maxactive_val <= USHRT_MAX);
          s.op->line() << " .maxactive_val=" << p->maxactive_val << ",";
        }
      if (p->locations[0]->optional)
        s.op->line() << " .optional_p=1,";
      if (p->has_statement)
        s.op->line() << " .address=(unsigned long)0x" << hex << p->addr << dec << "ULL,";
      else
        s.op->line() << " .symbol_string=\"" << p->symbol_name << "\",";
      s.op->line() << " .probe=" << common_probe_init (p) << ",";
      s.op->line() << " },";
    }
  s.op->newline(-1) << "};";
    s.op->newline();
  s.op->newline() << "static int enter_kprobe2_probe (struct kprobe *inst,";
  s.op->line() << " struct pt_regs *regs) {";
    s.op->newline(1) << "int kprobe_idx = ((uintptr_t)inst-(uintptr_t)stap_dwarfless_kprobes)/sizeof(struct stap_dwarfless_kprobe);";
    s.op->newline() << "struct stap_dwarfless_probe *sdp = &stap_dwarfless_probes[";
  s.op->line() << "((kprobe_idx >= 0 && kprobe_idx < " << probes_by_module.size() << ")?";
  s.op->line() << "kprobe_idx:0)";   XXX  s.op->line() << "];";
  common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sdp->probe",
                 "stp_probe_type_kprobe");
  s.op->newline() << "c->kregs = regs;";
        s.op->newline() << "{";
  s.op->indent(1);
  s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->kregs);";
  s.op->newline() << "SET_REG_IP(regs, (unsigned long) inst->addr);";
  s.op->newline() << "(*sdp->probe->ph) (c);";
  s.op->newline() << "SET_REG_IP(regs, kprobes_ip);";
  s.op->newline(-1) << "}";
  common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
  s.op->newline() << "return 0;";
  s.op->newline(-1) << "}";
    s.op->newline();
  s.op->newline() << "static int enter_kretprobe2_probe (struct kretprobe_instance *inst,";
  s.op->line() << " struct pt_regs *regs) {";
  s.op->newline(1) << "struct kretprobe *krp = inst->rp;";
    s.op->newline() << "int kprobe_idx = ((uintptr_t)krp-(uintptr_t)stap_dwarfless_kprobes)/sizeof(struct stap_dwarfless_kprobe);";
    s.op->newline() << "struct stap_dwarfless_probe *sdp = &stap_dwarfless_probes[";
  s.op->line() << "((kprobe_idx >= 0 && kprobe_idx < " << probes_by_module.size() << ")?";
  s.op->line() << "kprobe_idx:0)";   XXX  s.op->line() << "];";
  common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sdp->probe",
                 "stp_probe_type_kretprobe");
  s.op->newline() << "c->kregs = regs;";
  s.op->newline() << "c->ips.krp.pi = inst;"; 
        s.op->newline() << "{";
  s.op->indent(1);
  s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->kregs);";
  s.op->newline() << "SET_REG_IP(regs, (unsigned long) inst->rp->kp.addr);";
  s.op->newline() << "(*sdp->probe->ph) (c);";
  s.op->newline() << "SET_REG_IP(regs, kprobes_ip);";
  s.op->newline(-1) << "}";
  common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
  s.op->newline() << "return 0;";
  s.op->newline(-1) << "}";
  s.op->newline() << "#ifdef STAPCONF_KALLSYMS_ON_EACH_SYMBOL";
  s.op->newline() << "static int kprobe_resolve(void *data, const char *name,";
  s.op->newline() << "                          struct module *owner,";
  s.op->newline() << "                          unsigned long val) {";
  s.op->newline(1) << "int i;";
  s.op->newline() << "int *p = (int *) data;";
  s.op->newline() << "for (i=0; i<" << probes_by_module.size()
          << " && *p > 0; i++) {";
  s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
  s.op->newline() << "if (! sdp->address) {";
  s.op->indent(1);
  s.op->newline() << "const char *colon;";
  s.op->newline() << "if (owner && (colon = strchr(sdp->symbol_string, ':'))) {";
  s.op->indent(1);
  s.op->newline() << "if ((strlen(owner->name) == (colon - sdp->symbol_string))";
  s.op->newline() << "    && (strncmp(sdp->symbol_string, owner->name, colon - sdp->symbol_string) == 0)";
  s.op->newline() << "    && (strcmp(colon + 1, name) == 0)) {";
  s.op->newline(1) << "sdp->address = val;";
  s.op->newline() << "(*p)--;";
  s.op->newline(-1) << "}";
  s.op->newline(-1) << "}";
  s.op->newline() << "else {";
  s.op->newline(1) << "if (strcmp(sdp->symbol_string, name) == 0) {";
  s.op->newline(1) << "sdp->address = val;";
  s.op->newline() << "(*p)--;";
  s.op->newline(-1) << "}";
  s.op->newline(-1) << "}";
  s.op->newline(-1) << "}";
  s.op->newline(-1) << "}";
  s.op->newline() << "return (p > 0) ? 0 : -1;";
  s.op->newline(-1) << "}";
  s.op->newline() << "#endif";
}
void
kprobe_derived_probe_group::emit_module_init (systemtap_session& s)
{
  s.op->newline() << "#ifdef STAPCONF_KALLSYMS_ON_EACH_SYMBOL";
  s.op->newline() << "{";
  s.op->newline(1) << "int p = 0;";
  s.op->newline() << "for (i = 0; i < " << probes_by_module.size() << "; i++) {";
  s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
  s.op->newline() << "if (! sdp->address)";
  s.op->newline(1) << "p++;";
  s.op->newline(-2) << "}";
  s.op->newline() << "kallsyms_on_each_symbol(kprobe_resolve, &p);";
  s.op->newline(-1) << "}";
  s.op->newline() << "#endif";
  s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
  s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
  s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
  s.op->newline() << "void *addr = (void *) sdp->address;";
  s.op->newline() << "const char *symbol_name = addr ? NULL : sdp->symbol_string;";
  s.op->newline() << "#ifdef STAPCONF_KALLSYMS_ON_EACH_SYMBOL";
  s.op->newline() << "if (! addr) {";
  s.op->newline(1) << "sdp->registered_p = 0;";
  s.op->newline() << "if (!sdp->optional_p)";
  s.op->newline(1) << "_stp_warn (\"probe %s registration error (symbol not found)\", probe_point);";
  s.op->newline(-1) << "continue;";
  s.op->newline(-1) << "}";
  s.op->newline() << "#endif";
  s.op->newline() << "probe_point = sdp->probe->pp;";   s.op->newline() << "if (sdp->return_p) {";
  s.op->newline(1) << "kp->u.krp.kp.addr = addr;";
  s.op->newline() << "#ifdef STAPCONF_KPROBE_SYMBOL_NAME";
  s.op->newline() << "kp->u.krp.kp.symbol_name = (char *) symbol_name;";
  s.op->newline() << "#endif";
  s.op->newline() << "if (sdp->maxactive_p) {";
  s.op->newline(1) << "kp->u.krp.maxactive = sdp->maxactive_val;";
  s.op->newline(-1) << "} else {";
  s.op->newline(1) << "kp->u.krp.maxactive = KRETACTIVE;";
  s.op->newline(-1) << "}";
  s.op->newline() << "kp->u.krp.handler = &enter_kretprobe2_probe;";
    s.op->newline() << "#ifdef __ia64__";
  s.op->newline() << "kp->dummy.addr = kp->u.krp.kp.addr;";
  s.op->newline() << "#ifdef STAPCONF_KPROBE_SYMBOL_NAME";
  s.op->newline() << "kp->dummy.symbol_name = kp->u.krp.kp.symbol_name;";
  s.op->newline() << "#endif";
  s.op->newline() << "kp->dummy.pre_handler = NULL;";
  s.op->newline() << "rc = register_kprobe (& kp->dummy);";
  s.op->newline() << "if (rc == 0) {";
  s.op->newline(1) << "rc = register_kretprobe (& kp->u.krp);";
  s.op->newline() << "if (rc != 0)";
  s.op->newline(1) << "unregister_kprobe (& kp->dummy);";
  s.op->newline(-2) << "}";
  s.op->newline() << "#else";
  s.op->newline() << "rc = register_kretprobe (& kp->u.krp);";
  s.op->newline() << "#endif";
  s.op->newline(-1) << "} else {";
    s.op->newline(1) << "kp->u.kp.addr = addr;";
  s.op->newline() << "#ifdef STAPCONF_KPROBE_SYMBOL_NAME";
  s.op->newline() << "kp->u.kp.symbol_name = (char *) symbol_name;";
  s.op->newline() << "#endif";
  s.op->newline() << "kp->u.kp.pre_handler = &enter_kprobe2_probe;";
  s.op->newline() << "#ifdef __ia64__";
  s.op->newline() << "kp->dummy.pre_handler = NULL;";
  s.op->newline() << "kp->dummy.addr = kp->u.kp.addr;";
  s.op->newline() << "#ifdef STAPCONF_KPROBE_SYMBOL_NAME";
  s.op->newline() << "kp->dummy.symbol_name = kp->u.kp.symbol_name;";
  s.op->newline() << "#endif";
  s.op->newline() << "rc = register_kprobe (& kp->dummy);";
  s.op->newline() << "if (rc == 0) {";
  s.op->newline(1) << "rc = register_kprobe (& kp->u.kp);";
  s.op->newline() << "if (rc != 0)";
  s.op->newline(1) << "unregister_kprobe (& kp->dummy);";
  s.op->newline(-2) << "}";
  s.op->newline() << "#else";
  s.op->newline() << "rc = register_kprobe (& kp->u.kp);";
  s.op->newline() << "#endif";
  s.op->newline(-1) << "}";
  s.op->newline() << "if (rc) {";   s.op->newline(1) << "sdp->registered_p = 0;";
  s.op->newline() << "if (!sdp->optional_p)";
  s.op->newline(1) << "_stp_warn (\"probe %s (address 0x%lx) registration error (rc %d)\", probe_point, (unsigned long) addr, rc);";
  s.op->newline(-1) << "rc = 0;";   XXX  s.op->newline(-1) << "}";
  s.op->newline() << "else sdp->registered_p = 1;";
  s.op->newline(-1) << "}"; }
void
kprobe_derived_probe_group::emit_module_exit (systemtap_session& s)
{
    s.op->newline() << "#if defined(STAPCONF_UNREGISTER_KPROBES)";
  s.op->newline() << "j = 0;";
  s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
  s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
  s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
  s.op->newline() << "if (! sdp->registered_p) continue;";
  s.op->newline() << "if (!sdp->return_p)";
  s.op->newline(1) << "stap_unreg_kprobes2[j++] = &kp->u.kp;";
  s.op->newline(-2) << "}";
  s.op->newline() << "unregister_kprobes((struct kprobe **)stap_unreg_kprobes2, j);";
  s.op->newline() << "j = 0;";
  s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
  s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
  s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
  s.op->newline() << "if (! sdp->registered_p) continue;";
  s.op->newline() << "if (sdp->return_p)";
  s.op->newline(1) << "stap_unreg_kprobes2[j++] = &kp->u.krp;";
  s.op->newline(-2) << "}";
  s.op->newline() << "unregister_kretprobes((struct kretprobe **)stap_unreg_kprobes2, j);";
  s.op->newline() << "#ifdef __ia64__";
  s.op->newline() << "j = 0;";
  s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
  s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
  s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
  s.op->newline() << "if (! sdp->registered_p) continue;";
  s.op->newline() << "stap_unreg_kprobes2[j++] = &kp->dummy;";
  s.op->newline(-1) << "}";
  s.op->newline() << "unregister_kprobes((struct kprobe **)stap_unreg_kprobes2, j);";
  s.op->newline() << "#endif";
  s.op->newline() << "#endif";
  s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
  s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
  s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
  s.op->newline() << "if (! sdp->registered_p) continue;";
  s.op->newline() << "if (sdp->return_p) {";
  s.op->newline() << "#if !defined(STAPCONF_UNREGISTER_KPROBES)";
  s.op->newline(1) << "unregister_kretprobe (&kp->u.krp);";
  s.op->newline() << "#endif";
  s.op->newline() << "atomic_add (kp->u.krp.nmissed, skipped_count());";
  s.op->newline() << "#ifdef STP_TIMING";
  s.op->newline() << "if (kp->u.krp.nmissed)";
  s.op->newline(1) << "_stp_warn (\"Skipped due to missed kretprobe/1 on '%s': %d\\n\", sdp->probe->pp, kp->u.krp.nmissed);";
  s.op->newline(-1) << "#endif";
  s.op->newline() << "atomic_add (kp->u.krp.kp.nmissed, skipped_count());";
  s.op->newline() << "#ifdef STP_TIMING";
  s.op->newline() << "if (kp->u.krp.kp.nmissed)";
  s.op->newline(1) << "_stp_warn (\"Skipped due to missed kretprobe/2 on '%s': %lu\\n\", sdp->probe->pp, kp->u.krp.kp.nmissed);";
  s.op->newline(-1) << "#endif";
  s.op->newline(-1) << "} else {";
  s.op->newline() << "#if !defined(STAPCONF_UNREGISTER_KPROBES)";
  s.op->newline(1) << "unregister_kprobe (&kp->u.kp);";
  s.op->newline() << "#endif";
  s.op->newline() << "atomic_add (kp->u.kp.nmissed, skipped_count());";
  s.op->newline() << "#ifdef STP_TIMING";
  s.op->newline() << "if (kp->u.kp.nmissed)";
  s.op->newline(1) << "_stp_warn (\"Skipped due to missed kprobe on '%s': %lu\\n\", sdp->probe->pp, kp->u.kp.nmissed);";
  s.op->newline(-1) << "#endif";
  s.op->newline(-1) << "}";
  s.op->newline() << "#if !defined(STAPCONF_UNREGISTER_KPROBES) && defined(__ia64__)";
  s.op->newline() << "unregister_kprobe (&kp->dummy);";
  s.op->newline() << "#endif";
  s.op->newline() << "sdp->registered_p = 0;";
  s.op->newline(-1) << "}";
}
struct kprobe_builder: public derived_probe_builder
{
public:
  kprobe_builder() {}
  void build_no_more (systemtap_session &s) {}
  virtual void build(systemtap_session & sess,
             probe * base,
             probe_point * location,
             literal_map_t const & parameters,
             vector<derived_probe *> & finished_results);
};
void
kprobe_builder::build(systemtap_session & sess,
              probe * base,
              probe_point * location,
              literal_map_t const & parameters,
              vector<derived_probe *> & finished_results)
{
  string function_string_val, module_string_val;
  string path, library, path_tgt, library_tgt;
  int64_t statement_num_val = 0, maxactive_val = 0;
  bool has_function_str, has_module_str, has_statement_num;
  bool has_absolute, has_call, has_return, has_maxactive;
  bool has_path, has_library;
  has_function_str = get_param(parameters, TOK_FUNCTION, function_string_val);
  has_module_str = get_param(parameters, TOK_MODULE, module_string_val);
  has_call = has_null_param (parameters, TOK_CALL);
  has_return = has_null_param (parameters, TOK_RETURN);
  has_maxactive = get_param(parameters, TOK_MAXACTIVE, maxactive_val);
  has_statement_num = get_param(parameters, TOK_STATEMENT, statement_num_val);
  has_absolute = has_null_param (parameters, TOK_ABSOLUTE);
  has_path = get_param (parameters, TOK_PROCESS, path);
  has_library = get_param (parameters, TOK_LIBRARY, library);
  if (has_path)
    {
      path = find_executable (path, sess.sysroot, sess.sysenv);
      path_tgt = path_remove_sysroot(sess, path);
    }
  if (has_library)
    {
      library = find_executable (library, sess.sysroot, sess.sysenv,
                                 "LD_LIBRARY_PATH");
      library_tgt = path_remove_sysroot(sess, library);
    }
  if (has_function_str)
    {
      if (has_module_str)
        {
      function_string_val = module_string_val + ":" + function_string_val;
      derived_probe *dp
        = new kprobe_derived_probe (sess, finished_results, base,
                    location, function_string_val,
                    0, has_call, has_return,
                    has_statement_num, has_maxactive,
                    has_path, has_library, maxactive_val,
                    path_tgt, library_tgt);
      finished_results.push_back (dp);
    }
      else
        {
          vector<string> matches;
                    if (function_string_val.find_first_of("*?[") == string::npos)
            {
              if (sess.kernel_functions.count(function_string_val))
                matches.push_back(function_string_val);
            }
          else             {
              for (set<string>::const_iterator it = sess.kernel_functions.begin();
                   it != sess.kernel_functions.end(); it++)
                                if (fnmatch(function_string_val.c_str(), it->c_str(), 0) == 0)
                  matches.push_back(*it);
            }
      for (vector<string>::const_iterator it = matches.begin();
           it != matches.end(); it++)
        {
              derived_probe *dp
                = new kprobe_derived_probe (sess, finished_results, base,
                                            location, *it, 0, has_call,
                                            has_return, has_statement_num,
                                            has_maxactive, has_path,
                                            has_library, maxactive_val,
                                            path_tgt, library_tgt);
              finished_results.push_back (dp);
        }
    }
    }
  else
    {
            if ( has_statement_num && has_absolute && !base->privileged )
    throw SEMANTIC_ERROR (_("absolute statement probe in unprivileged script; need stap -g"), base->tok);
      finished_results.push_back (new kprobe_derived_probe (sess,
                                finished_results,
                                base,
                                location, "",
                                statement_num_val,
                                has_call,
                                has_return,
                                has_statement_num,
                                has_maxactive,
                                has_path,
                                has_library,
                                maxactive_val,
                                path_tgt,
                                library_tgt));
    }
}
void
kprobe_var_expanding_visitor::visit_entry_op (entry_op *e)
{
  expression *repl = e;
  if (has_return)
    {
            has_return = false;
      replace (e->operand);
      has_return = true;
      XXX                  repl = gen_mapped_saved_return (sess, e->operand, "entry",
                      add_block, add_block_tid,
                      add_call_probe, add_call_probe_tid);
    }
  provide (repl);
}
static const string TOK_HWBKPT("data");
static const string TOK_HWBKPT_WRITE("write");
static const string TOK_HWBKPT_RW("rw");
static const string TOK_LENGTH("length");
#define HWBKPT_READ 0
#define HWBKPT_WRITE 1
#define HWBKPT_RW 2
struct hwbkpt_derived_probe: public derived_probe
{
  hwbkpt_derived_probe (probe *base,
                        probe_point *location,
                        uint64_t addr,
            string symname,
            unsigned int len,
            bool has_only_read_access,
            bool has_only_write_access,
            bool has_rw_access
                        );
  Dwarf_Addr hwbkpt_addr;
  string symbol_name;
  unsigned int hwbkpt_access,hwbkpt_len;
  void printsig (std::ostream &o) const;
  void join_group (systemtap_session& s);
};
struct hwbkpt_derived_probe_group: public derived_probe_group
{
private:
  vector<hwbkpt_derived_probe*> hwbkpt_probes;
public:
  void enroll (hwbkpt_derived_probe* probe, systemtap_session& s);
  void emit_module_decls (systemtap_session& s);
  void emit_module_init (systemtap_session& s);
  void emit_module_exit (systemtap_session& s);
};
hwbkpt_derived_probe::hwbkpt_derived_probe (probe *base,
                                            probe_point *location,
                                            uint64_t addr,
                                            string symname,
                                            unsigned int len,
                                            bool has_only_read_access,
                                            bool has_only_write_access,
                                            bool):
  derived_probe (base, location, true  ),
  hwbkpt_addr (addr),
  symbol_name (symname),
  hwbkpt_len (len)
{
  this->tok = base->tok;
  vector<probe_point::component*> comps;
  comps.push_back (new probe_point::component(TOK_KERNEL));
  if (hwbkpt_addr)
    comps.push_back (new probe_point::component (TOK_HWBKPT,
                                                 new literal_number(hwbkpt_addr, true)));
  else if (symbol_name.size())
    comps.push_back (new probe_point::component (TOK_HWBKPT, new literal_string(symbol_name)));
  comps.push_back (new probe_point::component (TOK_LENGTH, new literal_number(hwbkpt_len)));
  if (has_only_read_access)
    this->hwbkpt_access = HWBKPT_READ ;
TODO
  else
    {
      if (has_only_write_access)
        {
          this->hwbkpt_access = HWBKPT_WRITE ;
          comps.push_back (new probe_point::component(TOK_HWBKPT_WRITE));
        }
      else
        {
          this->hwbkpt_access = HWBKPT_RW ;
          comps.push_back (new probe_point::component(TOK_HWBKPT_RW));
        }
    }
  this->sole_location()->components = comps;
}
void hwbkpt_derived_probe::printsig (ostream& o) const
{
  sole_location()->print (o);
  printsig_nested (o);
}
void hwbkpt_derived_probe::join_group (systemtap_session& s)
{
  if (! s.hwbkpt_derived_probes)
    s.hwbkpt_derived_probes = new hwbkpt_derived_probe_group ();
  s.hwbkpt_derived_probes->enroll (this, s);
  this->group = s.hwbkpt_derived_probes;
}
void hwbkpt_derived_probe_group::enroll (hwbkpt_derived_probe* p, systemtap_session& s)
{
  hwbkpt_probes.push_back (p);
  unsigned max_hwbkpt_probes_by_arch = 0;
  if (s.architecture == "i386" || s.architecture == "x86_64")
    max_hwbkpt_probes_by_arch = 4;
  else if (s.architecture == "s390")
    max_hwbkpt_probes_by_arch = 1;
  if (hwbkpt_probes.size() >= max_hwbkpt_probes_by_arch)
    s.print_warning (_F("Too many hardware breakpoint probes requested for %s (%zu vs. %u)",
                          s.architecture.c_str(), hwbkpt_probes.size(), max_hwbkpt_probes_by_arch));
}
void
hwbkpt_derived_probe_group::emit_module_decls (systemtap_session& s)
{
  if (hwbkpt_probes.empty()) return;
  s.op->newline() << "/* ---- hwbkpt-based probes ---- */";
  s.op->newline() << "#include <linux/perf_event.h>";
  s.op->newline() << "#include <linux/hw_breakpoint.h>";
  s.op->newline();
    s.op->newline() << "#ifdef STAPCONF_PERF_HANDLER_NMI";
  s.op->newline() << "static int enter_hwbkpt_probe (struct perf_event *bp,";
  s.op->line() << " int nmi,";
  s.op->line() << " struct perf_sample_data *data,";
  s.op->line() << " struct pt_regs *regs);";
  s.op->newline() << "#else";
  s.op->newline() << "static int enter_hwbkpt_probe (struct perf_event *bp,";
  s.op->line() << " struct perf_sample_data *data,";
  s.op->line() << " struct pt_regs *regs);";
  s.op->newline() << "#endif";
  
  s.op->newline() << "static struct perf_event_attr ";
  s.op->newline() << "stap_hwbkpt_probe_array[" << hwbkpt_probes.size() << "];";
  s.op->newline() << "static struct perf_event **";
  s.op->newline() << "stap_hwbkpt_ret_array[" << hwbkpt_probes.size() << "];";
  s.op->newline() << "static struct stap_hwbkpt_probe {";
  s.op->newline() << "int registered_p:1;";
      s.op->newline() << "const char * const symbol;";
  s.op->newline() << "const unsigned long address;";
  s.op->newline() << "uint8_t atype;";
  s.op->newline() << "unsigned int len;";
  s.op->newline() << "const struct stap_probe * const probe;";
  s.op->newline() << "} stap_hwbkpt_probes[] = {";
  s.op->indent(1);
  for (unsigned int it = 0; it < hwbkpt_probes.size(); it++)
    {
      hwbkpt_derived_probe* p = hwbkpt_probes.at(it);
      s.op->newline() << "{";
      if (p->symbol_name.size())
      s.op->line() << " .address=(unsigned long)0x0" << "ULL,";
      else
      s.op->line() << " .address=(unsigned long)0x" << hex << p->hwbkpt_addr << dec << "ULL,";
      switch(p->hwbkpt_access){
      case HWBKPT_READ:
        s.op->line() << " .atype=HW_BREAKPOINT_R ,";
        break;
      case HWBKPT_WRITE:
        s.op->line() << " .atype=HW_BREAKPOINT_W ,";
        break;
      case HWBKPT_RW:
        s.op->line() << " .atype=HW_BREAKPOINT_R|HW_BREAKPOINT_W ,";
        break;
    };
      s.op->line() << " .len=" << p->hwbkpt_len << ",";
      s.op->line() << " .probe=" << common_probe_init (p) << ",";
      s.op->line() << " .symbol=\"" << p->symbol_name << "\",";
      s.op->line() << " },";
    }
  s.op->newline(-1) << "};";
    s.op->newline() ;
  s.op->newline() << "#ifdef STAPCONF_PERF_HANDLER_NMI";
  s.op->newline() << "static int enter_hwbkpt_probe (struct perf_event *bp,";
  s.op->line() << " int nmi,";
  s.op->line() << " struct perf_sample_data *data,";
  s.op->line() << " struct pt_regs *regs) {";
  s.op->newline() << "#else";
  s.op->newline() << "static int enter_hwbkpt_probe (struct perf_event *bp,";
  s.op->line() << " struct perf_sample_data *data,";
  s.op->line() << " struct pt_regs *regs) {";
  s.op->newline() << "#endif";
  s.op->newline(1) << "unsigned int i;";
  s.op->newline() << "if (bp->attr.type != PERF_TYPE_BREAKPOINT) return -1;";
  s.op->newline() << "for (i=0; i<" << hwbkpt_probes.size() << "; i++) {";
  s.op->newline(1) << "struct perf_event_attr *hp = & stap_hwbkpt_probe_array[i];";
  XXX  s.op->newline() << "if (bp->attr.bp_addr==hp->bp_addr && bp->attr.bp_type==hp->bp_type && bp->attr.bp_len==hp->bp_len) {";
  s.op->newline(1) << "struct stap_hwbkpt_probe *sdp = &stap_hwbkpt_probes[i];";
  common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sdp->probe",
                 "stp_probe_type_hwbkpt");
  s.op->newline() << "if (user_mode(regs)) {";
  s.op->newline(1)<< "c->user_mode_p = 1;";
  s.op->newline() << "c->uregs = regs;";
  s.op->newline(-1) << "} else {";
  s.op->newline(1) << "c->kregs = regs;";
  s.op->newline(-1) << "}";
  s.op->newline() << "(*sdp->probe->ph) (c);";
  common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
  s.op->newline(-1) << "}";
  s.op->newline(-1) << "}";
  s.op->newline() << "return 0;";
  s.op->newline(-1) << "}";
}
void
hwbkpt_derived_probe_group::emit_module_init (systemtap_session& s)
{
  s.op->newline() << "for (i=0; i<" << hwbkpt_probes.size() << "; i++) {";
  s.op->newline(1) << "struct stap_hwbkpt_probe *sdp = & stap_hwbkpt_probes[i];";
  s.op->newline() << "struct perf_event_attr *hp = & stap_hwbkpt_probe_array[i];";
  s.op->newline() << "void *addr = (void *) sdp->address;";
  s.op->newline() << "const char *hwbkpt_symbol_name = addr ? NULL : sdp->symbol;";
  s.op->newline() << "hw_breakpoint_init(hp);";
  s.op->newline() << "if (addr)";
  s.op->newline(1) << "hp->bp_addr = (unsigned long) addr;";
  s.op->newline(-1) << "else { ";
  s.op->newline(1) << "hp->bp_addr = kallsyms_lookup_name(hwbkpt_symbol_name);";
  s.op->newline() << "if (!hp->bp_addr) { ";
  s.op->newline(1) << "_stp_warn(\"Probe %s registration skipped: invalid symbol %s \",sdp->probe->pp,hwbkpt_symbol_name);";
  s.op->newline() << "continue;";
  s.op->newline(-1) << "}";
  s.op->newline(-1) << "}";
  s.op->newline() << "hp->bp_type = sdp->atype;";
    if (s.architecture == "i386" || s.architecture == "x86_64" )
    {
      s.op->newline() << "switch(sdp->len) {";
      s.op->newline() << "case 1:";
      s.op->newline(1) << "hp->bp_len = HW_BREAKPOINT_LEN_1;";
      s.op->newline() << "break;";
      s.op->newline(-1) << "case 2:";
      s.op->newline(1) << "hp->bp_len = HW_BREAKPOINT_LEN_2;";
      s.op->newline() << "break;";
      s.op->newline(-1) << "case 3:";
      s.op->newline() << "case 4:";
      s.op->newline(1) << "hp->bp_len = HW_BREAKPOINT_LEN_4;";
      s.op->newline() << "break;";
      s.op->newline(-1) << "case 5:";
      s.op->newline() << "case 6:";
      s.op->newline() << "case 7:";
      s.op->newline() << "case 8:";
      s.op->newline() << "default:"; XXX      s.op->newline(1) << "hp->bp_len = HW_BREAKPOINT_LEN_8;";
      s.op->newline() << "break;";
      s.op->newline(-1) << "}";
    }
  else     s.op->newline() << "hp->bp_len = sdp->len;";
  s.op->newline() << "probe_point = sdp->probe->pp;";   s.op->newline() << "#ifdef STAPCONF_HW_BREAKPOINT_CONTEXT";
  s.op->newline() << "stap_hwbkpt_ret_array[i] = register_wide_hw_breakpoint(hp, (void *)&enter_hwbkpt_probe, NULL);";
  s.op->newline() << "#else";
  s.op->newline() << "stap_hwbkpt_ret_array[i] = register_wide_hw_breakpoint(hp, (void *)&enter_hwbkpt_probe);";
  s.op->newline() << "#endif";
  s.op->newline() << "rc = 0;";
  s.op->newline() << "if (IS_ERR(stap_hwbkpt_ret_array[i])) {";
  s.op->newline(1) << "rc = PTR_ERR(stap_hwbkpt_ret_array[i]);";
  s.op->newline() << "stap_hwbkpt_ret_array[i] = 0;";
  s.op->newline(-1) << "}";
  s.op->newline() << "if (rc) {";
  s.op->newline(1) << "_stp_warn(\"Hwbkpt probe %s: registration error %d, addr %p, name %s\", probe_point, rc, addr, hwbkpt_symbol_name);";
  s.op->newline() << "sdp->registered_p = 0;";
  s.op->newline(-1) << "}";
  s.op->newline() << " else sdp->registered_p = 1;";
  s.op->newline(-1) << "}"; }
void
hwbkpt_derived_probe_group::emit_module_exit (systemtap_session& s)
{
    s.op->newline() << "for (i=0; i<" << hwbkpt_probes.size() << "; i++) {";
  s.op->newline(1) << "struct stap_hwbkpt_probe *sdp = & stap_hwbkpt_probes[i];";
  s.op->newline() << "if (sdp->registered_p == 0) continue;";
  s.op->newline() << "unregister_wide_hw_breakpoint(stap_hwbkpt_ret_array[i]);";
  s.op->newline() << "sdp->registered_p = 0;";
  s.op->newline(-1) << "}";
}
struct hwbkpt_builder: public derived_probe_builder
{
  hwbkpt_builder() {}
  virtual void build(systemtap_session & sess,
             probe * base,
             probe_point * location,
             literal_map_t const & parameters,
             vector<derived_probe *> & finished_results);
};
void
hwbkpt_builder::build(systemtap_session & sess,
              probe * base,
              probe_point * location,
              literal_map_t const & parameters,
              vector<derived_probe *> & finished_results)
{
  string symbol_str_val;
  int64_t hwbkpt_address, len;
  bool has_addr, has_symbol_str, has_write, has_rw, has_len;
  if (! (sess.kernel_config["CONFIG_PERF_EVENTS"] == string("y")))
      throw SEMANTIC_ERROR (_("CONFIG_PERF_EVENTS not available on this kernel"),
                            location->components[0]->tok);
  if (! (sess.kernel_config["CONFIG_HAVE_HW_BREAKPOINT"] == string("y")))
      throw SEMANTIC_ERROR (_("CONFIG_HAVE_HW_BREAKPOINT not available on this kernel"),
                            location->components[0]->tok);
  has_addr = get_param (parameters, TOK_HWBKPT, hwbkpt_address);
  has_symbol_str = get_param (parameters, TOK_HWBKPT, symbol_str_val);
  has_len = get_param (parameters, TOK_LENGTH, len);
  has_write = (parameters.find(TOK_HWBKPT_WRITE) != parameters.end());
  has_rw = (parameters.find(TOK_HWBKPT_RW) != parameters.end());
      probe_point* well_formed_loc = new probe_point(*location);
  well_formed_loc->well_formed = true;
  vector<probe_point::component*> well_formed_comps;
  vector<probe_point::component*>::iterator it;
  for (it = location->components.begin();
      it != location->components.end(); ++it)
    if ((*it)->functor == TOK_HWBKPT && has_addr)
      well_formed_comps.push_back(new probe_point::component(TOK_HWBKPT,
          new literal_number(hwbkpt_address, true  )));
    else
      well_formed_comps.push_back(*it);
  well_formed_loc->components = well_formed_comps;
  probe *new_base = new probe (base, well_formed_loc);
  if (!has_len)
    len = 1;
  if (has_addr)
      finished_results.push_back (new hwbkpt_derived_probe (new_base,
                                location,
                                hwbkpt_address,
                                "",len,0,
                                has_write,
                                has_rw));
  else if (has_symbol_str)
      finished_results.push_back (new hwbkpt_derived_probe (new_base,
                                location,
                                0,
                                symbol_str_val,len,0,
                                has_write,
                                has_rw));
  else
    assert (0);
}
struct tracepoint_arg
{
  string name, c_type, typecast;
  bool usable, used, isptr;
  Dwarf_Die type_die;
  tracepoint_arg(): usable(false), used(false), isptr(false) {}
};
struct tracepoint_derived_probe: public derived_probe
{
  tracepoint_derived_probe (systemtap_session& s,
                            dwflpp& dw, Dwarf_Die& func_die,
                            const string& tracepoint_name,
                            probe* base_probe, probe_point* location);
  systemtap_session& sess;
  string tracepoint_name, header;
  vector <struct tracepoint_arg> args;
  void build_args(dwflpp& dw, Dwarf_Die& func_die);
  void getargs (std::list<std::string> &arg_set) const;
  void join_group (systemtap_session& s);
  void print_dupe_stamp(ostream& o);
};
struct tracepoint_derived_probe_group: public generic_dpg<tracepoint_derived_probe>
{
  void emit_module_decls (systemtap_session& s);
  void emit_module_init (systemtap_session& s);
  void emit_module_exit (systemtap_session& s);
};
struct tracepoint_var_expanding_visitor: public var_expanding_visitor
{
  tracepoint_var_expanding_visitor(dwflpp& dw, const string& probe_name,
                                   vector <struct tracepoint_arg>& args):
    dw (dw), probe_name (probe_name), args (args) {}
  dwflpp& dw;
  const string& probe_name;
  vector <struct tracepoint_arg>& args;
  void visit_target_symbol (target_symbol* e);
  void visit_target_symbol_arg (target_symbol* e);
  void visit_target_symbol_context (target_symbol* e);
};
void
tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
{
  string argname = e->sym_name();
    tracepoint_arg *arg = NULL;
  for (unsigned i = 0; i < args.size(); ++i)
    if (args[i].usable && args[i].name == argname)
      {
        arg = &args[i];
        arg->used = true;
        break;
      }
  if (arg == NULL)
    {
      set<string> vars;
      for (unsigned i = 0; i < args.size(); ++i)
        vars.insert("$" + args[i].name);
      vars.insert("$$name");
      vars.insert("$$parms");
      vars.insert("$$vars");
      string sugs = levenshtein_suggest(e->name, vars); 
                  throw SEMANTIC_ERROR(_F("unable to find tracepoint variable '%s'%s",
                              e->name.c_str(), sugs.empty() ? "" :
                              (_(" (alternatives: ") + sugs + ")").c_str()), e->tok);
                                                    }
    bool deref_p = arg->isptr && !null_die(&arg->type_die);
  if (!deref_p)
    e->assert_no_components("tracepoint", true);
    bool lvalue = is_active_lvalue(e);
  if (lvalue && (!dw.sess.guru_mode || e->components.empty()))
    throw SEMANTIC_ERROR(_F("write to tracepoint variable '%s' not permitted; need stap -g", e->name.c_str()), e->tok);
  XXX    
  if (e->components.empty())
    {
      if (e->addressof)
        throw SEMANTIC_ERROR(_("cannot take address of tracepoint variable"), e->tok);
            symbol* sym = new symbol;
      sym->tok = e->tok;
      sym->name = "__tracepoint_arg_" + arg->name;
      sym->type_details.reset(new exp_type_dwarf(&dw, &arg->type_die, false, false));
      provide (sym);
    }
  else
    {
                  target_symbol* e2 = deep_copy_visitor::deep_copy(e);
      e2->components.clear();
      if (e->check_pretty_print (lvalue))
        {
          dwarf_pretty_print dpp(dw, &arg->type_die, e2, deref_p, false, *e);
          dpp.expand()->visit (this);
          return;
        }
      bool userspace_p = false;
      string fname = (string(lvalue ? "_tracepoint_tvar_set" : "_tracepoint_tvar_get")
                      + "_" + e->sym_name()
                      + "_" + lex_cast(tick++));
      Dwarf_Die endtype;
      string code = dw.literal_stmt_for_pointer (&arg->type_die, e, lvalue, &endtype);
      functioncall* n = synthetic_embedded_deref_call(dw, &endtype, fname, code,
                                                      userspace_p, lvalue, e, e2);
      if (lvalue)
    provide_lvalue_call (n);
            n->visit (this);
    }
}
void
tracepoint_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
{
  if (e->addressof)
    throw SEMANTIC_ERROR(_("cannot take address of context variable"), e->tok);
  if (is_active_lvalue (e))
    throw SEMANTIC_ERROR(_F("write to tracepoint '%s' not permitted", e->name.c_str()), e->tok);
  if (e->name == "$$name")
    {
      e->assert_no_components("tracepoint");
            embedded_expr *expr = new embedded_expr;
      expr->tok = e->tok;
      expr->code = string("/* string */ /* pure */ ")
    + string("c->ips.tracepoint_name ? c->ips.tracepoint_name : \"\"");
      provide (expr);
    }
  else if (e->name == "$$vars" || e->name == "$$parms")
    {
      e->assert_no_components("tracepoint", true);
      print_format* pf = print_format::create(e->tok, "sprintf");
      for (unsigned i = 0; i < args.size(); ++i)
        {
          if (!args[i].usable)
            continue;
          if (i > 0)
            pf->raw_components += " ";
          pf->raw_components += args[i].name;
          target_symbol *tsym = new target_symbol;
          tsym->tok = e->tok;
          tsym->name = "$" + args[i].name;
          tsym->components = e->components;
                    tsym->saved_conversion_error = 0;
          expression *texp = require<expression> (tsym);           if (tsym->saved_conversion_error)             {
              if (dw.sess.verbose>2)
                for (const semantic_error *c = tsym->saved_conversion_error;
                     c != 0; c = c->get_chain())
                  clog << _("variable location problem [man error::dwarf]: ") << c->what() << endl;
              pf->raw_components += "=?";
              continue;
            }
          if (e->check_pretty_print ())
            pf->raw_components += "=%s";
          else
            pf->raw_components += args[i].isptr ? "=%p" : "=%#x";
          pf->args.push_back(texp);
        }
      pf->components = print_format::string_to_components(pf->raw_components);
      provide (pf);
    }
  else
    assert(0); }
void
tracepoint_var_expanding_visitor::visit_target_symbol (target_symbol* e)
{
  try
    {
      assert(e->name.size() > 0 && e->name[0] == '$');
      if (e->name == "$$name" || e->name == "$$parms" || e->name == "$$vars")
        visit_target_symbol_context (e);
      else
        visit_target_symbol_arg (e);
    }
  catch (const semantic_error &er)
    {
      e->chain (er);
      provide (e);
    }
}
tracepoint_derived_probe::tracepoint_derived_probe (systemtap_session& s,
                                                    dwflpp& dw, Dwarf_Die& func_die,
                                                    const string& tracepoint_name,
                                                    probe* base, probe_point* loc):
  derived_probe (base, loc, true ),
  sess (s), tracepoint_name (tracepoint_name)
{
    vector<probe_point::component*> comps;
  comps.push_back (new probe_point::component (TOK_KERNEL));
  comps.push_back (new probe_point::component (TOK_TRACE, new literal_string (tracepoint_name)));
  this->sole_location()->components = comps;
    build_args(dw, func_die);
    string decl_file = dwarf_decl_file(&func_die);
  header = decl_file;
#if 0#endif
    XXX    XXX  size_t header_pos = header.find("_event_types");
  if (header_pos != string::npos)
    header.erase(header_pos, 12);
    tracepoint_var_expanding_visitor v (dw, name, args);
  v.replace (this->body);
  for (unsigned i = 0; i < args.size(); i++)
    if (args[i].used)
      {
    vardecl* v = new vardecl;
    v->name = "__tracepoint_arg_" + args[i].name;
    v->tok = this->tok;
    v->set_arity(0, this->tok);
    v->type = pe_long;
    v->synthetic = true;
    this->locals.push_back (v);
      }
  if (sess.verbose > 2)
    clog << "tracepoint-based " << name << " tracepoint='" << tracepoint_name << "'" << endl;
}
static bool
resolve_pointer_type(Dwarf_Die& die, bool& isptr)
{
  if (null_die(&die))
    {
      isptr = true;
      return true;
    }
  Dwarf_Die type;
  switch (dwarf_tag(&die))
    {
    case DW_TAG_typedef:
    case DW_TAG_const_type:
    case DW_TAG_volatile_type:
    case DW_TAG_restrict_type:
            return (dwarf_attr_die(&die, DW_AT_type, &die)
              && resolve_pointer_type(die, isptr));
    case DW_TAG_base_type:
    case DW_TAG_enumeration_type:
    case DW_TAG_structure_type:
    case DW_TAG_union_type:
                  isptr = false;
      return true;
    case DW_TAG_array_type:
    case DW_TAG_pointer_type:
    case DW_TAG_reference_type:
    case DW_TAG_rvalue_reference_type:
                  isptr = true;
      type = die;
      while (dwarf_attr_die(&type, DW_AT_type, &type))
        {
                              int tag = dwarf_tag(&type);
          if (tag != DW_TAG_typedef &&
              tag != DW_TAG_const_type &&
              tag != DW_TAG_volatile_type &&
              tag != DW_TAG_restrict_type)
            {
              die = type;
              return true;
            }
        }
            std::memset(&die, 0, sizeof(die));
      return true;
    default:
            return false;
    }
}
static bool
resolve_tracepoint_arg_type(tracepoint_arg& arg)
{
  if (!resolve_pointer_type(arg.type_die, arg.isptr))
    return false;
  if (arg.isptr)
    arg.typecast = "(intptr_t)";
  else if (dwarf_tag(&arg.type_die) == DW_TAG_structure_type ||
           dwarf_tag(&arg.type_die) == DW_TAG_union_type)
    {
                  arg.isptr = true;
      arg.typecast = "(intptr_t)&";
    }
  return true;
}
void
tracepoint_derived_probe::build_args(dwflpp&, Dwarf_Die& func_die)
{
  Dwarf_Die arg;
  if (dwarf_child(&func_die, &arg) == 0)
    do
      if (dwarf_tag(&arg) == DW_TAG_formal_parameter)
        {
                    tracepoint_arg tparg;
          tparg.name = dwarf_diename(&arg) ?: "";
                    if (!dwarf_attr_die (&arg, DW_AT_type, &tparg.type_die)
              || !dwarf_type_name(&tparg.type_die, tparg.c_type))
            throw SEMANTIC_ERROR (_F("cannot get type of parameter '%s' of tracepoint '%s'",
                                     tparg.name.c_str(), tracepoint_name.c_str()));
          tparg.usable = resolve_tracepoint_arg_type(tparg);
          args.push_back(tparg);
          if (sess.verbose > 4)
            clog << _F("found parameter for tracepoint '%s': type:'%s' name:'%s' %s",
                       tracepoint_name.c_str(), tparg.c_type.c_str(), tparg.name.c_str(),
                       tparg.usable ? "ok" : "unavailable") << endl;
        }
    while (dwarf_siblingof(&arg, &arg) == 0);
}
void
tracepoint_derived_probe::getargs(std::list<std::string> &arg_set) const
{
  for (unsigned i = 0; i < args.size(); ++i)
    if (args[i].usable)
      arg_set.push_back("$"+args[i].name+":"+args[i].c_type);
}
void
tracepoint_derived_probe::join_group (systemtap_session& s)
{
  if (! s.tracepoint_derived_probes)
    s.tracepoint_derived_probes = new tracepoint_derived_probe_group ();
  s.tracepoint_derived_probes->enroll (this);
  this->group = s.tracepoint_derived_probes;
}
void
tracepoint_derived_probe::print_dupe_stamp(ostream& o)
{
  for (unsigned i = 0; i < args.size(); i++)
    if (args[i].used)
      o << "__tracepoint_arg_" << args[i].name << endl;
}
static vector<string> tracepoint_extra_decls (systemtap_session& s, const string& header)
{
  vector<string> they_live;
    XXX  they_live.push_back ("#include <linux/skbuff.h>");
      if (s.kernel_config["CONFIG_KVM"] != string("")) {
    they_live.push_back ("#include <linux/kvm_host.h>");
  }
  if (header.find("xfs") != string::npos && s.kernel_config["CONFIG_XFS_FS"] != string("")) {
    they_live.push_back ("#define XFS_BIG_BLKNOS 1");
    if (s.kernel_source_tree != "")
      they_live.push_back ("#include \"fs/xfs/xfs_types.h\"");     they_live.push_back ("struct xfs_mount;");
    they_live.push_back ("struct xfs_inode;");
    they_live.push_back ("struct xfs_buf;");
    they_live.push_back ("struct xfs_bmbt_irec;");
    they_live.push_back ("struct xfs_trans;");
  }
  if (header.find("nfs") != string::npos && s.kernel_config["CONFIG_NFSD"] != string("")) {
    they_live.push_back ("struct rpc_task;");
  }
    if (header.find("rpc") != string::npos && s.kernel_config["CONFIG_NFSD"] != string("")) {
    they_live.push_back ("struct rpc_clnt;");
    they_live.push_back ("struct rpc_wait_queue;");
  }
  they_live.push_back ("#include <asm/cputime.h>");
    they_live.push_back ("struct cpu_workqueue_struct;");
  if (header.find("ext4") != string::npos && s.kernel_config["CONFIG_EXT4_FS"] != string(""))
    if (s.kernel_source_tree != "")
      they_live.push_back ("#include \"fs/ext4/ext4.h\""); 
  if (header.find("ext3") != string::npos)
    they_live.push_back ("struct ext3_reserve_window_node;");
  if (header.find("workqueue") != string::npos)
    {
      they_live.push_back ("struct pool_workqueue;");
      they_live.push_back ("struct work_struct;");
    }
  if (header.find("asoc") != string::npos)
    they_live.push_back ("struct snd_soc_dapm_path;");
  if (header.find("9p") != string::npos)
    {
      they_live.push_back ("struct p9_client;");
      they_live.push_back ("struct p9_fcall;");
    }
  if (header.find("bcache") != string::npos)
    {
      they_live.push_back ("struct bkey;");
      they_live.push_back ("struct btree;");
      they_live.push_back ("struct cache_set;");
      they_live.push_back ("struct cache;");
    }
  if (header.find("f2fs") != string::npos)
    {
            they_live.push_back ("typedef u32 block_t;");
      they_live.push_back ("typedef u32 nid_t;");
    }
  if (header.find("radeon") != string::npos)
    they_live.push_back ("struct radeon_bo;");
      XXX
  if (header.find("/ath/") != string::npos)
    they_live.push_back ("struct ath5k_hw;");
  return they_live;
}
void
tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
{
  if (probes.empty())
    return;
  s.op->newline() << "/* ---- tracepoint probes ---- */";
  s.op->newline() << "#include <linux/stp_tracepoint.h>" << endl;
  s.op->newline();
      
  map<string,translator_output*> per_header_aux;
  
  for (unsigned i = 0; i < probes.size(); ++i)
    {
      tracepoint_derived_probe *p = probes[i];
      string header = p->header;
                  translator_output *tpop = per_header_aux[header];
      if (tpop == 0)
        {
          tpop = s.op_create_auxiliary();
          per_header_aux[header] = tpop;
                              const vector<string>& extra_decls = tracepoint_extra_decls (s, header);
          for (unsigned z=0; z<extra_decls.size(); z++)
            tpop->newline() << extra_decls[z] << "\n";
                    size_t root_pos = header.rfind("include/");
          header = ((root_pos != string::npos) ? header.substr(root_pos + 8) : header);
          tpop->newline() << "#include <linux/stp_tracepoint.h>" << endl;
          tpop->newline() << "#include <" << header << ">";
        }
            vector<const tracepoint_arg*> used_args;
      for (unsigned j = 0; j < p->args.size(); ++j)
        if (p->args[j].used)
          used_args.push_back(&p->args[j]);
                  string enter_real_fn = "enter_real_tracepoint_probe_" + lex_cast(i);
      if (used_args.empty())
        {
          tpop->newline() << "STP_TRACE_ENTER_REAL_NOARGS(" << enter_real_fn << ");";
          s.op->newline() << "STP_TRACE_ENTER_REAL_NOARGS(" << enter_real_fn << ")";
        }
      else
        {
          tpop->newline() << "STP_TRACE_ENTER_REAL(" << enter_real_fn;
          s.op->newline() << "STP_TRACE_ENTER_REAL(" << enter_real_fn;
          s.op->indent(2);
          for (unsigned j = 0; j < used_args.size(); ++j)
            {
              tpop->line() << ", int64_t";
              s.op->newline() << ", int64_t __tracepoint_arg_" << used_args[j]->name;
            }
          tpop->line() << ");";
          s.op->newline() << ")";
          s.op->indent(-2);
        }
      s.op->newline() << "{";
      s.op->newline(1) << "const struct stap_probe * const probe = "
                       << common_probe_init (p) << ";";
      common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "probe",
                     "stp_probe_type_tracepoint");
      s.op->newline() << "c->ips.tracepoint_name = "
                      << lex_cast_qstring (p->tracepoint_name)
                      << ";";
      for (unsigned j = 0; j < used_args.size(); ++j)
        {
          s.op->newline() << "c->probe_locals." << p->name
                          << "." + s.up->c_localname("__tracepoint_arg_" + used_args[j]->name)
                          << " = __tracepoint_arg_" << used_args[j]->name << ";";
        }
      s.op->newline() << "(*probe->ph) (c);";
      common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
      s.op->newline(-1) << "}";
            string enter_fn = "enter_tracepoint_probe_" + lex_cast(i);
      if (p->args.empty())
        tpop->newline() << "static STP_TRACE_ENTER_NOARGS(" << enter_fn << ")";
      else
        {
          tpop->newline() << "static STP_TRACE_ENTER(" << enter_fn;
          s.op->indent(2);
          for (unsigned j = 0; j < p->args.size(); ++j)
            {
              tpop->newline() << ", " << p->args[j].c_type
                              << " __tracepoint_arg_" << p->args[j].name;
            }
          tpop->newline() << ")";
          s.op->indent(-2);
        }
      tpop->newline() << "{";
      tpop->newline(1) << enter_real_fn << "(";
      tpop->indent(2);
      for (unsigned j = 0; j < used_args.size(); ++j)
        {
          if (j > 0)
            tpop->line() << ", ";
          tpop->newline() << "(int64_t)" << used_args[j]->typecast
                          << "__tracepoint_arg_" << used_args[j]->name;
        }
      tpop->newline() << ");";
      tpop->newline(-3) << "}";
            tpop->newline() << "int register_tracepoint_probe_" << i << "(void) {";
      tpop->newline(1) << "return STP_TRACE_REGISTER(" << p->tracepoint_name
                       << ", " << enter_fn << ");";
      tpop->newline(-1) << "}";
                              tpop->newline() << "void unregister_tracepoint_probe_" << i << "(void) {";
      tpop->newline(1) << "(void) STP_TRACE_UNREGISTER(" << p->tracepoint_name
                       << ", " << enter_fn << ");";
      tpop->newline(-1) << "}";
      tpop->newline();
            s.op->newline() << "int register_tracepoint_probe_" << i << "(void);";
      s.op->newline() << "void unregister_tracepoint_probe_" << i << "(void);";
      tpop->assert_0_indent();
    }
    s.op->newline() << "static struct stap_tracepoint_probe {";
  s.op->newline(1) << "int (*reg)(void);";
  s.op->newline(0) << "void (*unreg)(void);";
  s.op->newline(-1) << "} stap_tracepoint_probes[] = {";
  s.op->indent(1);
  for (unsigned i = 0; i < probes.size(); ++i)
    {
      s.op->newline () << "{";
      s.op->line() << " .reg=®ister_tracepoint_probe_" << i << ",";
      s.op->line() << " .unreg=&unregister_tracepoint_probe_" << i;
      s.op->line() << " },";
    }
  s.op->newline(-1) << "};";
  s.op->newline();
}
void
tracepoint_derived_probe_group::emit_module_init (systemtap_session &s)
{
  if (probes.size () == 0)
    return;
  s.op->newline() << "/* init tracepoint probes */";
  s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
  s.op->newline(1) << "rc = stap_tracepoint_probes[i].reg();";
  s.op->newline() << "if (rc) {";
  s.op->newline(1) << "for (j=i-1; j>=0; j--)";   s.op->newline(1) << "stap_tracepoint_probes[j].unreg();";
  s.op->newline(-1) << "break;";   s.op->newline(-1) << "}";
  s.op->newline(-1) << "}";
        
      }
void
tracepoint_derived_probe_group::emit_module_exit (systemtap_session& s)
{
  if (probes.empty())
    return;
  s.op->newline() << "/* deregister tracepoint probes */";
  s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
  s.op->newline(1) << "stap_tracepoint_probes[i].unreg();";
  s.op->indent(-1);
  
  }
struct tracepoint_query : public base_query
{
  tracepoint_query(dwflpp & dw, const string & tracepoint,
                   probe * base_probe, probe_point * base_loc,
                   vector<derived_probe *> & results):
    base_query(dw, "*"), tracepoint(tracepoint),
    base_probe(base_probe), base_loc(base_loc),
    results(results) {}
  const string& tracepoint;
  probe * base_probe;
  probe_point * base_loc;
  vector<derived_probe *> & results;
  set<string> probed_names;
  void handle_query_module();
  int handle_query_cu(Dwarf_Die * cudie);
  int handle_query_func(Dwarf_Die * func);
  void query_library (const char *) {}
  void query_plt (const char *entry, size_t addr) {}
  static int tracepoint_query_cu (Dwarf_Die * cudie, tracepoint_query * q);
  static int tracepoint_query_func (Dwarf_Die * func, tracepoint_query * q);
};
void
tracepoint_query::handle_query_module()
{
    dw.iterate_over_cus(tracepoint_query_cu, this, false);
}
int
tracepoint_query::handle_query_cu(Dwarf_Die * cudie)
{
  dw.focus_on_cu (cudie);
  dw.mod_info->get_symtab();
    string function = "stapprobe_" + tracepoint;
  return dw.iterate_over_functions (tracepoint_query_func, this, function);
}
int
tracepoint_query::handle_query_func(Dwarf_Die * func)
{
  dw.focus_on_function (func);
  assert(startswith(dw.function_name, "stapprobe_"));
  string tracepoint_instance = dw.function_name.substr(10);
      if (!probed_names.insert(tracepoint_instance).second)
    return DWARF_CB_OK;
    if (!sess.guru_mode)
    {
      if ((sess.architecture.substr(0,3) == "ppc" ||
           sess.architecture.substr(0,7) == "powerpc") &&
          (tracepoint_instance == "hcall_entry" ||
           tracepoint_instance == "hcall_exit"))
        {
          sess.print_warning(_F("tracepoint %s is blacklisted on architecture %s",
                                tracepoint_instance.c_str(), sess.architecture.c_str()));
          return DWARF_CB_OK;
        }
  }
  derived_probe *dp = new tracepoint_derived_probe (dw.sess, dw, *func,
                                                    tracepoint_instance,
                                                    base_probe, base_loc);
  results.push_back (dp);
  return DWARF_CB_OK;
}
int
tracepoint_query::tracepoint_query_cu (Dwarf_Die * cudie, tracepoint_query * q)
{
  if (pending_interrupts) return DWARF_CB_ABORT;
  return q->handle_query_cu(cudie);
}
int
tracepoint_query::tracepoint_query_func (Dwarf_Die * func, tracepoint_query * q)
{
  if (pending_interrupts) return DWARF_CB_ABORT;
  return q->handle_query_func(func);
}
struct tracepoint_builder: public derived_probe_builder
{
private:
  dwflpp *dw;
  bool init_dw(systemtap_session& s);
  void get_tracequery_modules(systemtap_session& s,
                              const vector<string>& headers,
                              vector<string>& modules);
public:
  tracepoint_builder(): dw(0) {}
  ~tracepoint_builder() { delete dw; }
  void build_no_more (systemtap_session& s)
  {
    if (dw && s.verbose > 3)
      clog << _("tracepoint_builder releasing dwflpp") << endl;
    delete dw;
    dw = NULL;
    delete_session_module_cache (s);
  }
  void build(systemtap_session& s,
             probe *base, probe_point *location,
             literal_map_t const& parameters,
             vector<derived_probe*>& finished_results);
};
void
tracepoint_builder::get_tracequery_modules(systemtap_session& s,
                                           const vector<string>& headers,
                                           vector<string>& modules)
{
  if (s.verbose > 2)
    {
      clog << _F("Pass 2: getting a tracepoint query for %zu headers: ", headers.size()) << endl;
      for (size_t i = 0; i < headers.size(); ++i)
        clog << "  " << headers[i] << endl;
    }
  map<string,string> headers_cache_obj;          vector<string> uncached_headers;
  for (size_t i=0; i<headers.size(); i++)
    headers_cache_obj[headers[i]] = find_tracequery_hash(s, headers[i]);
    if (s.use_cache && !s.poison_cache)
    for (size_t i=0; i<headers.size(); i++)
      {
                const string& tracequery_path = headers_cache_obj[headers[i]];
        if (!tracequery_path.empty() && file_exists(tracequery_path))
          {
            if (s.verbose > 2)
              clog << _F("Pass 2: using cached %s", tracequery_path.c_str()) << endl;
                        if (get_file_size(tracequery_path) > 0)
              modules.push_back (tracequery_path);
          }
        else
          uncached_headers.push_back(headers[i]);
      }
  else
    uncached_headers = headers;
    if (uncached_headers.empty()) return;
  map<string,string> headers_tracequery_src; 
      for (size_t i=0; i<uncached_headers.size(); i++)
    {
      const string& header = uncached_headers[i];
            ostringstream osrc;
                  vector<string> short_decls = tracepoint_extra_decls(s, header);
            size_t root_pos = header.rfind("include/");
      short_decls.push_back(string("#include <") +
                            ((root_pos != string::npos) ? header.substr(root_pos + 8) : header) +
                            string(">"));
      osrc << "#ifdef CONFIG_TRACEPOINTS" << endl;
      osrc << "#include <linux/tracepoint.h>" << endl;
                  osrc << "#ifndef PARAMS" << endl;
      osrc << "#define PARAMS(args...) args" << endl;
      osrc << "#endif" << endl;
            osrc << "#undef DECLARE_TRACE" << endl;
      osrc << "#define DECLARE_TRACE(name, proto, args) \\" << endl;
      osrc << "  void stapprobe_##name(proto) {}" << endl;
            osrc << "#undef DECLARE_TRACE_NOARGS" << endl;
      osrc << "#define DECLARE_TRACE_NOARGS(name) \\" << endl;
      osrc << "  DECLARE_TRACE(name, void, )" << endl;
            osrc << "#undef DECLARE_TRACE_CONDITION" << endl;
      osrc << "#define DECLARE_TRACE_CONDITION(name, proto, args, cond) \\" << endl;
      osrc << "  DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))" << endl;
            osrc << "#undef DEFINE_TRACE" << endl;
      osrc << "#define DEFINE_TRACE(name, proto, args) \\" << endl;
      osrc << "  DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))" << endl;
            for (unsigned z=0; z<short_decls.size(); z++)
        osrc << "#undef TRACE_INCLUDE_FILE\n"
             << "#undef TRACE_INCLUDE_PATH\n"
             << short_decls[z] << "\n";
            osrc << "#endif /* CONFIG_TRACEPOINTS */" << endl;
            headers_tracequery_src[header] = osrc.str();
    }
    map<string,string> tracequery_objs = make_tracequeries(s, headers_tracequery_src);
    if (s.use_cache)
    for (size_t i=0; i<uncached_headers.size(); i++)
      {
        const string& header = uncached_headers[i];
        const string& tracequery_obj = tracequery_objs[header];
        const string& tracequery_path = headers_cache_obj[header];
        if (tracequery_obj !="" && file_exists(tracequery_obj))
          {
            copy_file(tracequery_obj, tracequery_path, s.verbose > 2);
            modules.push_back (tracequery_path);
          }
        else
                    copy_file("/dev/null", tracequery_path, s.verbose > 2);
      }
}
bool
tracepoint_builder::init_dw(systemtap_session& s)
{
  if (dw != NULL)
    return true;
  vector<string> tracequery_modules;
  vector<string> system_headers;
  glob_t trace_glob;
    if (s.kernel_source_tree == "")
    {
      unsigned found;
      Dwfl *dwfl = setup_dwfl_kernel ("kernel", &found, s);
      if (found)
        {
          Dwarf_Die *cudie = 0;
          Dwarf_Addr bias;
          while ((cudie = dwfl_nextcu (dwfl, cudie, &bias)) != NULL)
            {
              assert_no_interrupts();
              Dwarf_Attribute attr;
              const char* name = dwarf_formstring (dwarf_attr (cudie, DW_AT_comp_dir, &attr));
              if (name)
                {
                                    if (file_exists(name))
                    {
                      if (s.verbose > 2)
                        clog << _F("Located kernel source tree (DW_AT_comp_dir) at '%s'", name) << endl;
                      s.kernel_source_tree = name;
                    }
                  else
                    {
                      if (s.verbose > 2)
                        clog << _F("Ignoring inaccessible kernel source tree (DW_AT_comp_dir) at '%s'", name) << endl;
                    }
                  break;                 }
            }
        }
      dwfl_end (dwfl);
    }
    vector<string> glob_prefixes;
  glob_prefixes.push_back (s.kernel_build_tree);
  if (s.kernel_source_tree != "")
    glob_prefixes.push_back (s.kernel_source_tree);
    vector<string> glob_suffixes;
  glob_suffixes.push_back("include/trace/events/*.h");
  glob_suffixes.push_back("include/trace/*.h");
  glob_suffixes.push_back("include/ras/*_event.h");
  glob_suffixes.push_back("arch/x86/kvm/*trace.h");
  glob_suffixes.push_back("arch/x86/kernel/*trace.h");
  glob_suffixes.push_back("arch/*/include/asm/trace*.h");
  glob_suffixes.push_back("arch/*/include/asm/trace/*.h");
  glob_suffixes.push_back("fs/xfs/linux-*/xfs_tr*.h");
  glob_suffixes.push_back("fs/*/*trace*.h");
  glob_suffixes.push_back("net/*/*trace*.h");
  glob_suffixes.push_back("sound/pci/hda/*_trace.h");
  glob_suffixes.push_back("drivers/gpu/drm/*_trace.h");
  glob_suffixes.push_back("drivers/gpu/drm/*/*_trace.h");
  glob_suffixes.push_back("drivers/net/wireless/*/*/*trace*.h");
  glob_suffixes.push_back("drivers/usb/host/*trace*.h");
  
    vector<string> globs;
  for (unsigned i=0; i<glob_prefixes.size(); i++)
    for (unsigned j=0; j<glob_suffixes.size(); j++)
      globs.push_back (glob_prefixes[i]+string("/")+glob_suffixes[j]);
  set<string> duped_headers;
  for (unsigned z = 0; z < globs.size(); z++)
    {
      string glob_str = globs[z];
      if (s.verbose > 3)
        clog << _("Checking tracepoint glob ") << glob_str << endl;
      int r = glob(glob_str.c_str(), 0, NULL, &trace_glob);
      if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
        throw runtime_error("Error globbing tracepoint");
      for (unsigned i = 0; i < trace_glob.gl_pathc; ++i)
        {
          string header(trace_glob.gl_pathv[i]);
                    if (endswith(header, "/define_trace.h") ||
              endswith(header, "/ftrace.h")       ||
              endswith(header, "/trace_events.h") ||
              endswith(header, "_event_types.h"))
            continue;
                    #if 0
#endif
          system_headers.push_back(header);
        }
      globfree(&trace_glob);
    }
    get_tracequery_modules(s, system_headers, tracequery_modules);
  TODO  
  dw = new dwflpp(s, tracequery_modules, true);
  return true;
}
void
tracepoint_builder::build(systemtap_session& s,
                          probe *base, probe_point *location,
                          literal_map_t const& parameters,
                          vector<derived_probe*>& finished_results)
{
  if (!init_dw(s))
    return;
  string tracepoint;
  assert(get_param (parameters, TOK_TRACE, tracepoint));
  tracepoint_query q(*dw, tracepoint, base, location, finished_results);
  unsigned results_pre = finished_results.size();
  dw->iterate_over_modules<base_query>(&query_module, &q);
  unsigned results_post = finished_results.size();
    if (results_pre == results_post)
    {
      size_t pos;
      string sugs = suggest_dwarf_functions(s, q.visited_modules, tracepoint);
      while ((pos = sugs.find("stapprobe_")) != string::npos)
        sugs.erase(pos, string("stapprobe_").size());
      if (!sugs.empty())
        throw SEMANTIC_ERROR (_NF("no match (similar tracepoint: %s)",
                                  "no match (similar tracepoints: %s)",
                                  sugs.find(',') == string::npos,
                                  sugs.c_str()));
    }
}
void
register_standard_tapsets(systemtap_session & s)
{
  register_tapset_been(s);
  register_tapset_itrace(s);
  register_tapset_mark(s);
  register_tapset_procfs(s);
  register_tapset_timers(s);
  register_tapset_netfilter(s);
  register_tapset_utrace(s);
    dwarf_derived_probe::register_patterns(s);
  XXX  s.pattern_root->bind_num(TOK_PROCESS)
    ->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)
    ->bind_privilege(pr_all)
    ->bind(new uprobe_builder ());
  s.pattern_root->bind_num(TOK_PROCESS)
    ->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(TOK_RETURN)
    ->bind_privilege(pr_all)
    ->bind(new uprobe_builder ());
    s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_TRACE)
    ->bind(new tracepoint_builder());
    s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_FUNCTION)
     ->bind(new kprobe_builder());
  s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_FUNCTION)->bind(TOK_CALL)
     ->bind(new kprobe_builder());
  s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_MODULE)
     ->bind_str(TOK_FUNCTION)->bind(new kprobe_builder());
  s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_MODULE)
     ->bind_str(TOK_FUNCTION)->bind(TOK_CALL)->bind(new kprobe_builder());
  s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_FUNCTION)->bind(TOK_RETURN)
     ->bind(new kprobe_builder());
  s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_FUNCTION)->bind(TOK_RETURN)
     ->bind_num(TOK_MAXACTIVE)->bind(new kprobe_builder());
  s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_MODULE)
     ->bind_str(TOK_FUNCTION)->bind(TOK_RETURN)->bind(new kprobe_builder());
  s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_MODULE)
     ->bind_str(TOK_FUNCTION)->bind(TOK_RETURN)
     ->bind_num(TOK_MAXACTIVE)->bind(new kprobe_builder());
  s.pattern_root->bind(TOK_KPROBE)->bind_num(TOK_STATEMENT)
      ->bind(TOK_ABSOLUTE)->bind(new kprobe_builder());
        s.pattern_root->bind(TOK_KERNEL)->bind_num(TOK_HWBKPT)
    ->bind(TOK_HWBKPT_WRITE)->bind(new hwbkpt_builder());
  s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_HWBKPT)
    ->bind(TOK_HWBKPT_WRITE)->bind(new hwbkpt_builder());
  s.pattern_root->bind(TOK_KERNEL)->bind_num(TOK_HWBKPT)
    ->bind(TOK_HWBKPT_RW)->bind(new hwbkpt_builder());
  s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_HWBKPT)
    ->bind(TOK_HWBKPT_RW)->bind(new hwbkpt_builder());
  s.pattern_root->bind(TOK_KERNEL)->bind_num(TOK_HWBKPT)
    ->bind_num(TOK_LENGTH)->bind(TOK_HWBKPT_WRITE)->bind(new hwbkpt_builder());
  s.pattern_root->bind(TOK_KERNEL)->bind_num(TOK_HWBKPT)
    ->bind_num(TOK_LENGTH)->bind(TOK_HWBKPT_RW)->bind(new hwbkpt_builder());
  
    register_tapset_perf(s);
  register_tapset_java(s);
}
vector<derived_probe_group*>
all_session_groups(systemtap_session& s)
{
  vector<derived_probe_group*> g;
#define DOONE(x) \
  if (s. x##_derived_probes) \
    g.push_back ((derived_probe_group*)(s. x##_derived_probes))
              DOONE(be);
  DOONE(dwarf);
  DOONE(uprobe);
  DOONE(timer);
  DOONE(profile);
  DOONE(mark);
  DOONE(tracepoint);
  DOONE(kprobe);
  DOONE(hwbkpt);
  DOONE(perf);
  DOONE(hrtimer);
  DOONE(procfs);
  DOONE(netfilter);
        DOONE(utrace);
  DOONE(itrace);
  DOONE(dynprobe);
  DOONE(task_finder);
#undef DOONE
  return g;
}