[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#771196: (pre-approval) unblock: gdb-arm-none-eabi/7.7.1+dfsg-5+7



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Hi there,

A new update release of the ARM embedded toolchain was released few days
before the freeze but we missed the deadline due to various reasons
(internal process, holidays, etc.). The update consists solely of
important bugfixes and support for the recently announced Cortex-M7
ARM processors.

I understand that this latter change is against the freeze policy which
is why we haven't uploaded the package to unstable yet but please
consider that it's a quite small change and isolated. It doesn't affect
the current support of other processors and in the worst case it would
only offer a broken support for this new processor. In addition, this is
considered as a minor update by ARM and is rigorously tested on a wide
range of devices.

Note that this package only contains bug fixes backported for this
version of gdb.

I would understand and respect any decision you would make but I would
just ask you to consider the toolchain as a whole when making the
decision, i.e. approve or reject the unblock for all 3 [1] packages that
needs updating.

[1] binutils-arm-none-eabi, gcc-arm-none-eabi, gdb-arm-none-eabi

debdiff for the package attached. Also attached is the ARM embedded
toolchain patch from debian/patches for easier review.

unblock gdb-arm-none-eabi/7.7.1+dfsg-5+7

-- System Information:
Debian Release: jessie/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 3.13.0-38-generic (SMP w/8 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) (ignored: 
LC_ALL set to en_US.UTF-8)
Shell: /bin/sh linked to /bin/dash
diff --git a/debian/changelog b/debian/changelog
index 0aab5b3..f78f7d6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+gdb-arm-none-eabi (7) UNRELEASED; urgency=medium
+
+  * New upstream release: 4.8-2014-q3-update.
+  * Fix my email.
+
+ -- Thomas Preud'homme <thomas.preudhomme@arm.com>  Mon, 20 Oct 2014 15:38:58 +0000
+
 gdb-arm-none-eabi (6) unstable; urgency=medium
 
   * Workaround for upstream manpages stripped on the last gdb-source version
diff --git a/debian/control b/debian/control
index 0f2370b..8fa6261 100644
--- a/debian/control
+++ b/debian/control
@@ -3,7 +3,7 @@ Section: devel
 Priority: extra
 Maintainer: Agustin Henze <tin@debian.org>
 Uploaders: Keith Packard <keithp@keithp.com>,
-           Thomas Preud'homme <thomas.preud-homme@arm.com>
+           Thomas Preud'homme <thomas.preudhomme@arm.com>
 Build-Depends:
  debhelper (>= 8.0.0),
  gdb-source,
diff --git a/debian/patches/0001-Add-GNU-ARM-embedded-toolchain-patches.patch b/debian/patches/0001-Add-GNU-ARM-embedded-toolchain-patches.patch
new file mode 100644
index 0000000..cce7b83
--- /dev/null
+++ b/debian/patches/0001-Add-GNU-ARM-embedded-toolchain-patches.patch
@@ -0,0 +1,383 @@
+diff --git a/gdb/ChangeLog.arm b/gdb/ChangeLog.arm
+new file mode 100644
+index 0000000..7f60687
+--- /dev/null
++++ b/gdb/ChangeLog.arm
+@@ -0,0 +1,18 @@
++Backport from 9a9a76082919371f4ceb571f6c9892325b80a2e0
++
++2014-07-09  Andrew Burgess  <andrew.burgess@embecosm.com>
++
++	* ada-varobj.c (ada_varobj_ops): Fill in is_path_expr_parent
++	field.
++	* c-varobj.c (c_is_path_expr_parent): New function, moved core
++	from varobj.c, with additional checks.
++	(c_varobj_ops): Fill in is_path_expr_parent field.
++	(cplus_varobj_ops): Fill in is_path_expr_parent field.
++	* jv-varobj.c (java_varobj_ops): Fill in is_path_expr_parent
++	field.
++	* varobj.c (is_path_expr_parent): Call is_path_expr_parent varobj
++	ops method.
++	(varobj_default_is_path_expr_parent): New function.
++	* varobj.h (lang_varobj_ops): Add is_path_expr_parent field.
++	(varobj_default_is_path_expr_parent): Declare new function.
++
+diff --git a/gdb/ada-varobj.c b/gdb/ada-varobj.c
+index 3da6018..b49eaf0 100644
+--- a/gdb/ada-varobj.c
++++ b/gdb/ada-varobj.c
+@@ -1032,5 +1032,6 @@ const struct lang_varobj_ops ada_varobj_ops =
+   ada_type_of_child,
+   ada_value_of_variable,
+   ada_value_is_changeable_p,
+-  ada_value_has_mutated
++  ada_value_has_mutated,
++  varobj_default_is_path_expr_parent
+ };
+diff --git a/gdb/c-varobj.c b/gdb/c-varobj.c
+index 9c2860d..f7bc52b 100644
+--- a/gdb/c-varobj.c
++++ b/gdb/c-varobj.c
+@@ -126,6 +126,56 @@ adjust_value_for_child_access (struct value **value,
+     }
+ }
+ 
++/* Is VAR a path expression parent, i.e., can it be used to construct
++   a valid path expression?  */
++
++static int
++c_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 = varobj_get_gdb_type (var);
++
++  /* Anonymous unions and structs are also not path_expr parents.  */
++  if ((TYPE_CODE (type) == TYPE_CODE_STRUCT
++       || TYPE_CODE (type) == TYPE_CODE_UNION)
++      && TYPE_NAME (type) == NULL
++      && TYPE_TAG_NAME (type) == NULL)
++    {
++      struct varobj *parent = var->parent;
++
++      while (parent != NULL && CPLUS_FAKE_CHILD (parent))
++	parent = parent->parent;
++
++      if (parent != NULL)
++	{
++	  struct type *parent_type;
++	  int was_ptr;
++
++	  parent_type = varobj_get_value_type (parent);
++	  adjust_value_for_child_access (NULL, &parent_type, &was_ptr, 0);
++
++	  if (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT
++	      || TYPE_CODE (parent_type) == TYPE_CODE_UNION)
++	    {
++	      const char *field_name;
++
++	      gdb_assert (var->index < TYPE_NFIELDS (parent_type));
++	      field_name = TYPE_FIELD_NAME (parent_type, var->index);
++	      return !(field_name == NULL || *field_name == '\0');
++	    }
++	}
++
++      return 0;
++    }
++
++  return 1;
++}
++
+ /* C */
+ 
+ static int
+@@ -493,7 +543,8 @@ const struct lang_varobj_ops c_varobj_ops =
+    c_type_of_child,
+    c_value_of_variable,
+    varobj_default_value_is_changeable_p,
+-   NULL /* value_has_mutated */
++   NULL, /* value_has_mutated */
++   c_is_path_expr_parent  /* is_path_expr_parent */
+ };
+ 
+ /* A little convenience enum for dealing with C++/Java.  */
+@@ -904,7 +955,8 @@ const struct lang_varobj_ops cplus_varobj_ops =
+    cplus_type_of_child,
+    cplus_value_of_variable,
+    varobj_default_value_is_changeable_p,
+-   NULL /* value_has_mutated */
++   NULL, /* value_has_mutated */
++   c_is_path_expr_parent  /* is_path_expr_parent */
+ };
+ 
+ 
+diff --git a/gdb/jv-varobj.c b/gdb/jv-varobj.c
+index 0bb8e64..fb4d417 100644
+--- a/gdb/jv-varobj.c
++++ b/gdb/jv-varobj.c
+@@ -101,5 +101,6 @@ const struct lang_varobj_ops java_varobj_ops =
+    java_type_of_child,
+    java_value_of_variable,
+    varobj_default_value_is_changeable_p,
+-   NULL /* value_has_mutated */
++   NULL, /* value_has_mutated */
++   varobj_default_is_path_expr_parent
+ };
+diff --git a/gdb/testsuite/ChangeLog.arm b/gdb/testsuite/ChangeLog.arm
+new file mode 100644
+index 0000000..4eed77a
+--- /dev/null
++++ b/gdb/testsuite/ChangeLog.arm
+@@ -0,0 +1,11 @@
++Backport from 9a9a76082919371f4ceb571f6c9892325b80a2e0
++
++2014-07-09  Andrew Burgess  <andrew.burgess@embecosm.com>
++
++	* gdb.mi/var-cmd.c (do_nested_struct_union_tests): New function
++	setting up test structures.
++	(main): Call new test function.
++	* gdb.mi/mi2-var-child.exp: Create additional breakpoint in new
++	test function, continue into test function and walk test
++	structures.
++
+diff --git a/gdb/testsuite/gdb.mi/mi2-var-child.exp b/gdb/testsuite/gdb.mi/mi2-var-child.exp
+index d2f65c5..d504b8b 100644
+--- a/gdb/testsuite/gdb.mi/mi2-var-child.exp
++++ b/gdb/testsuite/gdb.mi/mi2-var-child.exp
+@@ -1162,6 +1162,13 @@ 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"
++
++set lineno [gdb_get_line_number "nested struct union tests breakpoint"]
++mi_create_breakpoint \
++    "$srcfile:$lineno" "break in do_nested_struct_union_tests" \
++    -disp keep -func do_nested_struct_union_tests \
++    -file ".*var-cmd.c" -line $lineno
++
+ mi_execute_to "exec-continue" "breakpoint-hit" "do_anonymous_type_tests" ""\
+     ".*" ".*" {"" "disp=\"keep\""} \
+     "continue to do_anonymous_type_tests breakpoint"
+@@ -1235,5 +1242,74 @@ set tree {
+ 
+ mi_walk_varobj_tree c $tree verify_everything
+ 
++mi_send_resuming_command "exec-continue" \
++    "continuing execution to enter do_nested_struct_union_tests"
++mi_expect_stop "breakpoint-hit" "do_nested_struct_union_tests" ".*" ".*" ".*" \
++    {.* disp="keep"} "Run till MI stops in do_nested_struct_union_tests"
++
++set struct_ss_tree {
++    {struct s_a} a1 {
++      int a {}
++    }
++    {struct s_b} b1 {
++      int b {}
++    }
++    {union u_ab} u1 {
++      {struct s_a} a {
++        int a {}
++      }
++      {struct s_b} b {
++        int b {}
++      }
++    }
++    anonymous union {
++      {struct s_a} a2 {
++        int a {}
++      }
++      {struct s_b} b2 {
++        int b {}
++      }
++    }
++    {union {...}} u2 {
++      {struct s_a} a3 {
++        int a {}
++      }
++      {struct s_b} b3 {
++        int b {}
++      }
++    }
++  }
++
++set tree "
++  {struct ss} var {
++    $struct_ss_tree
++  }
++"
++
++mi_walk_varobj_tree c $tree verify_everything
++
++set tree {
++  {struct {...}} var2 {
++    {td_u_ab} ab {
++      {td_s_a} a {
++	int a {}
++      }
++      {td_s_b} b {
++	int b {}
++      }
++    }
++  }
++}
++
++mi_walk_varobj_tree c $tree verify_everything
++
++set tree "
++  {struct ss *} ss_ptr {
++    $struct_ss_tree
++  }
++"
++
++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 698b294..4bb2746 100644
+--- a/gdb/testsuite/gdb.mi/var-cmd.c
++++ b/gdb/testsuite/gdb.mi/var-cmd.c
+@@ -552,6 +552,73 @@ do_anonymous_type_tests (void)
+   return; /* anonymous type tests breakpoint */
+ }
+ 
++void
++do_nested_struct_union_tests (void)
++{
++  struct s_a
++  {
++    int a;
++  };
++  struct s_b
++  {
++    int b;
++  };
++  union u_ab
++  {
++    struct s_a a;
++    struct s_b b;
++  };
++  struct ss
++  {
++    struct s_a a1;
++    struct s_b b1;
++    union u_ab u1;
++
++    /* Anonymous union.  */
++    union
++    {
++      struct s_a a2;
++      struct s_b b2;
++    };
++
++    union
++    {
++      struct s_a a3;
++      struct s_b b3;
++    } u2;
++  };
++
++  typedef struct
++  {
++    int a;
++  } td_s_a;
++
++  typedef struct
++  {
++    int b;
++  } td_s_b;
++
++  typedef union
++  {
++    td_s_a a;
++    td_s_b b;
++  } td_u_ab;
++
++  struct ss var;
++  struct
++  {
++    td_u_ab ab;
++  } var2;
++
++  struct ss *ss_ptr;
++
++  memset (&var, 0, sizeof (var));
++  memset (&var2, 0, sizeof (var2));
++  ss_ptr = &var;
++
++  return; /* nested struct union tests breakpoint */
++}
++
+ int
+ main (int argc, char *argv [])
+ {
+@@ -563,6 +630,7 @@ main (int argc, char *argv [])
+   do_at_tests ();
+   do_bitfield_tests ();
+   do_anonymous_type_tests ();
++  do_nested_struct_union_tests ();
+   exit (0);
+ }
+ 
+diff --git a/gdb/varobj.c b/gdb/varobj.c
+index bbe4213..c28b372 100644
+--- a/gdb/varobj.c
++++ b/gdb/varobj.c
+@@ -1069,18 +1069,18 @@ varobj_get_gdb_type (struct varobj *var)
+ 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;
++  gdb_assert (var->root->lang_ops->is_path_expr_parent != NULL);
++  return var->root->lang_ops->is_path_expr_parent (var);
++}
+ 
+-  type = varobj_get_value_type (var);
++/* Is VAR a path expression parent, i.e., can it be used to construct
++   a valid path expression?  By default we assume any VAR can be a path
++   parent.  */
+ 
+-  /* 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);
++int
++varobj_default_is_path_expr_parent (struct varobj *var)
++{
++  return 1;
+ }
+ 
+ /* Return the path expression parent for VAR.  */
+diff --git a/gdb/varobj.h b/gdb/varobj.h
+index e4007bf..10f51c5 100644
+--- a/gdb/varobj.h
++++ b/gdb/varobj.h
+@@ -213,6 +213,12 @@ struct lang_varobj_ops
+      Languages where types do not mutate can set this to NULL.  */
+   int (*value_has_mutated) (struct varobj *var, struct value *new_value,
+ 			    struct type *new_type);
++
++  /* Return nonzero if VAR is a suitable path expression parent.
++
++     For C like languages with anonymous structures and unions an anonymous
++     structure or union is not a suitable parent.  */
++  int (*is_path_expr_parent) (struct varobj *var);
+ };
+ 
+ const struct lang_varobj_ops c_varobj_ops;
+@@ -326,4 +332,7 @@ extern void varobj_formatted_print_options (struct value_print_options *opts,
+ 
+ extern void varobj_restrict_range (VEC (varobj_p) *children, int *from,
+ 				   int *to);
++
++extern int varobj_default_is_path_expr_parent (struct varobj *var);
++
+ #endif /* VAROBJ_H */
diff --git a/debian/rules b/debian/rules
index 0a6549f..10b1abe 100755
--- a/debian/rules
+++ b/debian/rules
@@ -18,6 +18,7 @@ src_dir=gdb
 build_dir=build
 
 unpack_stamp=$(stampdir)/unpack
+tar_stamp=$(stampdir)/tar
 
 buildflags=$(shell dpkg-buildflags --export=configure)
 
@@ -39,7 +40,16 @@ configure_flags = \
 %:
 	dh $@ -D$(src_dir) -B$(build_dir) --with autotools-dev
 
-$(unpack_stamp):
+$(unpack_stamp): $(tar_stamp)
+	set -ex; \
+		cd gdb; \
+		for patch in ../debian/patches/[0-9]*.patch; do \
+			echo Applying patch "$$patch"; \
+			patch -p1 < "$$patch"; \
+		done
+	touch $@
+
+$(tar_stamp):
 	tar xf $(gdb_dir)/gdb.tar.*
 	mkdir -p $(stampdir)
 	touch $@
diff --git a/gdb/ChangeLog.arm b/gdb/ChangeLog.arm
new file mode 100644
index 0000000..7f60687
--- /dev/null
+++ b/gdb/ChangeLog.arm
@@ -0,0 +1,18 @@
+Backport from 9a9a76082919371f4ceb571f6c9892325b80a2e0
+
+2014-07-09  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+	* ada-varobj.c (ada_varobj_ops): Fill in is_path_expr_parent
+	field.
+	* c-varobj.c (c_is_path_expr_parent): New function, moved core
+	from varobj.c, with additional checks.
+	(c_varobj_ops): Fill in is_path_expr_parent field.
+	(cplus_varobj_ops): Fill in is_path_expr_parent field.
+	* jv-varobj.c (java_varobj_ops): Fill in is_path_expr_parent
+	field.
+	* varobj.c (is_path_expr_parent): Call is_path_expr_parent varobj
+	ops method.
+	(varobj_default_is_path_expr_parent): New function.
+	* varobj.h (lang_varobj_ops): Add is_path_expr_parent field.
+	(varobj_default_is_path_expr_parent): Declare new function.
+
diff --git a/gdb/ada-varobj.c b/gdb/ada-varobj.c
index 3da6018..b49eaf0 100644
--- a/gdb/ada-varobj.c
+++ b/gdb/ada-varobj.c
@@ -1032,5 +1032,6 @@ const struct lang_varobj_ops ada_varobj_ops =
   ada_type_of_child,
   ada_value_of_variable,
   ada_value_is_changeable_p,
-  ada_value_has_mutated
+  ada_value_has_mutated,
+  varobj_default_is_path_expr_parent
 };
