public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Keith Seitz <keiths@redhat.com>
To: "gdb-patches@sourceware.org ml" <gdb-patches@sourceware.org>
Subject: Re: [RFA] mi/10586
Date: Sat, 17 Dec 2011 01:55:00 -0000	[thread overview]
Message-ID: <4EEBD762.1010201@redhat.com> (raw)
In-Reply-To: <m3ehw8b6rb.fsf@fleche.redhat.com>

[-- Attachment #1: Type: text/plain, Size: 2930 bytes --]

On 12/13/2011 11:39 AM, Tom Tromey wrote:
> I didn't see 'is_name_anonymous_type' anywhere in the tree or in the patch.
> I guess it needs an update.

I hate it when that happens! Comment updated.

> Keith>  +static int
> Keith>  +is_path_expr_parent (struct varobj *var)
> [...]
> Keith>  +  type  = get_value_type (var);
>
> Extra space.

Fixed.

> Keith>  +  return strncmp (child->name, ANONYMOUS_STRUCT_NAME, 11) == 0;
>
> I think this is wrong since the macros have _() in their expansion.
> I think you have to use strlen.

Yeah, very wrong indeed! I've fixed that test.

> Keith>  +	field_name = TYPE_FIELD_NAME (type, index);
> Keith>  +	if (*field_name == '\0')
>
> Can field_name == NULL?
> It is not clear to me.  There is some code in gdb that checks this, but
> I don't know whether that is defensive programming or checking a
> condition that is truly possible.

Comments in gdbtypes.h seem to indicate that name could be NULL, but 
I've not seen that. To be defensive, I've treated name == NULL and name 
== "" the same.

On 12/13/2011 11:58 AM, Jan Kratochvil wrote:
> Program received signal SIGSEGV, Segmentation fault.
> 0x00000000007ab58b in get_value_type (var=0x0) at varobj.c:2397
> 2397	  if (var->value)
> (gdb) bt
> #0  in get_value_type (var=0x0) at varobj.c:2397
> #1  in is_path_expr_parent (var=0x0) at varobj.c:1310
> #2  in get_path_expr_parent (var=0x2cbbd80) at varobj.c:1325
> #3  in c_describe_child (parent=0x2cbbd80, index=0, cname=0x0,
cvalue=0x0, ctype=0x0, cfull_expression=0x2cbf5f8) at varobj.c:3015
> #4  in c_path_expr_of_child (child=0x2cbf5f0) at varobj.c:3140
[snip]

I've fixed this, too, and added a test for that. A very simple omission: 
get_path_expr_parent was attempting to walk the parent chain past the 
root variable. Whoops.

Keith

ChangeLog
2011-12-16  Keith Seitz  <keiths@redhat.com>

	PR mi/10586
	* varobj.c (ANONYMOUS_STRUCT_NAME): Define.
	(ANONYMOUS_UNION_NAME): Define.
	(is_path_expr_parent): New function.
	(get_path_expr_parent): New function.
	(is_anonymous_child): New function.
	(create_child_with_value): If the child is anonymous and without
	a name, assign an object name to it.
	(c_describe_child): Use get_path_expr_parent to determine
	the parent expression.
	If there field represents an anonymous struct or union and
	has no name, set an appropriate display name and expression.
	(cplus_describe_child): Likewise.

testsuite/ChangeLog
2011-12-16  Keith Seitz  <keiths@redhat.com>

	PR mi/10586
	* gdb.mi/var-cmd.c (struct anonymous): New structure.
	(do_anonymous_type_tests): New function.
	(main): Call do_anonymous_type_tests.
	* gdb.mi/mi2-var-child.exp: Add anonymous type tests.
	(verify_everything): New procedure.
	* gdb.mi/mi-var-cp.cc (class A): New class.
	(anonymous_structs_and_unions): New function.
	(main): Call anonymous_structs_and_unions.
	* gdb.mi/mi-var-cp.exp: Add anonymous type tests.
	(verify_everything): New procedure.

