diff mbox

[Ping,v5] Add patch for debugging compiler ICEs

Message ID 53D0FE80.8070903@partner.samsung.com
State New
Headers show

Commit Message

max July 24, 2014, 12:39 p.m. UTC
Ping.

-------- Original Message --------
Subject: 	[PATCH][Ping v4] Add patch for debugging compiler ICEs
Date: 	Fri, 11 Jul 2014 17:44:28 +0400
From: 	Maxim Ostapenko <m.ostapenko@partner.samsung.com>
To: 	GCC Patches <gcc-patches@gcc.gnu.org>
CC: 	Yury Gribov <y.gribov@samsung.com>, Slava Garbuzov 
<v.garbuzov@samsung.com>, Jakub Jelinek <jakub@redhat.com>, 
tsaunders@mozilla.com, Maxim Ostapenko <chefmax7@gmail.com>



Ping. Added small changes due to previous discussion in community.


-------- Original Message --------
Subject: 	[PATCH][Ping v3] Add patch for debugging compiler ICEs
Date: 	Fri, 04 Jul 2014 18:32:44 +0400
From: 	Maxim Ostapenko <m.ostapenko@partner.samsung.com>
To: 	GCC Patches <gcc-patches@gcc.gnu.org>
CC: 	Yury Gribov <y.gribov@samsung.com>, Slava Garbuzov
<v.garbuzov@samsung.com>, Jakub Jelinek <jakub@redhat.com>,
tsaunders@mozilla.com, Maxim Ostapenko <chefmax7@gmail.com>



Ping.


-------- Original Message --------
Subject: 	[PATCH][Ping v2] Add patch for debugging compiler ICEs
Date: 	Thu, 26 Jun 2014 19:46:08 +0400
From: 	Maxim Ostapenko <m.ostapenko@partner.samsung.com>
To: 	GCC Patches <gcc-patches@gcc.gnu.org>
CC: 	Yury Gribov <y.gribov@samsung.com>, Slava Garbuzov
<v.garbuzov@samsung.com>, Jakub Jelinek <jakub@redhat.com>,
tsaunders@mozilla.com, Maxim Ostapenko <chefmax7@gmail.com>



Ping.


-------- Original Message --------
Subject: 	[PATCH][Ping] Add patch for debugging compiler ICEs
Date: 	Wed, 11 Jun 2014 18:15:27 +0400
From: 	Maxim Ostapenko <m.ostapenko@partner.samsung.com>
To: 	GCC Patches <gcc-patches@gcc.gnu.org>
CC: 	Yury Gribov <y.gribov@samsung.com>, Slava Garbuzov
<v.garbuzov@samsung.com>, Jakub Jelinek <jakub@redhat.com>,
tsaunders@mozilla.com, chefmax7@gmail.com



Ping.


-------- Original Message --------
Subject: 	[PATCH] Add patch for debugging compiler ICEs
Date: 	Mon, 02 Jun 2014 19:21:14 +0400
From: 	Maxim Ostapenko <m.ostapenko@partner.samsung.com>
To: 	GCC Patches <gcc-patches@gcc.gnu.org>
CC: 	Yury Gribov <y.gribov@samsung.com>, Slava Garbuzov
<v.garbuzov@samsung.com>, Jakub Jelinek <jakub@redhat.com>,
tsaunders@mozilla.com, chefmax7@gmail.com



Hi,

A years ago there was a discussion (https://gcc.gnu.org/ml/gcc-patches/2004-01/msg02437.html) about debugging compiler ICEs that resulted in a patch from Jakub, which dumps
useful information into temporary file, but for some reasons this patch wasn't applied to trunk.

This is the resurrected patch with added GCC version information into generated repro file.

-Maxim

Comments

Jakub Jelinek Aug. 1, 2014, 8 a.m. UTC | #1
On Thu, Jul 24, 2014 at 04:39:28PM +0400, Maxim Ostapenko wrote:
> Ping.

Don't want to review a patch I wrote partially, so just a few comments:
1) IMHO it should be configure time selectable (not sure about the default,
but for non-release branches IMHO it should default to off, for release
branches I don't know).  The point is that while it is useful for
people to report gcc bugs in production compilers, it is not useful for
gcc developers on their boxes, having ICEs take 3 times as long is not
desirable for people who deal with those all the time
2) recently a bug has been reported that some ICEs which print RTL
to stderr are considered non-reproduceable, because the addresses e.g.
in call_insn fndecl change through address space randomization.  For the
retries the driver should supposedly append -fdump-noaddr.

	Jakub