diff --git a/gdb/c-varobj.c b/gdb/c-varobj.c
index 9c2860d..f7bc52b 100644
--- a/gdb/c-varobj.c
+++ b/gdb/c-varobj.c
@@ -126,6 +126,56 @@ adjust_value_for_child_access (struct value **value,
     }
 }
 
+/* Is VAR a path expression parent, i.e., can it be used to construct
+   a valid path expression?  */
+
+static int
+c_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 = varobj_get_gdb_type (var);
+
+  /* Anonymous unions and structs are also not path_expr parents.  */
+  if ((TYPE_CODE (type) == TYPE_CODE_STRUCT
+       || TYPE_CODE (type) == TYPE_CODE_UNION)
+      && TYPE_NAME (type) == NULL
+      && TYPE_TAG_NAME (type) == NULL)
+    {
+      struct varobj *parent = var->parent;
+
+      while (parent != NULL && CPLUS_FAKE_CHILD (parent))
+	parent = parent->parent;
+
+      if (parent != NULL)
+	{
+	  struct type *parent_type;
+	  int was_ptr;
+
+	  parent_type = varobj_get_value_type (parent);
+	  adjust_value_for_child_access (NULL, &parent_type, &was_ptr, 0);
+
+	  if (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT
+	      || TYPE_CODE (parent_type) == TYPE_CODE_UNION)
+	    {
+	      const char *field_name;
+
+	      gdb_assert (var->index < TYPE_NFIELDS (parent_type));
+	      field_name = TYPE_FIELD_NAME (parent_type, var->index);
+	      return !(field_name == NULL || *field_name == '\0');
+	    }
+	}
+
+      return 0;
+    }
+
+  return 1;
+}
+
 /* C */
 
 static int
