This is the mail archive of the gdb-patches@sources.redhat.com 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]

[dictionary] determine type name correctly via cross-references


As discussed in
<http://sources.redhat.com/ml/gdb/2003-05/msg00173.html>, the branch
tries to determine names of nested classes correctly, but screws up
when those names are accessed via cross-references.  Oops.

This patch fixes that: when it hits a cross-reference, it figures out
the current context and sets the name appropriately.  To do this, I
added parent pointers to struct die_info.  (And, while I was at it, I
replaced the current 'has_children' and 'next' members by 'child' and
'sibling' members.)

It seems to work; it fixes the error I was seeing.  I'll give it
another look in a bit to see if I can clean it up or make it more
efficient, but it's fine for now.

David Carlton
carlton@bactrian.org

2003-05-16  David Carlton  <carlton@bactrian.org>

	* dwarf2read.c (read_comp_unit): Separate code out into
	read_die_and_children and read_die_and_siblings.
	(read_die_and_children): New.
	(read_die_and_siblings): New.
	(read_full_die): Add HAS_CHILDREN argument.
	struct die_info: Delete HAS_CHILDREN, NEXT members; add CHILD,
	SIBLING, PARENT members.
	(psymtab_to_symtab_1): Use new members of struct die_info.
	(process_die, read_file_scope, read_func_scope)
	(read_lexical_block_scope, read_structure_scope, read_enumeration)
	(read_array_type, read_common_block, read_namespace) 
	(read_subroutine_type, read_die_and_children, free_die_list)
	(dump_die, dump_die_list): Ditto.
	(read_namespace): Separate code out into namespace_name.
	(namespace_name): New.
	(typename_concat): New.
	(determine_prefix): New.
	(read_type_die): Set prefix appropriately.
	(class_name): New.

2003-05-16  David Carlton  <carlton@bactrian.org>

	* gdb.c++/rtti.exp: Convert the gdb/488 kfail into a fail, and
	delete the <.*BaseN> branches.
	
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.66.4.25
diff -u -p -r1.66.4.25 dwarf2read.c
--- dwarf2read.c	18 Apr 2003 18:10:48 -0000	1.66.4.25
+++ dwarf2read.c	16 May 2003 23:14:25 -0000
@@ -316,13 +316,14 @@ struct attr_abbrev
 struct die_info
   {
     enum dwarf_tag tag;		/* Tag indicating type of die */
-    unsigned short has_children;	/* Does the die have children */
     unsigned int abbrev;	/* Abbrev number */
     unsigned int offset;	/* Offset in .debug_info section */
     unsigned int num_attrs;	/* Number of attributes */
     struct attribute *attrs;	/* An array of attributes */
     struct die_info *next_ref;	/* Next die in ref hash table */
-    struct die_info *next;	/* Next die in linked list */
+    struct die_info *child;	/* Its first child, if any.  */
+    struct die_info *sibling;	/* Its next sibling, if any.  */
+    struct die_info *parent;	/* Its parent, if any.  */
     struct type *type;		/* Cached type information */
   };
 
@@ -731,7 +732,7 @@ static char *read_partial_die (struct pa
 			       const struct comp_unit_head *);
 
 static char *read_full_die (struct die_info **, bfd *, char *,
-			    const struct comp_unit_head *);
+			    const struct comp_unit_head *, int *);
 
 static char *read_attribute (struct attribute *, struct attr_abbrev *,
 			     bfd *, char *, const struct comp_unit_head *);
@@ -813,6 +814,12 @@ static struct type *tag_type_to_type (st
 static void read_type_die (struct die_info *, struct objfile *,
 			   const struct comp_unit_head *);
 
+static char *determine_prefix (struct die_info *die);
+
+static char *typename_concat (const char *prefix, const char *suffix);
+
+static char *class_name (struct die_info *die);
+
 static void read_typedef (struct die_info *, struct objfile *,
 			  const struct comp_unit_head *);
 
@@ -854,6 +861,9 @@ static void read_common_block (struct di
 static void read_namespace (struct die_info *die, struct objfile *objfile,
 			    const struct comp_unit_head *cu_header);
 
+static const char *namespace_name (struct die_info *die,
+				   int *is_anonymous);
+
 static void read_enumeration (struct die_info *, struct objfile *,
 			      const struct comp_unit_head *);
 
@@ -888,6 +898,16 @@ static void read_subroutine_type (struct
 static struct die_info *read_comp_unit (char *, bfd *,
                                         const struct comp_unit_head *);
 
+static struct die_info *read_die_and_children (char *info_ptr, bfd *abfd,
+					       const struct comp_unit_head *,
+					       char **new_info_ptr,
+					       struct die_info *parent);
+
+static struct die_info *read_die_and_siblings (char *info_ptr, bfd *abfd,
+					       const struct comp_unit_head *,
+					       char **new_info_ptr,
+					       struct die_info *parent);
+
 static void free_die_list (struct die_info *);
 
 static struct cleanup *make_cleanup_free_die_list (struct die_info *);
@@ -1941,9 +1961,9 @@ psymtab_to_symtab_1 (struct partial_symt
          the compilation unit.   If the DW_AT_high_pc is missing,
          synthesize it, by scanning the DIE's below the compilation unit.  */
       highpc = 0;
-      if (dies->has_children)
+      if (dies->child != NULL)
 	{
-	  child_die = dies->next;
+	  child_die = dies->child;
 	  while (child_die && child_die->tag)
 	    {
 	      if (child_die->tag == DW_TAG_subprogram)
@@ -2053,7 +2073,7 @@ process_die (struct die_info *die, struc
 	 Fortran case, so we'll have to replace this gdb_assert if
 	 Fortran compilers start generating that info.  */
       processing_has_namespace_info = 1;
-      gdb_assert (!die->has_children);
+      gdb_assert (die->child == NULL);
       break;
     default:
       new_symbol (die, NULL, objfile, cu_header);
@@ -2083,9 +2103,9 @@ read_file_scope (struct die_info *die, s
 
   if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile, cu_header))
     {
-      if (die->has_children)
+      if (die->child != NULL)
 	{
-	  child_die = die->next;
+	  child_die = die->child;
 	  while (child_die && child_die->tag)
 	    {
 	      if (child_die->tag == DW_TAG_subprogram)
@@ -2162,9 +2182,9 @@ read_file_scope (struct die_info *die, s
   initialize_cu_func_list ();
 
   /* Process all dies in compilation unit.  */
-  if (die->has_children)
+  if (die->child != NULL)
     {
-      child_die = die->next;
+      child_die = die->child;
       while (child_die && child_die->tag)
 	{
 	  process_die (child_die, objfile, cu_header);
@@ -2302,9 +2322,9 @@ read_func_scope (struct die_info *die, s
 
   list_in_scope = &local_symbols;
 
-  if (die->has_children)
+  if (die->child != NULL)
     {
-      child_die = die->next;
+      child_die = die->child;
       while (child_die && child_die->tag)
 	{
 	  process_die (child_die, objfile, cu_header);
@@ -2352,9 +2372,9 @@ read_lexical_block_scope (struct die_inf
   highpc += baseaddr;
 
   push_context (0, lowpc);
-  if (die->has_children)
+  if (die->child != NULL)
     {
-      child_die = die->next;
+      child_die = die->child;
       while (child_die && child_die->tag)
 	{
 	  process_die (child_die, objfile, cu_header);
@@ -3043,7 +3063,7 @@ read_structure_scope (struct die_info *d
      type within the structure itself. */
   die->type = type;
 
-  if (die->has_children && ! die_is_declaration (die))
+  if (die->child != NULL && ! die_is_declaration (die))
     {
       struct field_info fi;
       struct die_info *child_die;
@@ -3051,7 +3071,7 @@ read_structure_scope (struct die_info *d
 
       memset (&fi, 0, sizeof (struct field_info));
 
-      child_die = die->next;
+      child_die = die->child;
 
       while (child_die && child_die->tag)
 	{
@@ -3233,9 +3253,9 @@ read_enumeration (struct die_info *die, 
 
   num_fields = 0;
   fields = NULL;
-  if (die->has_children)
+  if (die->child != NULL)
     {
-      child_die = die->next;
+      child_die = die->child;
       while (child_die && child_die->tag)
 	{
 	  if (child_die->tag != DW_TAG_enumerator)
@@ -3314,7 +3334,7 @@ read_array_type (struct die_info *die, s
 
   /* Irix 6.2 native cc creates array types without children for
      arrays with unspecified length.  */
-  if (die->has_children == 0)
+  if (die->child == NULL)
     {
       index_type = dwarf2_fundamental_type (objfile, FT_INTEGER);
       range_type = create_range_type (NULL, index_type, 0, -1);
@@ -3323,7 +3343,7 @@ read_array_type (struct die_info *die, s
     }
 
   back_to = make_cleanup (null_cleanup, NULL);
-  child_die = die->next;
+  child_die = die->child;
   while (child_die && child_die->tag)
     {
       if (child_die->tag == DW_TAG_subrange_type)
@@ -3469,9 +3489,9 @@ read_common_block (struct die_info *die,
 						 "common block member");
         }
     }
-  if (die->has_children)
+  if (die->child != NULL)
     {
-      child_die = die->next;
+      child_die = die->child;
       while (child_die && child_die->tag)
 	{
 	  sym = new_symbol (child_die, NULL, objfile, cu_header);
@@ -3494,26 +3514,11 @@ read_namespace (struct die_info *die, st
 		const struct comp_unit_head *cu_header)
 {
   const char *previous_prefix = processing_current_prefix;
-  const char *name = NULL;
+  const char *name;
   int is_anonymous;
   struct die_info *current_die;
 
-  /* Loop through the extensions until we find a name.  */
-
-  for (current_die = die;
-       current_die != NULL;
-       current_die = dwarf2_extension (die))
-    {
-      name = dwarf2_name (current_die);
-      if (name != NULL)
-	break;
-    }
-
-  /* Is it an anonymous namespace?  */
-
-  is_anonymous = (name == NULL);
-  if (is_anonymous)
-    name = "(anonymous namespace)";
+  name = namespace_name (die, &is_anonymous);
 
   /* Now build the name of the current namespace.  */
 
@@ -3542,9 +3547,9 @@ read_namespace (struct die_info *die, st
 			    strlen (previous_prefix),
 			    strlen (processing_current_prefix));
   
-  if (die->has_children)
+  if (die->child != NULL)
     {
-      struct die_info *child_die = die->next;
+      struct die_info *child_die = die->child;
       
       while (child_die && child_die->tag)
 	{
@@ -3556,6 +3561,32 @@ read_namespace (struct die_info *die, st
   processing_current_prefix = previous_prefix;
 }
 
+static const char *
+namespace_name (struct die_info *die, int *is_anonymous)
+{
+  struct die_info *current_die;
+  const char *name = NULL;
+
+  /* Loop through the extensions until we find a name.  */
+
+  for (current_die = die;
+       current_die != NULL;
+       current_die = dwarf2_extension (die))
+    {
+      name = dwarf2_name (current_die);
+      if (name != NULL)
+	break;
+    }
+
+  /* Is it an anonymous namespace?  */
+
+  *is_anonymous = (name == NULL);
+  if (*is_anonymous)
+    name = "(anonymous namespace)";
+
+  return name;
+}
+
 /* Extract all information from a DW_TAG_pointer_type DIE and add to
    the user defined type vector.  */
 
@@ -3779,7 +3810,7 @@ read_subroutine_type (struct die_info *d
       || cu_language == language_cplus)
     TYPE_FLAGS (ftype) |= TYPE_FLAG_PROTOTYPED;
 
-  if (die->has_children)
+  if (die->child != NULL)
     {
       struct die_info *child_die;
       int nparams = 0;
@@ -3788,7 +3819,7 @@ read_subroutine_type (struct die_info *d
       /* Count the number of parameters.
          FIXME: GDB currently ignores vararg functions, but knows about
          vararg member functions.  */
-      child_die = die->next;
+      child_die = die->child;
       while (child_die && child_die->tag)
 	{
 	  if (child_die->tag == DW_TAG_formal_parameter)
@@ -3803,7 +3834,7 @@ read_subroutine_type (struct die_info *d
       TYPE_FIELDS (ftype) = (struct field *)
 	TYPE_ALLOC (ftype, nparams * sizeof (struct field));
 
-      child_die = die->next;
+      child_die = die->child;
       while (child_die && child_die->tag)
 	{
 	  if (child_die->tag == DW_TAG_formal_parameter)
@@ -3935,46 +3966,82 @@ static struct die_info *
 read_comp_unit (char *info_ptr, bfd *abfd,
 		const struct comp_unit_head *cu_header)
 {
-  struct die_info *first_die, *last_die, *die;
-  char *cur_ptr;
-  int nesting_level;
-
   /* Reset die reference table; we are
      building new ones now.  */
   dwarf2_empty_hash_tables ();
 
+  return read_die_and_children (info_ptr, abfd, cu_header, &info_ptr, NULL);
+}
+
+/* Read a single die and all its descendents.  */
+
+static struct die_info *
+read_die_and_children (char *info_ptr, bfd *abfd,
+		       const struct comp_unit_head *cu_header,
+		       char **new_info_ptr,
+		       struct die_info *parent)
+{
+  struct die_info *die;
+  char *cur_ptr;
+  int has_children;
+
+  cur_ptr = read_full_die (&die, abfd, info_ptr, cu_header, &has_children);
+  store_in_ref_table (die->offset, die);
+
+  if (has_children)
+    {
+      die->child = read_die_and_siblings (cur_ptr, abfd, cu_header,
+					  new_info_ptr, die);
+    }
+  else
+    {
+      die->child = NULL;
+      *new_info_ptr = cur_ptr;
+    }
+
+  die->sibling = NULL;
+  die->parent = parent;
+  return die;
+}
+
+/* Helper function for read_comp_unit; it reads in a die, all of its
+   descendents, and all of its siblings.  */
+
+static struct die_info *
+read_die_and_siblings (char *info_ptr, bfd *abfd,
+		       const struct comp_unit_head *cu_header,
+		       char **new_info_ptr,
+		       struct die_info *parent)
+{
+  struct die_info *first_die, *last_sibling, *die;
+  char *cur_ptr;
+
   cur_ptr = info_ptr;
-  nesting_level = 0;
-  first_die = last_die = NULL;
-  do
+  first_die = last_sibling = NULL;
+
+  while (1)
     {
-      cur_ptr = read_full_die (&die, abfd, cur_ptr, cu_header);
-      if (die->has_children)
+      die = read_die_and_children (cur_ptr, abfd, cu_header, &cur_ptr, parent);
+
+      if (!first_die)
 	{
-	  nesting_level++;
+	  first_die = die;
 	}
-      if (die->tag == 0)
+      else
 	{
-	  nesting_level--;
+	  last_sibling->sibling = die;
 	}
 
-      die->next = NULL;
-
-      /* Enter die in reference hash table */
-      store_in_ref_table (die->offset, die);
-
-      if (!first_die)
+      if (die->tag == 0)
 	{
-	  first_die = last_die = die;
+	  *new_info_ptr = cur_ptr;
+	  return first_die;
 	}
       else
 	{
-	  last_die->next = die;
-	  last_die = die;
+	  last_sibling = die;
 	}
     }
-  while (nesting_level > 0);
-  return first_die;
 }
 
 /* Free a linked list of dies.  */
@@ -3987,7 +4054,9 @@ free_die_list (struct die_info *dies)
   die = dies;
   while (die)
     {
-      next = die->next;
+      if (die->child != NULL)
+	free_die_list (die->child);
+      next = die->sibling;
       xfree (die->attrs);
       xfree (die);
       die = next;
@@ -4301,12 +4370,13 @@ read_partial_die (struct partial_die_inf
   return info_ptr;
 }
 
-/* Read the die from the .debug_info section buffer.  And set diep to
-   point to a newly allocated die with its information.  */
+/* Read the die from the .debug_info section buffer.  Set DIEP to
+   point to a newly allocated die with its information, and set
+   HAS_CHILDREN to tell whether the die has children or not.  */
 
 static char *
 read_full_die (struct die_info **diep, bfd *abfd, char *info_ptr,
-	       const struct comp_unit_head *cu_header)
+	       const struct comp_unit_head *cu_header, int *has_children)
 {
   unsigned int abbrev_number, bytes_read, i, offset;
   struct abbrev_info *abbrev;
@@ -4322,6 +4392,7 @@ read_full_die (struct die_info **diep, b
       die->abbrev = abbrev_number;
       die->type = NULL;
       *diep = die;
+      *has_children = 0;
       return info_ptr;
     }
 
@@ -4334,7 +4405,6 @@ read_full_die (struct die_info **diep, b
   die = dwarf_alloc_die ();
   die->offset = offset;
   die->tag = abbrev->tag;
-  die->has_children = abbrev->has_children;
   die->abbrev = abbrev_number;
   die->type = NULL;
 
@@ -4349,6 +4419,7 @@ read_full_die (struct die_info **diep, b
     }
 
   *diep = die;
+  *has_children = abbrev->has_children;
   return info_ptr;
 }
 
@@ -5869,6 +5940,11 @@ static void
 read_type_die (struct die_info *die, struct objfile *objfile,
 	       const struct comp_unit_head *cu_header)
 {
+  char *prefix = determine_prefix (die);
+  const char *old_prefix = processing_current_prefix;
+  struct cleanup *back_to = make_cleanup (xfree, prefix);
+  processing_current_prefix = prefix;
+  
   switch (die->tag)
     {
     case DW_TAG_class_type:
@@ -5915,8 +5991,100 @@ read_type_die (struct die_info *die, str
 		 dwarf_tag_name (die->tag));
       break;
     }
+
+  processing_current_prefix = old_prefix;
+  do_cleanups (back_to);
+}
+
+/* Determine the name of the namespace/class that DIE is defined
+   within, or NULL if we can't tell.  The caller should xfree the
+   result.  */
+
+static char *
+determine_prefix (struct die_info *die)
+{
+  struct die_info *parent;
+
+  if (cu_language != language_cplus)
+    return NULL;
+
+  parent = die->parent;
+
+  if (parent == NULL)
+    {
+      return (processing_has_namespace_info ? xstrdup ("") : NULL);
+    }
+  else
+    {
+      char *parent_prefix = determine_prefix (parent);
+
+      switch (parent->tag) {
+      case DW_TAG_namespace:
+	{
+	  int dummy;
+
+	  return typename_concat (parent_prefix,
+				  namespace_name (parent, &dummy));
+	}
+      case DW_TAG_class_type:
+      case DW_TAG_structure_type:
+	{
+
+	  if (parent_prefix != NULL)
+	    return typename_concat (parent_prefix, dwarf2_name (parent));
+	  else
+	    return class_name (parent);
+	}
+      default:
+	return parent_prefix;
+      }
+    }
+}
+
+/* Return a newly-allocated string formed by concatenating PREFIX,
+   "::", and SUFFIX, except that if PREFIX is NULL or the empty
+   string, just return a copy of SUFFIX.  */
+
+static char *
+typename_concat (const char *prefix, const char *suffix)
+{
+  if (prefix == NULL || prefix[0] == '\0')
+    return xstrdup (suffix);
+  else
+    {
+      char *retval = xmalloc (strlen (prefix) + 2 + strlen (suffix) + 1);
+
+      strcpy (retval, prefix);
+      strcat (retval, "::");
+      strcat (retval, suffix);
+
+      return retval;
+    }
 }
 
+/* Return a newly-allocated string giving the name of the class given
+   by DIE.  */
+
+static char *
+class_name (struct die_info *die)
+{
+  struct die_info *child;
+  const char *name;
+
+  for (child = die->child; child != NULL; child = sibling_die (child))
+    {
+      if (child->tag == DW_TAG_subprogram)
+	return class_name_from_physname (dwarf2_linkage_name (child));
+    }
+
+  name = dwarf2_name (die);
+  if (name != NULL)
+    return xstrdup (name);
+  else
+    return xstrdup ("");
+}
+
+
 static struct type *
 dwarf_base_type (int encoding, int size, struct objfile *objfile)
 {
@@ -6031,43 +6199,7 @@ copy_die (struct die_info *old_die)
 static struct die_info *
 sibling_die (struct die_info *die)
 {
-  int nesting_level = 0;
-
-  if (!die->has_children)
-    {
-      if (die->next && (die->next->tag == 0))
-	{
-	  return NULL;
-	}
-      else
-	{
-	  return die->next;
-	}
-    }
-  else
-    {
-      do
-	{
-	  if (die->has_children)
-	    {
-	      nesting_level++;
-	    }
-	  if (die->tag == 0)
-	    {
-	      nesting_level--;
-	    }
-	  die = die->next;
-	}
-      while (nesting_level);
-      if (die && (die->tag == 0))
-	{
-	  return NULL;
-	}
-      else
-	{
-	  return die;
-	}
-    }
+  return die->sibling;
 }
 
 /* Get linkage name of a die, return NULL if not found.  */
@@ -6936,7 +7068,7 @@ dump_die (struct die_info *die)
   fprintf_unfiltered (gdb_stderr, "Die: %s (abbrev = %d, offset = %d)\n",
 	   dwarf_tag_name (die->tag), die->abbrev, die->offset);
   fprintf_unfiltered (gdb_stderr, "\thas children: %s\n",
-	   dwarf_bool_name (die->has_children));
+	   dwarf_bool_name (die->child != NULL));
 
   fprintf_unfiltered (gdb_stderr, "\tattributes:\n");
   for (i = 0; i < die->num_attrs; ++i)
@@ -6999,7 +7131,10 @@ dump_die_list (struct die_info *die)
   while (die)
     {
       dump_die (die);
-      die = die->next;
+      if (die->child != NULL)
+	dump_die_list (die->child);
+      if (die->sibling != NULL)
+	dump_die_list (die->sibling);
     }
 }
 
Index: testsuite/gdb.c++/rtti.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.c++/Attic/rtti.exp,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 rtti.exp
--- testsuite/gdb.c++/rtti.exp	16 May 2003 16:10:54 -0000	1.1.2.2
+++ testsuite/gdb.c++/rtti.exp	16 May 2003 23:18:29 -0000
@@ -83,17 +83,12 @@ gdb_continue_to_breakpoint "end of const
 
 gdb_test_multiple "print *e1" "print *e1" {
     -re "warning: can't find class named `n1::D1', as given by C\\+\\+ RTTI.*$gdb_prompt $" {
-	kfail "gdb/488" "print *e1"
+	#kfail "gdb/488" "print *e1"
+	fail "print *e1"
     }
     -re "\\$\[0-9\]* = {<n1::Base1> = .*}\r\n$gdb_prompt $" {
 	pass "print *e1"
     }
-    -re "\\$\[0-9\]* = {<.*Base1> = .*}\r\n$gdb_prompt $" {
-	# NOTE: carlton/2003-05-09: Sometimes, the DWARF reader gets
-	# confused about names.  I've seen just Base1 or
-	# n1::D1::C1::Base1.
-	kfail "gdb/TBA" "print *e2"
-    }
 }
 
 # NOTE: carlton/2003-05-02: This test fails on my branch because,
@@ -106,16 +101,14 @@ gdb_test_multiple "print *e1" "print *e1
 
 gdb_test_multiple "print *e2" "print *e2" {
     -re "warning: can't find class named `n2::D2', as given by C\\+\\+ RTTI.*$gdb_prompt $" {
-	kfail "gdb/488" "print *e2"
+	#kfail "gdb/488" "print *e2"
+	fail "print *e2"
     }
     -re "\\$\[0-9\]* = <incomplete type>\r\n$gdb_prompt $" {
 	kfail "gdb/TBA" "print *e2"
     }
     -re "\\$\[0-9\]* = {<n2::Base2> = .*}\r\n$gdb_prompt $" {
 	pass "print *e2"
-    }
-    -re "\\$\[0-9\]* = {<.*Base2> = .*}\r\n$gdb_prompt $" {
-	kfail "gdb/TBA" "print *e2"
     }
 }
 


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