diff mbox

Updated to respond to various email comments from Jason, Diego and Cary (issue6197069)

Message ID 20120601175840.DC7DC160730@sterling.mtv.corp.google.com
State New
Headers show

Commit Message

Sterling Augustine June 1, 2012, 5:58 p.m. UTC
The enclosed patch updates the earlier patch to address all of the feedback I
have gotten regarding generating pubnames. It fixes the offset problem in
the pubtypes table; switches DW_AT_pubtypes to a flag and so on.

It also adds and documents a new option "-g[no-]pubtypes" which allows users
to generate pubtypes even if the target disables them by default.

Tested with bootstrap and running the test_pubnames_and_indices.py script
recently contributed to the GDB project.

OK for mainline?

Sterling

2012-05-10   Sterling Augustine  <saugustine@google.com>
        Cary Coutant  <ccoutant@google.com>

	* gcc/dwarf2out.c (is_cu_die, is_namespace_die, is_class_die,
	add_AT_pubnames, add_enumerator_pubname, want_pubnames): New functions.
	(comdat_type_struct): New field 'skeleton_die'.
	(breakout_comdat_types): Update it.
	(add_pubname): Rework logic.  Call is_class_die, is_cu_die and
	is_namespace_die.  Fix minor style violation.  Call want_pubnames.
	(add_pubname_string): Call want_pubnames.
	(add_pubtype): Rework logic for calculating type name.  Call
	is_namespace_die.  Call want_pubnames.
	(output_pubnames): Move conditional logic deciding when to produce the
	section from dwarf2out_finish.  Use new skeleton_die field.
	(base_type_die): Call add_pubtype.
	(gen_enumeration_type_die): Unconditionally call add_pubtype.
	(gen_subprogram_die): Adjust calls to add_pubname.
	(gen_namespace_die): Call add_pubname_string.
	(dwarf2out_finish): Call add_AT_pubnames; Move logic on when to
	produce pubnames and pubtypes sections to output_pubnames.
	(gcc/common.opt): New option '-gpubnames'.
	(gcc/invoke.texi): Document it.


--
This patch is available for review at http://codereview.appspot.com/6197069

Comments

Jason Merrill June 8, 2012, 6:45 p.m. UTC | #1
On 06/01/2012 01:58 PM, Sterling Augustine wrote:
> It also adds and documents a new option "-g[no-]pubtypes" which allows users
> to generate pubtypes even if the target disables them by default.

Hmm, I thought the convention for this sort of flag was to start with 
-f, that -g flags were only for selecting the type and level of debug 
info.  But I see that there are other debug dialect switches that use 
-g, so I guess this is OK.

> +  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))

Why not include public class members?  Is the theory that you'll need to 
read the type DIE anyway to do anything with the member, so you might as 
well read it to look up the member in the first place?  There should be 
a comment about this.

> +  VEC_safe_push (pubname_entry, gc, pubtype_table, &e);

Why add enumerators to pubtypes rather than pubnames?  They seem more 
like variables than types to me.

> +         here.  This isn't protected by the name conditional because anoymous

Missing an 'n' in "anonymous".

A C++ opaque enumeration is considered complete, but does not yet have 
its enumerators, which can be added later.  Does this code handle that?

> +	  if (use_debug_types && names == pubtype_table)

This should check pub->die->comdat_type_p

Jason
Jakub Jelinek June 8, 2012, 6:47 p.m. UTC | #2
On Fri, Jun 08, 2012 at 02:45:09PM -0400, Jason Merrill wrote:
> On 06/01/2012 01:58 PM, Sterling Augustine wrote:
> >It also adds and documents a new option "-g[no-]pubtypes" which allows users
> >to generate pubtypes even if the target disables them by default.
> 
> Hmm, I thought the convention for this sort of flag was to start
> with -f, that -g flags were only for selecting the type and level of
> debug info.  But I see that there are other debug dialect switches
> that use -g, so I guess this is OK.

But we have -f{,no-}debug-types-section, so perhaps consistent with that
would be -f{,no-}debug-pubtypes-section ?

	Jakub
Cary Coutant June 8, 2012, 9:22 p.m. UTC | #3
> Hmm, I thought the convention for this sort of flag was to start with -f,
> that -g flags were only for selecting the type and level of debug info.  But
> I see that there are other debug dialect switches that use -g, so I guess
> this is OK.

