[PATCH] Revised: Allow struct compare in expressions.

Michael Snyder msnyder@cygnus.com
Thu Mar 23 11:54:00 GMT 2000


I've revised this patch, to account for the concern that a 
binary compare might fail because of padding bytes.  This
supercedes the previous patch.  We now compare struct objects
field by field, instead of using a binary compare.

The following change allows GDB to evaluate (and set watchpoints on)
expressions of the form (a == b) and (a != b), where a and b are
simple C structs or unions.  It would be possible to extend this
further by allowing simple binary comparison for classes that don't
have an operator== method: I leave that as an exercise for someone
else.

Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.167
diff -c -r1.167 ChangeLog
*** ChangeLog	2000/03/23 04:27:26	1.167
--- ChangeLog	2000/03/23 19:51:28
***************
*** 1,3 ****
--- 1,12 ----
+ 2000-03-22  Michael Snyder  <msnyder@cleaver.cygnus.com>
+ 
+ 	* eval.c (evaluate_subexp_standard): allow for simple comparison
+ 	of structures, in the absense of C++ method symbols.
+ 	* symtab.c (total_number_of_methods): make public, for use above.
+ 	* symtab.h (total_number_of_methods): publish prototype.
+ 	* valarith.c (value_struct_equal): New function.  Compare
+ 	struct values field by field, to avoid comparing padding bytes.
+ 	
  2000-03-22  Kevin Buettner  <kevinb@redhat.com>
  
  	* ia64-linux-nat.c: Fix copyright.
Index: eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.2
diff -c -r1.2 eval.c
*** eval.c	2000/03/14 17:01:04	1.2
--- eval.c	2000/03/23 19:51:28
***************
*** 1448,1454 ****
        arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
        if (noside == EVAL_SKIP)
  	goto nosideret;
!       if (binop_user_defined_p (op, arg1, arg2))
  	{
  	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
  	}
--- 1448,1459 ----
        arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
        if (noside == EVAL_SKIP)
  	goto nosideret;
! 
!       /* NOTE: because BINOP_EQUAL is a legal operator for 
! 	 C structs (as opposed to C++ classes), revert to 
! 	 simple value comparison if the type has no methods.  */
!       if (binop_user_defined_p (op, arg1, arg2) &&
! 	  total_number_of_methods (arg1->type) > 0)
  	{
  	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
  	}
***************
*** 1463,1469 ****
        arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
        if (noside == EVAL_SKIP)
  	goto nosideret;
!       if (binop_user_defined_p (op, arg1, arg2))
  	{
  	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
  	}
--- 1468,1479 ----
        arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
        if (noside == EVAL_SKIP)
  	goto nosideret;
! 
!       /* NOTE: because BINOP_NOTEQUAL is a legal operator for 
! 	 C structs (as opposed to C++ classes), revert to 
! 	 simple value comparison if the type has no methods.  */
!       if (binop_user_defined_p (op, arg1, arg2) &&
! 	  total_number_of_methods (arg1->type) > 0)
  	{
  	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
  	}
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.2
diff -c -r1.2 symtab.c
*** symtab.c	2000/02/08 04:39:02	1.2
--- symtab.c	2000/03/23 19:51:28
***************
*** 2217,2225 ****
     reader because the type of the baseclass might still be stubbed
     when the definition of the derived class is parsed.  */
  