[-- Attachment #2: 10586-3.patch --]
[-- Type: text/x-patch, Size: 14992 bytes --]

diff --git a/gdb/testsuite/gdb.mi/mi-var-cp.cc b/gdb/testsuite/gdb.mi/mi-var-cp.cc
index 54439e6..51d30cf 100644
--- a/gdb/testsuite/gdb.mi/mi-var-cp.cc
+++ b/gdb/testsuite/gdb.mi/mi-var-cp.cc
@@ -205,6 +205,51 @@ int path_expression ()
   /*: END: path_expression :*/
 }
 
+class Anonymous
+{
+public:
+  struct { /* index: 0 */
+    int b;
+  };
+  struct { /* index: 1 */
+    int c;
+  };
+  struct { /* index: 2 */
+    int d;
+    struct { /* index: 1 */
+      int e;
+      struct { /* index: 0 */
+        int f;
+        union { /* index: 0 */
+          int g;
+          char h;
+        };
+      };
+      union { /* index: 0 */
+        int i;
+        char j;
+      };
+    };
+  };
+};
+
+/* Test anonymous structs and unions.  */
+int
+anonymous_structs_and_unions (void)
+{
+  Anonymous a;
+  a.b = 1;
+  a.c = 2;
+  a.d = 3;
+  a.e = 4;
+  a.f = 5;
+  a.g = 6;
+  a.h = '7';
+  a.i = 8;
+  a.j = '8';
+  return 0;  /* anonymous_structs_and_unions */
+}
+
 int main ()
 {
   reference_update_tests ();
@@ -212,5 +257,6 @@ int main ()
   reference_to_pointer ();
   reference_to_struct ();
   path_expression ();
+  anonymous_structs_and_unions ();
   return 0;
 }
diff --git a/gdb/testsuite/gdb.mi/mi-var-cp.exp b/gdb/testsuite/gdb.mi/mi-var-cp.exp
index 4ca3a68..4fea332 100644
--- a/gdb/testsuite/gdb.mi/mi-var-cp.exp
+++ b/gdb/testsuite/gdb.mi/mi-var-cp.exp
@@ -46,5 +46,78 @@ mi_run_inline_test reference_to_pointer
 mi_run_inline_test reference_to_struct
 mi_run_inline_test path_expression
 
+set lineno [gdb_get_line_number "/* anonymous_structs_and_unions */"]
+mi_create_breakpoint \
+    "$srcfile:$lineno" {[0-9]+} keep {anonymous_structs_and_unions\(\)} \
+    ".*mi-var-cp.cc" $lineno $hex "break in anonymous_structs_and_unions"
+mi_execute_to "exec-continue" "breakpoint-hit" \
+    "anonymous_structs_and_unions" "" ".*" ".*" {"" "disp=\"keep\""} \
+    "continue to anonymous_structs breakpoint"
+
+set tree {
+  Anonymous a {
+    {} public {
+      anonymous struct {
+        {} public {
+          int b {}
+        }
+      }
+      anonymous struct {
+        {} public {
+          int c {}
+        }
+      }
+      anonymous struct {
+        {} public {
+          int d {}
+          anonymous struct {
+            {} public {
+              int e {}
+              anonymous struct {
+                {} public {
+                  int f {}
+                  anonymous union {
+                    {} public {
+                      int g {}
+                      char h {}
+                    }
+                  }
+                }
+              }
+	      anonymous union {
+		{} public {
+		  int i {}
+		  char j {}
+		}
+	      }
+	    }
+	  }
+	}
+      }
+    }
+  }
+}
+
+proc verify_everything {variable_name} {
+  # Test -var-list-children
+  mi_varobj_tree_test_children_callback $variable_name
+
+  # Bring the variable named by VARIABLE_NAME into the current scope
+  # in VAROBJ.
+  upvar #0 $variable_name varobj
+
+  # Test -var-info-path-expression
+  mi_gdb_test "-var-info-path-expression $varobj(obj_name)" \
+      "\\^done,path_expr=\"[string_to_regexp $varobj(path_expr)]\"" \
+      "path expression for $varobj(obj_name)"
+
+  # Test -var-info-expression
+  mi_gdb_test "-var-info-expression $varobj(obj_name)" \
+      "\\^done,lang=\"C\\+\\+\",exp=\"[string_to_regexp $varobj(display_name)]\"" \
+      "expression for $varobj(obj_name)"
+}
+
+mi_walk_varobj_tree c++ $tree verify_everything
+
 mi_gdb_exit
 return 0
