This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB 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] More C++ static fields for tracepoints


This patch solves a couple intertwined problems relating to tracepoint collection of C++ classes with static fields. First, it adds recognition of variables (including static fields) whose location expressions indicate that they have been optimized out. Second, to collect an instance of a class with static fields, we need to issue more bytecodes, since static fields are stored at their own addresses, separately from the instance. The two are intertwined because when collecting the instance, we want to silently pass over any optimized-out static fields instead of error()ing out. (And believe it or not, all this was motivated by tracepoints choking on actual user code...)

Stan

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.



Index: ax-gdb.c
===================================================================
RCS file: /cvs/src/src/gdb/ax-gdb.c,v
retrieving revision 1.68
diff -p -r1.68 ax-gdb.c
*** ax-gdb.c	16 Mar 2010 00:52:54 -0000	1.68
--- ax-gdb.c	17 Mar 2010 22:02:00 -0000
*************** static struct value *const_var_ref (stru
*** 70,76 ****
  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_sign_extend (struct agent_expr *, struct type *);
  static void gen_extend (struct agent_expr *, struct type *);
--- 70,76 ----
  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 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 *);
*************** static void gen_struct_ref (struct expre
*** 144,150 ****
  			    struct axs_value *value,
  			    char *field,
  			    char *operator_name, char *operand_name);
! static void gen_static_field (struct expression *exp,
  			      struct agent_expr *ax, struct axs_value *value,
  			      struct type *type, int fieldno);
  static void gen_repeat (struct expression *exp, union exp_element **pc,
--- 144,150 ----
  			    struct axs_value *value,
  			    char *field,
  			    char *operator_name, char *operand_name);
! 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,
*************** maybe_const_expr (union exp_element **pc
*** 331,341 ****
     emits the trace bytecodes at the appropriate points.  */
  static int trace_kludge;
  
  /* 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)
  {
    if (trace_kludge)
      switch (value->kind)
--- 331,394 ----
     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 gdbarch *gdbarch,
! 		struct agent_expr *ax, struct axs_value *value)
  {
    if (trace_kludge)
      switch (value->kind)
*************** gen_traced_pop (struct agent_expr *ax, s
*** 371,376 ****
--- 424,435 ----
    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);
  }
  
  
*************** gen_var_ref (struct gdbarch *gdbarch, st
*** 554,559 ****
--- 613,619 ----
  {
    /* 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))
*************** gen_var_ref (struct gdbarch *gdbarch, st
*** 650,657 ****
        break;
  
      case LOC_OPTIMIZED_OUT:
!       error (_("The variable `%s' has been optimized out."),
! 	     SYMBOL_PRINT_NAME (var));
        break;
  
      default:
--- 710,718 ----
        break;
  
      case LOC_OPTIMIZED_OUT:
!       /* Flag this, but don't say anything; leave it up to callers to
! 	 warn the user.  */
!       value->optimized_out = 1;
        break;
  
      default:
*************** gen_struct_ref_recursive (struct express
*** 1342,1348 ****
  		 being handled as a global.  */
  	      if (field_is_static (&TYPE_FIELD (type, i)))
  		{
! 		  gen_static_field (exp, ax, value, type, i);
  		  return 1;
  		}
  
--- 1403,1412 ----
  		 being handled as a global.  */
  	      if (field_is_static (&TYPE_FIELD (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;
  		}
  
*************** gen_maybe_namespace_elt (struct expressi
*** 1425,1431 ****
  			 const struct type *curtype, char *name);
  
  static void
! gen_static_field (struct expression *exp,
  		  struct agent_expr *ax, struct axs_value *value,
  		  struct type *type, int fieldno)
  {
--- 1489,1495 ----
  			 const struct type *curtype, char *name);
  
  static void
! gen_static_field (struct gdbarch *gdbarch,
  		  struct agent_expr *ax, struct axs_value *value,
  		  struct type *type, int fieldno)
  {
*************** gen_static_field (struct expression *exp
*** 1434,1448 ****
        ax_const_l (ax, TYPE_FIELD_STATIC_PHYSADDR (type, fieldno));
        value->kind = axs_lvalue_memory;
        value->type = TYPE_FIELD_TYPE (type, fieldno);
      }
    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);
      }
  }
  
--- 1498,1524 ----
        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)
! 	{
! 	  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;
! 	}
      }
  }
  
