summaryrefslogtreecommitdiff
path: root/gcc/compiler-probe.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/compiler-probe.c')
-rw-r--r--gcc/compiler-probe.c2078
1 files changed, 2078 insertions, 0 deletions
diff --git a/gcc/compiler-probe.c b/gcc/compiler-probe.c
new file mode 100644
index 00000000000..6a7a5e0c922
--- /dev/null
+++ b/gcc/compiler-probe.c
@@ -0,0 +1,2078 @@
+/* Compiler probe
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Contributed by Basile Starynkevitch <basile@starynkevitch.net>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "regs.h"
+#include "timevar.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "hashtab.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "tree-flow.h"
+#include "tree-dump.h"
+#include "tree-inline.h"
+#include "tree-iterator.h"
+#include "diagnostic.h"
+#include "toplev.h"
+#include "ggc.h"
+#include "vec.h"
+#include "cgraph.h"
+#include "flags.h"
+#include "options.h"
+#include "safe-ctype.h"
+#include "basic-block.h"
+#include "rtl.h"
+#include "version.h"
+
+#include "compiler-probe.h"
+
+#if !defined(ENABLE_COMPILER_PROBE) || ENABLE_COMPILER_PROBE==0
+/* this file is linked in only if the compiler probe is enabled at
+ configure time */
+#error messy configuration: compiler-probe.c compiled but not enabled
+#endif
+
+const char *tree_code_names[] = {
+#define DEFTREECODE(SYM, STRING, TYPE, NARGS) STRING,
+#include "tree.def"
+#undef DEFTREECODE
+ (char *) 0
+};
+
+
+#define debugeprintf_raw(Fmt,...) do{if (flag_compiler_probe_debug) \
+ {fprintf(stderr, Fmt, ##__VA_ARGS__); fflush(stderr);}}while(0)
+#define debugeprintf(Fmt,...) debugeprintf_raw("@!%s:%d: " Fmt "\n", \
+ basename(__FILE__), __LINE__, ##__VA_ARGS__)
+/* some debugeprintf give warnings so I disable them */
+#define nodebugeprintf(Fmt,...) do {}while(0)
+
+/* #define nodebugprintf debugprintf */
+
+#if ! defined( SIGCHLD ) && defined( SIGCLD )
+# define SIGCHLD SIGCLD
+#endif
+
+/* set this flag on SIGIO */
+volatile sig_atomic_t comprobe_interrupted;
+
+int comprobe_bb_ok_rtl; /* declared in basic-block.h */
+
+/* the probe command process */
+pid_t comprobe_pid;
+/* the command stream piped into the compiler probe process */
+FILE *comprobe_replf;
+/* the file descriptor for requests from the probe process; it is never 0 */
+int comprobe_reqfd;
+
+
+
+/* grace delay in milliseconds for the compiler probe */
+#define PROBE_GRACE_DELAY_MS 250
+
+
+struct proberequest_buffer_st
+{
+ unsigned len;
+ unsigned used;
+ char str[1]; /* actual size is len, zero-terminated */
+};
+/* the buffer above is allocate in multiple of (should be a power of 2) : */
+#define PROBUF_GRAN 0x1000
+static struct proberequest_buffer_st *proberequest_buf;
+
+
+/* hash table for requests (from probe to compiler) handlers contain entries like */
+struct proberequesthentry_st
+{
+ const char *verb; /* strdup-ed */
+ void *data; /* explicitly allocated & freed by caller */
+ comprobe_requestfun_t *rout;
+};
+
+static htab_t proberequest_htable;
+
+
+/* filename are e.g. unix paths */
+typedef char *filename_t;
+/* hash table for filenames contain entries like */
+struct filenamehentry_st
+{
+ filename_t file; /* strdup-ed filename */
+ int rank; /* strictly positive rank in filename vector */
+};
+
+static htab_t filename_htable;
+
+/* *INDENT-OFF* */
+static GTY(()) VEC(tree,gc) *unique_tree_vector;
+static GTY(()) VEC(basic_block,gc) *unique_bb_vector;
+/* each tree of unique_tree_vector or basic_block of unique_bb_vector is
+ unique; we manage an hash table of indexes (>2) there. the index 0
+ is HTAB_EMPTY_ENTRY, the index 1 is HTAB_DELETED_ENTRY, the index 2
+ is for the seeked entry */
+static GTY (()) tree unique_seeked_tree;
+static GTY (()) basic_block unique_seeked_bb;
+/* *INDENT-ON* */
+/* hashtables of integer indexes into the unique_tree_vector & unique_bb_vector */
+static htab_t unique_tree_htable;
+static htab_t unique_bb_htable;
+#define HTAB_SEEKED_ENTRY ((PTR) 2)
+
+/***
+we would like to use vectors of filenames, but I cannot make them work
+ with GTY:
+ // see thread http://gcc.gnu.org/ml/gcc/2007-01/msg00172.html
+ DEF_VEC_P (filename_t);
+ DEF_VEC_ALLOC_P (filename_t,heap); // don't work
+ VEC(filename_t,heap) *file_vector;
+ the gengtype parser choke on this with an error: unidentified type
+`filename_t'
+****/
+
+/* variable array of filenames */
+static struct
+{
+ int size; /* allocated size */
+ int last; /* last used index */
+ char **tab;
+} files_varr;
+
+struct displaychoice_st
+{
+ long di_magic;
+#define DI_MAGIC 2491573L
+ HOST_WIDE_INT di_data;
+ comprobe_infodisplay_fun_t *di_fun;
+ char di_msg[1]; /* duplicated display message
+ - longer than 1 */
+};
+typedef struct displaychoice_st *displaychoice_ptr_t;
+/* *INDENT-OFF* */
+DEF_VEC_P (displaychoice_ptr_t);
+DEF_VEC_ALLOC_P (displaychoice_ptr_t, heap);
+
+struct comprobe_infodisplay_st {
+ int idis_num; /* unique infodisplay number */
+ int idis_choice; /* current display choice*/
+ struct infopointhentry_st* idis_infp; /* the information point */
+ VEC(displaychoice_ptr_t,heap) *idis_navig; /* the navigation vector */
+ void*idis_data; /* client data */
+ void (*idis_destroy)(struct comprobe_infodisplay_st*idi); /* destructor */
+};
+
+typedef struct comprobe_infodisplay_st* infodisplay_ptr_t;
+DEF_VEC_P(infodisplay_ptr_t);
+DEF_VEC_ALLOC_P(infodisplay_ptr_t,heap);
+static VEC(infodisplay_ptr_t,heap) *infodisplay_vector;
+
+/* the info point hashtable contains entries like : */
+struct infopointhentry_st
+{
+ int infp_filerank; /* file rank */
+ int infp_lineno; /* line number */
+ int infp_num; /* unique infopoint number */
+ VEC(displaychoice_ptr_t,heap) *infp_dischvec;
+};
+typedef struct infopointhentry_st *infopoint_ptr_t;
+static htab_t infopoint_htable;
+DEF_VEC_P (infopoint_ptr_t);
+DEF_VEC_ALLOC_P (infopoint_ptr_t, heap);
+VEC (infopoint_ptr_t, heap) * infopoint_vector;
+/* *INDENT-ON* */
+
+/* random data for multiline replies */
+static struct drand48_data randata;
+
+
+/****
+ * supporting functions for probe reply hashtable
+ *****/
+static hashval_t
+hash_proberequest (const void *d)
+{
+ const struct proberequesthentry_st *p = d;
+ return htab_hash_string (p->verb);
+}
+
+static int
+eq_proberequest (const void *dx, const void *dy)
+{
+ const struct proberequesthentry_st *px = dx;
+ const struct proberequesthentry_st *py = dy;
+ return !strcmp (px->verb, py->verb);
+}
+
+static void
+del_proberequest (void *d)
+{
+ struct proberequesthentry_st *p = d;
+ gcc_assert (p && p->verb);
+ free ((void *) p->verb);
+ p->verb = NULL;
+}
+
+
+
+/****
+ * supporting functions for filename hashtable
+ *****/
+static hashval_t
+hash_filename (const void *d)
+{
+ const struct filenamehentry_st *p = d;
+ return htab_hash_string (p->file);
+}
+
+static int
+eq_filename (const void *dx, const void *dy)
+{
+ const struct filenamehentry_st *px = dx;
+ const struct filenamehentry_st *py = dy;
+ return !strcmp (px->file, py->file);
+}
+
+static void
+del_filename (void *d)
+{
+ struct filenamehentry_st *p = d;
+ gcc_assert (p && p->file && p->rank > 0);
+ free ((void *) p->file);
+ p->file = NULL;
+}
+
+/****
+ * supporting functions for infopoint hashtable
+ *****/
+static hashval_t
+hash_infopoint (const void *d)
+{
+ const struct infopointhentry_st *ifp = d;
+ return (hashval_t)
+ (((long) (ifp->infp_filerank << 12)) ^ ((long) ifp->infp_lineno));
+}
+
+static int
+eq_infopoint (const void *dx, const void *dy)
+{
+ const struct infopointhentry_st *ifx = dx;
+ const struct infopointhentry_st *ify = dy;
+ return ifx->infp_lineno == ify->infp_lineno
+ && ifx->infp_filerank == ify->infp_filerank;
+}
+
+/***
+ * supporting functions for unique_tree_htable
+ ***/
+static hashval_t
+hash_info_tree (const void *d)
+{
+ comprobe_ix_t lg = (comprobe_ix_t) d;
+ switch (lg)
+ {
+ case (comprobe_ix_t) HTAB_EMPTY_ENTRY:
+ case (comprobe_ix_t) HTAB_DELETED_ENTRY:
+ return (hashval_t) 0;
+ case (comprobe_ix_t) HTAB_SEEKED_ENTRY:
+ lg = (comprobe_ix_t) unique_seeked_tree;
+ return (hashval_t) (lg ^ (lg >> 10));
+ default:
+ if (lg > 2 && unique_tree_vector
+ && lg < VEC_length (tree, unique_tree_vector))
+ {
+ lg = (comprobe_ix_t) VEC_index (tree, unique_tree_vector, lg);
+ return (hashval_t) (lg ^ (lg >> 10));
+ };
+ return 0;
+ }
+}
+
+
+static int
+eq_info_tree (const void *dx, const void *dy)
+{
+ comprobe_ix_t lx = (comprobe_ix_t) dx;
+ comprobe_ix_t ly = (comprobe_ix_t) dy;
+ comprobe_ix_t nbtree = 0;
+ tree tx = NULL_TREE, ty = NULL_TREE;
+ if (lx == ly)
+ return 1;
+ if (unique_tree_vector)
+ nbtree = VEC_length (tree, unique_tree_vector);
+ else
+ return 0;
+ if (lx == (comprobe_ix_t) HTAB_SEEKED_ENTRY)
+ tx = unique_seeked_tree;
+ else if (lx > 2 && lx < nbtree)
+ tx = VEC_index (tree, unique_tree_vector, lx);
+ if (ly == (comprobe_ix_t) HTAB_SEEKED_ENTRY)
+ ty = unique_seeked_tree;
+ else if (ly > 2 && ly < nbtree)
+ ty = VEC_index (tree, unique_tree_vector, ly);
+ return tx == ty && tx != NULL_TREE;
+}
+
+
+comprobe_ix_t
+comprobe_unique_index_of_tree (tree tr)
+{
+ comprobe_ix_t trix = 0;
+ comprobe_ix_t l = 0, nbtree = 0;
+ void **sp = NULL;
+ if (tr == NULL_TREE)
+ return 0;
+ gcc_assert (unique_tree_vector
+ && VEC_length (tree, unique_tree_vector) > 2);
+ l = (comprobe_ix_t) HTAB_SEEKED_ENTRY;
+ nbtree = VEC_length (tree, unique_tree_vector);
+ unique_seeked_tree = tr;
+ sp = htab_find_slot (unique_tree_htable, &l, INSERT);
+ if (sp)
+ {
+ if (*sp != HTAB_EMPTY_ENTRY && *sp != HTAB_DELETED_ENTRY
+ && *sp != HTAB_SEEKED_ENTRY)
+ l = *(comprobe_ix_t *) (*sp);
+ else
+ l = 0;
+ if (l > 2)
+ {
+ gcc_assert (l < nbtree
+ && VEC_index (tree, unique_tree_vector, l) == tr);
+ trix = l;
+ }
+ else
+ {
+ VEC_safe_push (tree, gc, unique_tree_vector, tr);
+ trix = nbtree;
+ *(comprobe_ix_t *) (sp) = trix;
+ }
+ }
+ else /* failed to insert into unique_tree_htable */
+ gcc_unreachable ();
+ return trix;
+}
+
+tree
+comprobe_tree_of_unique_index (comprobe_ix_t ix)
+{
+ unsigned nbtree = 0;
+ if (ix < 2 || !unique_tree_vector)
+ return 0;
+ nbtree = VEC_length (tree, unique_tree_vector);
+ if ((int) ix < (int) nbtree)
+ return VEC_index (tree, unique_tree_vector, ix);
+ return 0;
+}
+
+
+
+/***
+ * supporting functions for unique_bb_htable
+ ***/
+static hashval_t
+hash_info_bb (const void *d)
+{
+ comprobe_ix_t lg = (comprobe_ix_t) d;
+ switch (lg)
+ {
+ case (comprobe_ix_t) HTAB_EMPTY_ENTRY:
+ case (comprobe_ix_t) HTAB_DELETED_ENTRY:
+ return (hashval_t) 0;
+ case (comprobe_ix_t) HTAB_SEEKED_ENTRY:
+ lg = (comprobe_ix_t) unique_seeked_bb;
+ return (hashval_t) (lg ^ (lg >> 10));
+ default:
+ if (lg > 2 && unique_bb_vector
+ && lg < VEC_length (basic_block, unique_bb_vector))
+ {
+ lg = (comprobe_ix_t) VEC_index (basic_block, unique_bb_vector, lg);
+ return (hashval_t) (lg ^ (lg >> 10));
+ };
+ return 0;
+ }
+}
+
+
+static int
+eq_info_bb (const void *dx, const void *dy)
+{
+ comprobe_ix_t lx = (comprobe_ix_t) dx;
+ comprobe_ix_t ly = (comprobe_ix_t) dy;
+ long nbbb = 0;
+ basic_block bx = NULL, by = NULL;
+ if (lx == ly)
+ return 1;
+ if (unique_bb_vector)
+ nbbb = VEC_length (basic_block, unique_bb_vector);
+ else
+ return 0;
+ if (lx == (comprobe_ix_t) HTAB_SEEKED_ENTRY)
+ bx = unique_seeked_bb;
+ else if (lx > 2 && lx < nbbb)
+ bx = VEC_index (basic_block, unique_bb_vector, lx);
+ if (ly == (comprobe_ix_t) HTAB_SEEKED_ENTRY)
+ by = unique_seeked_bb;
+ else if (ly > 2 && ly < nbbb)
+ by = VEC_index (basic_block, unique_bb_vector, ly);
+ return bx == by && bx != NULL;
+}
+
+/****
+ * register a reply verb
+ ****/
+static void
+comprobe_register_unchecked (const char *verb,
+ comprobe_requestfun_t * handler, void *data)
+{
+ struct proberequesthentry_st slot;
+ struct proberequesthentry_st **slotptr;
+ hashval_t h;
+ memset (&slot, 0, sizeof (slot));
+ slot.verb = verb;
+ h = hash_proberequest (&slot);
+ slotptr = (struct proberequesthentry_st **)
+ htab_find_slot_with_hash (proberequest_htable, &slot, h, INSERT);
+ if (!slotptr)
+ fatal_error
+ ("compiler probe failed to register request verb %s (memory full): %m",
+ verb);
+ if (*slotptr == HTAB_EMPTY_ENTRY || (*slotptr) == HTAB_DELETED_ENTRY)
+ {
+ struct proberequesthentry_st *newslot;
+ newslot = xcalloc (sizeof (struct proberequesthentry_st), 1);
+ newslot->verb = xstrdup (verb);
+ newslot->rout = handler;
+ newslot->data = data;
+ *slotptr = newslot;
+ }
+ else
+ {
+ struct proberequesthentry_st *oldslot = *slotptr;
+ gcc_assert (!strcmp (oldslot->verb, verb));
+ oldslot->rout = handler;
+ oldslot->data = data;
+ }
+}
+
+
+/****
+ * register a verb (and check that it is alphanumerical)
+ ****/
+void
+comprobe_register (const char *verb, comprobe_requestfun_t * handler,
+ void *data)
+{
+ const char *pc;
+ if (!verb)
+ return;
+ if (!ISALPHA (verb[0]))
+ fatal_error ("compiler probe: invalid verb %s to register", verb);
+ for (pc = verb + 1; *pc; pc++)
+ if (!ISALNUM (*pc) && *pc != '_')
+ fatal_error ("compiler probe: invalid verb %s to register", verb);
+ comprobe_register_unchecked (verb, handler, data);
+}
+
+
+/****
+ * remove a registered verb @@@@@@ HAS TO BE CODED
+ ****/
+void
+comprobe_unregister (const char *verb)
+{
+ gcc_assert (verb && *verb);
+ /* #warning to be written comprobe_unregister */
+ gcc_unreachable ();
+}
+
+
+void
+comprobe_infopoint_add_display (int infoptrank,
+ comprobe_infodisplay_fun_t * dispfun,
+ const char *msg, HOST_WIDE_INT data)
+{
+ infopoint_ptr_t infp = NULL;
+ displaychoice_ptr_t dch = NULL;
+ size_t msgl = 0;
+ if (!comprobe_replf)
+ return;
+ debugeprintf ("infopoint_add_display infoptrank %d msg %s", infoptrank,
+ msg);
+ if (infoptrank < 0 || !infopoint_vector
+ || infoptrank >= (int) VEC_length (infopoint_ptr_t, infopoint_vector))
+ return;
+ infp = VEC_index (infopoint_ptr_t, infopoint_vector, infoptrank);
+ nodebugeprintf ("infopoint_add_display infp %p msg %s dispfun %p",
+ infp, msg, (void *) dispfun);
+ if (!infp || !msg || !dispfun)
+ return;
+ msgl = strlen (msg);
+ gcc_assert (infp->infp_num == infoptrank);
+ dch = xcalloc (sizeof (*dch) + msgl, 1);
+ dch->di_data = data;
+ dch->di_magic = DI_MAGIC;
+ dch->di_fun = dispfun;
+ memcpy (dch->di_msg, msg, msgl);
+ debugeprintf ("infopoint_add_display dch %p", (void*)dch);
+ VEC_safe_push (displaychoice_ptr_t, heap, infp->infp_dischvec, dch);
+}
+
+void
+comprobe_display_add_navigator (struct comprobe_infodisplay_st *idi,
+ comprobe_infodisplay_fun_t * navfun,
+ const char *msg, HOST_WIDE_INT data)
+{
+ displaychoice_ptr_t dch = NULL;
+ size_t msgl = 0;
+ gcc_assert (idi);
+ gcc_assert (msg);
+ if (!comprobe_replf)
+ return;
+ msgl = strlen (msg);
+ if (!idi->idis_navig)
+ idi->idis_navig = VEC_alloc (displaychoice_ptr_t, heap, 3);
+ dch = xcalloc (sizeof (*dch) + msgl, 1);
+ dch->di_data = data;
+ dch->di_fun = navfun;
+ dch->di_magic = DI_MAGIC;
+ memcpy (dch->di_msg, msg, msgl);
+ nodebugeprintf ("add_navigator display %d navfun %p msg '%s'",
+ idi->idis_num, (void *) navfun, msg);
+ VEC_safe_push (displaychoice_ptr_t, heap, idi->idis_navig, dch);
+}
+
+
+
+/****
+ * the SIGIO and SIGCHLD signal handler just sets a flag
+ ****/
+static void
+sig_interrupted (int sig)
+{
+ gcc_assert (sig != 0);
+ comprobe_interrupted = 1;
+}
+
+
+/****
+ * Create the probing process and set up the pipes to it.
+ * Do not exchange anything yet
+ ****/
+static void
+create_probe_process (void)
+{
+ /* the probe process */
+ pid_t probpid;
+ /* the pipes from probe to gcc, and from gcc to probe */
+ int pip2gcc[2], pip2probe[2];
+ const char *progarg[5];
+ if (comprobe_pid > 0 && comprobe_replf && comprobe_reqfd >= 0)
+ return;
+ /* we do not use the pex_* routines from liberty.h because the
+ compiler probe is quite specific to Linux and similar Unix
+ operating systems with SIGIO, select, .... (probably Solaris,
+ and recent *BSD should be ok) */
+ pip2gcc[0] = pip2gcc[1] = -1;
+ pip2probe[0] = pip2probe[1] = -1;
+ if (pipe (pip2gcc) || pipe (pip2probe))
+ fatal_error ("failed to create pipes for compiler probe: %m");
+ probpid = fork ();
+ if (probpid == (pid_t) 0)
+ {
+ /* child process */
+ int ifd;
+ signal (SIGIO, SIG_DFL);
+#ifdef SIGSEGV
+ signal (SIGSEGV, SIG_DFL);
+#endif
+#ifdef SIGINT
+ signal (SIGINT, SIG_DFL);
+#endif
+#ifdef SIGTERM
+ signal (SIGTERM, SIG_DFL);
+#endif
+#ifdef SIGQUIT
+ signal (SIGQUIT, SIG_DFL);
+#endif
+#define perror_exit(Msg) do{perror(Msg); exit(1);}while(0)
+ /* write-pipe from probe to gcc is our stdout */
+ if (pip2gcc[1] != STDOUT_FILENO)
+ {
+ if (dup2 (pip2gcc[1], STDOUT_FILENO) < 0)
+ perror_exit
+ ("comprobe child process failed to dup2 pipe to stdout to gcc");
+ (void) close (pip2gcc[1]);
+ }
+ /* read-pipe from gcc to probe is our stdin */
+ if (pip2probe[0] != STDIN_FILENO)
+ {
+ if (dup2 (pip2probe[0], STDIN_FILENO) < 0)
+ perror_exit
+ ("comprobe child process failed to dup2 pipe to stdin from gcc");
+ (void) close (pip2probe[0]);
+ }
+ /* close useless fds in the child before exec */
+ for (ifd = STDERR_FILENO + 1; ifd < 64; ifd++)
+ (void) close (ifd);
+ /* use sh -c for the compiler probe command */
+ memset (progarg, 0, sizeof (progarg));
+ progarg[0] = "sh";
+ progarg[1] = "-c";
+ progarg[2] = compiler_probe_string;
+ progarg[3] = (char *) 0;
+ execv ("/bin/sh", (char *const *) progarg);
+ perror_exit ("comprobe child process failed to exec /bin/sh");
+ }
+#undef perror_exit
+ else if (probpid < (pid_t) 0)
+ {
+ /* error fork failed */
+ fatal_error ("failed to fork for compiler probe: %m");
+ }
+ else
+ { /* parent */
+ (void) close (pip2gcc[1]);
+ (void) close (pip2probe[0]);
+ comprobe_pid = probpid;
+ comprobe_replf = fdopen (pip2probe[1], "a");
+ comprobe_reqfd = pip2gcc[0];
+ if (!comprobe_replf)
+ fatal_error ("failed to open pipe stream to compiler probe: %m");
+ if (comprobe_reqfd <= 0)
+ {
+ /* this should almost never happen; I could think it might
+ happen if gcc is run without any open file descriptor - not
+ even stdin; but I expect the request file descriptor to be
+ positive */
+ fatal_error ("failed to get pipe fd %d from compiler probe: %m",
+ comprobe_reqfd);
+ };
+ if (fcntl (comprobe_reqfd, F_SETFL, (long) O_NONBLOCK) < 0)
+ fatal_error
+ ("failed to make non-blocking the pipe fd %d from compiler probe: %m",
+ comprobe_reqfd);
+ if (fcntl (comprobe_reqfd, F_SETOWN, (long) getpid ()) < 0)
+ fatal_error ("failed to SETOWN pipe fd %d from compiler probe: %m",
+ comprobe_reqfd);
+ setlinebuf (comprobe_replf);
+ fprintf (stderr, "created compiler probe '%s' process %ld\n",
+ compiler_probe_string, (long) comprobe_pid);
+ }
+}
+
+
+
+/****
+ * wait for the compiler probe process, returns 0 when waited successfully;
+ * if BLOCKING is set, wait indefinitely, otherwise just test without
+ * blocking
+ ****/
+static int
+wait_for_probe (int blocking, int *pstatus)
+{
+ int probstatus = 0;
+ gcc_assert (comprobe_pid > 0);
+#if HAVE_WAITPID || HAVE_SYS_WAIT_H
+ if (waitpid (comprobe_pid, &probstatus, blocking ? WNOHANG : 0) ==
+ comprobe_pid)
+ {
+ if (pstatus)
+ *pstatus = probstatus;
+ return 0;
+ }
+#elif HAVE_WAIT4
+ if (wait4
+ (comprobe_pid, &probstatus, blocking ? WNOHANG : 0,
+ (struct rusage *) 0) == comprobepid)
+ {
+ if (pstatus)
+ *pstatus = probstatus;
+ return 0;
+ };
+#else
+#error should have waitpid or wait4
+#endif
+ return 1;
+}
+
+/****
+ * output a string URL encoded wtih STR89' prefix for a string of 89
+ * chars and a ' suffix
+ ****/
+void
+comprobe_outenc_string (const char *s)
+{
+ int c, l;
+ if (!comprobe_replf || !s)
+ return;
+ l = strlen (s);
+ comprobe_printf ("STR%d'", l);
+ for (; (c = (*s)) != 0; s++)
+ {
+ if ((c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
+ putc (c, comprobe_replf);
+ else
+ switch (c)
+ {
+ case ' ':
+ putc ('+', comprobe_replf);
+ break;
+ case '*':
+ case '/':
+ case '_':
+ case '@':
+ case '-':
+ case '(':
+ case ')':
+ case '!':
+ case '[':
+ case ']':
+ case '.':
+ case ',':
+ case ';':
+ putc (c, comprobe_replf);
+ break;
+ default:
+ fprintf (comprobe_replf, "%%%02x", c & 0xff);
+ break;
+ }
+ }
+ putc ('\'', comprobe_replf);
+}
+
+/****
+ * process a single line of request (from probe to compiler)
+ ****/
+static void
+process_request_line (struct comprobe_whatpos_st *wp, char *line)
+{
+ struct proberequesthentry_st *ptrslot;
+ struct proberequesthentry_st slot;
+ char *pc;
+ char *argreq;
+ if (line[0] == '#' || line[0] == 0)
+ return;
+ debugeprintf ("req.lin: %s", line);
+ memset (&slot, 0, sizeof (slot));
+ for (pc = line; ISALNUM (*pc) || *pc == '_'; pc++);
+ argreq = 0;
+ if (*pc)
+ argreq = pc + 1;
+ *pc = 0;
+ slot.verb = line;
+ ptrslot =
+ (struct proberequesthentry_st *) htab_find (proberequest_htable, &slot);
+ if (ptrslot && ptrslot->rout)
+ (*ptrslot->rout) (wp, argreq, ptrslot->data);
+ else
+ fprintf (stderr, "gcc compiler-probe don't understand request: %s\n",
+ line);
+ debugeprintf ("req.lin done: %s", line);
+}
+
+/****
+ * stop the compiler probe
+ ****/
+void
+comprobe_stop (void)
+{
+ int status = 0;
+ if (!compiler_probe_string || !compiler_probe_string[0] || !comprobe_pid)
+ return;
+ /* kill the probing process and wait for it nicely, first by closing the pipe to it */
+ fclose (comprobe_replf);
+ close (comprobe_reqfd);
+ /* give a little time to the probe */
+ usleep ((unsigned long) PROBE_GRACE_DELAY_MS * 1000);
+ if (wait_for_probe (0, &status))
+ {
+ (void) kill (comprobe_pid, SIGTERM);
+ while (!wait_for_probe (1, &status))
+ {
+ usleep ((unsigned long) PROBE_GRACE_DELAY_MS * 1000);
+ (void) kill (comprobe_pid, SIGQUIT);
+ };
+ };
+ fprintf (stderr, "ended compiler probe process %ld [status %d]:",
+ (long) comprobe_pid, status);
+ if (WIFEXITED (status))
+ fprintf (stderr, "probe exited %d\n", WEXITSTATUS (status));
+ else if (WIFSIGNALED (status))
+ psignal (WTERMSIG (status),
+ WCOREDUMP (status)
+ ? "probe coredumped on signal" : "probe terminated with signal");
+ putc ('\n', stderr);
+ fflush (stderr);
+ comprobe_reqfd = -1;
+ comprobe_replf = (FILE *) 0;
+ comprobe_pid = 0;
+ compiler_probe_string = 0;
+ signal (SIGIO, SIG_DFL);
+ signal (SIGCHLD, SIG_DFL);
+}
+
+/* forced kill of probe - called only on unrecoverable errors */
+void
+comprobe_forced_kill (void)
+{
+ if (!compiler_probe_string || !compiler_probe_string[0]
+ || !comprobe_pid || !comprobe_replf)
+ return;
+ fflush (comprobe_replf);
+ (void) kill (comprobe_pid, SIGTERM);
+ comprobe_stop ();
+}
+
+/****
+ * read all probe requests, waiting for them for a delay in milliseconds
+ * and process every newline terminated reply line
+ ****/
+static void
+read_probe_requests (struct comprobe_whatpos_st *wp, unsigned millisec)
+{
+ fd_set rdset;
+ struct timeval tv;
+ int maxfd = 0;
+ int selnb = 0;
+ if (comprobe_reqfd <= 0)
+ return;
+ /* flush the reply stream to send any pending stuff */
+ if (comprobe_replf)
+ fflush (comprobe_replf);
+ FD_ZERO (&rdset);
+ if (comprobe_reqfd >= 0)
+ FD_SET (comprobe_reqfd, &rdset);
+ maxfd = MAX (maxfd, comprobe_reqfd);
+ if (millisec >= 1000)
+ millisec = 999;
+ tv.tv_sec = 0;
+ tv.tv_usec = millisec * 1000;
+ selnb = select (maxfd + 1, &rdset, (fd_set *) 0, (fd_set *) 0, &tv);
+ if (selnb > 0 && FD_ISSET (comprobe_reqfd, &rdset))
+ {
+ int again = 0;
+ do
+ {
+ int newsiz;
+ int readcnt, readlen;
+ if (comprobe_reqfd < 0)
+ break;
+ newsiz = 0;
+ if (!proberequest_buf)
+ newsiz = 2 * PIPE_BUF;
+ else if (proberequest_buf->used + PIPE_BUF <= proberequest_buf->len)
+ newsiz =
+ (((5 * proberequest_buf->len / 4 + 2 * PIPE_BUF))
+ | (PROBUF_GRAN - 1)) + 1;
+ if (newsiz > 0)
+ {
+ struct proberequest_buffer_st *newbuf;
+ newbuf = xcalloc (1,
+ sizeof (struct
+ proberequest_buffer_st) + newsiz - 1);
+ newbuf->len = newsiz;
+ if (proberequest_buf)
+ {
+ gcc_assert (proberequest_buf->used <=
+ proberequest_buf->len);
+ memcpy (newbuf->str, proberequest_buf->str,
+ proberequest_buf->used);
+ newbuf->used = proberequest_buf->used;
+ free (proberequest_buf);
+ };
+ proberequest_buf = newbuf;
+ };
+ gcc_assert (proberequest_buf->used + PIPE_BUF <
+ proberequest_buf->len);
+ readlen = proberequest_buf->len - proberequest_buf->used - 1;
+ readcnt = read (comprobe_reqfd,
+ proberequest_buf->str + proberequest_buf->used,
+ readlen);
+ again = 0;
+ if (readcnt == 0)
+ { /* got end of file on the probe reply pipe */
+ again = 0;
+ comprobe_stop ();
+ }
+ else if (readcnt < 0)
+ {
+ if (errno == EINTR)
+ again = 1;
+ else if (errno == EAGAIN)
+ again = 0;
+ else
+ fatal_error ("unexpected read error from compiler probe: %m");
+ }
+ else /*readcnt>0 */
+ {
+ char *eol = 0;
+ char *pc = 0;
+ off_t off, rlen;
+ proberequest_buf->used += readcnt;
+ proberequest_buf->str[proberequest_buf->used] = 0;
+ for (pc = proberequest_buf->str; (eol = strchr (pc, '\n')) != 0;
+ pc = eol + 1)
+ {
+ *eol = 0;
+ process_request_line (wp, pc);
+ if (comprobe_replf)
+ fflush (comprobe_replf);
+ };
+ off = pc - proberequest_buf->str;
+ if (off > 0)
+ {
+ rlen = proberequest_buf->str + proberequest_buf->used - pc;
+ memmove (proberequest_buf->str, pc, rlen);
+ proberequest_buf->str[rlen] = 0;
+ proberequest_buf->used = rlen;
+ if (proberequest_buf->len - rlen > 3 * PIPE_BUF)
+ {
+ unsigned newsiz =
+ ((rlen + 2 * PIPE_BUF) | (PROBUF_GRAN - 1)) + 1;
+ if (newsiz < proberequest_buf->len && newsiz > rlen)
+ {
+ proberequest_buf =
+ xrealloc (proberequest_buf, newsiz);
+ proberequest_buf->len = newsiz;
+ }
+ }
+ };
+ again = 1;
+ }
+ }
+ while (again);
+ }
+}
+
+/****
+ * handle a request (called by comprobe_check macro)
+ ****/
+void
+comprobe_handle_probe (const char *what, const char *file, int lineno)
+{
+ struct comprobe_whatpos_st wp;
+ if (!compiler_probe_string || !compiler_probe_string[0]
+ || comprobe_pid <= 0)
+ return;
+ memset (&wp, 0, sizeof (wp));
+ wp.wp_what = what;
+ wp.wp_file = file;
+ wp.wp_line = lineno;
+ read_probe_requests (&wp, 0);
+}
+
+/****
+ * handle all requests until a given variable is cleared, or the probe ended
+ ****/
+void
+comprobe_while_probe (const char *what, const char *file, int lineno,
+ int *pvar)
+{
+ struct comprobe_whatpos_st wp;
+ if (comprobe_pid <= 0 || !pvar)
+ return;
+ memset (&wp, 0, sizeof (wp));
+ wp.wp_what = what;
+ wp.wp_file = file;
+ wp.wp_line = lineno;
+ while (comprobe_pid > 0 && *pvar)
+ {
+ read_probe_requests (&wp, PROBE_GRACE_DELAY_MS);
+ };
+}
+
+/***
+ * big commands are uniquely bracketed
+ ***/
+static long leftcode, rightcode;
+void
+comprobe_begin_big (void)
+{
+ gcc_assert (leftcode == 0 && rightcode == 0);
+ if (!comprobe_replf)
+ return;
+ do
+ {
+ lrand48_r (&randata, &leftcode);
+ }
+ while (leftcode == 0);
+ do
+ {
+ lrand48_r (&randata, &rightcode);
+ }
+ while (rightcode == 0);
+ fprintf (comprobe_replf, "\n!#%x/%X[\n",
+ (int) (leftcode & 0xfffffff), (int) (rightcode & 0xfffffff));
+}
+
+void
+comprobe_end_big (void)
+{
+ gcc_assert (leftcode != 0 && rightcode != 0);
+ if (comprobe_replf)
+ {
+ fprintf (comprobe_replf, "\n!#%x/%X]\n",
+ (int) (leftcode & 0xfffffff), (int) (rightcode & 0xfffffff));
+ fflush (comprobe_replf);
+ }
+ leftcode = rightcode = 0;
+}
+
+
+static int nonstopped;
+
+/* the STOP request from probe stops properly the probe */
+static void
+stop_reqfun (struct comprobe_whatpos_st *wp ATTRIBUTE_UNUSED,
+ char *reqlin ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED)
+{
+ if (comprobe_replf)
+ fflush (comprobe_replf);
+ nonstopped = 0;
+ comprobe_stop ();
+}
+
+static int
+cmp_displaychoice_ptr (const void *x, const void *y)
+{
+ displaychoice_ptr_t dx = *(displaychoice_ptr_t *) x;
+ displaychoice_ptr_t dy = *(displaychoice_ptr_t *) y;
+ return strcmp (dx->di_msg, dy->di_msg);
+}
+
+/* the NEWINFODIALOG request from probe make a new dialog for an infopoint */
+static void
+newinfodialog_reqfun (struct comprobe_whatpos_st *wp ATTRIBUTE_UNUSED,
+ char *reqlin, void *data ATTRIBUTE_UNUSED)
+{
+ int infork = -1, dialrk = -1, nbdisp = 0, chix = 0;
+ infopoint_ptr_t ip = NULL;
+ infodisplay_ptr_t idisp = NULL;
+ if (!comprobe_replf)
+ return;
+ debugeprintf ("newinfodialog_reqfun reqlin: %s", reqlin);
+ if (sscanf (reqlin, " pt: %d dia: %d", &infork, &dialrk) < 2
+ || infork < 0 || dialrk < 0)
+ return;
+ debugeprintf ("newinfodialog_reqfun infork=%d dialrk=%d", infork, dialrk);
+ if (infork >= (int) VEC_length (infopoint_ptr_t, infopoint_vector))
+ return;
+ ip = VEC_index (infopoint_ptr_t, infopoint_vector, infork);
+ if (!ip)
+ return;
+ if ((int) VEC_length (infodisplay_ptr_t, infodisplay_vector) <= dialrk)
+ VEC_safe_grow_cleared (infodisplay_ptr_t, heap, infodisplay_vector,
+ 5 * dialrk / 4 + 16);
+ idisp = xcalloc (sizeof (*idisp), 1);
+ idisp->idis_num = dialrk;
+ idisp->idis_infp = ip;
+ VEC_replace (infodisplay_ptr_t, infodisplay_vector, dialrk, idisp);
+ /* sort the display choices in alphanumerical order */
+ if (ip->infp_dischvec)
+ nbdisp = VEC_length (displaychoice_ptr_t, ip->infp_dischvec);
+ debugeprintf ("newinfodialog_reqfun nbdisp=%d", nbdisp);
+ if (nbdisp > 0)
+ qsort ((VEC_address (displaychoice_ptr_t, ip->infp_dischvec)),
+ (size_t) nbdisp, sizeof (displaychoice_ptr_t),
+ cmp_displaychoice_ptr);
+ for (chix = 0; chix < nbdisp; chix++)
+ {
+ displaychoice_ptr_t dch =
+ VEC_index (displaychoice_ptr_t, ip->infp_dischvec, chix);
+ gcc_assert (dch && dch->di_fun);
+ gcc_assert (dch->di_magic == DI_MAGIC);
+ comprobe_printf ("PROB_dialogchoice dia:%d msg:", dialrk);
+ comprobe_outenc_string (dch->di_msg);
+ comprobe_printf (" ch:%d\n", chix);
+ };
+ comprobe_printf ("PROB_showdialog dia:%d\n", dialrk);
+ comprobe_flush ();
+}
+
+static void bb_starting_displayer (struct comprobe_whatpos_st *wp,
+ struct comprobe_infodisplay_st *di,
+ HOST_WIDE_INT data, HOST_WIDE_INT navig);
+
+static void tree_starting_displayer (struct comprobe_whatpos_st *wp,
+ struct comprobe_infodisplay_st *di,
+ HOST_WIDE_INT data, HOST_WIDE_INT navig);
+
+static void tree_ending_displayer (struct comprobe_whatpos_st *wp,
+ struct comprobe_infodisplay_st *di,
+ HOST_WIDE_INT data, HOST_WIDE_INT navig);
+
+static void
+display_tree (tree tr, struct comprobe_infodisplay_st *di)
+{
+ gcc_assert (di != 0);
+ if (!tr)
+ comprobe_printf ("*** NULL TREE %p ***\n", (void*)tr);
+ else if (GIMPLE_STMT_P (tr))
+ {
+ comprobe_printf ("*** GIMPLE STMT %p ***\n", (void*)tr);
+ print_generic_stmt_indented (comprobe_replf, tr,
+ TDF_LINENO | TDF_VOPS | TDF_MEMSYMS |
+ TDF_UID, 1);
+ }
+ else if (EXPR_P (tr))
+ {
+ comprobe_printf ("*** EXPR %p ***\n", (void*)tr);
+ print_generic_expr (comprobe_replf, tr,
+ TDF_LINENO | TDF_VOPS | TDF_MEMSYMS);
+ }
+ else if (TREE_CODE (tr) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator tsi;
+ int rk = 0;
+ comprobe_printf ("*** STATEMENT LIST %p ***\n", (void*)tr);
+ print_generic_expr (comprobe_replf, tr,
+ TDF_LINENO | TDF_VOPS | TDF_MEMSYMS);
+ for (tsi = tsi_start (tr); !tsi_end_p (tsi); tsi_next (&tsi))
+ {
+ tree stmt = tsi_stmt (tsi);
+ rk++;
+ if (stmt)
+ {
+ static char titbuf[64];
+ memset (titbuf, 0, sizeof (titbuf));
+ snprintf (titbuf, sizeof (titbuf) - 1, "%d-th substmt", rk);
+ comprobe_display_add_navigator (di, tree_starting_displayer,
+ titbuf,
+ comprobe_unique_index_of_tree
+ (stmt));
+ }
+
+ }
+ }
+ else
+ comprobe_printf ("*** tree of code %d <%s>***\n",
+ TREE_CODE (tr), tree_code_names[TREE_CODE (tr)]);
+ if (TREE_CODE (tr) == PHI_NODE)
+ {
+ basic_block bb = PHI_BB (tr);
+ if (bb)
+ {
+ comprobe_ix_t bbix = comprobe_unique_index_of_basic_block (bb);
+ comprobe_display_add_navigator (di, bb_starting_displayer,
+ "phi node basic block", bbix);
+ }
+ }
+}
+
+static void
+tree_starting_displayer (struct comprobe_whatpos_st *wp,
+ struct comprobe_infodisplay_st *di,
+ HOST_WIDE_INT data,
+ HOST_WIDE_INT navig ATTRIBUTE_UNUSED)
+{
+ tree tr = NULL_TREE;
+ comprobe_ix_t ix = (comprobe_ix_t) data;
+ unsigned nbtree = VEC_length (tree, unique_tree_vector);
+ debugeprintf ("tree_starting_displayer ix %d nbtree %d", (int) ix,
+ (int) nbtree);
+ if (ix > 0 && ix < (long) nbtree)
+ {
+ tr = VEC_index (tree, unique_tree_vector, ix);
+ comprobe_printf
+ ("// starting tree_%ld #%d shown when '%s' \n// from gcc file %s line %d\n",
+ ix, di->idis_infp->infp_num, wp->wp_what, basename (wp->wp_file),
+ wp->wp_line);
+ display_tree (tr, di);
+ }
+ else
+ comprobe_printf
+ (" ?? invalid starting tree index %ld nbtree %d info #%d??", (long) ix,
+ (int) nbtree, di->idis_infp->infp_num);
+}
+
+static void
+tree_ending_displayer (struct comprobe_whatpos_st *wp,
+ struct comprobe_infodisplay_st *di,
+ HOST_WIDE_INT data,
+ HOST_WIDE_INT navig ATTRIBUTE_UNUSED)
+{
+ tree tr = NULL_TREE;
+ comprobe_ix_t ix = (comprobe_ix_t) data;
+ unsigned nbtree = VEC_length (tree, unique_tree_vector);
+ debugeprintf ("tree_ending_displayer ix %d nbtree %d", (int) ix,
+ (int) nbtree);
+ if (ix > 0 && ix < (long) nbtree)
+ {
+ tr = VEC_index (tree, unique_tree_vector, ix);
+ comprobe_printf
+ ("// ending tree_%ld #%d shown when '%s'\n// from gcc file %s line %d\n",
+ (long) ix, di->idis_infp->infp_num, wp->wp_what,
+ basename (wp->wp_file), wp->wp_line);
+ display_tree (tr, di);
+ }
+ else
+ comprobe_printf (" ?? invalid ending tree index %ld nbtree %d info #%d??",
+ (long) ix, (int) nbtree, di->idis_infp->infp_num);
+}
+
+
+static void
+bb_starting_displayer (struct comprobe_whatpos_st *wp,
+ struct comprobe_infodisplay_st *di,
+ HOST_WIDE_INT data,
+ HOST_WIDE_INT navig ATTRIBUTE_UNUSED)
+{
+ comprobe_ix_t ix = (comprobe_ix_t) data;
+ char pfx[24];
+ basic_block bb = NULL;
+ debugeprintf ("bb_starting_displayer ix %d", (int) ix);
+ comprobe_bb_ok_rtl = 1;
+ if (ix > 0 && ix < VEC_length (basic_block, unique_bb_vector))
+ {
+ bb = VEC_index (basic_block, unique_bb_vector, ix);
+ comprobe_printf
+ ("// starting basic block _%ld #%d shown when '%s' \n// from gcc file %s line %d\n",
+ (long) ix, di->idis_infp->infp_num, wp->wp_what,
+ basename (wp->wp_file), wp->wp_line);
+ snprintf (pfx, sizeof (pfx), "[+bb#%d] ", di->idis_infp->infp_num);
+ comprobe_printf ("\n// basic block info _%ld #%d is\n",
+ (long) ix, di->idis_infp->infp_num);
+ dump_bb_info (bb, true, true,
+ TDF_DETAILS | TDF_LINENO | TDF_VOPS | TDF_MEMSYMS,
+ pfx, comprobe_replf);
+ if (phi_nodes(bb))
+ {
+ comprobe_printf ("\n// basic block phi_nodes _%ld #%d is\n",
+ ix, di->idis_infp->infp_num);
+ display_tree (phi_nodes(bb), di);
+ comprobe_display_add_navigator
+ (di, tree_starting_displayer,
+ "phi nodes", comprobe_unique_index_of_tree (phi_nodes(bb)));
+ };
+ if (bb_stmt_list(bb))
+ {
+ comprobe_printf ("\n// basic block stmt_list _%ld #%d is\n", ix,
+ di->idis_infp->infp_num);
+ display_tree (bb_stmt_list(bb), di);
+ comprobe_display_add_navigator
+ (di, tree_starting_displayer,
+ "stmt list", comprobe_unique_index_of_tree (bb_stmt_list(bb)));
+ };
+ }
+ else
+ comprobe_printf ("?? invalid starting basic block index %ld info #%d??",
+ ix, di->idis_infp->infp_num);
+ comprobe_bb_ok_rtl = 0;
+}
+
+static void
+bb_ending_displayer (struct comprobe_whatpos_st *wp,
+ struct comprobe_infodisplay_st *di,
+ HOST_WIDE_INT data, HOST_WIDE_INT navig ATTRIBUTE_UNUSED)
+{
+ comprobe_ix_t ix = (comprobe_ix_t) data;
+ char pfx[24];
+ basic_block bb = NULL;
+ int infoptrk = di->idis_infp->infp_num;
+ debugeprintf ("bb_ending_displayer ix %d", (int) ix);
+ comprobe_bb_ok_rtl = 1;
+ if (ix > 0 && ix < VEC_length (basic_block, unique_bb_vector))
+ {
+ bb = VEC_index (basic_block, unique_bb_vector, ix);
+ comprobe_printf
+ ("// ending basic block _%ld #%d shown when '%s'\n// from gcc file %s line %d\n",
+ ix, infoptrk, wp->wp_what, basename (wp->wp_file), wp->wp_line);
+ snprintf (pfx, sizeof (pfx), "[-bb#%d] ", infoptrk);
+ dump_bb_info (bb, true, true,
+ TDF_DETAILS | TDF_LINENO | TDF_VOPS | TDF_MEMSYMS,
+ pfx, comprobe_replf);
+ }
+ else
+ comprobe_printf ("?? invalid ending basic block index %ld info #%d??", ix,
+ infoptrk);
+ comprobe_bb_ok_rtl = 0;
+}
+
+/* clear the navigation vector inside a display */
+static void
+infodialog_clear_navig (infodisplay_ptr_t disp)
+{
+ int navix = 0;
+ displaychoice_ptr_t navch = NULL;
+ debugeprintf ("infodialog_clear_navig disp %p num %d", (void*)disp,
+ disp->idis_num);
+ if (disp->idis_navig)
+ {
+ for (navix = 0;
+ VEC_iterate (displaychoice_ptr_t, disp->idis_navig, navix,
+ navch); navix++)
+ {
+ if (!navch)
+ continue;
+ gcc_assert (navch->di_magic == DI_MAGIC);
+ VEC_replace (displaychoice_ptr_t, disp->idis_navig, navix, NULL);
+ memset (navch, 0, sizeof (navch));
+ free (navch);
+ }
+ VEC_free (displaychoice_ptr_t, heap, disp->idis_navig);
+ disp->idis_navig = NULL;
+ }
+}
+
+
+static void
+fill_infodialog (struct comprobe_whatpos_st *wp, infodisplay_ptr_t disp,
+ displaychoice_ptr_t ch, comprobe_ix_t chix)
+{
+ debugeprintf("fill_infodialog ch %p chix %d", (void*)ch, (int)chix);
+ gcc_assert (ch && ch->di_magic == DI_MAGIC);
+ infodialog_clear_navig (disp);
+ if (ch->di_fun)
+ {
+ comprobe_begin_big_printf ("PROB_dialogcontent dia:%d\n",
+ disp->idis_num);
+ (*ch->di_fun) (wp, disp, ch->di_data, chix);
+ comprobe_end_big ();
+ if (disp->idis_navig
+ && VEC_length (displaychoice_ptr_t, disp->idis_navig) > 0)
+ {
+ int navix = 0;
+ displaychoice_ptr_t navch = NULL;
+ for (navix = 0;
+ VEC_iterate (displaychoice_ptr_t, disp->idis_navig, navix,
+ navch); navix++)
+ {
+ gcc_assert (navch->di_magic == DI_MAGIC);
+ debugeprintf ("fill_infodialog %d navix %d navch msg '%s'",
+ disp->idis_num, navix, navch->di_msg);
+ comprobe_printf ("PROB_dialognavig dia:%d msg:",
+ disp->idis_num);
+ comprobe_outenc_string (navch->di_msg);
+ comprobe_printf (" nav:%d\n", navix);
+ }
+ }
+ comprobe_printf ("PROB_showdialog dia:%d\n", disp->idis_num);
+ comprobe_flush ();
+ }
+ else debugeprintf("fill_infodialog no function in ch %p", (void*)ch);
+}
+
+
+/* the SHOWINFODIALOG request from probe ask for the dialog to be shown */
+static void
+showinfodialog_reqfun (struct comprobe_whatpos_st *wp,
+ char *reqlin, void *data ATTRIBUTE_UNUSED)
+{
+ int dialrk = -1, chrk = -1;
+ infodisplay_ptr_t disp = NULL;
+ infopoint_ptr_t ip = NULL;
+ displaychoice_ptr_t ch = NULL;
+ if (!comprobe_replf)
+ return;
+ debugeprintf ("showinfodialog_reqfun reqlin: %s", reqlin);
+ if (sscanf (reqlin, " dia: %d ch: %d", &dialrk, &chrk) < 2
+ || chrk < 0 || dialrk < 0)
+ return;
+ if (!infodisplay_vector
+ || dialrk >= (int) VEC_length (infodisplay_ptr_t, infodisplay_vector))
+ return;
+ disp = VEC_index (infodisplay_ptr_t, infodisplay_vector, dialrk);
+ if (!disp)
+ return;
+ gcc_assert (disp->idis_num == dialrk);
+ ip = disp->idis_infp;
+ gcc_assert (ip);
+ if (chrk >= (int) VEC_length (displaychoice_ptr_t, ip->infp_dischvec))
+ return;
+ ch = VEC_index (displaychoice_ptr_t, ip->infp_dischvec, chrk);
+ if (!ch)
+ return;
+ gcc_assert (ch->di_magic == DI_MAGIC);
+ disp->idis_choice = chrk;
+ debugeprintf ("showinfodialog_reqfun ch %p str= %s", (void*)ch, ch->di_msg);
+ fill_infodialog (wp, disp, ch, -1);
+ debugeprintf ("showinfodialog_reqfun end reqlin: %s", reqlin);
+}
+
+
+static void
+updateinfodialog_reqfun (struct comprobe_whatpos_st *wp,
+ char *reqlin, void *data ATTRIBUTE_UNUSED)
+{
+ int dialrk = -1;
+ infodisplay_ptr_t disp = NULL;
+ infopoint_ptr_t ip = NULL;
+ displaychoice_ptr_t ch = NULL;
+ if (!comprobe_replf)
+ return;
+ debugeprintf ("updateinfodialog_reqfun reqlin: %s", reqlin);
+ if (sscanf (reqlin, " dia: %d", &dialrk) <= 0 || dialrk < 0)
+ return;
+ if (!infodisplay_vector
+ || dialrk >= (int) VEC_length (infodisplay_ptr_t, infodisplay_vector))
+ return;
+ disp = VEC_index (infodisplay_ptr_t, infodisplay_vector, dialrk);
+ if (!disp)
+ return;
+ gcc_assert (disp->idis_num == dialrk);
+ ip = disp->idis_infp;
+ if (disp->idis_choice >= 0
+ && disp->idis_choice <
+ (int) VEC_length (displaychoice_ptr_t, ip->infp_dischvec))
+ ch =
+ VEC_index (displaychoice_ptr_t, ip->infp_dischvec, disp->idis_choice);
+ if (!ch) {
+ debugeprintf("updateinfodialog_reqfun no ch %p", (void*)ch);
+ return;
+ };
+ gcc_assert (ch->di_magic == DI_MAGIC);
+ debugeprintf ("updateinfodialog_reqfun ch %p str= %s", (void*)ch, ch->di_msg);
+ fill_infodialog (wp, disp, ch, -1);
+ debugeprintf ("updateinfodialog_reqfun end reqlin: %s", reqlin);
+}
+
+static void
+naviginfodialog_reqfun (struct comprobe_whatpos_st *wp,
+ char *reqlin, void *data ATTRIBUTE_UNUSED)
+{
+ int dialrk = -1, navrk = -1;
+ infodisplay_ptr_t disp = NULL;
+ infopoint_ptr_t ip = NULL;
+ displaychoice_ptr_t ch = NULL;
+ if (!comprobe_replf)
+ return;
+ debugeprintf ("naviginfodialog_reqfun reqlin: %s", reqlin);
+ if (sscanf (reqlin, " dia: %d nav: %d", &dialrk, &navrk) <= 0
+ || dialrk < 0 || navrk < 0)
+ return;
+ if (!infodisplay_vector
+ || dialrk >= (int) VEC_length (infodisplay_ptr_t, infodisplay_vector))
+ return;
+ disp = VEC_index (infodisplay_ptr_t, infodisplay_vector, dialrk);
+ debugeprintf ("naviginfodialog_reqfun disp %p", (void*)disp);
+ if (!disp)
+ return;
+ gcc_assert (disp->idis_num == dialrk);
+ ip = disp->idis_infp;
+ if (navrk < (int) VEC_length (displaychoice_ptr_t, disp->idis_navig))
+ ch = VEC_index (displaychoice_ptr_t, disp->idis_navig, navrk);
+ if (!ch)
+ return;
+ debugeprintf ("naviginfodialog_reqfun ch %p navrk %d", (void*)ch, navrk);
+ gcc_assert (ch->di_magic == DI_MAGIC);
+ debugeprintf ("naviginfodialog_reqfun ch %p str= %s", (void*)ch, ch->di_msg);
+ fill_infodialog (wp, disp, ch, navrk);
+ debugeprintf ("naviginfodialog_reqfun end reqlin: %s\n", reqlin);
+}
+
+static void
+removeinfodialog_reqfun (struct comprobe_whatpos_st *wp ATTRIBUTE_UNUSED,
+ char *reqlin, void *data ATTRIBUTE_UNUSED)
+{
+ int dialrk = -1;
+ infodisplay_ptr_t disp = NULL;
+ if (!comprobe_replf)
+ return;
+ debugeprintf ("removeinfodialog_reqfun reqlin: %s", reqlin);
+ if (sscanf (reqlin, " dia: %d", &dialrk) <= 0 || dialrk < 0)
+ return;
+ if (!infodisplay_vector
+ || dialrk >= (int) VEC_length (infodisplay_ptr_t, infodisplay_vector))
+ return;
+ disp = VEC_index (infodisplay_ptr_t, infodisplay_vector, dialrk);
+ if (!disp)
+ return;
+ gcc_assert (disp->idis_num == dialrk);
+ infodialog_clear_navig (disp);
+ free (disp);
+ VEC_replace (infodisplay_ptr_t, infodisplay_vector, dialrk, 0);
+ comprobe_printf ("PROB_destroydialog dia:%d\n", dialrk);
+ comprobe_flush ();
+ debugeprintf ("removeinfodialog_reqfun end reqlin: %s", reqlin);
+}
+
+/****
+ * send a message to be shown
+ ****/
+void
+comprobe_show_message (const char *msg)
+{
+ if (!msg || !comprobe_replf)
+ return;
+ comprobe_puts ("PROB_message msg:");
+ comprobe_outenc_string (msg);
+ comprobe_puts ("\n");
+ comprobe_flush ();
+}
+
+
+/****
+ * Initialize the probe. Called from toplev.c
+ ****/
+void
+comprobe_initialize (void)
+{
+ static int inited;
+ long seed = 0;
+ const char *pc;
+ const char* randomseed = get_random_seed(false);
+ gcc_assert (!inited);
+ gcc_assert (randomseed != (char *) 0);
+ inited = 1;
+ if (!compiler_probe_string || !compiler_probe_string[0])
+ return;
+ for (pc = randomseed; *pc; pc++)
+ seed ^= (seed << 5) + (*pc);
+ srand48_r ((long) seed, &randata);
+ signal (SIGIO, sig_interrupted);
+ signal (SIGCHLD, sig_interrupted);
+ proberequest_htable =
+ htab_create (113, hash_proberequest, eq_proberequest, del_proberequest);
+ filename_htable =
+ htab_create (229, hash_filename, eq_filename, del_filename);
+ infopoint_htable = htab_create (2081, hash_infopoint, eq_infopoint, NULL);
+ infopoint_vector = VEC_alloc (infopoint_ptr_t, heap, 2048);
+ unique_tree_vector = VEC_alloc (tree, gc, 1024);
+ unique_bb_vector = VEC_alloc (basic_block, gc, 512);
+ /* reserve but don't use the first 4 entries hence HTAB_SEEKED_ENTRY unused */
+ VEC_safe_push (tree, gc, unique_tree_vector, (tree) 0);
+ VEC_safe_push (tree, gc, unique_tree_vector, (tree) 0);
+ VEC_safe_push (tree, gc, unique_tree_vector, (tree) 0);
+ VEC_safe_push (tree, gc, unique_tree_vector, (tree) 0);
+ VEC_safe_push (basic_block, gc, unique_bb_vector, (basic_block) 0);
+ VEC_safe_push (basic_block, gc, unique_bb_vector, (basic_block) 0);
+ VEC_safe_push (basic_block, gc, unique_bb_vector, (basic_block) 0);
+ VEC_safe_push (basic_block, gc, unique_bb_vector, (basic_block) 0);
+ unique_tree_htable = htab_create (4007, hash_info_tree, eq_info_tree, NULL);
+ unique_bb_htable = htab_create (3001, hash_info_bb, eq_info_bb, NULL);
+ files_varr.tab = XNEWVEC (char *, 100);
+ files_varr.size = 100;
+ files_varr.last = 0;
+ memset (files_varr.tab, 0, sizeof (char **) * files_varr.size);
+ comprobe_register ("prob_NAVIGINFODIALOG", naviginfodialog_reqfun, (void *) 0);
+ comprobe_register ("prob_NEWINFODIALOG", newinfodialog_reqfun, (void *) 0);
+ comprobe_register ("prob_REMOVEINFODIALOG", removeinfodialog_reqfun, (void *) 0);
+ comprobe_register ("prob_SHOWINFODIALOG", showinfodialog_reqfun, (void *) 0);
+ comprobe_register ("prob_STOP", stop_reqfun, (void *) 0);
+ comprobe_register ("prob_UPDATEINFODIALOG", updateinfodialog_reqfun, (void *) 0);
+ create_probe_process ();
+ comprobe_printf ("PROB_version proto:%d msg:", COMPROBE_PROTOCOL_NUMBER);
+ comprobe_outenc_string (version_string);
+ comprobe_puts ("\n");
+ comprobe_flush ();
+ atexit (comprobe_forced_kill);
+}
+
+/****
+ * Finish the probe. Called from toplev.c
+ ****/
+void
+comprobe_finish (void)
+{
+ nonstopped = 1;
+ comprobe_puts ("PROB_message msg:");
+ comprobe_outenc_string ("probe finished");
+ comprobe_puts ("\n");
+ comprobe_flush ();
+ comprobe_while ("finishing", &nonstopped);
+ comprobe_stop ();
+ if (proberequest_htable)
+ {
+ htab_empty (proberequest_htable);
+ htab_delete (proberequest_htable);
+ proberequest_htable = 0;
+ };
+ if (filename_htable)
+ {
+ htab_empty (filename_htable);
+ htab_delete (filename_htable);
+ filename_htable = 0;
+ };
+}
+
+
+
+int
+comprobe_file_rank (const char *filename)
+{
+ struct filenamehentry_st slot;
+ struct filenamehentry_st **slotptr = 0;
+ int filerank = 0;
+
+ if (!filename || !comprobe_replf)
+ return 0;
+ memset (&slot, 0, sizeof (slot));
+ slot.file = (char *) filename;
+ slotptr = (struct filenamehentry_st **)
+ htab_find_slot (filename_htable, &slot, INSERT);
+ if (!slotptr)
+ fatal_error
+ ("compiler probe failed to register file %s (memory full): %m",
+ filename);
+ if (*slotptr == HTAB_EMPTY_ENTRY || (*slotptr) == HTAB_DELETED_ENTRY)
+ {
+ struct filenamehentry_st *newslot = 0;
+ const char *dupfilename = xstrdup (filename);
+ newslot = xcalloc (sizeof (*newslot), 1);
+ if (files_varr.last + 1 >= files_varr.size)
+ {
+ int newsiz = ((5 * files_varr.last) / 4 + 50) | 0x1f;
+ int ix;
+ char **newarr = XNEWVEC (char *, newsiz);
+ newarr[0] = 0;
+ for (ix = files_varr.last; ix > 0; ix--)
+ newarr[ix] = files_varr.tab[ix];
+ for (ix = files_varr.last + 1; ix < newsiz; ix++)
+ newarr[ix] = (char *) 0;
+ memset (files_varr.tab, 0, sizeof (char *) * files_varr.size);
+ XDELETEVEC (files_varr.tab);
+ files_varr.tab = newarr;
+ }
+ /* dont use index 0 */
+ filerank = ++files_varr.last;
+ files_varr.tab[filerank] = (char *) dupfilename;
+ gcc_assert (filerank > 0);
+ newslot->file = (char *) dupfilename;
+ newslot->rank = filerank;
+ *slotptr = newslot;
+ debugeprintf ("new file rank filerank%d file %s newslot %p", filerank,
+ dupfilename, (void*)newslot);
+ comprobe_printf ("PROB_file rank:%d fpath:", filerank);
+ comprobe_outenc_string(dupfilename);
+ comprobe_puts("\n");
+ comprobe_flush();
+ }
+ else
+ {
+ struct filenamehentry_st *oldslot = *slotptr;
+ filerank = oldslot->rank;
+ gcc_assert (!strcmp (files_varr.tab[filerank], filename));
+ debugeprintf ("old file rank filerank%d file %s oldslot %p", filerank,
+ filename, (void*)oldslot);
+ }
+ return filerank;
+}
+
+
+int
+comprobe_infopoint_rank (int filerank, int lineno)
+{
+ int inforank = 0;
+ struct infopointhentry_st slot;
+ struct infopointhentry_st **slotptr = 0;
+ gcc_assert (filerank > 0 && filerank <= files_varr.last);
+ gcc_assert (lineno > 0);
+ gcc_assert (infopoint_vector != NULL);
+ memset (&slot, 0, sizeof (slot));
+ slot.infp_filerank = filerank;
+ slot.infp_lineno = lineno;
+ slotptr = (struct infopointhentry_st **)
+ htab_find_slot (infopoint_htable, &slot, INSERT);
+ if (!slotptr)
+ fatal_error
+ ("compiler probe failed to register infopoint filerank=%d,lineno=%d (memory full): %m",
+ filerank, lineno);
+ if (*slotptr == HTAB_EMPTY_ENTRY || (*slotptr) == HTAB_DELETED_ENTRY)
+ {
+ struct infopointhentry_st *newslot = 0;
+ newslot = xcalloc (sizeof (*newslot), 1);
+ /* dont use index 0 */
+ if (VEC_length (infopoint_ptr_t, infopoint_vector) == 0)
+ VEC_safe_push (infopoint_ptr_t, heap, infopoint_vector,
+ (struct infopointhentry_st *) 0);
+ VEC_safe_push (infopoint_ptr_t, heap, infopoint_vector, newslot);
+ inforank = VEC_length (infopoint_ptr_t, infopoint_vector) - 1;
+ comprobe_printf ("PROB_infopoint fil:%d lin:%d rk:%d\n", filerank,
+ lineno, inforank);
+ comprobe_flush ();
+ newslot->infp_filerank = filerank;
+ newslot->infp_lineno = lineno;
+ newslot->infp_num = inforank;
+ newslot->infp_dischvec = VEC_alloc (displaychoice_ptr_t, heap, 3);
+ debugeprintf
+ ("new infopoint slot filerank%d lineno%d inforank%d slot%p", filerank,
+ lineno, inforank, (void*) newslot);
+ *slotptr = newslot;
+ }
+ else
+ {
+ struct infopointhentry_st *oldslot = (*slotptr);
+ gcc_assert (oldslot->infp_filerank == filerank
+ && oldslot->infp_lineno == lineno);
+ inforank = oldslot->infp_num;
+ gcc_assert (inforank >= 0
+ && inforank < (int) VEC_length (infopoint_ptr_t,
+ infopoint_vector));
+ gcc_assert (VEC_index (infopoint_ptr_t, infopoint_vector, inforank)
+ == oldslot);
+ debugeprintf
+ ("old infopoint slot filerank%d lineno%d inforank%d oldslot%p",
+ filerank, lineno, inforank, (void*)oldslot);
+ }
+ return inforank;
+}
+
+
+
+/***
+ * return true if a (GIMPLE/SSA) tree TR has a position
+ * and in that case fill the PFILENAME and PLINENO
+ * if the END flag is set, return the last position
+ ***/
+bool
+comprobe_get_position (tree tr, char **pfilename, int *plineno, int end)
+{
+ if (CAN_HAVE_LOCATION_P (tr) && EXPR_HAS_LOCATION (tr))
+ {
+ char *pfile = (char *) EXPR_FILENAME (tr);
+ if (pfile)
+ {
+ *pfilename = pfile;
+ *plineno = EXPR_LINENO (tr);
+ return TRUE;
+ }
+ }
+ else if (TREE_CODE (tr) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator iter;
+ tree tr_stmt;
+ if (end)
+ {
+ for (iter = tsi_last (tr); !tsi_end_p (iter); tsi_prev (&iter))
+ {
+ tr_stmt = tsi_stmt (iter);
+ if (comprobe_get_position
+ (tr_stmt, pfilename, plineno, POS_END))
+ return TRUE;
+ }
+ }
+ else
+ for (iter = tsi_start (tr); !tsi_end_p (iter); tsi_next (&iter))
+ {
+ tr_stmt = tsi_stmt (iter);
+ if (comprobe_get_position
+ (tr_stmt, pfilename, plineno, POS_START))
+ return TRUE;
+ }
+ }
+ else if (GIMPLE_STMT_P (tr))
+ {
+ char *pfile = (char *) EXPR_FILENAME (tr);
+ if (pfile)
+ {
+ *pfilename = pfile;
+ *plineno = EXPR_LINENO (tr);
+ return TRUE;
+ }
+ }
+ else if (GIMPLE_TUPLE_P (tr) && GIMPLE_TUPLE_HAS_LOCUS_P (tr))
+ {
+ /* @@@@ dont know yet how to get location of a tuple */
+ gcc_unreachable ();
+ }
+ return FALSE;
+}
+
+int
+comprobe_file_rank_of_tree (tree tr, int *plineno)
+{
+ char *filename = 0;
+ int lineno = 0, filerank = 0;
+ if (!tr)
+ return 0;
+ if (!comprobe_get_position (tr, &filename, &lineno, POS_START))
+ return 0;
+ filerank = comprobe_file_rank (filename);
+ if (filerank > 0 && plineno)
+ *plineno = lineno;
+ return filerank;
+}
+
+
+/* run the compiler probe pass only if we have a real probe */
+static bool
+gate_comprobe (void)
+{
+ return comprobe_replf != (FILE *) 0 && comprobe_pid != (pid_t) 0;
+}
+
+
+/* add information point and display start of a given tree TR with
+ string DMESG - return the infopoint rank */
+static int
+added_infopoint_display_tree (tree tr, const char *dmesg)
+{
+ int frk = 0, lin = 0, infrk = 0;
+ comprobe_ix_t trix = 0;
+ debugeprintf ("added_infopoint_display_tree tr+ %p dmesg %s", (void*)tr, dmesg);
+ if (!tr)
+ return 0;
+ frk = comprobe_file_rank_of_tree (tr, &lin);
+ if (frk > 0 && lin > 0)
+ {
+ trix = comprobe_unique_index_of_tree (tr);
+ gcc_assert (trix > 2);
+ infrk = comprobe_infopoint_rank (frk, lin);
+ debugeprintf
+ ("added_infopoint_display_tree infrk%d frk%d lin%d tree %p dmesg %s",
+ infrk, frk, lin, (void*)tr, dmesg);
+ comprobe_infopoint_add_display (infrk, tree_starting_displayer, dmesg,
+ (HOST_WIDE_INT) trix);
+ return infrk;
+ };
+ return 0;
+}
+
+
+/* add information point for a given function body */
+static void
+add_infopoint_funbody (tree tr_body)
+{
+ int frk_body = 0, lin_body = 0;
+ debugeprintf ("add_infopoint_funbody tr_body %p start", (void*)tr_body);
+ frk_body = comprobe_file_rank_of_tree (tr_body, &lin_body);
+ if (frk_body >= 0 && lin_body > 0)
+ {
+ int esnumins = 0;
+ char *endfile = 0;
+ /* @@@ should probably dynamically allocate the message buffer */
+ static char msgbuf[200];
+ int endline = -1, endfrk = -1, infendnum = -1;
+ comprobe_ix_t trix = 0;
+ int infstartnum = -1;
+ infstartnum = comprobe_infopoint_rank (frk_body, lin_body);
+ if (comprobe_get_position (tr_body, &endfile, &endline, POS_END)
+ && (endfrk = comprobe_file_rank (endfile)) >= 0)
+ infendnum = comprobe_infopoint_rank (endfrk, endline);
+ trix = comprobe_unique_index_of_tree (tr_body);
+ esnumins = estimate_num_insns (tr_body, &eni_inlining_weights);
+ debugeprintf
+ ("add_infopoint_funbody tr%p infstartnum%d lin_body%d infendnum%d endline%d",
+ (void*)tr_body, infstartnum, lin_body, infendnum, endline);
+ if (infstartnum > 0 && lin_body > 0)
+ {
+ memset (msgbuf, 0, sizeof (msgbuf));
+ if (frk_body == endfrk && endline > lin_body)
+ snprintf (msgbuf, sizeof (msgbuf) - 1,
+ _("starting body of %d lines & %d instrs"),
+ endline - lin_body, esnumins);
+ else
+ snprintf (msgbuf, sizeof (msgbuf) - 1,
+ _("starting body of %d instrs"), esnumins);
+ if (added_infopoint_display_tree (tr_body, msgbuf) != infstartnum)
+ gcc_unreachable ();
+ }
+ if (infendnum > 0 && endline > 0)
+ {
+ memset (msgbuf, 0, sizeof (msgbuf));
+ if (frk_body == endfrk && endline > lin_body && lin_body > 0)
+ snprintf (msgbuf,
+ sizeof (msgbuf) - 1,
+ _("ending body of %d lines & %d instrs"),
+ endline - lin_body, esnumins);
+ else
+ snprintf (msgbuf,
+ sizeof (msgbuf) - 1,
+ _("ending body of %d instrs"), esnumins);
+ comprobe_infopoint_add_display
+ (infendnum, tree_ending_displayer, msgbuf, (HOST_WIDE_INT) trix);
+ }
+ }
+ debugeprintf ("add_infopoint_funbody tr_body %p end", (void*)tr_body);
+}
+
+
+comprobe_ix_t
+comprobe_unique_index_of_basic_block (basic_block bb)
+{
+ comprobe_ix_t bbix = 0;
+ comprobe_ix_t l = 0, nbbb = 0;
+ void **sp = 0;
+ if (bb == NULL || !unique_bb_vector)
+ return 0;
+ gcc_assert (unique_bb_vector
+ && VEC_length (basic_block, unique_bb_vector) > 2);
+ l = (comprobe_ix_t) HTAB_SEEKED_ENTRY;
+ nbbb = VEC_length (basic_block, unique_bb_vector);
+ unique_seeked_bb = bb;
+ sp = htab_find_slot (unique_bb_htable, &l, INSERT);
+ if (sp)
+ {
+ if (*sp != HTAB_EMPTY_ENTRY && *sp != HTAB_DELETED_ENTRY
+ && *sp != HTAB_SEEKED_ENTRY)
+ l = *(comprobe_ix_t *) (*sp);
+ else
+ l = 0;
+ if (l > 2)
+ {
+ gcc_assert (l < nbbb
+ && VEC_index (basic_block, unique_bb_vector, l) == bb);
+ bbix = l;
+ }
+ else
+ {
+ VEC_safe_push (basic_block, gc, unique_bb_vector, bb);
+ bbix = nbbb;
+ *(comprobe_ix_t *) (sp) = bbix;
+ }
+ }
+ else /* failed to insert into unique_bb_htable */
+ gcc_unreachable ();
+ return bbix;
+}
+
+
+basic_block
+comprobe_basic_block_of_unique_index (comprobe_ix_t ix)
+{
+ int nbbb = 0;
+ if (ix < 2 || !unique_bb_vector)
+ return NULL;
+ nbbb = VEC_length (basic_block, unique_bb_vector);
+ if ((long) ix < (long) nbbb)
+ return VEC_index (basic_block, unique_bb_vector, ix);
+ return NULL;
+}
+
+/* add information point for a given basic block */
+static void
+add_infopoint_basic_block (basic_block bb)
+{
+ block_stmt_iterator bsi;
+ int stmtcnt = 0;
+ comprobe_ix_t bbix = 0;
+ bool bbgotpos = 0;
+ debugeprintf ("add_infopoint_basic_block bb %p start", (void*)bb);
+ if (bb == NULL)
+ return;
+ bbix = comprobe_unique_index_of_basic_block (bb);
+ gcc_assert (bbix > 2);
+ bbgotpos = FALSE;
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+ char *filename = 0;
+ int lineno = 0;
+ int filrk = 0, infrk = 0;
+ static char msgbuf[64];
+ if (stmt)
+ stmtcnt++;
+ else
+ continue;
+ if (comprobe_get_position (stmt, &filename, &lineno, POS_START))
+ {
+ filrk = comprobe_file_rank (filename);
+ infrk = comprobe_infopoint_rank (filrk, lineno);
+ if (!bbgotpos)
+ {
+ bbgotpos = TRUE;
+ memset (msgbuf, 0, sizeof (msgbuf));
+ snprintf (msgbuf,
+ sizeof (msgbuf) - 1, "start bb#%d", bb->index);
+ comprobe_infopoint_add_display
+ (infrk, bb_starting_displayer, msgbuf, (HOST_WIDE_INT) bbix);
+ };
+ memset (msgbuf, 0, sizeof (msgbuf));
+ snprintf (msgbuf,
+ sizeof (msgbuf) - 1, "stmt#%d bb#%d", stmtcnt, bb->index);
+ (void) added_infopoint_display_tree (stmt, msgbuf);
+ }
+ }
+ for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+ char *filename = 0;
+ int lineno = 0;
+ int filrk = 0, infrk = 0;
+ static char msgbuf[64];
+ if (comprobe_get_position (stmt, &filename, &lineno, POS_END))
+ {
+ filrk = comprobe_file_rank (filename);
+ infrk = comprobe_infopoint_rank (filrk, lineno);
+ memset (msgbuf, 0, sizeof (msgbuf));
+ snprintf (msgbuf, sizeof (msgbuf) - 1, "end bb#%d", bb->index);
+ comprobe_infopoint_add_display
+ (infrk, bb_ending_displayer, msgbuf, (HOST_WIDE_INT) bbix);
+ break;
+ }
+ };
+ debugeprintf ("add_infopoint_basic_block bb %p end", (void*)bb);
+}
+
+
+/* this function does the bulk of the work of the pass and returns
+ additional TODOs to the pass machinery */
+static unsigned int
+execute_comprobe (void)
+{
+ struct cgraph_node *cgr_fun = 0;
+ basic_block bb = 0;
+ for (cgr_fun = cgraph_nodes; cgr_fun; cgr_fun = cgr_fun->next)
+ {
+ tree tr_decl, tr_body;
+ int frk_decl = 0, lin_decl = 0;
+ if (!comprobe_replf)
+ break;
+ debugeprintf ("execute_comprobe cgr_fun=%p", (void*)cgr_fun);
+ if (flag_compiler_probe_debug)
+ dump_cgraph_node (stderr, cgr_fun);
+ tr_decl = cgr_fun->decl;
+ frk_decl = comprobe_file_rank_of_tree (tr_decl, &lin_decl);
+ tr_body = DECL_SAVED_TREE (tr_decl);
+ if (!tr_body)
+ continue;
+ comprobe_check ("comprobe cgraph loop");
+ add_infopoint_funbody (tr_body);
+ comprobe_flush ();
+ }
+ FOR_EACH_BB (bb)
+ {
+ if (!comprobe_replf)
+ break;
+ debugeprintf ("execute_comprobe bb %p", (void*)bb);
+ if (!bb_stmt_list(bb))
+ continue;
+ comprobe_check ("comprobe bb loop");
+ add_infopoint_basic_block (bb);
+ comprobe_flush ();
+ }
+ comprobe_flush ();
+ return 0; /* no additional todos */
+}
+
+struct tree_opt_pass pass_compiler_probe = {
+ "comprobe", /* name */
+ gate_comprobe, /* gate */
+ execute_comprobe, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ 0 /*PROP_cfg | PROP_ssa */ , /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+#include "gt-compiler-probe.h"
+/* eof compiler-probe.c */