I kind of prefer -g, but I did notice that it's -fdebug-types-section,
so I could go with -f[no-]pubnames (or, as Jakub suggests,
-f[no-]debug-pubnames-section). On the other hand, there's
-g[no-]record-gcc-switches. What would you prefer?

If we change it, should we also change (in a later patch)
-gsplit-dwarf (orig. -gfission) to -fsplit-dwarf?

>> +  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
>
> Why not include public class members?  Is the theory that you'll need to
> read the type DIE anyway to do anything with the member, so you might as
> well read it to look up the member in the first place?  There should be a
> comment about this.

Yes, that's the theory. We're just trying to do the same thing that
GDB does when it builds .gdb_index.

>> +  VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
>
> Why add enumerators to pubtypes rather than pubnames?  They seem more like
> variables than types to me.

That looks like a typo. It hasn't caused us any trouble because the
linker just throws all the names into the same table in .gdb_index,
but yes, I think it should go in pubnames_table.

-cary
Sterling Augustine June 8, 2012, 10:03 p.m. UTC | #4
On Fri, Jun 8, 2012 at 2:22 PM, Cary Coutant <ccoutant@google.com> wrote:
>> Hmm, I thought the convention for this sort of flag was to start with -f,
>> that -g flags were only for selecting the type and level of debug info.  But
>> I see that there are other debug dialect switches that use -g, so I guess
>> this is OK.
>
> I kind of prefer -g, but I did notice that it's -fdebug-types-section,
> so I could go with -f[no-]pubnames (or, as Jakub suggests,
> -f[no-]debug-pubnames-section). On the other hand, there's
> -g[no-]record-gcc-switches. What would you prefer?
>
> If we change it, should we also change (in a later patch)
> -gsplit-dwarf (orig. -gfission) to -fsplit-dwarf?
>
>>> +  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
>>
>> Why not include public class members?  Is the theory that you'll need to
>> read the type DIE anyway to do anything with the member, so you might as
>> well read it to look up the member in the first place?  There should be a
>> comment about this.
>
> Yes, that's the theory. We're just trying to do the same thing that
> GDB does when it builds .gdb_index.
>
>>> +  VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
>>
>> Why add enumerators to pubtypes rather than pubnames?  They seem more like
>> variables than types to me.
>
> That looks like a typo. It hasn't caused us any trouble because the
> linker just throws all the names into the same table in .gdb_index,
> but yes, I think it should go in pubnames_table.
>
> -cary

OK, I've updated the patch with all these additional comments. Just
waiting on the decision between -f and -g. I'll repost and then commit
it when that is settled--hopefully soon.

Next up, the big fission patch!

Sterling
Sterling Augustine June 12, 2012, 6:53 p.m. UTC | #5
On Fri, Jun 8, 2012 at 3:03 PM, Sterling Augustine
<saugustine@google.com> wrote:

[Regarding generating pubnames]

> OK, I've updated the patch with all these additional comments. Just
> waiting on the decision between -f and -g. I'll repost and then commit
> it when that is settled--hopefully soon.
>
> Next up, the big fission patch!
>
> Sterling

Ping
Jason Merrill June 13, 2012, 4:32 a.m. UTC | #6
On 06/08/2012 05:22 PM, Cary Coutant wrote:
> I kind of prefer -g, but I did notice that it's -fdebug-types-section,
> so I could go with -f[no-]pubnames (or, as Jakub suggests,
> -f[no-]debug-pubnames-section). On the other hand, there's
> -g[no-]record-gcc-switches. What would you prefer?
>
> If we change it, should we also change (in a later patch)
> -gsplit-dwarf (orig. -gfission) to -fsplit-dwarf?

I lean toward -g myself, since there doesn't seem to be a strong rule 
one way or the other.

Jason
Sterling Augustine June 13, 2012, 11:26 p.m. UTC | #7
> I lean toward -g myself, since there doesn't seem to be a strong rule one
> way or the other.

Unless there are further comments, I'll stick with -g then.

I think that covers all the comments, so I think I will commit this
Friday morning unless I hear anything further.