*************** gen_struct_elt_for_reference (struct exp
*** 1468,1474 ****
  	{
  	  if (field_is_static (&TYPE_FIELD (t, i)))
  	    {
! 	      gen_static_field (exp, ax, value, t, i);
  	      return 1;
  	    }
  	  if (TYPE_FIELD_PACKED (t, i))
--- 1544,1553 ----
  	{
  	  if (field_is_static (&TYPE_FIELD (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_maybe_namespace_elt (struct expressi
*** 1526,1531 ****
--- 1605,1614 ----
  
    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;
  }
  
*************** gen_expr (struct expression *exp, union 
*** 1815,1821 ****
        /* 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_expr (exp, pc, ax, value);
        /* It's the consumer's responsibility to trace the right operand.  */
        break;
--- 1898,1904 ----
        /* 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 (exp->gdbarch, ax, &value1);
        gen_expr (exp, pc, ax, value);
        /* It's the consumer's responsibility to trace the right operand.  */
        break;
*************** gen_expr (struct expression *exp, union 
*** 1831,1836 ****
--- 1914,1924 ----
  
      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;
  
*************** gen_expr (struct expression *exp, union 
*** 2004,2009 ****
--- 2092,2102 ----
  	  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;
*************** cannot subscript requested type: cannot 
*** 2199,2205 ****
     name comes from a list of local variables of a function.  */
  
  struct agent_expr *
! gen_trace_for_var (CORE_ADDR scope, struct symbol *var)
  {
    struct cleanup *old_chain = 0;
    struct agent_expr *ax = new_agent_expr (scope);
--- 2292,2299 ----
     name comes from a list of local variables of a function.  */
  
  struct agent_expr *
! 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);
*************** gen_trace_for_var (CORE_ADDR scope, stru
*** 2208,2217 ****
    old_chain = make_cleanup_free_agent_expr (ax);
  
    trace_kludge = 1;
!   gen_var_ref (NULL, ax, &value, var);
  
    /* Make sure we record the final object, and get rid of it.  */
!   gen_traced_pop (ax, &value);
  
    /* Oh, and terminate.  */
    ax_simple (ax, aop_end);
--- 2302,2319 ----
    old_chain = make_cleanup_free_agent_expr (ax);
  
    trace_kludge = 1;
!   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 (gdbarch, ax, &value);
  
    /* Oh, and terminate.  */
    ax_simple (ax, aop_end);
*************** gen_trace_for_expr (CORE_ADDR scope, str
*** 2245,2251 ****
    gen_expr (expr, &pc, ax, &value);
  
    /* Make sure we record the final object, and get rid of it.  */
!   gen_traced_pop (ax, &value);
  
    /* Oh, and terminate.  */
    ax_simple (ax, aop_end);
--- 2347,2353 ----
    gen_expr (expr, &pc, ax, &value);
  
    /* Make sure we record the final object, and get rid of it.  */
!   gen_traced_pop (expr->gdbarch, ax, &value);
  
    /* Oh, and terminate.  */
    ax_simple (ax, aop_end);
Index: ax-gdb.h
===================================================================
RCS file: /cvs/src/src/gdb/ax-gdb.h,v
retrieving revision 1.14
diff -p -r1.14 ax-gdb.h
*** ax-gdb.h	1 Jan 2010 07:31:30 -0000	1.14
--- ax-gdb.h	17 Mar 2010 22:02:00 -0000
*************** struct axs_value
*** 81,86 ****
--- 81,90 ----
         "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 */
*************** struct axs_value
*** 99,105 ****
     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_eval_for_expr (CORE_ADDR, struct expression *);
  
--- 103,110 ----
     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 gdbarch *,
! 					     struct symbol *);
  
  extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
  
Index: dwarf2loc.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2loc.c,v
retrieving revision 1.73
diff -p -r1.73 dwarf2loc.c
*** dwarf2loc.c	26 Feb 2010 12:48:18 -0000	1.73
--- dwarf2loc.c	17 Mar 2010 22:02:00 -0000
*************** dwarf2_tracepoint_var_ref (struct symbol
*** 619,629 ****
  			   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
        && data[0] >= DW_OP_reg0
        && data[0] <= DW_OP_reg31)
      {
--- 619,629 ----
  			   struct agent_expr *ax, struct axs_value *value,
  			   gdb_byte *data, int size)
  {
!   if (!data || size == 0)
!     {
!       value->optimized_out = 1;
!     }
!   else if (size == 1
        && data[0] >= DW_OP_reg0
        && data[0] <= DW_OP_reg31)
      {
*************** loclist_tracepoint_var_ref (struct symbo
*** 883,890 ****
    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);
  }
--- 883,888 ----
Index: tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.c,v
retrieving revision 1.146
diff -p -r1.146 tracepoint.c
*** tracepoint.c	12 Mar 2010 03:54:45 -0000	1.146
--- tracepoint.c	17 Mar 2010 22:02:00 -0000
*************** collect_symbol (struct collection_list *
*** 949,954 ****
--- 949,955 ----
    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))
*************** collect_symbol (struct collection_list *
*** 973,979 ****
  			   SYMBOL_PRINT_NAME (sym), len,
  			   tmp /* address */);
  	}
!       add_memrange (collect, memrange_absolute, offset, len);
        break;
      case LOC_REGISTER:
        reg = SYMBOL_REGISTER_OPS (sym)->register_number (sym, gdbarch);
--- 974,985 ----
  			   SYMBOL_PRINT_NAME (sym), len,
  			   tmp /* address */);
  	}
!       /* 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);
*************** collect_symbol (struct collection_list *
*** 1038,1086 ****
        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);
! 		  }
! 	      }
! 	  }
!       }
        break;
      }
  }
  
  /* Add all locals (or args) symbols to collection list */
--- 1044,1105 ----
        break;
  
      case LOC_COMPUTED:
!       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 */

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