@@ -493,7 +543,8 @@ const struct lang_varobj_ops c_varobj_ops =
    c_type_of_child,
    c_value_of_variable,
    varobj_default_value_is_changeable_p,
-   NULL /* value_has_mutated */
+   NULL, /* value_has_mutated */
+   c_is_path_expr_parent  /* is_path_expr_parent */
 };
 
 /* A little convenience enum for dealing with C++/Java.  */
@@ -904,7 +955,8 @@ const struct lang_varobj_ops cplus_varobj_ops =
    cplus_type_of_child,
    cplus_value_of_variable,
    varobj_default_value_is_changeable_p,
-   NULL /* value_has_mutated */
+   NULL, /* value_has_mutated */
+   c_is_path_expr_parent  /* is_path_expr_parent */
 };
 
 
diff --git a/gdb/jv-varobj.c b/gdb/jv-varobj.c
index 0bb8e64..fb4d417 100644
--- a/gdb/jv-varobj.c
+++ b/gdb/jv-varobj.c
@@ -101,5 +101,6 @@ const struct lang_varobj_ops java_varobj_ops =
    java_type_of_child,
    java_value_of_variable,
    varobj_default_value_is_changeable_p,
-   NULL /* value_has_mutated */
+   NULL, /* value_has_mutated */
+   varobj_default_is_path_expr_parent
 };
