2010-03-17 Stan Shebs <stan@codesourcery.com>
authorStan Shebs <shebs@codesourcery.com>
Wed, 17 Mar 2010 22:04:43 +0000 (22:04 +0000)
committerStan Shebs <shebs@codesourcery.com>
Wed, 17 Mar 2010 22:04:43 +0000 (22:04 +0000)
* ax-gdb.h (struct axs_value): New field optimized_out.
(gen_trace_for_var): Add gdbarch argument.
* ax-gdb.c (gen_trace_static_fields): New function.
(gen_traced_pop): Call it, add gdbarch argument.
(gen_trace_for_expr): Update call to it.
(gen_trace_for_var): Ditto, and report optimized-out variables.
(gen_struct_ref_recursive): Check for optimized-out value.
(gen_struct_elt_for_reference): Ditto.
(gen_static_field): Pass gdbarch instead of expression, assume
optimization if field not found.
(gen_var_ref): Set the optimized_out flag.
(gen_expr): Error on optimized-out variable.
* tracepoint.c (collect_symbol): Handle struct-valued vars as
expressions, skip optimized-out variables with computed locations.
* dwarf2loc.c (dwarf2_tracepoint_var_ref): Flag instead of
erroring out if location expression missing.
(loclist_tracepoint_var_ref): Don't error out here.

gdb/ChangeLog
gdb/ax-gdb.c
gdb/ax-gdb.h
gdb/dwarf2loc.c
gdb/tracepoint.c

index da6e1f8..af86e48 100644 (file)
@@ -1,3 +1,23 @@
+2010-03-17 Stan Shebs  <stan@codesourcery.com>
+
+       * ax-gdb.h (struct axs_value): New field optimized_out.
+       (gen_trace_for_var): Add gdbarch argument.
+       * ax-gdb.c (gen_trace_static_fields): New function.
+       (gen_traced_pop): Call it, add gdbarch argument.
+       (gen_trace_for_expr): Update call to it.
+       (gen_trace_for_var): Ditto, and report optimized-out variables.
+       (gen_struct_ref_recursive): Check for optimized-out value.
+       (gen_struct_elt_for_reference): Ditto.
+       (gen_static_field): Pass gdbarch instead of expression, assume
+       optimization if field not found.
+       (gen_var_ref): Set the optimized_out flag.
+       (gen_expr): Error on optimized-out variable.
+       * tracepoint.c (collect_symbol): Handle struct-valued vars as
+       expressions, skip optimized-out variables with computed locations.
+       * dwarf2loc.c (dwarf2_tracepoint_var_ref): Flag instead of
+       erroring out if location expression missing.
+       (loclist_tracepoint_var_ref): Don't error out here.
+
 2010-03-17  Tom Tromey  <tromey@redhat.com>
 
        * dwarf2read.c (dwarf2_get_section_info): Handle case where no
index 0e95bdf..091fd95 100644 (file)
@@ -70,7 +70,7 @@ static struct value *const_var_ref (struct symbol *var);
 static struct value *const_expr (union exp_element **pc);
 static struct value *maybe_const_expr (union exp_element **pc);
 
-static void gen_traced_pop (struct agent_expr *, struct axs_value *);
+static void gen_traced_pop (struct gdbarch *, struct agent_expr *, struct axs_value *);
 
 static void gen_sign_extend (struct agent_expr *, struct type *);
 static void gen_extend (struct agent_expr *, struct type *);
@@ -144,7 +144,7 @@ static void gen_struct_ref (struct expression *exp, struct agent_expr *ax,
                            struct axs_value *value,
                            char *field,
                            char *operator_name, char *operand_name);
