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 *);
                            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,
    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)
   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
 
 {
   /* 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))
       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:
                 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;
                }
 
                         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)
 {
       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;
+       }
     }
 }
 
        {
          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))
 
   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;
 }
 
       /* 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;
 
     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;
 
          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;
    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);
   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);
   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);
 
   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))
                           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);
       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 */