diff --git a/gdb/testsuite/ChangeLog.arm b/gdb/testsuite/ChangeLog.arm
new file mode 100644
index 0000000..4eed77a
--- /dev/null
+++ b/gdb/testsuite/ChangeLog.arm
@@ -0,0 +1,11 @@
+Backport from 9a9a76082919371f4ceb571f6c9892325b80a2e0
+
+2014-07-09  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+	* gdb.mi/var-cmd.c (do_nested_struct_union_tests): New function
+	setting up test structures.
+	(main): Call new test function.
+	* gdb.mi/mi2-var-child.exp: Create additional breakpoint in new
+	test function, continue into test function and walk test
+	structures.
+
diff --git a/gdb/testsuite/gdb.mi/mi2-var-child.exp b/gdb/testsuite/gdb.mi/mi2-var-child.exp
index d2f65c5..d504b8b 100644
--- a/gdb/testsuite/gdb.mi/mi2-var-child.exp
+++ b/gdb/testsuite/gdb.mi/mi2-var-child.exp
@@ -1162,6 +1162,13 @@ 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"
+
+set lineno [gdb_get_line_number "nested struct union tests breakpoint"]
+mi_create_breakpoint \
+    "$srcfile:$lineno" "break in do_nested_struct_union_tests" \
+    -disp keep -func do_nested_struct_union_tests \
+    -file ".*var-cmd.c" -line $lineno
+
 mi_execute_to "exec-continue" "breakpoint-hit" "do_anonymous_type_tests" ""\
     ".*" ".*" {"" "disp=\"keep\""} \
     "continue to do_anonymous_type_tests breakpoint"