Yury Gribov Aug. 1, 2014, 8:13 a.m. UTC | #2
On 08/01/2014 12:00 PM, Jakub Jelinek wrote:
> Don't want to review a patch I wrote partially, so just a few comments:
> 1) IMHO it should be configure time selectable (not sure about the default,
> but for non-release branches IMHO it should default to off, for release
> branches I don't know).  The point is that while it is useful for
> people to report gcc bugs in production compilers, it is not useful for
> gcc developers on their boxes, having ICEs take 3 times as long is not
> desirable for people who deal with those all the time

I think we should use David Malcolm's approach i.e. add some 
--report-bug flag
to driver. This could be enabled by default at configure time via 
--with-spec.

> 2) recently a bug has been reported that some ICEs which print RTL
> to stderr are considered non-reproduceable, because the addresses e.g.
> in call_insn fndecl change through address space randomization.  For the
> etries the driver should supposedly append -fdump-noaddr.

+1

-Y
Andi Kleen Aug. 1, 2014, 3:43 p.m. UTC | #3
Jakub Jelinek <jakub@redhat.com> writes:
> Don't want to review a patch I wrote partially, so just a few comments:
> 1) IMHO it should be configure time selectable (not sure about the default,
> but for non-release branches IMHO it should default to off, for release
> branches I don't know).  The point is that while it is useful for
> people to report gcc bugs in production compilers, it is not useful for
> gcc developers on their boxes, having ICEs take 3 times as long is not
> desirable for people who deal with those all the time

It may also not be desirable for LTO builds, which can take very long
by themselves.

-Andi
Jakub Jelinek Aug. 1, 2014, 3:49 p.m. UTC | #4
On Fri, Aug 01, 2014 at 08:43:27AM -0700, Andi Kleen wrote:
> Jakub Jelinek <jakub@redhat.com> writes:
> > Don't want to review a patch I wrote partially, so just a few comments:
> > 1) IMHO it should be configure time selectable (not sure about the default,
> > but for non-release branches IMHO it should default to off, for release
> > branches I don't know).  The point is that while it is useful for
> > people to report gcc bugs in production compilers, it is not useful for
> > gcc developers on their boxes, having ICEs take 3 times as long is not
> > desirable for people who deal with those all the time
> 
> It may also not be desirable for LTO builds, which can take very long
> by themselves.

Indeed, and preparing preprocessed sources for all the files is hard in that
case anyway.  But as it is keyed on cc1 substring being present in the
compiler's name and lto uses lto1, it shouldn't trigger for that.
Only if you get ICEs with -flto already when compiling from C/C++ source,
but then it doesn't take very long usually and there is preprocessed source
available.

	Jakub
Jakub Jelinek Aug. 1, 2014, 3:53 p.m. UTC | #5
On Fri, Aug 01, 2014 at 12:13:18PM +0400, Yury Gribov wrote:
> On 08/01/2014 12:00 PM, Jakub Jelinek wrote:
> >Don't want to review a patch I wrote partially, so just a few comments:
> >1) IMHO it should be configure time selectable (not sure about the default,
> >but for non-release branches IMHO it should default to off, for release
> >branches I don't know).  The point is that while it is useful for
> >people to report gcc bugs in production compilers, it is not useful for
> >gcc developers on their boxes, having ICEs take 3 times as long is not
> >desirable for people who deal with those all the time
> 
> I think we should use David Malcolm's approach i.e. add some --report-bug
> flag
> to driver. This could be enabled by default at configure time via
> --with-spec.

-freport-bug or whatever we call it should not be, at least if it attempts
to communicate over the network, should not be required though, lots of
people do e.g. package builds in various chroots etc. and you really don't
want to perform any network activity from there.  Still, having
info whether an ICE was reproduceable or not is useful in that case, and
having preprocessed source left in /tmp with the path printed to stderr
is also useful, you can e.g. grab those /tmp/cc*.out files from the chroot
and allow people to report later on.  The ICE message can of course suggest
an option or script or command line to run to report the bug or navigate the
user through bug reporting process.

	Jakub
Jeff Law Aug. 1, 2014, 7:29 p.m. UTC | #6
On 08/01/14 02:00, Jakub Jelinek wrote:
> On Thu, Jul 24, 2014 at 04:39:28PM +0400, Maxim Ostapenko wrote:
>> Ping.
>
> Don't want to review a patch I wrote partially, so just a few comments:
> 1) IMHO it should be configure time selectable (not sure about the default,
> but for non-release branches IMHO it should default to off, for release
> branches I don't know).  The point is that while it is useful for
> people to report gcc bugs in production compilers, it is not useful for
> gcc developers on their boxes, having ICEs take 3 times as long is not
> desirable for people who deal with those all the time
We definitely want the ability to select.  Waiting on an ICE to trigger 
3 times would be painful for the developers.  So I'd think that enabled 
for the release branches and disabled for the trunk would be the right 
default.


> 2) recently a bug has been reported that some ICEs which print RTL
> to stderr are considered non-reproduceable, because the addresses e.g.
> in call_insn fndecl change through address space randomization.  For the
> retries the driver should supposedly append -fdump-noaddr.
Right.  I think we discussed this at Cauldron.