diff --git a/gdb/testsuite/gdb.mi/mi2-var-child.exp b/gdb/testsuite/gdb.mi/mi2-var-child.exp
index 0f9b4d4..740a79f 100644
--- a/gdb/testsuite/gdb.mi/mi2-var-child.exp
+++ b/gdb/testsuite/gdb.mi/mi2-var-child.exp
@@ -1,4 +1,5 @@
-# Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2009 Free Software Foundation
+# Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2009, 2011
+# Free Software Foundation
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -1139,7 +1140,102 @@ mi_gdb_test "-var-update *" \
 	"update all vars psnp->next->next->long_ptr (and 2.long_ptr) changed"
 
 
+# Anonymous type tests
+proc verify_everything {variable_name} {
+  # Test -var-list-children
+  mi_varobj_tree_test_children_callback $variable_name
 
+  # Bring the variable named by VARIABLE_NAME into the current scope
+  # in VAROBJ.
+  upvar #0 $variable_name varobj
+
+  # Test -var-info-path-expression
+  mi_gdb_test "-var-info-path-expression $varobj(obj_name)" \
+      "\\^done,path_expr=\"[string_to_regexp $varobj(path_expr)]\"" \
+      "path expression for $varobj(obj_name)"
+
+  # Test -var-info-expression
+  mi_gdb_test "-var-info-expression $varobj(obj_name)" \
+      "\\^done,lang=\"C\",exp=\"[string_to_regexp $varobj(display_name)]\"" \
+      "expression for $varobj(obj_name)"
+}
+
+set lineno [gdb_get_line_number "anonymous type tests breakpoint"]
+mi_create_breakpoint \
+    "$srcfile:$lineno" {[0-9]+} keep {do_anonymous_type_tests} \
+    ".*var-cmd.c" $lineno $hex "break in do_anonymous_type_tests"
+mi_execute_to "exec-continue" "breakpoint-hit" "do_anonymous_type_tests" ""\
+    ".*" ".*" {"" "disp=\"keep\""} \
+    "continue to do_anonymous_type_tests breakpoint"
+
+# Run the varobj tree on variable "ptr".
+set tree {
+  {struct anonymous **} ptr {
+    {struct anonymous *} {*ptr} {
+      int a {}
+      anonymous struct {
+	int b {}
+	{char *} c {
+	  char {*c} {}
+	}
+	anonymous union {
+	  int d {}
+	  {void *} e {}
+	  char f {}
+	  anonymous struct {
+	    char g {}
+	    {const char **} h {
+	      {const char *} {*h} {
+		{const char} {**h} {}
+	      }
+	    }
+	    {simpleton ***} simple {
+	      {simpleton **} {*simple} {
+		{simpleton *} {**simple} {
+		  int integer {}
+		  {unsigned int} unsigned_integer {}
+		  char character {}
+		  {signed char} signed_character {}
+		  {char *} char_ptr {
+		    char {*char_ptr} {}
+		  }
+		  {int [10]} array_of_10 {
+		    int 0 {}
+		    int 1 {}
+		    int 2 {}
+		    int 3 {}
+		    int 4 {}
+		    int 5 {}
+		    int 6 {}
+		    int 7 {}
+		    int 8 {}
+		    int 9 {}
+		  }
+		}
+	      }
+	    }
+	  }
+	}
+      }
+    }
+  }
+}
+
+mi_walk_varobj_tree c $tree verify_everything
+
+set tree {
+  {struct {...}} v {
+    int x {}
+    anonymous struct {
+      int a {}
+    }
+    anonymous struct {
+      int b {}
+    }
+  }
+}
+
+mi_walk_varobj_tree c $tree verify_everything
 
 mi_gdb_exit
 return 0