@@ -1235,5 +1242,74 @@ set tree {
 
 mi_walk_varobj_tree c $tree verify_everything
 
+mi_send_resuming_command "exec-continue" \
+    "continuing execution to enter do_nested_struct_union_tests"
+mi_expect_stop "breakpoint-hit" "do_nested_struct_union_tests" ".*" ".*" ".*" \
+    {.* disp="keep"} "Run till MI stops in do_nested_struct_union_tests"
+
+set struct_ss_tree {
+    {struct s_a} a1 {
+      int a {}
+    }
+    {struct s_b} b1 {
+      int b {}
+    }
+    {union u_ab} u1 {
+      {struct s_a} a {
+        int a {}
+      }
+      {struct s_b} b {
+        int b {}
+      }
+    }
+    anonymous union {
+      {struct s_a} a2 {
+        int a {}
+      }
+      {struct s_b} b2 {
+        int b {}
+      }
+    }
+    {union {...}} u2 {
+      {struct s_a} a3 {
+        int a {}
+      }
+      {struct s_b} b3 {
+        int b {}
+      }
+    }
+  }
+
+set tree "
+  {struct ss} var {
+    $struct_ss_tree
+  }
+"
+
+mi_walk_varobj_tree c $tree verify_everything
+
+set tree {
+  {struct {...}} var2 {
+    {td_u_ab} ab {
+      {td_s_a} a {
+	int a {}
+      }
+      {td_s_b} b {
+	int b {}
+      }
+    }
+  }
+}
+
+mi_walk_varobj_tree c $tree verify_everything
+
+set tree "
+  {struct ss *} ss_ptr {
+    $struct_ss_tree
+  }
+"
+
+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 698b294..4bb2746 100644
--- a/gdb/testsuite/gdb.mi/var-cmd.c
+++ b/gdb/testsuite/gdb.mi/var-cmd.c
@@ -552,6 +552,73 @@ do_anonymous_type_tests (void)
   return; /* anonymous type tests breakpoint */
 }
 