Sterling
Jason Merrill June 14, 2012, 5:47 a.m. UTC | #8
On 06/13/2012 04:26 PM, Sterling Augustine wrote:
>> I lean toward -g myself, since there doesn't seem to be a strong rule one
>> way or the other.
>
> Unless there are further comments, I'll stick with -g then.
>
> I think that covers all the comments, so I think I will commit this
> Friday morning unless I hear anything further.

Weren't you going to repost the patch first?  :)

Jason
Sterling Augustine June 19, 2012, 5:12 p.m. UTC | #9
On Wed, Jun 13, 2012 at 10:47 PM, Jason Merrill <jason@redhat.com> wrote:
> On 06/13/2012 04:26 PM, Sterling Augustine wrote:
>>>
>>> I lean toward -g myself, since there doesn't seem to be a strong rule one
>>> way or the other.
>>
>>
>> Unless there are further comments, I'll stick with -g then.
>>
>> I think that covers all the comments, so I think I will commit this
>> Friday morning unless I hear anything further.
>
>
> Weren't you going to repost the patch first?  :)

I hate how codereview.appspot.com doesn't connect some messages properly.

After this prompting, I re-posted the patch here:

http://gcc.gnu.org/ml/gcc-patches/2012-06/msg00949.html

As this has addressed all previous comments, and barring any
objections, I'll check it in tomorrow morning.

Sterling
Jason Merrill June 20, 2012, 12:51 a.m. UTC | #10
On 06/19/2012 10:12 AM, Sterling Augustine wrote:
> +	  /* If we're putting types in their own .debug_types sections,
> +	     the .debug_pubtypes table will still point to the compile
> +	     unit (not the type unit), so we want to use the offset of
> +	     the skeleton DIE (if there is one).  */
> +	  if (pub->die->comdat_type_p && names == pubtype_table)
> +	    {
> +	      comdat_type_node_ref type_node = pub->die->die_id.die_type_node;
> +
> +	      if (type_node != NULL && type_node->skeleton_die != NULL)
> +		die_offset = type_node->skeleton_die->die_offset;
> +	    }

I think we had agreed that if there is no skeleton, we should use an 
offset of 0.

Jason
Cary Coutant June 20, 2012, 9:57 p.m. UTC | #11
>> +         /* If we're putting types in their own .debug_types sections,
>> +            the .debug_pubtypes table will still point to the compile
>> +            unit (not the type unit), so we want to use the offset of
>> +            the skeleton DIE (if there is one).  */
>> +         if (pub->die->comdat_type_p && names == pubtype_table)
>>
>> +           {
>> +             comdat_type_node_ref type_node =
>> pub->die->die_id.die_type_node;
>> +
>> +             if (type_node != NULL && type_node->skeleton_die != NULL)
>> +               die_offset = type_node->skeleton_die->die_offset;
>> +           }
>
>
> I think we had agreed that if there is no skeleton, we should use an offset
> of 0.

You're right, I forgot to handle that case. How's this look?

             if (type_node != NULL)
               die_offset = (type_node->skeleton_die != NULL
                             ? type_node->skeleton_die->die_offset
                             : 0);

Is that OK if it passes regression tests?

-cary
Jason Merrill June 21, 2012, 12:27 a.m. UTC | #12
OK.

Jason
Sterling Augustine June 21, 2012, 6:18 p.m. UTC | #13
Committed as attached. Thanks for your reviews.

Sterling

gcc/ChangeLog

2012-06-21   Sterling Augustine  <saugustine@google.com>
        Cary Coutant  <ccoutant@google.com>

	* dwarf2out.c (is_cu_die, is_namespace_die, is_class_die,
	add_AT_pubnames, add_enumerator_pubname, want_pubnames): New functions.
	(comdat_type_struct): New field 'skeleton_die'.
	(breakout_comdat_types): Update it.
	(add_pubname): Rework logic.  Call is_class_die, is_cu_die and
	is_namespace_die.  Fix minor style violation.  Call want_pubnames.
	(add_pubname_string): Call want_pubnames.
	(add_pubtype): Rework logic for calculating type name.  Call
	is_namespace_die.  Call want_pubnames.
	(output_pubnames): Move conditional logic deciding when to produce the
	section from dwarf2out_finish.  Use new skeleton_die field.
	(base_type_die): Call add_pubtype.
	(gen_enumeration_type_die): Unconditionally call add_pubtype.
	(gen_subprogram_die): Adjust calls to add_pubname.
	(gen_namespace_die): Call add_pubname_string.
	(dwarf2out_finish): Call add_AT_pubnames; Move logic on when to
	produce pubnames and pubtypes sections to output_pubnames.
	(common.opt): New option '-gpubnames'.
	(invoke.texi): Document it.



On Wed, Jun 20, 2012 at 5:27 PM, Jason Merrill <jason@redhat.com> wrote:
> OK.
>
> Jason
Jason Merrill June 22, 2012, 9:35 a.m. UTC | #14
On 06/21/2012 11:18 AM, Sterling Augustine wrote:
> Committed as attached. Thanks for your reviews.

I've heard reports of new test failures due to this patch:

FAIL: gcc.dg/pubtypes-2.c scan-assembler long+[ \\t]+0x6a+[ \\t]+[#;]+[ 
\\t]+Length of Public Type Names Info
FAIL: gcc.dg/pubtypes-3.c scan-assembler long+[ \\t]+0x6a+[ \\t]+[#;]+[ 
\\t]+Length of Public Type Names Info
FAIL: gcc.dg/pubtypes-4.c scan-assembler long+[ \\t]+0xa1+[ \\t]+[#;]+[ 
\\t]+Length of Public Type Names Info

FAIL: g++.dg/debug/dwarf2/static-data-member2.C -std=gnu++98 
scan-assembler-not DW_TAG_enumerator
FAIL: g++.dg/debug/dwarf2/static-data-member2.C -std=gnu++98 
scan-assembler-not DW_TAG_enumeration_type
FAIL: g++.dg/debug/dwarf2/static-data-member2.C -std=gnu++11 
scan-assembler-not DW_TAG_enumerator
FAIL: g++.dg/debug/dwarf2/static-data-member2.C -std=gnu++11 
scan-assembler-not DW_TAG_enumeration_type

For the first group, you probably just need to update the test.  For the 
second, we still don't want to emit unused enumerations.

Jason
Sterling Augustine June 22, 2012, 8:44 p.m. UTC | #15
On Fri, Jun 22, 2012 at 2:35 AM, Jason Merrill <jason@redhat.com> wrote:
> FAIL: g++.dg/debug/dwarf2/static-data-member2.C -std=gnu++98
> scan-assembler-not DW_TAG_enumerator
> FAIL: g++.dg/debug/dwarf2/static-data-member2.C -std=gnu++98
> scan-assembler-not DW_TAG_enumeration_type
> FAIL: g++.dg/debug/dwarf2/static-data-member2.C -std=gnu++11
> scan-assembler-not DW_TAG_enumerator
> FAIL: g++.dg/debug/dwarf2/static-data-member2.C -std=gnu++11
> scan-assembler-not DW_TAG_enumeration_type

This is a side effect of moving enumerators from pubnames to pubtypes
as requested in an earlier message in this thread. I should have
pushed back harder on this change.

prune_unused_types marks everything in the pubnames_table. If the
enumerators go in the pubname table (but the enum itself goes in the
pubtype table), then the unused enum becomes reachable from the
pubnames table.

The least complicated solution is to put them back in the
pubtypes_table. I could also defer adding them until after types are
pruned, I guess.

One somewhat unsatisfying way to rationalize it in my mind is to say
that as fields are to structs, so are enumerators to enums.

What do you think?

Sterling

gcc/ChangeLog
2012-06-22  Sterling Augustine  <sagustine@google.com>

	* dwarf2out.c (add_enumerator_pubname): Use pubtypes_table.
Cary Coutant June 22, 2012, 9:15 p.m. UTC | #16
> prune_unused_types marks everything in the pubnames_table. If the
> enumerators go in the pubname table (but the enum itself goes in the
> pubtype table), then the unused enum becomes reachable from the
> pubnames table.
>
> The least complicated solution is to put them back in the
> pubtypes_table. I could also defer adding them until after types are
> pruned, I guess.
>
> One somewhat unsatisfying way to rationalize it in my mind is to say
> that as fields are to structs, so are enumerators to enums.

It doesn't matter much to me -- it was working with enumerators in the
pubtypes table, as far as I can tell.

But if the consensus turns out to be that enumerators should be in
pubnames, wouldn't it also be fairly easy to change prune_unused_types
so that it doesn't mark enumerators, and change output_pubnames to
skip enumerators that have been pruned?

-cary
Jason Merrill June 23, 2012, 4:46 a.m. UTC | #17
On 06/22/2012 02:15 PM, Cary Coutant wrote:
> But if the consensus turns out to be that enumerators should be in
> pubnames, wouldn't it also be fairly easy to change prune_unused_types
> so that it doesn't mark enumerators, and change output_pubnames to
> skip enumerators that have been pruned?

This makes sense to me.

Jason
Sterling Augustine June 26, 2012, 1:08 a.m. UTC | #18
On Fri, Jun 22, 2012 at 9:46 PM, Jason Merrill <jason@redhat.com> wrote:
> On 06/22/2012 02:15 PM, Cary Coutant wrote:
>>
>> But if the consensus turns out to be that enumerators should be in
>> pubnames, wouldn't it also be fairly easy to change prune_unused_types
>> so that it doesn't mark enumerators, and change output_pubnames to
>> skip enumerators that have been pruned?
>
>
> This makes sense to me.

Enclosed is a patch that does it this way. It requires special-casing
enumerators in two places.

Personally, it seems cleaner to me just to put them in the pubtypes
table, but I am happy to do it whichever way you want.

Let me know,

Sterling

gcc/ChangeLog

2012-06-25  Sterling Augustine <saugustine@google.com>

        * dwarf2out.c (output_pubnames): Add check for DW_TAG_enumerator.
        (prune_unused_types): Add check for DW_TAG_enumerator.
Jason Merrill June 26, 2012, 3:35 a.m. UTC | #19
OK.

Jason
Sterling Augustine June 26, 2012, 6:18 p.m. UTC | #20
Committed as posted.

On Mon, Jun 25, 2012 at 8:35 PM, Jason Merrill <jason@redhat.com> wrote:
> OK.
>
> Jason
Cary Coutant July 23, 2012, 8:21 p.m. UTC | #21
>>> But if the consensus turns out to be that enumerators should be in
>>> pubnames, wouldn't it also be fairly easy to change prune_unused_types
>>> so that it doesn't mark enumerators, and change output_pubnames to
>>> skip enumerators that have been pruned?
>>
>> This makes sense to me.
>
> Enclosed is a patch that does it this way. It requires special-casing
> enumerators in two places.
>
> Personally, it seems cleaner to me just to put them in the pubtypes
> table, but I am happy to do it whichever way you want.

Sterling, I think you were right all along -- this fails with
-fdebug-types-section. When we move an enumeration type out to a
separate types section, the DIE isn't marked when we try to add the
enumerators to the pubnames table, so the enumerators never get added
to the pubnames table. I'm not sure if there's an easy way to get them
added to pubnames in that case; it might be easier to go back to
putting them in pubtypes.

-cary
diff mbox

Patch

Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 188035)
+++ gcc/dwarf2out.c	(working copy)
@@ -2539,6 +2539,7 @@ 
 {
   dw_die_ref root_die;
   dw_die_ref type_die;
+  dw_die_ref skeleton_die;
   char signature[DWARF_TYPE_SIGNATURE_SIZE];
   struct comdat_type_struct *next;
 }
@@ -3013,6 +3014,7 @@ 
 static void output_comdat_type_unit (comdat_type_node *);
 static const char *dwarf2_name (tree, int);
 static void add_pubname (tree, dw_die_ref);
+static void add_enumerator_pubname (const char *, dw_die_ref);
 static void add_pubname_string (const char *, dw_die_ref);
 static void add_pubtype (tree, dw_die_ref);
 static void output_pubnames (VEC (pubname_entry,gc) *);
@@ -3142,6 +3144,7 @@ 
 				     const char *, const char *);
 static void output_loc_list (dw_loc_list_ref);
 static char *gen_internal_sym (const char *);
+static bool want_pubnames (void);
 
 static void prune_unmark_dies (dw_die_ref);
 static void prune_unused_types_mark_generic_parms_dies (dw_die_ref);