I think it's conceptually ok with those two changes, then it's just 
reviewing the details.

If you or Maxim could make those changes and repost, I'll cover the review.

jeff
Yury Gribov Aug. 4, 2014, 6:30 a.m. UTC | #7
On 08/01/2014 07:53 PM, Jakub Jelinek wrote:
>> I think we should use David Malcolm's approach i.e. add some --report-bug
>> flag
>> to driver. This could be enabled by default at configure time via
>> --with-spec.
> -freport-bug or whatever we call it should not be, at least if it attempts
> to communicate over the network, should not be required though, lots of
> people do e.g. package builds in various chroots etc. and you really don't
> want to perform any network activity from there.

Oh sure, the actual "backend" of --report-bug could vary from just
generating the repro and storing it in /tmp (what your patch did in the 
first place)
to David's full blown automatic Bugzilla submission.

-Y
max Aug. 4, 2014, 5:13 p.m. UTC | #8
Thanks Jeff and Jakub, I've reposted ICE debugging patch into 
gcc-patches mailing list 
(https://gcc.gnu.org/ml/gcc-patches/2014-08/msg00285.html).

-Maxim
On 08/01/2014 11:29 PM, Jeff Law wrote:
> On 08/01/14 02:00, Jakub Jelinek wrote:
>> On Thu, Jul 24, 2014 at 04:39:28PM +0400, Maxim Ostapenko wrote:
>>> Ping.
>>
>> Don't want to review a patch I wrote partially, so just a few comments:
>> 1) IMHO it should be configure time selectable (not sure about the 
>> default,
>> but for non-release branches IMHO it should default to off, for release
>> branches I don't know).  The point is that while it is useful for
>> people to report gcc bugs in production compilers, it is not useful for
>> gcc developers on their boxes, having ICEs take 3 times as long is not
>> desirable for people who deal with those all the time
> We definitely want the ability to select.  Waiting on an ICE to 
> trigger 3 times would be painful for the developers.  So I'd think 
> that enabled for the release branches and disabled for the trunk would 
> be the right default.
>
>
>> 2) recently a bug has been reported that some ICEs which print RTL
>> to stderr are considered non-reproduceable, because the addresses e.g.
>> in call_insn fndecl change through address space randomization. For the
>> retries the driver should supposedly append -fdump-noaddr.
> Right.  I think we discussed this at Cauldron.
>
> I think it's conceptually ok with those two changes, then it's just 
> reviewing the details.
>
> If you or Maxim could make those changes and repost, I'll cover the 
> review.
>
> jeff
>
diff mbox