+void
+do_nested_struct_union_tests (void)
+{
+  struct s_a
+  {
+    int a;
+  };
+  struct s_b
+  {
+    int b;
+  };
+  union u_ab
+  {
+    struct s_a a;
+    struct s_b b;
+  };
+  struct ss
+  {
+    struct s_a a1;
+    struct s_b b1;
+    union u_ab u1;
+
+    /* Anonymous union.  */
+    union
+    {
+      struct s_a a2;
+      struct s_b b2;
+    };
+
+    union
+    {
+      struct s_a a3;
+      struct s_b b3;
+    } u2;
+  };
+
+  typedef struct
+  {
+    int a;
+  } td_s_a;
+
+  typedef struct
+  {
+    int b;
+  } td_s_b;
+
+  typedef union
+  {
+    td_s_a a;
+    td_s_b b;
+  } td_u_ab;
+
+  struct ss var;
+  struct
+  {
+    td_u_ab ab;
+  } var2;
+
+  struct ss *ss_ptr;
+
+  memset (&var, 0, sizeof (var));
+  memset (&var2, 0, sizeof (var2));
+  ss_ptr = &var;
+
+  return; /* nested struct union tests breakpoint */
+}
+
 int
 main (int argc, char *argv [])
 {
@@ -563,6 +630,7 @@ main (int argc, char *argv [])
   do_at_tests ();
   do_bitfield_tests ();
   do_anonymous_type_tests ();
+  do_nested_struct_union_tests ();
   exit (0);
 }
 