@@ -5972,6 +5975,23 @@ 
   return c && c->die_tag == DW_TAG_compile_unit;
 }
 
+/* Returns true iff C is a namespace DIE.  */
+
+static inline bool
+is_namespace_die (dw_die_ref c)
+{
+  return c && c->die_tag == DW_TAG_namespace;
+}
+
+/* Returns true iff C is a class or structure DIE.  */
+
+static inline bool
+is_class_die (dw_die_ref c)
+{
+  return c && (c->die_tag == DW_TAG_class_type
+               || c->die_tag == DW_TAG_structure_type);
+}
+
 static char *
 gen_internal_sym (const char *prefix)
 {
@@ -6559,6 +6579,7 @@ 
            declaration into the new type unit DIE, then remove this DIE
 	   from the main CU (or replace it with a skeleton if necessary).  */
 	replacement = remove_child_or_replace_with_skeleton (unit, c, prev);
+	type_node->skeleton_die = replacement;
 
         /* Break out nested types into their own type units.  */
         break_out_comdat_types (c);
@@ -8034,6 +8055,27 @@ 
     }
 }
 
+/* Whether to generate the DWARF accelerator tables in .debug_pubnames
+   and .debug_pubtypes.  This is configured per-target, but can be
+   overridden by the -gpubnames or -gno-pubnames options.  */
+
+static inline bool
+want_pubnames (void)
+{
+  return (debug_generate_pub_sections != -1
+	  ? debug_generate_pub_sections
+	  : targetm.want_debug_pub_sections);
+}
+
+/* Add the DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes.  */
+
+static void
+add_AT_pubnames (dw_die_ref die)
+{
+  if (want_pubnames ())
+    add_AT_flag (die, DW_AT_GNU_pubnames, 1);
+}
+
 /* Output a comdat type unit DIE and its children.  */
 
 static void