Patch

2014-06-02  Jakub Jelinek  <jakub@redhat.com>
	    Max Ostapenko  <m.ostapenko@partner.samsung.com>

	* diagnostic.c (diagnostic_action_after_output): Exit with
	ICE_EXIT_CODE instead of FATAL_EXIT_CODE.
	* gcc.c (execute): Don't free first string early, but at the end
	of the function.  Call retry_ice if compiler exited with
	ICE_EXIT_CODE.
	(main): Factor out common code.
	(print_configuration): New function.
	(try_fork): Likewise.
	(redirect_stdout_stderr): Likewise.
	(files_equal_p): Likewise.
	(check_repro): Likewise.
	(run_attempt): Likewise.
	(generate_preprocessed_code): Likewise.
	(append_text): Likewise.
	(try_generate_repro): Likewise.

diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 0cc7593..67b8c5b 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -492,7 +492,7 @@  diagnostic_action_after_output (diagnostic_context *context,
 	real_abort ();
       diagnostic_finish (context);
       fnotice (stderr, "compilation terminated.\n");
-      exit (FATAL_EXIT_CODE);
+      exit (ICE_EXIT_CODE);
 
     default:
       gcc_unreachable ();
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 6cd08ea..045363c 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -43,6 +43,13 @@  compilation is specified by a string called a "spec".  */
 #include "params.h"
 #include "vec.h"
 #include "filenames.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if !(defined (__MSDOS__) || defined (OS2) || defined (VMS))
+#define RETRY_ICE_SUPPORTED
+#endif
 
 /* By default there is no special suffix for target executables.  */
 /* FIXME: when autoconf is fixed, remove the host check - dj */
@@ -253,6 +260,9 @@  static void init_gcc_specs (struct obstack *, const char *, const char *,
 static const char *convert_filename (const char *, int, int);
 #endif
 
+#ifdef RETRY_ICE_SUPPORTED
+static void try_generate_repro (const char *prog, const char **argv);
+#endif
 static const char *getenv_spec_function (int, const char **);
 static const char *if_exists_spec_function (int, const char **);
 static const char *if_exists_else_spec_function (int, const char **);
@@ -2850,7 +2860,7 @@  execute (void)
 	    }
 	}
 
-      if (string != commands[i].prog)
+      if (i && string != commands[i].prog)
 	free (CONST_CAST (char *, string));
     }
 
@@ -2903,6 +2913,16 @@  execute (void)
 	else if (WIFEXITED (status)
 		 && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
 	  {
+#ifdef RETRY_ICE_SUPPORTED
+	    /* For ICEs in cc1, cc1obj, cc1plus see if it is
+	       reproducible or not.  */
+	    const char *p;
+	    if (WEXITSTATUS (status) == ICE_EXIT_CODE
+		&& i == 0
+		&& (p = strrchr (commands[0].argv[0], DIR_SEPARATOR))
+		&& ! strncmp (p + 1, "cc1", 3))
+	      try_generate_repro (commands[0].prog, commands[0].argv);
+#endif
 	    if (WEXITSTATUS (status) > greatest_status)
 	      greatest_status = WEXITSTATUS (status);
 	    ret_code = -1;
@@ -2960,6 +2980,9 @@  execute (void)
 	  }
       }
 
+   if (commands[0].argv[0] != commands[0].prog)
+     free (CONST_CAST (char *, commands[0].argv[0]));
+
     return ret_code;
   }
 }
@@ -6151,6 +6174,341 @@  give_switch (int switchnum, int omit_first_word)
   switches[switchnum].validated = true;
 }
 