diff --git a/gdb/testsuite/gdb.mi/var-cmd.c b/gdb/testsuite/gdb.mi/var-cmd.c
index 71c5b9d..f724eb0 100644
--- a/gdb/testsuite/gdb.mi/var-cmd.c
+++ b/gdb/testsuite/gdb.mi/var-cmd.c
@@ -92,6 +92,24 @@ struct _struct_n_pointer {
   struct _struct_n_pointer *next;
 };
 
+struct anonymous {
+  int a;
+  struct {
+    int b;
+    char *c;
+    union {
+      int d;
+      void *e;
+      char f;
+      struct {
+	char g;
+	const char **h;
+	simpleton ***simple;
+      };
+    };
+  };
+};
+
 void do_locals_tests (void);
 void do_block_tests (void);
 void subroutine1 (int, long *);
@@ -503,6 +521,38 @@ void do_bitfield_tests ()
   /*: END: bitfield :*/  
 }
 
+void
+do_anonymous_type_tests (void)
+{
+  struct anonymous *anon;
+  struct anonymous **ptr;
+  struct
+  {
+    int x;
+    struct
+    {
+      int a;
+    };
+    struct
+    {
+      int b;
+    };
+  } v = {1, {2}, {3}};
+
+  anon = malloc (sizeof (struct anonymous));
+  anon->a = 1;
+  anon->b = 2;
+  anon->c = (char *) 3;
+  anon->d = 4;
+  anon->g = '5';
+  anon->h = (const char **) 6;
+  anon->simple = (simpleton ***) 7;
+
+  ptr = &anon;
+  free (anon);
+  return; /* anonymous type tests breakpoint */
+}
+
 int
 main (int argc, char *argv [])
 {
@@ -513,6 +563,7 @@ main (int argc, char *argv [])
   do_frozen_tests ();
   do_at_tests ();
   do_bitfield_tests ();
+  do_anonymous_type_tests ();
   exit (0);
 }
 
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 7c68a93..ab9dd4a 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -43,6 +43,10 @@
 typedef int PyObject;
 #endif
 
+/* The names of varobjs representing anonymous structs or unions.  */
+#define ANONYMOUS_STRUCT_NAME _("<anonymous struct>")
+#define ANONYMOUS_UNION_NAME _("<anonymous union>")
+
 /* Non-zero if we want to see trace of varobj level stuff.  */
 
 int varobjdebug = 0;
@@ -1289,6 +1293,39 @@ varobj_get_gdb_type (struct varobj *var)
   return var->type;
 }
 
+/* Is VAR a path expression parent, i.e., can it be used to construct
+   a valid path expression?  */
+
+static int
+is_path_expr_parent (struct varobj *var)
+{
+  struct type *type;
+
+  /* "Fake" children are not path_expr parents.  */
+  if (CPLUS_FAKE_CHILD (var))
+    return 0;
+
+  type = get_value_type (var);
+
+  /* Anonymous unions and structs are also not path_expr parents.  */
+  return !((TYPE_CODE (type) == TYPE_CODE_STRUCT
+	    || TYPE_CODE (type) == TYPE_CODE_UNION)
+	   && TYPE_NAME (type) == NULL);
+}
+
+/* Return the path expression parent for VAR.  */
+
+static struct varobj *
+get_path_expr_parent (struct varobj *var)
+{
+  struct varobj *parent = var;
+
+  while (!is_root_p (parent) && !is_path_expr_parent (parent))
+    parent = parent->parent;
+
+  return parent;
+}
+
 /* Return a pointer to the full rooted expression of varobj VAR.
    If it has not been computed yet, compute it.  */
 char *