@@ -8104,7 +8146,7 @@ 
 static void
 add_pubname_string (const char *str, dw_die_ref die)
 {
-  if (targetm.want_debug_pub_sections)
+  if (want_pubnames ())
     {
       pubname_entry e;
 
@@ -8117,14 +8159,32 @@ 
 static void
 add_pubname (tree decl, dw_die_ref die)
 {
-  if (targetm.want_debug_pub_sections && TREE_PUBLIC (decl))
+  if (!want_pubnames ())
+    return;
+
+  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
+      || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
     {
       const char *name = dwarf2_name (decl, 1);
+
       if (name)
 	add_pubname_string (name, die);
     }
 }
 
+/* Add an enumerator to the pubnames section.  */
+
+static void
+add_enumerator_pubname (const char *scope_name, dw_die_ref die)
+{
+  pubname_entry e;
+
+  gcc_assert (scope_name);
+  e.name = concat (scope_name, get_AT_string (die, DW_AT_name), NULL);
+  e.die = die;
+  VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+}
+
 /* Add a new entry to .debug_pubtypes if appropriate.  */
 
 static void
@@ -8132,40 +8192,55 @@ 
 {
   pubname_entry e;
 
-  if (!targetm.want_debug_pub_sections)
+  if (!want_pubnames ())
     return;
 
-  e.name = NULL;
   if ((TREE_PUBLIC (decl)
-       || is_cu_die (die->die_parent))
+       || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
       && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
     {
-      e.die = die;
-      if (TYPE_P (decl))
-	{
-	  if (TYPE_NAME (decl))
+      tree scope = NULL;
+      const char *scope_name = "";
+      const char *sep = is_cxx () ? "::" : ".";
+      const char *name;
+
+      scope = TYPE_P (decl) ? TYPE_CONTEXT (decl) : NULL;
+      if (scope && TREE_CODE (scope) == NAMESPACE_DECL)
 	    {
-	      if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
-		e.name = IDENTIFIER_POINTER (TYPE_NAME (decl));
-	      else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
-		       && DECL_NAME (TYPE_NAME (decl)))
-		e.name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl)));
+          scope_name = lang_hooks.dwarf_name (scope, 1);
+          if (scope_name != NULL && scope_name[0] != '\0')
+            scope_name = concat (scope_name, sep, NULL);
 	      else
-	       e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
-	    }
+            scope_name = "";
 	}
+
+      if (TYPE_P (decl))
+        name = type_tag (decl);
       else
-	{
-	  e.name = dwarf2_name (decl, 1);
-	  if (e.name)
-	    e.name = xstrdup (e.name);
-	}
+        name = lang_hooks.dwarf_name (decl, 1);
 
       /* If we don't have a name for the type, there's no point in adding
 	 it to the table.  */
-      if (e.name && e.name[0] != '\0')
+      if (name != NULL && name[0] != '\0')
+        {
+          e.die = die;
+          e.name = concat (scope_name, name, NULL);
 	VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
     }
+
+      /* Although it might be more consistent to add the pubinfo for the
+         enumerators as their dies are created, they should only be added if the
+         enum type meets the criteria above.  So rather than re-check the parent
+         enum type whenever an enumerator die is created, just output them all
+         here.  This isn't protected by the name conditional because anoymous
+         enums don't have names.  */
+      if (die->die_tag == DW_TAG_enumeration_type)
+        {
+          dw_die_ref c;
+
+          FOR_EACH_CHILD (die, c, add_enumerator_pubname (scope_name, c));
+        }
+    }
 }
 
 /* Output the public names table used to speed up access to externally
@@ -8178,6 +8253,12 @@ 
   unsigned long pubnames_length = size_of_pubnames (names);
   pubname_ref pub;
 
+  if (!want_pubnames () || !info_section_emitted)
+    return;
+  if (names == pubname_table)
+    switch_to_section (debug_pubnames_section);
+  else
+    switch_to_section (debug_pubtypes_section);
   if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
     dw2_asm_output_data (4, 0xffffffff,
       "Initial length escape value indicating 64-bit DWARF extension");
@@ -8205,9 +8286,22 @@ 
 	  || pub->die->die_offset != 0
 	  || !flag_eliminate_unused_debug_types)
 	{
-	  dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
-			       "DIE offset");
+	  dw_offset die_offset = pub->die->die_offset;
 
+	  /* If we're putting types in their own .debug_types sections,
+	     the .debug_pubtypes table will still point to the compile
+	     unit (not the type unit), so we want to use the offset of
+	     the skeleton DIE (if there is one).  */
+	  if (use_debug_types && names == pubtype_table)
+	    {
+	      comdat_type_node_ref type_node = pub->die->die_id.die_type_node;
+
+	      if (type_node != NULL && type_node->skeleton_die != NULL)
+		die_offset = type_node->skeleton_die->die_offset;
+	    }
+
+	  dw2_asm_output_data (DWARF_OFFSET_SIZE, die_offset, "DIE offset");
+
 	  dw2_asm_output_nstring (pub->name, -1, "external name");
 	}
     }
@@ -9091,6 +9185,7 @@ 
   add_AT_unsigned (base_type_result, DW_AT_byte_size,
 		   int_size_in_bytes (type));
   add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
+  add_pubtype (type, base_type_result);
 
   return base_type_result;
 }
@@ -16173,7 +16268,6 @@ 
   else
     add_AT_flag (type_die, DW_AT_declaration, 1);
 
-  if (get_AT (type_die, DW_AT_name))
     add_pubtype (type, type_die);
 
   return type_die;
@@ -16813,6 +16907,7 @@ 
 	{
 	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
 	  add_AT_specification (subr_die, old_die);
+          add_pubname (decl, subr_die);
 	  if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
 	    add_AT_file (subr_die, DW_AT_decl_file, file_index);
 	  if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
@@ -16827,6 +16922,7 @@ 
 	add_AT_flag (subr_die, DW_AT_external, 1);
 
       add_name_and_src_coords_attributes (subr_die, decl);
+      add_pubname (decl, subr_die);
       if (debug_info_level > DINFO_LEVEL_TERSE)
 	{
 	  add_prototyped_attribute (subr_die, TREE_TYPE (decl));
@@ -16938,7 +17034,6 @@ 
       }
 #endif
 
-	  add_pubname (decl, subr_die);
 	}
       else
 	{
@@ -16959,7 +17054,6 @@ 
 		  add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
 					fde->dw_fde_second_end,
 					&range_list_added);
