From patchwork Fri Jul 4 14:32:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: max X-Patchwork-Id: 367124 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 1E5A91400D6 for ; Sat, 5 Jul 2014 00:33:12 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=xAr5wtAjFchRtnFld BsqIGWuE/veXw84uN6GOLi/IlV9B2C1/bTh83mr+PNvZR8diZrvqL/B9QmYmWPLv 3HHshOfTKbIEWYQQmOI6vZMf2GyL06OBA7LeoTwnW/cn+siKJ0PyW33TTH6e2edo mCpspLB+F7DabVTFBhWgjsvAyA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=gnpc5cCVSnjywPrKDd6iZfU qh/s=; b=Q+dlN6NnaL/C1Up/lHtG1mUR2iZw0oCoHa9FhUK5Le/SBNdZScbY0Pg AdWhL6PafBO4qhJQKOKs9E72/QFpYZ4bZJZzJECD27qROcoI/8xHHmjNLofD7Zld IzgveYDQ3waAQC+0V21jcSFyEKBp03x3aXIG27YTSjmbj6H0BKxQ= Received: (qmail 13905 invoked by alias); 4 Jul 2014 14:33:04 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 13787 invoked by uid 89); 4 Jul 2014 14:32:58 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mailout3.w1.samsung.com Received: from mailout3.w1.samsung.com (HELO mailout3.w1.samsung.com) (210.118.77.13) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (DES-CBC3-SHA encrypted) ESMTPS; Fri, 04 Jul 2014 14:32:51 +0000 Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout3.w1.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0N86002EVZ2LFD80@mailout3.w1.samsung.com> for gcc-patches@gcc.gnu.org; Fri, 04 Jul 2014 15:32:45 +0100 (BST) Received: from eusync3.samsung.com ( [203.254.199.213]) by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id E8.F1.19257.D0BB6B35; Fri, 04 Jul 2014 15:32:45 +0100 (BST) Received: from [106.109.8.89] by eusync3.samsung.com (Oracle Communications Messaging Server 7u4-23.01(7.0.4.23.0) 64bit (built Aug 10 2011)) with ESMTPA id <0N86006WWZ2LTM10@eusync3.samsung.com>; Fri, 04 Jul 2014 15:32:45 +0100 (BST) Message-id: <53B6BB0C.1080600@partner.samsung.com> Date: Fri, 04 Jul 2014 18:32:44 +0400 From: Maxim Ostapenko User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.1.0 MIME-version: 1.0 To: GCC Patches Cc: Yury Gribov , Slava Garbuzov , Jakub Jelinek , tsaunders@mozilla.com, Maxim Ostapenko Subject: [PATCH][Ping v3] Add patch for debugging compiler ICEs References: <53AC4040.9090902@partner.samsung.com> In-reply-to: <53AC4040.9090902@partner.samsung.com> X-Forwarded-Message-Id: <53AC4040.9090902@partner.samsung.com> Content-type: multipart/mixed; boundary=------------060907010207000109080707 X-IsSubscribed: yes 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 To: GCC Patches CC: Yury Gribov , Slava Garbuzov , Jakub Jelinek , tsaunders@mozilla.com, Maxim Ostapenko Ping. -------- Original Message -------- Subject: [PATCH][Ping] Add patch for debugging compiler ICEs Date: Wed, 11 Jun 2014 18:15:27 +0400 From: Maxim Ostapenko To: GCC Patches CC: Yury Gribov , Slava Garbuzov , Jakub Jelinek , 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 To: GCC Patches CC: Yury Gribov , Slava Garbuzov , Jakub Jelinek , 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 2014-06-02 Jakub Jelinek Max Ostapenko * 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 9ac18e6..86dce03 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 +#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 **); @@ -2797,7 +2807,7 @@ execute (void) } } - if (string != commands[i].prog) + if (i && string != commands[i].prog) free (CONST_CAST (char *, string)); } @@ -2850,6 +2860,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; @@ -2907,6 +2927,9 @@ execute (void) } } + if (commands[0].argv[0] != commands[0].prog) + free (CONST_CAST (char *, commands[0].argv[0])); + return ret_code; } } @@ -6098,6 +6121,342 @@ 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 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 +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\n//", 4); + for (i = 0; i < nargs; i++) + { + write (fd, " ", 1); + write (fd, new_argv[i], strlen (new_argv[i])); + } + write (fd, "\n", 1); + 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_stdout_files, '\0', sizeof (temp_stdout_files)); + memset (temp_stderr_files, '\0', sizeof (temp_stderr_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; + } + } + + 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. */ + 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. */ @@ -6867,43 +7226,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)