-static void gen_static_field (struct expression *exp,
+static void gen_static_field (struct gdbarch *gdbarch,
                              struct agent_expr *ax, struct axs_value *value,
                              struct type *type, int fieldno);
 static void gen_repeat (struct expression *exp, union exp_element **pc,
@@ -331,11 +331,64 @@ maybe_const_expr (union exp_element **pc)
    emits the trace bytecodes at the appropriate points.  */
 static int trace_kludge;
 
+/* Scan for all static fields in the given class, including any base
+   classes, and generate tracing bytecodes for each.  */
+
+static void
+gen_trace_static_fields (struct gdbarch *gdbarch,
+                        struct agent_expr *ax,
+                        struct type *type)
+{
+  int i, nbases = TYPE_N_BASECLASSES (type);
+  struct axs_value value;
+
+  CHECK_TYPEDEF (type);
+
+  for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--)
+    {
+      if (field_is_static (&TYPE_FIELD (type, i)))
+       {
+         gen_static_field (gdbarch, ax, &value, type, i);
+         if (value.optimized_out)
+           continue;
+         switch (value.kind)
+           {
+           case axs_lvalue_memory:
+             {
+               int length = TYPE_LENGTH (check_typedef (value.type));
+
+               ax_const_l (ax, length);
+               ax_simple (ax, aop_trace);
+             }
+             break;
+
+           case axs_lvalue_register:
+             /* We need to mention the register somewhere in the bytecode,
+                so ax_reqs will pick it up and add it to the mask of
+                registers used.  */
+             ax_reg (ax, value.u.reg);
+
+           default:
+             break;
+           }
+       }
+    }
+
+  /* Now scan through base classes recursively.  */
+  for (i = 0; i < nbases; i++)
+    {
+      struct type *basetype = check_typedef (TYPE_BASECLASS (type, i));
+
+      gen_trace_static_fields (gdbarch, ax, basetype);
+    }
+}
+
 /* Trace the lvalue on the stack, if it needs it.  In either case, pop
    the value.  Useful on the left side of a comma, and at the end of
    an expression being used for tracing.  */
 static void
-gen_traced_pop (struct agent_expr *ax, struct axs_value *value)
+gen_traced_pop (struct gdbarch *gdbarch,
+               struct agent_expr *ax, struct axs_value *value)
 {
   if (trace_kludge)
     switch (value->kind)
@@ -371,6 +424,12 @@ gen_traced_pop (struct agent_expr *ax, struct axs_value *value)
   else
     /* If we're not tracing, just pop the value.  */
     ax_simple (ax, aop_pop);
+
+  /* To trace C++ classes with static fields stored elsewhere.  */
+  if (trace_kludge
+      && (TYPE_CODE (value->type) == TYPE_CODE_STRUCT
+         || TYPE_CODE (value->type) == TYPE_CODE_UNION))
+    gen_trace_static_fields (gdbarch, ax, value->type);
 }
 \f
 
@@ -554,6 +613,7 @@ gen_var_ref (struct gdbarch *gdbarch, struct agent_expr *ax,
 {
   /* Dereference any typedefs. */
   value->type = check_typedef (SYMBOL_TYPE (var));
+  value->optimized_out = 0;
 
   /* I'm imitating the code in read_var_value.  */
   switch (SYMBOL_CLASS (var))
@@ -650,8 +710,9 @@ gen_var_ref (struct gdbarch *gdbarch, struct agent_expr *ax,
       break;
 
     case LOC_OPTIMIZED_OUT:
-      error (_("The variable `%s' has been optimized out."),
-            SYMBOL_PRINT_NAME (var));
+      /* Flag this, but don't say anything; leave it up to callers to
+        warn the user.  */
+      value->optimized_out = 1;
       break;
 
     default:
@@ -1342,7 +1403,10 @@ gen_struct_ref_recursive (struct expression *exp, struct agent_expr *ax,
                 being handled as a global.  */
              if (field_is_static (&TYPE_FIELD (type, i)))
                {
-                 gen_static_field (exp, ax, value, type, i);
+                 gen_static_field (exp->gdbarch, ax, value, type, i);
+                 if (value->optimized_out)
+                   error (_("static field `%s' has been optimized out, cannot use"),
+                          field);
                  return 1;
                }
 
@@ -1425,7 +1489,7 @@ gen_maybe_namespace_elt (struct expression *exp,
                         const struct type *curtype, char *name);
 
 static void
-gen_static_field (struct expression *exp,
+gen_static_field (struct gdbarch *gdbarch,
                  struct agent_expr *ax, struct axs_value *value,
                  struct type *type, int fieldno)
 {
@@ -1434,15 +1498,27 @@ gen_static_field (struct expression *exp,
       ax_const_l (ax, TYPE_FIELD_STATIC_PHYSADDR (type, fieldno));
       value->kind = axs_lvalue_memory;
       value->type = TYPE_FIELD_TYPE (type, fieldno);
+      value->optimized_out = 0;
     }
   else
     {
       char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
       struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0);
-      if (sym == NULL)
-       error (_("symbol not found"));
 
-      gen_var_ref (exp->gdbarch, ax, value, sym);
+      if (sym)
+       {
+         gen_var_ref (gdbarch, ax, value, sym);
+  
+         /* Don't error if the value was optimized out, we may be
+            scanning all static fields and just want to pass over this
+            and continue with the rest.  */
+       }
+      else
+       {
+         /* Silently assume this was optimized out; class printing
+            will let the user know why the data is missing.  */
+         value->optimized_out = 1;
+       }
     }
 }
 
@@ -1468,7 +1544,10 @@ gen_struct_elt_for_reference (struct expression *exp,
        {
          if (field_is_static (&TYPE_FIELD (t, i)))
            {
-             gen_static_field (exp, ax, value, t, i);
+             gen_static_field (exp->gdbarch, ax, value, t, i);
+             if (value->optimized_out)
+               error (_("static field `%s' has been optimized out, cannot use"),
+                      fieldname);
              return 1;
            }
          if (TYPE_FIELD_PACKED (t, i))
@@ -1526,6 +1605,10 @@ gen_maybe_namespace_elt (struct expression *exp,
 
   gen_var_ref (exp->gdbarch, ax, value, sym);
 
+  if (value->optimized_out)
+    error (_("`%s' has been optimized out, cannot use"),
+          SYMBOL_PRINT_NAME (sym));
+
   return 1;
 }
 
@@ -1815,7 +1898,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
       /* Don't just dispose of the left operand.  We might be tracing,
          in which case we want to emit code to trace it if it's an
          lvalue.  */
-      gen_traced_pop (ax, &value1);
+      gen_traced_pop (exp->gdbarch, ax, &value1);
       gen_expr (exp, pc, ax, value);
       /* It's the consumer's responsibility to trace the right operand.  */
       break;
@@ -1831,6 +1914,11 @@ gen_expr (struct expression *exp, union exp_element **pc,
 
     case OP_VAR_VALUE:
       gen_var_ref (exp->gdbarch, ax, value, (*pc)[2].symbol);
+
+      if (value->optimized_out)
+       error (_("`%s' has been optimized out, cannot use"),
+              SYMBOL_PRINT_NAME ((*pc)[2].symbol));
+
       (*pc) += 4;
       break;
 
@@ -2004,6 +2092,11 @@ gen_expr (struct expression *exp, union exp_element **pc,
          error (_("no `%s' found"), this_name);
 
        gen_var_ref (exp->gdbarch, ax, value, sym);
+
+       if (value->optimized_out)
+         error (_("`%s' has been optimized out, cannot use"),
+                SYMBOL_PRINT_NAME (sym));
+
        (*pc) += 2;
       }
       break;
@@ -2199,7 +2292,8 @@ cannot subscript requested type: cannot call user defined functions"));
    name comes from a list of local variables of a function.  */
 
 struct agent_expr *
-gen_trace_for_var (CORE_ADDR scope, struct symbol *var)
+gen_trace_for_var (CORE_ADDR scope, struct gdbarch *gdbarch,
+                  struct symbol *var)
 {
   struct cleanup *old_chain = 0;
   struct agent_expr *ax = new_agent_expr (scope);
@@ -2208,10 +2302,18 @@ gen_trace_for_var (CORE_ADDR scope, struct symbol *var)
   old_chain = make_cleanup_free_agent_expr (ax);
 
   trace_kludge = 1;
-  gen_var_ref (NULL, ax, &value, var);
+  gen_var_ref (gdbarch, ax, &value, var);
+
+  /* If there is no actual variable to trace, flag it by returning
+     an empty agent expression.  */
+  if (value.optimized_out)
+    {
+      do_cleanups (old_chain);
+      return NULL;
+    }
 
   /* Make sure we record the final object, and get rid of it.  */
-  gen_traced_pop (ax, &value);
+  gen_traced_pop (gdbarch, ax, &value);
 
   /* Oh, and terminate.  */
   ax_simple (ax, aop_end);
@@ -2245,7 +2347,7 @@ gen_trace_for_expr (CORE_ADDR scope, struct expression *expr)
   gen_expr (expr, &pc, ax, &value);
 
   /* Make sure we record the final object, and get rid of it.  */
-  gen_traced_pop (ax, &value);
+  gen_traced_pop (expr->gdbarch, ax, &value);
 
   /* Oh, and terminate.  */
   ax_simple (ax, aop_end);
index a5f3768..4ec21e1 100644 (file)
@@ -81,6 +81,10 @@ struct axs_value
        "pointer to" an object of this type. */
     struct type *type;
 
+    /* If nonzero, this is a variable which does not actually exist in
+       the program.  */
+    char optimized_out;
+
     union
       {
        /* if kind == axs_lvalue_register, this is the register number */
@@ -99,7 +103,8 @@ struct axs_value
    function to discover which registers the expression uses.  */
 extern struct agent_expr *gen_trace_for_expr (CORE_ADDR, struct expression *);
 
-extern struct agent_expr *gen_trace_for_var (CORE_ADDR, struct symbol *);
+extern struct agent_expr *gen_trace_for_var (CORE_ADDR, struct gdbarch *,
+                                            struct symbol *);
 
 extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
 
index 20ede3e..ed7dfb9 100644 (file)
@@ -619,11 +619,11 @@ dwarf2_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
                           struct agent_expr *ax, struct axs_value *value,
                           gdb_byte *data, int size)
 {
-  if (size == 0)
-    error (_("Symbol \"%s\" has been optimized out."),
-          SYMBOL_PRINT_NAME (symbol));
-
-  if (size == 1
+  if (!data || size == 0)
+    {
+      value->optimized_out = 1;
+    }
+  else if (size == 1
       && data[0] >= DW_OP_reg0
       && data[0] <= DW_OP_reg31)
     {
@@ -883,8 +883,6 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
   size_t size;
 
   data = find_location_expression (dlbaton, &size, ax->scope);
-  if (data == NULL)
-    error (_("Variable \"%s\" is not available."), SYMBOL_NATURAL_NAME (symbol));
 
   dwarf2_tracepoint_var_ref (symbol, gdbarch, ax, value, data, size);
 }
index e1679fa..b621334 100644 (file)
@@ -949,6 +949,7 @@ collect_symbol (struct collection_list *collect,
   unsigned long len;
   unsigned int reg;
   bfd_signed_vma offset;
+  int treat_as_expr = 0;
 
   len = TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym)));
   switch (SYMBOL_CLASS (sym))
@@ -973,7 +974,12 @@ collect_symbol (struct collection_list *collect,
                           SYMBOL_PRINT_NAME (sym), len,
                           tmp /* address */);
        }
-      add_memrange (collect, memrange_absolute, offset, len);
+      /* A struct may be a C++ class with static fields, go to general
+        expression handling.  */
+      if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT)
+       treat_as_expr = 1;
+      else
+       add_memrange (collect, memrange_absolute, offset, len);
       break;
     case LOC_REGISTER:
       reg = SYMBOL_REGISTER_OPS (sym)->register_number (sym, gdbarch);
@@ -1038,49 +1044,62 @@ collect_symbol (struct collection_list *collect,
       break;
 
     case LOC_COMPUTED:
-      {
-       struct agent_expr *aexpr;
-       struct cleanup *old_chain1 = NULL;
-       struct agent_reqs areqs;
-
-       aexpr = gen_trace_for_var (scope, sym);
-
-       old_chain1 = make_cleanup_free_agent_expr (aexpr);
-
-       ax_reqs (aexpr, &areqs);
-       if (areqs.flaw != agent_flaw_none)
-         error (_("malformed expression"));
-       
-       if (areqs.min_height < 0)
-         error (_("gdb: Internal error: expression has min height < 0"));
-       if (areqs.max_height > 20)
-         error (_("expression too complicated, try simplifying"));
-
-       discard_cleanups (old_chain1);
-       add_aexpr (collect, aexpr);
-
-       /* take care of the registers */
-       if (areqs.reg_mask_len > 0)
-         {
-           int ndx1, ndx2;
-
-           for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
-             {
-               QUIT;   /* allow user to bail out with ^C */
-               if (areqs.reg_mask[ndx1] != 0)
-                 {
-                   /* assume chars have 8 bits */
-                   for (ndx2 = 0; ndx2 < 8; ndx2++)
-                     if (areqs.reg_mask[ndx1] & (1 << ndx2))
-                       /* it's used -- record it */
-                       add_register (collect, 
-                                     ndx1 * 8 + ndx2);
-                 }
-             }
-         }
-      }
+      treat_as_expr = 1;
       break;
     }
+
+  /* Expressions are the most general case.  */
+  if (treat_as_expr)
+    {
+      struct agent_expr *aexpr;
+      struct cleanup *old_chain1 = NULL;
+      struct agent_reqs areqs;
+
+      aexpr = gen_trace_for_var (scope, gdbarch, sym);
+
+      /* It can happen that the symbol is recorded as a computed
+        location, but it's been optimized away and doesn't actually
+        have a location expression.  */
+      if (!aexpr)
+       {
+         printf_filtered ("%s has been optimized out of existence.\n",
+                          SYMBOL_PRINT_NAME (sym));
+         return;
+       }
+
+      old_chain1 = make_cleanup_free_agent_expr (aexpr);
+
+      ax_reqs (aexpr, &areqs);
+      if (areqs.flaw != agent_flaw_none)
+       error (_("malformed expression"));
+      
+      if (areqs.min_height < 0)
+       error (_("gdb: Internal error: expression has min height < 0"));
+      if (areqs.max_height > 20)
+       error (_("expression too complicated, try simplifying"));
+
+      discard_cleanups (old_chain1);
+      add_aexpr (collect, aexpr);
+
+      /* take care of the registers */
+      if (areqs.reg_mask_len > 0)
+       {
+         int ndx1, ndx2;
+
+         for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+           {
+             QUIT;     /* allow user to bail out with ^C */
+             if (areqs.reg_mask[ndx1] != 0)
+               {
+                 /* assume chars have 8 bits */
+                 for (ndx2 = 0; ndx2 < 8; ndx2++)
+                   if (areqs.reg_mask[ndx1] & (1 << ndx2))
+                     /* it's used -- record it */
+                     add_register (collect, ndx1 * 8 + ndx2);
+               }
+           }
+       }
+    }
 }
 
 /* Add all locals (or args) symbols to collection list */