diff mbox

[RFC] -grecord-gcc-switches (PR other/32998)

Message ID 20110712234608.GR2687@tyan-ft48-01.lab.bos.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek July 12, 2011, 11:46 p.m. UTC
Hi!

As discussed in the PR, this patch implements IMHO a better alternative
to the current -frecord-gcc-switches option which isn't very usable unless
inspected on relocatable files only.  As each switch is zero terminated and
the section is mergeable, for whole binary or shared library we end up with
a set of all options which ever showed up on the command line when compiling
some of the CUs, but it is impossible to narrow it down back to which CU has
been compiled with what options.

This patch insteads appends the options as one long string separated by
spaces to DW_AT_producer attribute (which is normally just a reference
to a string in .debug_str).  Thus, ideally if all or most of the CUs
are compiled with the same options there is just one or just small number of

	Jakub

Comments

Jason Merrill July 13, 2011, 1:56 p.m. UTC | #1
On 07/12/2011 07:46 PM, Jakub Jelinek wrote:
> The aim is to include just (or primarily) code generation affecting options
> explicitly passed on the command line.  So that the merging actually works,
> options or arguments which include filenames or paths shouldn't be added,
> on Roland's request -D*/-U* options aren't added either (that should be
> covered by .debug_macinfo)

...but only with -g3.

> Ideally we'd just include explicitly passed options from command line that
> haven't been overridden by other command line options, and would sort them,
> so that there are higher chances of DW_AT_producer strings being merged
> (e.g. -O2 -ffast-math vs. -ffast-math -O2 are now different strings, and
> similarly -O2 vs. -O3 -O2 vs. -O0 -O1 -Ofast -O2), but I'm not sure if it is
> easily possible using current option handling framework.

Why not?  Sorting sounds pretty straightforward to me, though you might 
want to copy the array first.

On the other hand, it probably isn't worthwhile; presumably most 
relocatables being linked together will share the same CFLAGS, so you'll 
get a high degree of merging without any sorting.

> --- gcc/testsuite/lib/dg-pch.exp.jj	2011-01-03 18:58:03.000000000 +0100
> +++ gcc/testsuite/lib/dg-pch.exp	2011-07-12 23:13:50.943670171 +0200
> -	dg-test -keep-output "./$bname$suffix" "$otherflags $flags" ""
> +	dg-test -keep-output "./$bname$suffix" "-gno-record-gcc-switches $otherflags $flags" ""

Why is this necessary?

Jason
Jakub Jelinek July 13, 2011, 2:06 p.m. UTC | #2
On Wed, Jul 13, 2011 at 09:56:58AM -0400, Jason Merrill wrote:
> On 07/12/2011 07:46 PM, Jakub Jelinek wrote:
> >The aim is to include just (or primarily) code generation affecting options
> >explicitly passed on the command line.  So that the merging actually works,
> >options or arguments which include filenames or paths shouldn't be added,
> >on Roland's request -D*/-U* options aren't added either (that should be
> >covered by .debug_macinfo)
> 
> ...but only with -g3.

Sure.  But if we put -D*/-U* into DW_AT_producer, -D_FORTIFY_SOURCE=2
on the command line acts the same as #define _FORTIFY_SOURCE 2
before including the first header and the latter wouldn't be recorded.
I'm working on smaller .debug_macinfo right now.

> >Ideally we'd just include explicitly passed options from command line that
> >haven't been overridden by other command line options, and would sort them,
> >so that there are higher chances of DW_AT_producer strings being merged
> >(e.g. -O2 -ffast-math vs. -ffast-math -O2 are now different strings, and
> >similarly -O2 vs. -O3 -O2 vs. -O0 -O1 -Ofast -O2), but I'm not sure if it is
> >easily possible using current option handling framework.
> 
> Why not?  Sorting sounds pretty straightforward to me, though you
> might want to copy the array first.

If the command line options contain options that override each other, then
sorting would drop important information what comes last and thus overrides
other options.  If we would have only options which weren't overridden,
we could sort.  Otherwise -O2 -O0 would be sorted as -O0 -O2 and we'd think
the code was optimized when it wasn't.

> On the other hand, it probably isn't worthwhile; presumably most
> relocatables being linked together will share the same CFLAGS, so
> you'll get a high degree of merging without any sorting.
> 
> >--- gcc/testsuite/lib/dg-pch.exp.jj	2011-01-03 18:58:03.000000000 +0100
> >+++ gcc/testsuite/lib/dg-pch.exp	2011-07-12 23:13:50.943670171 +0200
> >-	dg-test -keep-output "./$bname$suffix" "$otherflags $flags" ""
> >+	dg-test -keep-output "./$bname$suffix" "-gno-record-gcc-switches $otherflags $flags" ""
> 
> Why is this necessary?

