From: Maxim Ostapenko <m.ostapenko@partner.samsung.com>
To: GCC Patches <gcc-patches@gcc.gnu.org>, Jeff Law <law@redhat.com>,
joseph@codesourcery.com
Cc: Yury Gribov <y.gribov@samsung.com>,
Slava Garbuzov <v.garbuzov@samsung.com>,
Maxim Ostapenko <chefmax7@gmail.com>
Subject: [Ping v3][PATCH] Add patch for debugging compiler ICEs.
Date: Fri, 05 Sep 2014 14:16:00 -0000 [thread overview]
Message-ID: <5409C5AF.2000502@partner.samsung.com> (raw)
In-Reply-To: <53FEDAC2.9050306@partner.samsung.com>
[-- Attachment #1: Type: text/plain, Size: 2148 bytes --]
Ping.
-Maxim
On 08/28/2014 11:31 AM, Maxim Ostapenko wrote:
> Ping. Add Joseph S. Myers as driver maintainer.
>
> -Maxim
> -------- Original Message --------
> Subject: Fwd: [PATCH] Add patch for debugging compiler ICEs.
> Date: Tue, 19 Aug 2014 17:57:51 +0400
> From: Maxim Ostapenko <m.ostapenko@partner.samsung.com>
> To: Jeff Law <law@redhat.com>, GCC Patches <gcc-patches@gcc.gnu.org>
> CC: tsaunders@mozilla.com, Yury Gribov <y.gribov@samsung.com>,
> Slava Garbuzov <v.garbuzov@samsung.com>, Maxim Ostapenko
> <chefmax7@gmail.com>
>
>
>
> Ping.
>
> -Maxim
> -------- Original Message --------
> Subject: [PATCH] Add patch for debugging compiler ICEs.
> Date: Mon, 04 Aug 2014 21:03:22 +0400
> From: Maxim Ostapenko <m.ostapenko@partner.samsung.com>
> To: GCC Patches <gcc-patches@gcc.gnu.org>
> CC: Jeff Law <law@redhat.com>, Jakub Jelinek <jakub@redhat.com>,
> tsaunders@mozilla.com, Yury Gribov <y.gribov@samsung.com>, Slava
> Garbuzov <v.garbuzov@samsung.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.
>
> I've updated the patch that I've posted earlier
> (https://gcc.gnu.org/ml/gcc-patches/2014-07/msg01649.html ) according to
> recent upstream discussion
> (https://gcc.gnu.org/ml/gcc-patches/2014-08/msg00020.html).
>
> The debugging functionality is disabled by default and can be enabled
> with adding -freport-bug into compile options. It can be also enabled by
> default with
> --with-spec during GCC build.
>
> There are several directions in which this can be improved e.g:
>
> 1) more user-friendly ways to report bugs (autosubmitting to Bugzilla,
> etc.)
>
> 2) generate repro in case of segfault.
>
> but having basic functionality (autogenerating reprocase in temprorary
> file) already seems quite useful.
>
> -Maxim
>
>
>
>
>
>
[-- Attachment #2: ICE.diff --]
[-- Type: text/x-patch, Size: 14372 bytes --]
2014-08-04 Jakub Jelinek <jakub@redhat.com>
Max Ostapenko <m.ostapenko@partner.samsung.com>
* common.opt: New option.
* doc/invoke.texi: Describe new option.
* 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.
(do_report_bug): Likewise.
(append_text): Likewise.
(try_generate_repro): Likewise
diff --git a/gcc/common.opt b/gcc/common.opt
index f7021102..1133e61 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1120,6 +1120,11 @@ fdump-noaddr
Common Report Var(flag_dump_noaddr)
Suppress output of addresses in debugging dumps
+freport-bug
+Common Driver Var(flag_report_bug)
+Collect and dump debug information into temporary file if ICE in C/C++
+compiler occured.
+
fdump-passes
Common Var(flag_dump_passes) Init(0)
Dump optimization passes
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 73666d6..60ed607 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -494,7 +494,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/doc/invoke.texi b/gcc/doc/invoke.texi
index d15d4a9..f41a1d8 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6316,6 +6316,11 @@ feasible to use diff on debugging dumps for compiler invocations with
different compiler binaries and/or different
text / bss / data / heap / stack / dso start locations.
+@item -freport-bug
+@opindex freport-bug
+Collect and dump debug information into temporary file if ICE in C/C++
+compiler occured.
+
@item -fdump-unnumbered
@opindex fdump-unnumbered
When doing debugging dumps, suppress instruction numbers and address output.
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 44d0416..e0c403d 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 **);
@@ -2849,7 +2859,7 @@ execute (void)
}
}
- if (string != commands[i].prog)
+ if (i && string != commands[i].prog)
free (CONST_CAST (char *, string));
}
@@ -2902,6 +2912,17 @@ 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 (flag_report_bug
+ && 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;
@@ -2959,6 +2980,9 @@ execute (void)
}
}
+ if (commands[0].argv[0] != commands[0].prog)
+ free (CONST_CAST (char *, commands[0].argv[0]));
+
return ret_code;
}
}
@@ -6150,6 +6174,342 @@ give_switch (int switchnum, int omit_first_word)
switches[switchnum].validated = true;
}
\f
+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 int
+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);
+ return i == RETRY_ICE_ATTEMPTS - 2;
+}
+
+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
+do_report_bug (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 + 4);
+ memcpy (new_argv, argv, (nargs + 1) * sizeof (const char *));
+ new_argv[nargs++] = "-frandom-seed=0";
+ new_argv[nargs++] = "-fdump-noaddr";
+ 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;
+ }
+ }
+
+ if (!check_repro (temp_stdout_files, temp_stderr_files))
+ goto out;
+
+ /* In final attempt we append cc1 options and preprocesssed code to last
+ generated .err file with configuration and backtrace. */
+ do_report_bug (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. */
@@ -6919,41 +7279,7 @@ 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);
}
next prev parent reply other threads:[~2014-09-05 14:16 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-04 17:03 [PATCH] " Maxim Ostapenko
2014-08-12 16:14 ` [PING][PATCH] " Maxim Ostapenko
2014-08-19 13:58 ` Fwd: [PATCH] " Maxim Ostapenko
2014-08-28 7:31 ` [Ping v2][PATCH] " Maxim Ostapenko
2014-09-05 14:16 ` Maxim Ostapenko [this message]
2014-09-09 22:51 ` Joseph S. Myers
2014-09-10 4:57 ` Jakub Jelinek
2014-09-10 16:37 ` Joseph S. Myers
2014-09-11 16:18 ` [PATCH 1/2] Extend libiberty to allow append stdout and stderr to existing files Maxim Ostapenko
2014-09-11 16:33 ` Ian Lance Taylor
2014-09-11 16:20 ` [PATCH 2/2] Add patch for debugging compiler ICEs Maxim Ostapenko
2014-09-18 15:37 ` [PING] " Maxim Ostapenko
2014-09-18 22:17 ` Joseph S. Myers
2014-09-19 3:33 ` Yury Gribov
2014-09-23 7:15 ` Maxim Ostapenko
2014-09-25 19:05 ` Jeff Law
2014-09-26 8:04 ` Maxim Ostapenko
2014-09-26 13:11 ` Rainer Orth
2014-09-26 13:24 ` Thomas Schwinge
2014-09-26 13:32 ` Maxim Ostapenko
2014-09-26 16:18 ` Jeff Law
2014-09-26 16:31 ` Thomas Schwinge
2014-09-26 16:32 ` Jeff Law
2015-01-23 1:42 ` H.J. Lu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5409C5AF.2000502@partner.samsung.com \
--to=m.ostapenko@partner.samsung.com \
--cc=chefmax7@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=joseph@codesourcery.com \
--cc=law@redhat.com \
--cc=v.garbuzov@samsung.com \
--cc=y.gribov@samsung.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).