diff --git a/gdb/varobj.c b/gdb/varobj.c
index bbe4213..c28b372 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -1069,18 +1069,18 @@ varobj_get_gdb_type (struct varobj *var)
 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;
+  gdb_assert (var->root->lang_ops->is_path_expr_parent != NULL);
+  return var->root->lang_ops->is_path_expr_parent (var);
+}
 
-  type = varobj_get_value_type (var);
+/* Is VAR a path expression parent, i.e., can it be used to construct
+   a valid path expression?  By default we assume any VAR can be a path
+   parent.  */
 
-  /* 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);
+int
+varobj_default_is_path_expr_parent (struct varobj *var)
+{
+  return 1;
 }
 
 /* Return the path expression parent for VAR.  */
diff --git a/gdb/varobj.h b/gdb/varobj.h
index e4007bf..10f51c5 100644
--- a/gdb/varobj.h
+++ b/gdb/varobj.h
@@ -213,6 +213,12 @@ struct lang_varobj_ops
      Languages where types do not mutate can set this to NULL.  */
   int (*value_has_mutated) (struct varobj *var, struct value *new_value,
 			    struct type *new_type);
+
+  /* Return nonzero if VAR is a suitable path expression parent.
+
+     For C like languages with anonymous structures and unions an anonymous
+     structure or union is not a suitable parent.  */
+  int (*is_path_expr_parent) (struct varobj *var);
 };
 
 const struct lang_varobj_ops c_varobj_ops;
@@ -326,4 +332,7 @@ extern void varobj_formatted_print_options (struct value_print_options *opts,
 
 extern void varobj_restrict_range (VEC (varobj_p) *children, int *from,
 				   int *to);
+
+extern int varobj_default_is_path_expr_parent (struct varobj *var);
+
 #endif /* VAROBJ_H */

Reply to: