From 6a8bbb53e3252e1cfe47e8c17dd6e3301adcab69 Mon Sep 17 00:00:00 2001
From: "agentzh (Yichun Zhang)" <agentzh@gmail.com>
Date: Wed, 29 May 2013 20:49:06 -0700
Subject: [PATCH] Allow use of @var("somevar@somefile", "somemodule") in stap
 functions and context-free probes.

---
 parse.cxx   |   5 ++
 staptree.h  |   3 +-
 tapsets.cxx | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/parse.cxx b/parse.cxx
index bbdc2ad..dfcc1c3 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -3661,6 +3661,11 @@ target_symbol* parser::parse_target_symbol (const token* t)
 	tsym->cu_name = tsym->target_name.substr(found_at + 1);
       else
 	tsym->cu_name = "";
+      if (peek_op (","))
+        {
+          swallow ();
+          expect_unknown(tok_string, tsym->module);
+        }
       expect_op(")");
       parse_target_symbol_components(tsym);
       tsym->addressof = addressof;
diff --git a/staptree.h b/staptree.h
index 8eac23d..8913151 100644
--- a/staptree.h
+++ b/staptree.h
@@ -270,6 +270,7 @@ struct target_symbol: public symbol
   bool addressof;
   std::string target_name;
   std::string cu_name;
+  std::string module;
   std::vector<component> components;
   semantic_error* saved_conversion_error; // hand-made linked list
   target_symbol(): addressof(false), saved_conversion_error (0) {}
@@ -288,7 +289,7 @@ std::ostream& operator << (std::ostream& o, const target_symbol::component& c);
 struct cast_op: public target_symbol
 {
   expression *operand;
-  std::string type_name, module;
+  std::string type_name;
   void print (std::ostream& o) const;
   void visit (visitor* u);
 };
diff --git a/tapsets.cxx b/tapsets.cxx
index 6bede4c..a56b778 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -3953,6 +3953,7 @@ struct dwarf_cast_expanding_visitor: public var_expanding_visitor
     s(s), db(db) {}
   void visit_cast_op (cast_op* e);
   void filter_special_modules(string& module);
+  void visit_target_symbol(target_symbol* e);
 };
 
 
@@ -4161,6 +4162,171 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
 }
 
 
+struct dwarf_var_query: public base_query
+{
+  target_symbol& e;
+  const bool userspace_p;
+  functioncall*& result;
+  vector<Dwarf_Die> *scopes;
+  unsigned& tick;
+
+  dwarf_var_query(dwflpp& dw, const string& module, target_symbol& e,
+                  const bool userspace_p, functioncall*& result,
+                  unsigned& tick):
+    base_query(dw, module), e(e),
+    userspace_p(userspace_p), result(result), scopes(NULL), tick(tick) {}
+
+  void handle_query_module();
+  void query_library(const char *) {}
+  void query_plt(const char *entry, size_t addr) {}
+  void getscopes(target_symbol *e);
+  ~dwarf_var_query() { if (scopes) delete scopes; }
+};
+
+
+void
+dwarf_var_query::handle_query_module()
+{
+  string fname = (string("_dwarf_tvar_get")
+                  + "_" + e.sym_name()
+                  + "_" + lex_cast(tick++));
+
+  getscopes(&e);
+
+  if (scopes->size() == 0)
+    return;
+
+  this->dw.focus_on_cu(&(scopes->at(0)));
+
+  exp_type type = pe_long;
+  string code = this->dw.literal_stmt_for_local(*scopes, 0, e.sym_name(),
+                                                &e, 0, type);
+
+  result = synthetic_embedded_deref_call(this->sess, fname, code, type,
+                                         userspace_p, 0, &e);
+}
+
+
+void
+dwarf_var_query::getscopes(target_symbol *e)
+{
+  Dwarf_Off cu_off = 0;
+  const char *cu_name = NULL;
+
+  string prefixed_srcfile = string("*/") + e->cu_name;
+
+  Dwarf_Off off = 0;
+  size_t cuhl;
+  Dwarf_Off noff;
+  Dwarf_Off module_bias;
+  Dwarf *dw = dwfl_module_getdwarf(this->dw.module, &module_bias);
+  while (dwarf_nextcu(dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0)
+    {
+      Dwarf_Die die_mem;
+      Dwarf_Die *die;
+      die = dwarf_offdie(dw, off + cuhl, &die_mem);
+
+      /* We are not interested in partial units. */
+      if (dwarf_tag(die) == DW_TAG_compile_unit)
+	{
+	  const char *die_name = dwarf_diename(die);
+	  if (e->cu_name.empty()
+              || strcmp(die_name, e->cu_name.c_str()) == 0) // Perfect match.
+	    {
+	      cu_name = die_name;
+	      cu_off = off + cuhl;
+	      break;
+	    }
+
+	  if (fnmatch(prefixed_srcfile.c_str(), die_name, 0) == 0)
+	    if (cu_name == NULL || strlen(die_name) < strlen (cu_name))
+	      {
+		cu_name = die_name;
+		cu_off = off + cuhl;
+	      }
+	}
+      off = noff;
+    }
+
+  if (cu_name == NULL)
+    throw semantic_error ("unable to find CU '" + e->cu_name + "'"
+			  + " while searching for '" + e->target_name + "'",
+			  e->tok);
+
+  //cerr << "Found CU name: " << cu_name << endl;
+
+  if (scopes)
+    delete scopes;
+
+  scopes = new vector<Dwarf_Die>;
+  Dwarf_Die cu_die;
+  dwarf_offdie(dw, cu_off, &cu_die);
+  scopes->push_back(cu_die);
+}
+
+
+void
+dwarf_cast_expanding_visitor::visit_target_symbol(target_symbol* e)
+{
+  //cerr << "accessing target_symbol " << e->sym_name() << endl;
+
+  if (is_active_lvalue(e)
+      || e->name != "@var"
+      || e->target_name.empty()
+      || e->module.empty()
+      || (!e->components.empty()
+          && e->components.back().type == target_symbol::comp_pretty_print))
+    {
+      provide(e);
+      return;
+    }
+
+  functioncall* result = NULL;
+
+  // split the module string by ':' for alternatives
+  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)
+	    {
+	      // kernel or kernel module target
+	      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)
+	{
+	  /* ignore and go to the next module */
+	  continue;
+	}
+
+      dwarf_var_query q (*dw, module, *e, userspace_p, result, tick);
+      dw->iterate_over_modules(&query_module, &q);
+    }
+
+  if (!result)
+    {
+      provide(e);
+      return;
+    }
+
+  result->visit (this);
+}
+
+
 void
 dwarf_derived_probe::printsig (ostream& o) const
 {
-- 
1.7.11.7