-		  add_pubname (decl, subr_die);
 		  if (range_list_added)
 		    add_ranges (NULL);
 		}
@@ -16981,8 +17075,6 @@ 
 				 fde->dw_fde_begin);
 		  add_AT_lbl_id (subr_die, DW_AT_high_pc,
 				 fde->dw_fde_end);
-		  /* Add it.   */
-		  add_pubname (decl, subr_die);
 
 		  /* Build a minimal DIE for the secondary section.  */
 		  seg_die = new_die (DW_TAG_subprogram,
@@ -17018,7 +17110,6 @@ 
 	    {
 	      add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin);
 	      add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end);
-	      add_pubname (decl, subr_die);
 	    }
 	}
 
@@ -19049,6 +19140,8 @@ 
       add_AT_die_ref (namespace_die, DW_AT_import, origin_die);
       equate_decl_number_to_die (decl, namespace_die);
     }
+  /* Bypass dwarf2_name's check for DECL_NAMELESS.  */
+  add_pubname_string (lang_hooks.dwarf_name (decl, 1), namespace_die);
 }
 
 /* Generate Dwarf debug information for a decl described by DECL.
@@ -22309,6 +22402,8 @@ 
     }
   htab_delete (comdat_type_table);
 
+  add_AT_pubnames (comp_unit_die ());
+
   /* Output the main compilation unit if non-empty or if .debug_macinfo
      or .debug_macro will be emitted.  */
   output_comp_unit (comp_unit_die (), have_macinfo);
@@ -22332,42 +22427,12 @@ 
       output_location_lists (comp_unit_die ());
     }
 
-  /* Output public names table if necessary.  */
-  if (!VEC_empty (pubname_entry, pubname_table))
-    {
-      gcc_assert (info_section_emitted);
-      switch_to_section (debug_pubnames_section);
-      output_pubnames (pubname_table);
-    }
-
-  /* Output public types table if necessary.  */
+  /* Output public names and types tables if necessary.  */
+  output_pubnames (pubname_table);
   /* ??? Only defined by DWARF3, but emitted by Darwin for DWARF2.
      It shouldn't hurt to emit it always, since pure DWARF2 consumers
      simply won't look for the section.  */
-  if (!VEC_empty (pubname_entry, pubtype_table))
-    {
-      bool empty = false;
-      
-      if (flag_eliminate_unused_debug_types)
-	{
-	  /* The pubtypes table might be emptied by pruning unused items.  */
-	  unsigned i;
-	  pubname_ref p;
-	  empty = true;
-	  FOR_EACH_VEC_ELT (pubname_entry, pubtype_table, i, p)
-	    if (p->die->die_offset != 0)
-	      {
-		empty = false;
-		break;
-	      }
-	}
-      if (!empty)
-	{
-	  gcc_assert (info_section_emitted);
-	  switch_to_section (debug_pubtypes_section);
-	  output_pubnames (pubtype_table);
-	}
-    }
+  output_pubnames (pubtype_table);
 
   /* Output the address range information if a CU (.debug_info section)
      was emitted.  We output an empty table even if we had no functions
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 188034)
+++ gcc/common.opt	(working copy)
@@ -2239,6 +2239,14 @@ 
 Common JoinedOrMissing
 Generate debug information in default extended format
 
+gno-pubnames
+Common RejectNegative Var(debug_generate_pub_sections, 0) Init(-1)
+Don't generate DWARF pubnames and pubtypes sections.
+
+gpubnames
+Common RejectNegative Var(debug_generate_pub_sections, 1)
+Generate DWARF pubnames and pubtypes sections.
+
 gno-record-gcc-switches
 Common RejectNegative Var(dwarf_record_gcc_switches,0) Init(1)
 Don't record gcc command line switches in DWARF DW_AT_producer.
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 188034)
+++ gcc/doc/invoke.texi	(working copy)
@@ -4799,6 +4799,10 @@ 
 if neither of those are supported), including GDB extensions if at all
 possible.
 
+@item -gpubnames
+@opindex gpubnames
+Generate dwarf .debug_pubnames and .debug_pubtypes sections.
+
 @item -gstabs
 @opindex gstabs
 Produce debugging information in stabs format (if that is supported),