! static int total_number_of_methods PARAMS ((struct type * type));
! 
! static int
  total_number_of_methods (type)
       struct type *type;
  {
--- 2217,2223 ----
     reader because the type of the baseclass might still be stubbed
     when the definition of the derived class is parsed.  */
  
! int
  total_number_of_methods (type)
       struct type *type;
  {
Index: symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.4
diff -c -r1.4 symtab.h
*** symtab.h	2000/03/21 22:37:42	1.4
--- symtab.h	2000/03/23 19:51:28
***************
*** 1462,1467 ****
--- 1462,1472 ----
  extern int
  in_prologue PARAMS ((CORE_ADDR pc, CORE_ADDR func_start));
  
+ /* Number of method symbols for TYPE
+    (and all its base classes) */
+ extern int 
+ total_number_of_methods PARAMS ((struct type * type));
+ 
  extern struct symbol *
    fixup_symbol_section PARAMS ((struct symbol *, struct objfile *));
  
Index: valarith.c
===================================================================
RCS file: /cvs/src/src/gdb/valarith.c,v
retrieving revision 1.1.1.3
diff -c -r1.1.1.3 valarith.c
*** valarith.c	1999/12/14 01:05:39	1.1.1.3
--- valarith.c	2000/03/23 19:51:28
***************
*** 1187,1192 ****
--- 1187,1262 ----
      return 0;
  }
  
+ /* Simulate the C operator == on a pair of struct or class values.
+    Return 1 if all defined fields have equal value (including inherited ones).
+    Note: recursive function.  Operates by comparing each struct member, 
+    rather than by doing a binary compare.  */
+ 
+ int 
+ value_struct_equal (arg1, arg2, outer_type, base_type)
+      value_ptr arg1, arg2;
+      struct type *outer_type, *base_type;
+ {
+   value_ptr member1, member2;
+   struct type *this_type;
+   int i;
+ 
+   if (base_type != NULL)
+     this_type = base_type;
+   else
+     this_type = outer_type;
+ 
+   /* Compare the immediate (not inherited) fields of this object. */
+   for (i =  TYPE_NFIELDS (this_type) - 1;
+        i >= TYPE_N_BASECLASSES (this_type);
+        i--)
+     {
+       if (TYPE_FIELD_STATIC (this_type, i))
+ 	{
+ 	  /* static fields are (of course) always equal.  */
+ 	  continue;
+ 	}
+       else if (TYPE_VPTR_BASETYPE (this_type) == this_type &&
+ 	       TYPE_VPTR_FIELDNO  (this_type) == i)
+ 	{
+ 	  /* Don't compare the vptr.  */
+ 	  continue;
+ 	}
+       else if (TYPE_FIELD_IGNORE (this_type, i))
+ 	{
+ 	  /* Don't compare a field marked "ignore".  */
+ 	  continue;
+ 	}
+       else if (strncmp ("_vb.", TYPE_FIELD_NAME (this_type, i), 4) == 0)
+ 	{
+ 	  /* Don't compare a virtual base pointer.  */
+ 	  continue;
+ 	}
+       else
+ 	{
+ 	  member1 = value_struct_elt (&arg1, NULL, 
+ 				      TYPE_FIELD_NAME (this_type, i),
+ 				      NULL, "struct/union");
+ 	  member2 = value_struct_elt (&arg2, NULL, 
+ 				      TYPE_FIELD_NAME (this_type, i),
+ 				      NULL, "struct/union");
+ 
+ 	  /* Note: mutually-recursive call with value_equal.  */
+ 	  if (!value_equal (member1, member2))
+ 	    return 0;	/* found inequality. */
+ 	}
+     }
+ 
+   /* Now compare each base object by recursing.  */
+   for (i = 0; i < TYPE_N_BASECLASSES (this_type); i++)
+     if (!value_struct_equal (arg1, arg2, outer_type, 
+ 			     check_typedef (TYPE_BASECLASS (this_type, i))))
+       return 0;		/* base objects differ */
+ 
+   return 1;		/* made it to the end -- they're equal */
+ }
+ 
+ 
  /* Simulate the C operator == by returning a 1
     iff ARG1 and ARG2 have equal contents.  */
  
***************
*** 1195,1201 ****
       register value_ptr arg1, arg2;
  
  {
!   register int len;
    register char *p1, *p2;
    struct type *type1, *type2;
    enum type_code code1;
--- 1265,1271 ----
       register value_ptr arg1, arg2;
  
  {
!   register int len, i;
    register char *p1, *p2;
    struct type *type1, *type2;
    enum type_code code1;
***************
*** 1224,1229 ****
--- 1294,1307 ----
    else if (code2 == TYPE_CODE_PTR && (code1 == TYPE_CODE_INT || code1 == TYPE_CODE_BOOL))
      return (CORE_ADDR) value_as_long (arg1) == value_as_pointer (arg2);
  
+   else if ((code1 == TYPE_CODE_STRUCT && type2 == type1) ||
+ 	   (code1 == TYPE_CODE_UNION  && type2 == type1))
+     {
+       /* Compare struct/union values the hard way (field by field),
+        to avoid comparing padding values.  */
+ 
+       return value_struct_equal (arg1, arg2, type1, NULL);
+     }
    else if (code1 == code2
  	   && ((len = (int) TYPE_LENGTH (type1))
  	       == (int) TYPE_LENGTH (type2)))


More information about the Gdb-patches mailing list