It is only necessary if somebody wants to make -grecord-gcc-switches
the default (for bootstrap/regtest I've tweaked common.opt to do that
to test it better).  PCH is a big mess and screws debuginfo in many ways,
in this case it was just small differences in DW_AT_producer, but
we have e.g. ICEs with PCH and -feliminate-dwarf-dups etc.

	Jakub
Jason Merrill July 13, 2011, 2:30 p.m. UTC | #3
On 07/13/2011 10:06 AM, Jakub Jelinek wrote:
>>> --- gcc/testsuite/lib/dg-pch.exp.jj	2011-01-03 18:58:03.000000000 +0100
>>> +++ gcc/testsuite/lib/dg-pch.exp	2011-07-12 23:13:50.943670171 +0200
>>> -	dg-test -keep-output "./$bname$suffix" "$otherflags $flags" ""
>>> +	dg-test -keep-output "./$bname$suffix" "-gno-record-gcc-switches $otherflags $flags" ""
>>
> It is only necessary if somebody wants to make -grecord-gcc-switches
> the default (for bootstrap/regtest I've tweaked common.opt to do that
> to test it better).  PCH is a big mess and screws debuginfo in many ways,
> in this case it was just small differences in DW_AT_producer, but
> we have e.g. ICEs with PCH and -feliminate-dwarf-dups etc.

Why would PCH change DW_AT_producer?  Because we're restoring 
single_comp_unit_die from the PCH?  Then perhaps we should set 
DW_AT_producer in output_comp_unit rather than gen_compile_unit_die.

Jason
Joseph Myers July 21, 2011, 8:06 p.m. UTC | #4
On Wed, 13 Jul 2011, Jakub Jelinek wrote:

> Ideally we'd just include explicitly passed options from command line that
> haven't been overridden by other command line options, and would sort them,
> so that there are higher chances of DW_AT_producer strings being merged
> (e.g. -O2 -ffast-math vs. -ffast-math -O2 are now different strings, and
> similarly -O2 vs. -O3 -O2 vs. -O0 -O1 -Ofast -O2), but I'm not sure if it is
> easily possible using current option handling framework.

I don't think there's enough structure for that, although prune_options 
could always be enhanced to cover more cases of overridden options.

> +	  default:
> +	    if (save_decoded_options[j].orig_option_with_args_text[0] != '-')
> +	      continue;

Should instead be ignoring OPT_SPECIAL_*.