@@ -2170,6 +2207,20 @@ create_child (struct varobj *parent, int index, char *name)
 				  value_of_child (parent, index));
 }
 
+/* Does CHILD represent a child with no name?  This happens when
+   the child is an anonmous struct or union and it has no field name
+   in its parent variable.
+
+   This has already been determined by *_describe_child. The easiest
+   thing to do is to compare the child's name with ANONYMOUS_*_NAME.  */
+
+static int
+is_anonymous_child (struct varobj *child)
+{
+  return (strcmp (child->name, ANONYMOUS_STRUCT_NAME) == 0
+	  || strcmp (child->name, ANONYMOUS_UNION_NAME) == 0);
+}
+
 static struct varobj *
 create_child_with_value (struct varobj *parent, int index, const char *name,
 			 struct value *value)
@@ -2185,8 +2236,13 @@ create_child_with_value (struct varobj *parent, int index, const char *name,
   child->index = index;
   child->parent = parent;
   child->root = parent->root;
-  childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
+
+  if (is_anonymous_child (child))
+    childs_name = xstrprintf ("%s.%d_anonymous", parent->obj_name, index);
+  else
+    childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
   child->obj_name = childs_name;
+
   install_variable (child);
 
   /* Compute the type of the child.  Must do this before
@@ -2955,7 +3011,7 @@ c_describe_child (struct varobj *parent, int index,
   if (cfull_expression)
     {
       *cfull_expression = NULL;
-      parent_expression = varobj_get_path_expr (parent);
+      parent_expression = varobj_get_path_expr (get_path_expr_parent (parent));
     }
   adjust_value_for_child_access (&value, &type, &was_ptr);
       
@@ -2990,26 +3046,49 @@ c_describe_child (struct varobj *parent, int index,
 
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
-      if (cname)
-	*cname = xstrdup (TYPE_FIELD_NAME (type, index));
+      {
+	char *field_name;
 
-      if (cvalue && value)
-	{
-	  /* For C, varobj index is the same as type index.  */
-	  *cvalue = value_struct_element_index (value, index);
-	}
+	/* If the type is anonymous and the field has no name,
+	   set an appropriate name.  */
+	field_name = TYPE_FIELD_NAME (type, index);
+	if (field_name == NULL || *field_name == '\0')
+	  {
+	    if (cname)
+	      {
+		if (TYPE_CODE (TYPE_FIELD_TYPE (type, index))
+		    == TYPE_CODE_STRUCT)
+		  *cname = xstrdup (ANONYMOUS_STRUCT_NAME);
+		else
+		  *cname = xstrdup (ANONYMOUS_UNION_NAME);
+	      }
 
-      if (ctype)
-	*ctype = TYPE_FIELD_TYPE (type, index);
+	    if (cfull_expression)
+	      *cfull_expression = xstrdup ("");
+	  }
+	else
+	  {
+	    if (cname)
+	      *cname = xstrdup (field_name);
 
-      if (cfull_expression)
-	{
-	  char *join = was_ptr ? "->" : ".";
+	    if (cfull_expression)
+	      {
+		char *join = was_ptr ? "->" : ".";
 
-	  *cfull_expression = xstrprintf ("(%s)%s%s", parent_expression, join,
-					  TYPE_FIELD_NAME (type, index));
-	}
+		*cfull_expression = xstrprintf ("(%s)%s%s", parent_expression,
+						join, field_name);
+	      }
+	  }
 
+	if (cvalue && value)
+	  {
+	    /* For C, varobj index is the same as type index.  */
+	    *cvalue = value_struct_element_index (value, index);
+	  }
+
+	if (ctype)
+	  *ctype = TYPE_FIELD_TYPE (type, index);
+      }
       break;
 
     case TYPE_CODE_PTR:
@@ -3357,14 +3436,16 @@ cplus_describe_child (struct varobj *parent, int index,
       value = parent->parent->value;
       type = get_value_type (parent->parent);
       if (cfull_expression)
-	parent_expression = varobj_get_path_expr (parent->parent);
+	parent_expression
+	  = varobj_get_path_expr (get_path_expr_parent (parent->parent));
     }
   else
     {
       value = parent->value;
       type = get_value_type (parent);
       if (cfull_expression)
-	parent_expression = varobj_get_path_expr (parent);
+	parent_expression
+	  = varobj_get_path_expr (get_path_expr_parent (parent));
     }
 
   adjust_value_for_child_access (&value, &type, &was_ptr);
@@ -3386,6 +3467,7 @@ cplus_describe_child (struct varobj *parent, int index,
 	  enum accessibility acc = public_field;
 	  int vptr_fieldno;
 	  struct type *basetype = NULL;
+	  char *field_name;
 
 	  vptr_fieldno = get_vptr_fieldno (type, &basetype);
 	  if (strcmp (parent->name, "private") == 0)
@@ -3404,20 +3486,40 @@ cplus_describe_child (struct varobj *parent, int index,
 	    }
 	  --type_index;
 
-	  if (cname)
-	    *cname = xstrdup (TYPE_FIELD_NAME (type, type_index));
+	  /* If the type is anonymous and the field has no name,
+	     set an appopriate name.  */
+	  field_name = TYPE_FIELD_NAME (type, type_index);
+	  if (field_name == NULL || *field_name == '\0')
+	    {
+	      if (cname)
+		{
+		  if (TYPE_CODE (TYPE_FIELD_TYPE (type, type_index))
+		      == TYPE_CODE_STRUCT)
+		    *cname = xstrdup (ANONYMOUS_STRUCT_NAME);
+		  else if (TYPE_CODE (TYPE_FIELD_TYPE (type, type_index))
+			   == TYPE_CODE_UNION)
+		    *cname = xstrdup (ANONYMOUS_UNION_NAME);
+		}
+
+	      if (cfull_expression)
+		*cfull_expression = xstrdup ("");
+	    }
+	  else
+	    {
+	      if (cname)
+		*cname = xstrdup (TYPE_FIELD_NAME (type, type_index));
+
+	      if (cfull_expression)
+		*cfull_expression
+		  = xstrprintf ("((%s)%s%s)", parent_expression, join,
+				field_name);
+	    }
 
 	  if (cvalue && value)
 	    *cvalue = value_struct_element_index (value, type_index);
 
 	  if (ctype)
 	    *ctype = TYPE_FIELD_TYPE (type, type_index);
-
-	  if (cfull_expression)
-	    *cfull_expression
-	      = xstrprintf ("((%s)%s%s)", parent_expression,
-			    join, 
-			    TYPE_FIELD_NAME (type, type_index));
 	}
       else if (index < TYPE_N_BASECLASSES (type))
 	{

  reply	other threads:[~2011-12-16 23:43 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-11 21:30 Keith Seitz
2011-11-14 15:45 ` Tom Tromey
2011-11-14 18:04   ` Keith Seitz
2011-11-14 18:18     ` Tom Tromey
2011-11-14 19:28       ` Keith Seitz
2011-11-14 20:28         ` Tom Tromey
2011-11-15 17:10           ` Keith Seitz
2011-11-15 17:30             ` Tom Tromey
2011-12-02 22:28             ` Keith Seitz
2011-12-13  1:28               ` Keith Seitz
2011-12-13 19:58               ` Tom Tromey
2011-12-17  1:55                 ` Keith Seitz [this message]
2011-12-20 16:03                   ` Tom Tromey
2012-01-12 23:05                     ` Keith Seitz
2011-12-13 20:34               ` Crash regression with Eclipse [Re: [RFA] mi/10586] Jan Kratochvil

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4EEBD762.1010201@redhat.com \
    --to=keiths@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).