+static void
+print_configuration (void)
+{
+  int n;
+  const char *thrmod;
+
+  fnotice (stderr, "Target: %s\n", spec_machine);
+  fnotice (stderr, "Configured with: %s\n", configuration_arguments);
+
+#ifdef THREAD_MODEL_SPEC
+  /* We could have defined THREAD_MODEL_SPEC to "%*" by default,
+  but there's no point in doing all this processing just to get
+  thread_model back.  */
+  obstack_init (&obstack);
+  do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model);
+  obstack_1grow (&obstack, '\0');
+  thrmod = XOBFINISH (&obstack, const char *);
+#else
+  thrmod = thread_model;
+#endif
+
+  fnotice (stderr, "Thread model: %s\n", thrmod);
+
+  /* compiler_version is truncated at the first space when initialized
+  from version string, so truncate version_string at the first space
+  before comparing.  */
+  for (n = 0; version_string[n]; n++)
+    if (version_string[n] == ' ')
+      break;
+
+  if (! strncmp (version_string, compiler_version, n)
+      && compiler_version[n] == 0)
+    fnotice (stderr, "gcc version %s %s\n\n", version_string,
+             pkgversion_string);
+  else
+    fnotice (stderr, "gcc driver version %s %sexecuting gcc version %s\n\n",
+             version_string, pkgversion_string, compiler_version);
+}
+
+#ifdef RETRY_ICE_SUPPORTED
+#define RETRY_ICE_ATTEMPTS 3
+
+static int
+try_fork ()
+{
+  int pid, retries, sleep_interval;
+  sleep_interval = 1;
+  pid = -1;
+  for (retries = 0; retries < 4; retries++)
+    {
+      pid = fork ();
+      if (pid >= 0)
+        break;
+      sleep (sleep_interval);
+      sleep_interval *= 2;
+    }
+  return pid;
+}
+
+
+static void
+redirect_stdout_stderr (const char *out_temp, const char *err_temp,
+                        int append)
+{
+  int fd;
+  fd = open (out_temp, append ? O_RDWR | O_APPEND : O_RDWR);
+
+  if (fd < 0)
+    exit (-1);
+
+  close (STDOUT_FILENO);
+  dup (fd);
+  close (fd);
+
+  fd = open (err_temp, append ? O_RDWR | O_APPEND : O_RDWR);
+
+  if (fd < 0)
+    exit (-1);
+
+  close (STDERR_FILENO);
+  dup (fd);
+  close (fd);
+}
+
+static int
+files_equal_p (char *file1, char *file2, char *buf, const int bufsize)
+{
+  struct stat st1, st2;
+  size_t n, len;
+  int fd1, fd2;
+
+  fd1 = open (file1, O_RDONLY);
+  fd2 = open (file2, O_RDONLY);
+
+  if (fd1 < 0 || fd2 < 0)
+    goto error;
+
+  if (fstat (fd1, &st1) < 0 || fstat (fd2, &st2) < 0)
+    goto error;
+
+  if (st1.st_size != st2.st_size)
+    goto error;
+
+  for (n = st1.st_size; n; n -= len)
+    {
+      len = n;
+      if ((int) len > bufsize / 2)
+        len = bufsize / 2;
+
+      if (read (fd1, buf, len) != (int) len
+          || read (fd2, buf + bufsize / 2, len) != (int) len)
+        {
+          goto error;
+        }
+
+      if (memcmp (buf, buf + bufsize / 2, len) != 0)
+        goto error;
+    }
+
+  close (fd1);
+  close (fd2);
+
+  return 1;
+
+error:
+  close (fd1);
+  close (fd2);
+  return 0;
+}
+
+static void
+check_repro (char **temp_stdout_files, char **temp_stderr_files)
+{
+  int i;
+  const int ice_bufsize = 8192;
+  char *ice_buf = XNEWVEC (char, ice_bufsize);
+  for (i = 0; i < RETRY_ICE_ATTEMPTS - 2; ++i)
+    {
+     if (!files_equal_p (temp_stdout_files[i], temp_stdout_files[i + 1],
+                        ice_buf, ice_bufsize)
+         || !files_equal_p (temp_stderr_files[i], temp_stderr_files[i + 1],
+                          ice_buf, ice_bufsize))
+        {
+          fnotice (stderr, "The bug is not reproducible, so it is"
+                   " likely a hardware or OS problem.\n");
+          break;
+        }
+    }
+  free (ice_buf);
+}
+
+enum attempt_status {
+  ATTEMPT_STATUS_FAIL_TO_RUN,
+  ATTEMPT_STATUS_SUCCESS,
+  ATTEMPT_STATUS_ICE
+};
+
+static enum attempt_status
+run_attempt (const char *prog, const char **new_argv, const char *out_temp,
+             const char *err_temp, int emit_system_info, int append)
+{
+  int status;
+  int pid = try_fork ();
+  if (pid < 0)
+    return ATTEMPT_STATUS_FAIL_TO_RUN;
+  else if (pid == 0)
+    {
+      redirect_stdout_stderr (out_temp, err_temp, append);
+
+      if (emit_system_info)
+        print_configuration ();
+
+      if (prog == new_argv[0])
+        execvp (prog, CONST_CAST2 (char *const *, const char **, new_argv));
+      else
+        execv (new_argv[0], CONST_CAST2 (char *const *, const char **,
+               new_argv));
+      exit (-1);
+    }
+
+  if (waitpid (pid, &status, 0) < 0)
+    return ATTEMPT_STATUS_FAIL_TO_RUN;
+
+  switch (WEXITSTATUS (status))
+    {
+      case ICE_EXIT_CODE:
+        return ATTEMPT_STATUS_ICE;
+
+      case SUCCESS_EXIT_CODE:
+        return ATTEMPT_STATUS_SUCCESS;
+
+      default:
+        return ATTEMPT_STATUS_FAIL_TO_RUN;
+    }
+}
+
+static void
+generate_preprocessed_code (const char *prog, const char **new_argv,
+                            const int nargs, char **out_file, char **err_file)
+{
+  int i, status;
+  int fd = open (*out_file, O_RDWR | O_APPEND);
+  if (fd < 0)
+    return;
+  write (fd, "\n//", 3);
+  for (i = 0; i < nargs; i++)
+    {
+      write (fd, " ", 1);
+      write (fd, new_argv[i], strlen (new_argv[i]));
+    }
+  write (fd, "\n\n", 2);
+  close (fd);
+  new_argv[nargs] = "-E";
+  new_argv[nargs + 1] = NULL;
+
+  status = run_attempt (prog, new_argv, *out_file, *err_file, 0, 1);
+
+  if (status == ATTEMPT_STATUS_SUCCESS)
+    {
+      fnotice (stderr, "Preprocessed source stored into %s file,"
+               " please attach this to your bugreport.\n",
+               *out_file);
+      /* Make sure it is not deleted.  */
+      free (*out_file);
+      *out_file = NULL;
+    }
+}
+
+static void
+append_text (char *file, const char *str)
+{
+  int fd = open (file, O_RDWR | O_APPEND);
+  if (fd < 0)
+    return;
+
+  write (fd, str, strlen (str));
+  close (fd);
+}
+
+static void
+try_generate_repro (const char *prog, const char **argv)
+{
+  int i, nargs, out_arg = -1, quiet = 0, attempt;
+  const char **new_argv;
+  char *temp_files[RETRY_ICE_ATTEMPTS * 2];
+  char **temp_stdout_files = &temp_files[0];
+  char **temp_stderr_files = &temp_files[RETRY_ICE_ATTEMPTS];
+
+  if (gcc_input_filename == NULL || ! strcmp (gcc_input_filename, "-"))
+    return;
+
+  for (nargs = 0; argv[nargs] != NULL; ++nargs)
+    /* Only retry compiler ICEs, not preprocessor ones.  */
+    if (! strcmp (argv[nargs], "-E"))
+      return;
+    else if (argv[nargs][0] == '-' && argv[nargs][1] == 'o')
+      {
+        if (out_arg == -1)
+          out_arg = nargs;
+        else
+          return;
+      }
+    /* If the compiler is going to output any time information,
+       it might varry between invocations.  */
+    else if (! strcmp (argv[nargs], "-quiet"))
+      quiet = 1;
+    else if (! strcmp (argv[nargs], "-ftime-report"))
+      return;
+
+  if (out_arg == -1 || !quiet)
+    return;
+
+  memset (temp_files, '\0', sizeof (temp_files));
+  new_argv = XALLOCAVEC (const char *, nargs + 3);
+  memcpy (new_argv, argv, (nargs + 1) * sizeof (const char *));
+  new_argv[nargs++] = "-frandom-seed=0";
+  new_argv[nargs] = NULL;
+  if (new_argv[out_arg][2] == '\0')
+    new_argv[out_arg + 1] = "-";
+  else
+    new_argv[out_arg] = "-o-";
+
+  int status;
+  for (attempt = 0; attempt < RETRY_ICE_ATTEMPTS; ++attempt)
+    {
+      int emit_system_info = 0;
+      int append = 0;
+      temp_stdout_files[attempt] = make_temp_file (".out");
+      temp_stderr_files[attempt] = make_temp_file (".err");
+
+      if (attempt == RETRY_ICE_ATTEMPTS - 1)
+        {
+          append = 1;
+          emit_system_info = 1;
+        }
+
+      if (emit_system_info)
+        append_text (temp_stderr_files[attempt], "/*\n");
+
+      /* Fork a subprocess; wait and retry if it fails.  */
+      status = run_attempt (prog, new_argv, temp_stdout_files[attempt],
+                            temp_stderr_files[attempt], emit_system_info,
+                            append);
+
+      if (emit_system_info)
+        append_text (temp_stderr_files[attempt], "*/\n");
+
+      if (status != ATTEMPT_STATUS_ICE)
+        {
+          fnotice (stderr, "The bug is not reproducible, so it is"
+                   " likely a hardware or OS problem.\n");
+          goto out;
+        }
+    }
+
+  /* Don't abort because stderr messages can be different in various
+     attempts.  */
+  check_repro (temp_stdout_files, temp_stderr_files);
+
+  /* In final attempt we append cc1 options and preprocesssed code to last
+     generated .err file with configuration and backtrace.  */
+  generate_preprocessed_code (prog, new_argv, nargs,
+                              &temp_stderr_files[RETRY_ICE_ATTEMPTS - 1],
+                              &temp_stdout_files[RETRY_ICE_ATTEMPTS - 1]);
+
+out:
+  for (i = 0; i < RETRY_ICE_ATTEMPTS * 2; i++)
+    if (temp_files[i])
+      {
+        unlink (temp_stdout_files[i]);
+        free (temp_stdout_files[i]);
+      }
+}
+#endif
+
 /* Search for a file named NAME trying various prefixes including the
    user's -B prefix and some standard ones.
    Return the absolute file name found.  If nothing is found, return NAME.  */