> +	    switch (save_decoded_options[j].orig_option_with_args_text[1])
> +	      {
> +	      case 'M':
> +	      case 'i':
> +	      case 'W':

It would be better to check the canonical option text rather than the 
original text.  Normally this wouldn't make any difference because the 
driver will have passed canonical options to cc1, but if someone calls cc1 
directly then I think aliases should still act the same as the options 
they are aliases for in this regard.

> +		continue;
> +	      case 'n':
> +		if (save_decoded_options[j].orig_option_with_args_text[2]
> +		    == 'o')
> +		  continue;

When would a "-no" option ever get passed to cc1?
Jakub Jelinek July 21, 2011, 8:19 p.m. UTC | #5
On Thu, Jul 21, 2011 at 08:06:49PM +0000, Joseph S. Myers wrote:
> On Wed, 13 Jul 2011, Jakub Jelinek wrote:
> 
> > Ideally we'd just include explicitly passed options from command line that
> > haven't been overridden by other command line options, and would sort them,
> > so that there are higher chances of DW_AT_producer strings being merged
> > (e.g. -O2 -ffast-math vs. -ffast-math -O2 are now different strings, and
> > similarly -O2 vs. -O3 -O2 vs. -O0 -O1 -Ofast -O2), but I'm not sure if it is
> > easily possible using current option handling framework.
> 
> I don't think there's enough structure for that, although prune_options 
> could always be enhanced to cover more cases of overridden options.

Perhaps we can emit it in the original order even with duplicates for now
and if we get better infrastructure later, reduce its size.

> > +	  default:
> > +	    if (save_decoded_options[j].orig_option_with_args_text[0] != '-')
> > +	      continue;
> 
> Should instead be ignoring OPT_SPECIAL_*.

It already ignores them above:
+      case OPT_SPECIAL_unknown:
+      case OPT_SPECIAL_ignore:
+      case OPT_SPECIAL_program_name:
+      case OPT_SPECIAL_input_file:

I just didn't want to crash if it wouldn't start with -.
I can make it a gcc_checking_assert instead.

> 
> > +	    switch (save_decoded_options[j].orig_option_with_args_text[1])
> > +	      {
> > +	      case 'M':
> > +	      case 'i':
> > +	      case 'W':
> 
> It would be better to check the canonical option text rather than the 
> original text.  Normally this wouldn't make any difference because the 
> driver will have passed canonical options to cc1, but if someone calls cc1 
> directly then I think aliases should still act the same as the options 
> they are aliases for in this regard.

So 

	gcc_checking_assert (save_decoded_options[j].canonical_option[0][0] == '-');
	switch (save_decoded_options[j].canonical_option[0][1])

instead?  The reason for checking the option text instead of code
was just because there are hundreds of -W options etc. and I didn't want to
list them all and create a maintanance nightmare.

> 
> > +		continue;
> > +	      case 'n':
> > +		if (save_decoded_options[j].orig_option_with_args_text[2]
> > +		    == 'o')
> > +		  continue;
> 
> When would a "-no" option ever get passed to cc1?

If -no can't make it to cc1, I'll drop it.  Is -fdump* checking that way
ok (with the orig_option_with_args_text -> canonical_option[0] change)?

	Jakub
Joseph Myers July 21, 2011, 8:32 p.m. UTC | #6
On Thu, 21 Jul 2011, Jakub Jelinek wrote:

> So 
> 
> 	gcc_checking_assert (save_decoded_options[j].canonical_option[0][0] == '-');
> 	switch (save_decoded_options[j].canonical_option[0][1])
> 
> instead?  The reason for checking the option text instead of code

Yes.

> was just because there are hundreds of -W options etc. and I didn't want to
> list them all and create a maintanance nightmare.

Flags such as CL_WARNING and the various bit-fields in struct cl_option 
(bit-fields are preferred if --help doesn't need to care about a property 
of an option) could be used, but I don't think it would really be an 
improvement in this case.

> If -no can't make it to cc1, I'll drop it.  Is -fdump* checking that way
> ok (with the orig_option_with_args_text -> canonical_option[0] change)?

Yes, that seems reasonable.
diff mbox

Patch

different DW_AT_producer strings, but it is still possible to find out
what has been compiled with what options.

The aim is to include just (or primarily) code generation affecting options
explicitly passed on the command line.  So that the merging actually works,
options or arguments which include filenames or paths shouldn't be added,
on Roland's request -D*/-U* options aren't added either (that should be
covered by .debug_macinfo), similarly -I/-i* options (the interesting
stuff what headers have been actually used is recorded in .debug_line)
and warning options shouldn't affect code generation either.

Ideally we'd just include explicitly passed options from command line that
haven't been overridden by other command line options, and would sort them,
so that there are higher chances of DW_AT_producer strings being merged
(e.g. -O2 -ffast-math vs. -ffast-math -O2 are now different strings, and
similarly -O2 vs. -O3 -O2 vs. -O0 -O1 -Ofast -O2), but I'm not sure if it is
easily possible using current option handling framework.

Bootstrapped/regtested on x86_64-linux, e.g. cc1plus has just a few
different DW_AT_producers (sort|uniq -c|sort -n -r output):
    322  (indirect string, offset: 0x4fb3): GNU C 4.7.0 20110712 (experimental) -mtune=generic -march=x86-64 -g -O2 -pedantic -fno-common	
     48  (indirect string, offset: 0xf41f1): GNU C 4.7.0 20110712 (experimental) -mtune=generic -march=x86-64 -g -O2 -pedantic	
     16  (indirect string, offset: 0xebf8): GNU C 4.7.0 20110712 (experimental) -mtune=generic -march=x86-64 -g -O2 -fno-common	
      9  (indirect string, offset: 0xfa115): GNU C 4.7.0 20110712 (experimental) -mtune=generic -march=x86-64 -g -O2	
      2  (indirect string, offset: 0xfa974): GNU C 4.7.0 20110712 (experimental) -mtune=generic -march=x86-64 -g -g -g -O2 -O2 -O2 -fPIC -fbuilding-libgcc -fno-stack-protector -fvisibility=hidden	

2011-07-13  Jakub Jelinek  <jakub@redhat.com>

	PR other/32998
	* common.opt (grecord-gcc-switches, gno-record-gcc-switches): New
	options.
	* dwarf2out.c: Include opts.h.
	(dchar_p): New typedef.  Define heap VEC for it.
	(gen_compile_unit_die): Handle dwarf_record_gcc_switches.
	* Makefile.in (dwarf2out.o): Depend on $(OPTS_H).

	* lib/dg-pch.exp (dg-flags-pch): Compile tests for assembly comparison
	with -gno-record-gcc-switches.

--- gcc/common.opt.jj	2011-06-28 19:09:09.936421970 +0200
+++ gcc/common.opt	2011-07-12 21:17:13.809402161 +0200
@@ -2184,6 +2184,14 @@  ggdb
 Common JoinedOrMissing
 Generate debug information in default extended format
 
+gno-record-gcc-switches
+Common RejectNegative Var(dwarf_record_gcc_switches,0) Init(0)
+Don't record gcc command line switches in DWARF DW_AT_producer.
+
+grecord-gcc-switches
+Common RejectNegative Var(dwarf_record_gcc_switches,1)
+Record gcc command line switches in DWARF DW_AT_producer.
+
 gstabs
 Common JoinedOrMissing Negative(gstabs+)
 Generate debug information in STABS format
--- gcc/dwarf2out.c.jj	2011-07-12 21:15:46.987389471 +0200
+++ gcc/dwarf2out.c	2011-07-13 01:18:21.864451800 +0200
@@ -94,6 +94,7 @@  along with GCC; see the file COPYING3.  
 #include "tree-pass.h"
 #include "tree-flow.h"
 #include "cfglayout.h"
+#include "opts.h"
 
 static void dwarf2out_source_line (unsigned int, const char *, int, bool);
 static rtx last_var_location_insn;
@@ -18110,6 +18111,10 @@  gen_ptr_to_mbr_type_die (tree type, dw_d
 
 /* Generate the DIE for the compilation unit.  */
 
+typedef const char *dchar_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(dchar_p);
+DEF_VEC_ALLOC_P(dchar_p,heap);
+
 static dw_die_ref
 gen_compile_unit_die (const char *filename)
 {
@@ -18130,18 +18135,104 @@  gen_compile_unit_die (const char *filena
 
   sprintf (producer, "%s %s", language_string, version_string);
 
+  if (dwarf_record_gcc_switches)
+    {
+      size_t j;
+      VEC(dchar_p, heap) *switches = NULL;
+      char *producer_and_switches, *tail;
+      const char *p;
+      size_t len = 0, plen = strlen (producer);
+      for (j = 1; j < save_decoded_options_count; j++)
+	switch (save_decoded_options[j].opt_index)
+	  {
+	  case OPT_o:
+	  case OPT_d:
+	  case OPT_dumpbase:
+	  case OPT_dumpdir:
+	  case OPT_auxbase:
+	  case OPT_auxbase_strip:
+	  case OPT_quiet:
+	  case OPT_version:
+	  case OPT_v:
+	  case OPT_w:
+	  case OPT_L:
+	  case OPT_D:
+	  case OPT_I:
+	  case OPT_U:
+	  case OPT_SPECIAL_unknown:
+	  case OPT_SPECIAL_ignore:
+	  case OPT_SPECIAL_program_name:
+	  case OPT_SPECIAL_input_file:
+	  case OPT_grecord_gcc_switches:
+	  case OPT_gno_record_gcc_switches:
+	  case OPT__output_pch_:
+	  case OPT_fdiagnostics_show_location_:
+	  case OPT_fdiagnostics_show_option:
+	  case OPT____:
+	  case OPT__sysroot_:
+	    /* Ignore these.  */
+	    continue;
+	  default:
+	    if (save_decoded_options[j].orig_option_with_args_text[0] != '-')
+	      continue;
+	    switch (save_decoded_options[j].orig_option_with_args_text[1])
+	      {
+	      case 'M':
+	      case 'i':
+	      case 'W':
+		continue;
+	      case 'n':
+		if (save_decoded_options[j].orig_option_with_args_text[2]
+		    == 'o')
+		  continue;
+		break;
+	      case 'f':
+		if (strncmp (save_decoded_options[j].orig_option_with_args_text
+			     + 2, "dump", 4) == 0)
+		  continue;
+		break;
+	      default:
+		break;
+	      }
+	    VEC_safe_push (dchar_p, heap, switches,
+			   save_decoded_options[j].orig_option_with_args_text);
+	    len += strlen (save_decoded_options[j].orig_option_with_args_text)
+		   + 1;
+	    break;
+	  }
+
+      len += plen + 1;
+      producer_and_switches = XALLOCAVEC (char, len + 1);
+      tail = producer_and_switches;
+      memcpy (tail, producer, plen);
+      tail += plen;
+      FOR_EACH_VEC_ELT (dchar_p, switches, j, p)
+	{
+	  len = strlen (p);
+	  *tail = ' ';
+	  memcpy (tail + 1, p, len);
+	  tail += len + 1;
+	}
+      *tail = '\0';
+      add_AT_string (die, DW_AT_producer, producer_and_switches);
+      VEC_free (dchar_p, heap, switches);
+    }
+  else
+    {
 #ifdef MIPS_DEBUGGING_INFO
-  /* The MIPS/SGI compilers place the 'cc' command line options in the producer
-     string.  The SGI debugger looks for -g, -g1, -g2, or -g3; if they do
-     not appear in the producer string, the debugger reaches the conclusion
-     that the object file is stripped and has no debugging information.
-     To get the MIPS/SGI debugger to believe that there is debugging
-     information in the object file, we add a -g to the producer string.  */
-  if (debug_info_level > DINFO_LEVEL_TERSE)
-    strcat (producer, " -g");
+      /* The MIPS/SGI compilers place the 'cc' command line options in the
+	 producer string.  The SGI debugger looks for -g, -g1, -g2, or -g3;
+	 if they do not appear in the producer string, the debugger reaches
+	 the conclusion that the object file is stripped and has no debugging
+	 information.  To get the MIPS/SGI debugger to believe that there is
+	 debugging information in the object file, we add a -g to the producer
+	 string.  */
+      if (debug_info_level > DINFO_LEVEL_TERSE)
+	strcat (producer, " -g");
 #endif
 
-  add_AT_string (die, DW_AT_producer, producer);
+      add_AT_string (die, DW_AT_producer, producer);
+    }
 
   /* If our producer is LTO try to figure out a common language to use
      from the global list of translation units.  */
--- gcc/Makefile.in.jj	2011-07-11 18:34:37.297452455 +0200
+++ gcc/Makefile.in	2011-07-12 21:16:34.594796181 +0200
@@ -2968,7 +2968,7 @@  dwarf2out.o : dwarf2out.c $(CONFIG_H) $(
    $(GGC_H) $(EXCEPT_H) dwarf2asm.h $(TM_P_H) langhooks.h $(HASHTAB_H) \
    gt-dwarf2out.h $(TARGET_H) $(CGRAPH_H) $(MD5_H) $(INPUT_H) $(FUNCTION_H) \
    $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) $(CFGLAYOUT_H) \
-   tree-pretty-print.h $(COMMON_TARGET_H)
+   tree-pretty-print.h $(COMMON_TARGET_H) $(OPTS_H)
 dwarf2cfi.o : dwarf2cfi.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    version.h $(RTL_H) $(FUNCTION_H) $(DWARF2_H) dwarf2asm.h dwarf2out.h \
    $(GGC_H) $(TM_P_H) $(TARGET_H) $(TREE_PASS_H)
--- gcc/testsuite/lib/dg-pch.exp.jj	2011-01-03 18:58:03.000000000 +0100
+++ gcc/testsuite/lib/dg-pch.exp	2011-07-12 23:13:50.943670171 +0200
@@ -39,7 +39,7 @@  proc dg-flags-pch { subdir test otherfla
 	set dg-do-what-default precompile
 	catch { file_on_host delete "$bname$suffix" }
 	gcc_copy_files "[file rootname $test]${suffix}s" "$bname$suffix"
-	dg-test -keep-output "./$bname$suffix" "$otherflags $flags" ""
+	dg-test -keep-output "./$bname$suffix" "-gno-record-gcc-switches $otherflags $flags" ""
 
 	# For the rest, the default is to compile to .s.
 	set dg-do-what-default compile
@@ -50,14 +50,14 @@  proc dg-flags-pch { subdir test otherfla
 	    # Ensure that the PCH file is used, not the original header.
 	    file_on_host delete "$bname$suffix"
 
-	    dg-test -keep-output $test "$otherflags $flags -I." ""
+	    dg-test -keep-output $test "-gno-record-gcc-switches $otherflags $flags -I." ""
 	    file_on_host delete "$bname$suffix.gch"
 	    if { !$have_errs } {
 		if { [ file_on_host exists "$bname.s" ] } {
 		    remote_upload host "$bname.s" "$bname.s-gch"
 		    remote_download host "$bname.s-gch"
 		    gcc_copy_files "[file rootname $test]${suffix}s" "$bname$suffix"
-		    dg-test -keep-output $test "$otherflags $flags -I." ""
+		    dg-test -keep-output $test "-gno-record-gcc-switches $otherflags $flags -I." ""
 		    remote_upload host "$bname.s"
 		    set tmp [ diff "$bname.s" "$bname.s-gch" ]
 		    if { $tmp == 0 } {