This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix sematic error: empty struct


This error occurs when a particular module is in a file that never
used the elements of the structure (so it ends up being stubbed out
with DW_AT_declaration).  You can see this by trying to probe in
libata:ata_qc_issue:

probe module("libata").function("ata_qc_issue") {
      if ($qc->scsicmd->device->host->host_no  != 3 &&
          $qc->scsicmd->device->id != 0) {
      	 next;
      }
      ...
}

The fix is to collect a list of all such declarations globally and
allow them to be referred back to a defining instance of the structure
or union.  The patch implements this by having a global_alias_cache
which is used to cache defining DIEs for all structures or unions that
turn up wiht declarations elsewhere in the code.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
 tapsets.cxx |  105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 105 insertions(+), 0 deletions(-)

diff --git a/tapsets.cxx b/tapsets.cxx
index 38b075d..800835a 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -1157,6 +1157,52 @@ struct dwflpp
 
   // -----------------------------------------------------------------
 
+  /* The global alias cache is used to resolve any DIE found in a
+   * module that is stubbed out with DW_AT_declaration for a defining
+   * DIE found in a different module.  The current assumption is that
+   * this only applies to structures and unions, which have a global
+   * namespace (it deliberately only traverses program scope), so this
+   * cache is indexed by name.  If other declaration lookups were
+   * added to it, it would have to be indexed by name and tag
+   */
+  static cu_function_cache_t global_alias_cache;
+
+  static int global_alias_caching_callback(Dwarf_Die *die, void *arg)
+  {
+    int pass = (int)arg;
+    const char *name = dwarf_diename(die);
+
+    if (!name)
+      return DWARF_CB_OK;
+
+    string structure_name = name;
+
+    // add new declarations (don't replace: they might be resolved)
+    if (pass == 0 && dwarf_hasattr(die, DW_AT_declaration) &&
+	global_alias_cache.find(structure_name) ==
+	global_alias_cache.end())
+	global_alias_cache[structure_name] = *die;
+    else if (pass == 1 && !dwarf_hasattr(die, DW_AT_declaration) &&
+	     global_alias_cache.find(structure_name) !=
+	     global_alias_cache.end())
+	global_alias_cache[structure_name] = *die;
+
+    return DWARF_CB_OK;
+  }
+
+  static Dwarf_Die *declaration_resolve(Dwarf_Die *die)
+  {
+    const char *name = dwarf_diename(die);
+
+    if (!name)
+      return NULL;
+
+    if (global_alias_cache.find(name) == global_alias_cache.end())
+      return NULL;
+
+    return &global_alias_cache[name];
+  }
+
   mod_cu_function_cache_t cu_function_cache;
 
   static int cu_function_caching_callback (Dwarf_Die* func, void *arg)
@@ -1169,6 +1215,22 @@ struct dwflpp
 
   int iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg),
                               void * data);
+  int iterate_over_globals (int (* callback)(Dwarf_Die *, void *),
+				 void * data);
+
+  int update_alias_cache(void)
+  {
+    int rc;
+
+    // do a two pass iteration; pass 0 looks for declarations
+    rc = iterate_over_globals(global_alias_caching_callback, (void *)0);
+    if (rc != DWARF_CB_OK)
+      return rc;
+    // pass 1 takes found declarations and points them to defining DIEs
+    rc = iterate_over_globals(global_alias_caching_callback, (void *)1);
+
+    return rc;
+  }
 
   bool has_single_line_record (dwarf_query * q, char const * srcfile, int lineno);
 
@@ -1834,6 +1896,14 @@ struct dwflpp
 	  case DW_TAG_structure_type:
 	  case DW_TAG_union_type:
 	    struct_die = *die;
+	    if (dwarf_hasattr(die, DW_AT_declaration))
+	      {
+		Dwarf_Die *tmpdie = dwflpp::declaration_resolve(die);
+		if (tmpdie == NULL)
+		  throw semantic_error ("unresolved struct "
+					+ string (dwarf_diename_integrate (die) ?: "<anonymous>"));
+		*die_mem = *tmpdie;
+	      }
 	    switch (dwarf_child (die, die_mem))
 	      {
 	      case 1:		/* No children.  */
@@ -2517,6 +2587,39 @@ dwflpp::has_single_line_record (dwarf_query * q, char const * srcfile, int linen
     return false;
   }
 
+cu_function_cache_t dwflpp::global_alias_cache;
+
+/* This basically only goes one level down from the compile unit so it
+ * only picks up top level stuff (i.e. nothing in a lower scope) */
+int
+dwflpp::iterate_over_globals (int (* callback)(Dwarf_Die *, void *),
+				   void * data)
+{
+  int rc = DWARF_CB_OK;
+  Dwarf_Die die;
+
+  assert (module);
+  assert (cu);
+  assert (dwarf_tag(cu) == DW_TAG_compile_unit);
+
+  if (dwarf_child(cu, &die) != 0)
+    return rc;
+
+  do {
+    /* We're only currently looking for structures and unions,
+     * although other types of declarations exist */
+    if (dwarf_tag(&die) != DW_TAG_structure_type &&
+	dwarf_tag(&die) != DW_TAG_union_type)
+      continue;
+
+    rc = (*callback)(&die, data);
+    if (rc != DWARF_CB_OK)
+      break;
+
+  } while (dwarf_siblingof(&die, &die) == 0);
+
+  return rc;
+}
 
 int
 dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg),
@@ -3505,6 +3608,8 @@ query_cu (Dwarf_Die * cudie, void * arg)
     {
       q->dw.focus_on_cu (cudie);
 
+      q->dw.update_alias_cache();
+
       if (false && q->sess.verbose>2)
         clog << "focused on CU '" << q->dw.cu_name
              << "', in module '" << q->dw.module_name << "'\n";
-- 
1.5.5.4




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]