@@ -6920,43 +7278,9 @@  warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
   if (verbose_flag)
     {
-      int n;
-      const char *thrmod;
-
-      fnotice (stderr, "Target: %s\n", spec_machine);
-      fnotice (stderr, "Configured with: %s\n", configuration_arguments);
-
-#ifdef THREAD_MODEL_SPEC
-      /* We could have defined THREAD_MODEL_SPEC to "%*" by default,
-	 but there's no point in doing all this processing just to get
-	 thread_model back.  */
-      obstack_init (&obstack);
-      do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model);
-      obstack_1grow (&obstack, '\0');
-      thrmod = XOBFINISH (&obstack, const char *);
-#else
-      thrmod = thread_model;
-#endif
-
-      fnotice (stderr, "Thread model: %s\n", thrmod);
-
-      /* compiler_version is truncated at the first space when initialized
-	 from version string, so truncate version_string at the first space
-	 before comparing.  */
-      for (n = 0; version_string[n]; n++)
-	if (version_string[n] == ' ')
-	  break;
-
-      if (! strncmp (version_string, compiler_version, n)
-	  && compiler_version[n] == 0)
-	fnotice (stderr, "gcc version %s %s\n", version_string,
-		 pkgversion_string);
-      else
-	fnotice (stderr, "gcc driver version %s %sexecuting gcc version %s\n",
-		 version_string, pkgversion_string, compiler_version);
-
+      print_configuration ();
       if (n_infiles == 0)
-	return (0);
+        return (0);
     }
 
   if (n_infiles == added_libraries)