/* More subroutines needed by GCC output code on some machines. */
/* Compile this one with gcc. */
/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001 Free Software Foundation, Inc.
+ 2000, 2001, 2002 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC 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 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.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
the file, and distribution when not linked into a combine
executable.)
-GNU CC 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.
+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 GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
/* It is incorrect to include config.h here, because this file is being
compiled for the target, and hence definitions concerning only the host
#include "tconfig.h"
#include "tsystem.h"
-#include "machmode.h"
-
/* Don't use `fancy_abort' here even if config.h says to use it. */
#ifdef abort
#undef abort
#include "libgcc2.h"
\f
-#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
-#if defined (L_divdi3) || defined (L_moddi3)
-static inline
+#ifdef DECLARE_LIBRARY_RENAMES
+ DECLARE_LIBRARY_RENAMES
#endif
+
+#if defined (L_negdi2)
DWtype
__negdi2 (DWtype u)
{
abort ();
return w;
-}
+}
#endif
\f
#ifdef L_addvdi3
Wtype
__negvsi2 (Wtype a)
{
- Wtype w;
+ Wtype w;
- w = -a;
+ w = -a;
if (a >= 0 ? w > 0 : w < 0)
abort ();
DWtype
__negvdi2 (DWtype a)
{
- DWtype w;
+ DWtype w;
- w = -a;
+ w = -a;
if (a >= 0 ? w > 0 : w < 0)
abort ();
- return w;
+ return w;
}
#endif
\f
Wtype
__absvsi2 (Wtype a)
{
- Wtype w = a;
+ Wtype w = a;
- if (a < 0)
+ if (a < 0)
#ifdef L_negvsi2
- w = __negvsi2 (a);
+ w = __negvsi2 (a);
#else
- w = -a;
+ w = -a;
- if (w < 0)
- abort ();
+ if (w < 0)
+ abort ();
#endif
return w;
DWtype
__absvdi2 (DWtype a)
{
- DWtype w = a;
+ DWtype w = a;
- if (a < 0)
+ if (a < 0)
#ifdef L_negvsi2
- w = __negvsi2 (a);
+ w = __negvsi2 (a);
#else
- w = -a;
+ w = -a;
- if (w < 0)
- abort ();
+ if (w < 0)
+ abort ();
#endif
- return w;
+ return w;
}
#endif
\f
DWtype
__mulvdi3 (DWtype u, DWtype v)
{
- DWtype w;
+ DWtype w;
w = u * v;
if (uu.s.high < 0)
c = ~c,
- uu.ll = __negdi2 (uu.ll);
+ uu.ll = -uu.ll;
if (vv.s.high < 0)
c = ~c,
- vv.ll = __negdi2 (vv.ll);
+ vv.ll = -vv.ll;
w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
if (c)
- w = __negdi2 (w);
+ w = -w;
return w;
}
if (uu.s.high < 0)
c = ~c,
- uu.ll = __negdi2 (uu.ll);
+ uu.ll = -uu.ll;
if (vv.s.high < 0)
- vv.ll = __negdi2 (vv.ll);
+ vv.ll = -vv.ll;
(void) __udivmoddi4 (uu.ll, vv.ll, &w);
if (c)
- w = __negdi2 (w);
+ w = -w;
return w;
}
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
-#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
-
-/* Define codes for all the float formats that we know of. Note
- that this is copied from real.h. */
-
-#define UNKNOWN_FLOAT_FORMAT 0
-#define IEEE_FLOAT_FORMAT 1
-#define VAX_FLOAT_FORMAT 2
-#define IBM_FLOAT_FORMAT 3
-
-/* Default to IEEE float if not specified. Nearly all machines use it. */
-#ifndef HOST_FLOAT_FORMAT
-#define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT
-#endif
-#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-#define DF_SIZE 53
-#define SF_SIZE 24
-#endif
-
-#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
-#define DF_SIZE 56
-#define SF_SIZE 24
-#endif
-
-#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
-#define DF_SIZE 56
-#define SF_SIZE 24
-#endif
+#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
+#define DF_SIZE DBL_MANT_DIG
+#define SF_SIZE FLT_MANT_DIG
SFtype
__floatdisf (DWtype u)
&& u < ((DWtype) 1 << DF_SIZE)))
{
if ((UDWtype) u & (REP_BIT - 1))
- u |= REP_BIT;
+ {
+ u &= ~ (REP_BIT - 1);
+ u |= REP_BIT;
+ }
}
}
f = (Wtype) (u >> WORD_SIZE);
}
#endif
-\f\f
-#ifdef L__dummy
-void
-__dummy (void) {}
-#endif
-
-#ifdef L_varargs
-#ifdef __i860__
-#if defined(__svr4__) || defined(__alliant__)
- asm (" .text");
- asm (" .align 4");
-
-/* The Alliant needs the added underscore. */
- asm (".globl __builtin_saveregs");
-asm ("__builtin_saveregs:");
- asm (".globl ___builtin_saveregs");
-asm ("___builtin_saveregs:");
-
- asm (" andnot 0x0f,%sp,%sp"); /* round down to 16-byte boundary */
- asm (" adds -96,%sp,%sp"); /* allocate stack space for reg save
- area and also for a new va_list
- structure */
- /* Save all argument registers in the arg reg save area. The
- arg reg save area must have the following layout (according
- to the svr4 ABI):
-
- struct {
- union {
- float freg[8];
- double dreg[4];
- } float_regs;
- long ireg[12];
- };
- */
-
- asm (" fst.q %f8, 0(%sp)"); /* save floating regs (f8-f15) */
- asm (" fst.q %f12,16(%sp)");
-
- asm (" st.l %r16,32(%sp)"); /* save integer regs (r16-r27) */
- asm (" st.l %r17,36(%sp)");
- asm (" st.l %r18,40(%sp)");
- asm (" st.l %r19,44(%sp)");
- asm (" st.l %r20,48(%sp)");
- asm (" st.l %r21,52(%sp)");
- asm (" st.l %r22,56(%sp)");
- asm (" st.l %r23,60(%sp)");
- asm (" st.l %r24,64(%sp)");
- asm (" st.l %r25,68(%sp)");
- asm (" st.l %r26,72(%sp)");
- asm (" st.l %r27,76(%sp)");
-
- asm (" adds 80,%sp,%r16"); /* compute the address of the new
- va_list structure. Put in into
- r16 so that it will be returned
- to the caller. */
-
- /* Initialize all fields of the new va_list structure. This
- structure looks like:
-
- typedef struct {
- unsigned long ireg_used;
- unsigned long freg_used;
- long *reg_base;
- long *mem_ptr;
- } va_list;
- */
-
- asm (" st.l %r0, 0(%r16)"); /* nfixed */
- asm (" st.l %r0, 4(%r16)"); /* nfloating */
- asm (" st.l %sp, 8(%r16)"); /* __va_ctl points to __va_struct. */
- asm (" bri %r1"); /* delayed return */
- asm (" st.l %r28,12(%r16)"); /* pointer to overflow args */
-
-#else /* not __svr4__ */
-#if defined(__PARAGON__)
- /*
- * we'll use SVR4-ish varargs but need SVR3.2 assembler syntax,
- * and we stand a better chance of hooking into libraries
- * compiled by PGI. [andyp@ssd.intel.com]
- */
- asm (" .text");
- asm (" .align 4");
- asm (".globl __builtin_saveregs");
-asm ("__builtin_saveregs:");
- asm (".globl ___builtin_saveregs");
-asm ("___builtin_saveregs:");
-
- asm (" andnot 0x0f,sp,sp"); /* round down to 16-byte boundary */
- asm (" adds -96,sp,sp"); /* allocate stack space for reg save
- area and also for a new va_list
- structure */
- /* Save all argument registers in the arg reg save area. The
- arg reg save area must have the following layout (according
- to the svr4 ABI):
-
- struct {
- union {
- float freg[8];
- double dreg[4];
- } float_regs;
- long ireg[12];
- };
- */
-
- asm (" fst.q f8, 0(sp)");
- asm (" fst.q f12,16(sp)");
- asm (" st.l r16,32(sp)");
- asm (" st.l r17,36(sp)");
- asm (" st.l r18,40(sp)");
- asm (" st.l r19,44(sp)");
- asm (" st.l r20,48(sp)");
- asm (" st.l r21,52(sp)");
- asm (" st.l r22,56(sp)");
- asm (" st.l r23,60(sp)");
- asm (" st.l r24,64(sp)");
- asm (" st.l r25,68(sp)");
- asm (" st.l r26,72(sp)");
- asm (" st.l r27,76(sp)");
-
- asm (" adds 80,sp,r16"); /* compute the address of the new
- va_list structure. Put in into
- r16 so that it will be returned
- to the caller. */
-
- /* Initialize all fields of the new va_list structure. This
- structure looks like:
-
- typedef struct {
- unsigned long ireg_used;
- unsigned long freg_used;
- long *reg_base;
- long *mem_ptr;
- } va_list;
- */
-
- asm (" st.l r0, 0(r16)"); /* nfixed */
- asm (" st.l r0, 4(r16)"); /* nfloating */
- asm (" st.l sp, 8(r16)"); /* __va_ctl points to __va_struct. */
- asm (" bri r1"); /* delayed return */
- asm (" st.l r28,12(r16)"); /* pointer to overflow args */
-#else /* not __PARAGON__ */
- asm (" .text");
- asm (" .align 4");
-
- asm (".globl ___builtin_saveregs");
- asm ("___builtin_saveregs:");
- asm (" mov sp,r30");
- asm (" andnot 0x0f,sp,sp");
- asm (" adds -96,sp,sp"); /* allocate sufficient space on the stack */
-
-/* Fill in the __va_struct. */
- asm (" st.l r16, 0(sp)"); /* save integer regs (r16-r27) */
- asm (" st.l r17, 4(sp)"); /* int fixed[12] */
- asm (" st.l r18, 8(sp)");
- asm (" st.l r19,12(sp)");
- asm (" st.l r20,16(sp)");
- asm (" st.l r21,20(sp)");
- asm (" st.l r22,24(sp)");
- asm (" st.l r23,28(sp)");
- asm (" st.l r24,32(sp)");
- asm (" st.l r25,36(sp)");
- asm (" st.l r26,40(sp)");
- asm (" st.l r27,44(sp)");
-
- asm (" fst.q f8, 48(sp)"); /* save floating regs (f8-f15) */
- asm (" fst.q f12,64(sp)"); /* int floating[8] */
-
-/* Fill in the __va_ctl. */
- asm (" st.l sp, 80(sp)"); /* __va_ctl points to __va_struct. */
- asm (" st.l r28,84(sp)"); /* pointer to more args */
- asm (" st.l r0, 88(sp)"); /* nfixed */
- asm (" st.l r0, 92(sp)"); /* nfloating */
-
- asm (" adds 80,sp,r16"); /* return address of the __va_ctl. */
- asm (" bri r1");
- asm (" mov r30,sp");
- /* recover stack and pass address to start
- of data. */
-#endif /* not __PARAGON__ */
-#endif /* not __svr4__ */
-#else /* not __i860__ */
-#ifdef __sparc__
- asm (".global __builtin_saveregs");
- asm ("__builtin_saveregs:");
- asm (".global ___builtin_saveregs");
- asm ("___builtin_saveregs:");
-#ifdef NEED_PROC_COMMAND
- asm (".proc 020");
-#endif
- asm ("st %i0,[%fp+68]");
- asm ("st %i1,[%fp+72]");
- asm ("st %i2,[%fp+76]");
- asm ("st %i3,[%fp+80]");
- asm ("st %i4,[%fp+84]");
- asm ("retl");
- asm ("st %i5,[%fp+88]");
-#ifdef NEED_TYPE_COMMAND
- asm (".type __builtin_saveregs,#function");
- asm (".size __builtin_saveregs,.-__builtin_saveregs");
-#endif
-#else /* not __sparc__ */
-#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
-
- asm (" .text");
-#ifdef __mips16
- asm (" .set nomips16");
-#endif
- asm (" .ent __builtin_saveregs");
- asm (" .globl __builtin_saveregs");
- asm ("__builtin_saveregs:");
- asm (" sw $4,0($30)");
- asm (" sw $5,4($30)");
- asm (" sw $6,8($30)");
- asm (" sw $7,12($30)");
- asm (" j $31");
- asm (" .end __builtin_saveregs");
-#else /* not __mips__, etc. */
-
-void * ATTRIBUTE_NORETURN
-__builtin_saveregs ()
-{
- abort ();
-}
-
-#endif /* not __mips__ */
-#endif /* not __sparc__ */
-#endif /* not __i860__ */
-#endif
\f
+/* __eprintf used to be used by GCC's private version of <assert.h>.
+ We no longer provide that header, but this routine remains in libgcc.a
+ for binary backward compatibility. Note that it is not included in
+ the shared version of libgcc. */
#ifdef L_eprintf
#ifndef inhibit_libc
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
#include <stdio.h>
-/* This is used by the `assert' macro. */
+
void
__eprintf (const char *string, const char *expression,
unsigned int line, const char *filename)
#ifdef L_bb
-/* Structure emitted by -a */
+struct bb_function_info {
+ long checksum;
+ int arc_count;
+ const char *name;
+};
+
+/* Structure emitted by --profile-arcs */
struct bb
{
long zero_word;
const char *filename;
- long *counts;
+ gcov_type *counts;
long ncounts;
struct bb *next;
- const unsigned long *addresses;
/* Older GCC's did not emit these fields. */
- long nwords;
- const char **functions;
- const long *line_nums;
- const char **filenames;
- char *flags;
+ long sizeof_bb;
+ struct bb_function_info *function_infos;
};
-#ifdef BLOCK_PROFILER_CODE
-BLOCK_PROFILER_CODE
-#else
#ifndef inhibit_libc
-/* Simple minded basic block profiling output dumper for
- systems that don't provide tcov support. At present,
- it requires atexit and stdio. */
+/* Arc profile dumper. Requires atexit and stdio. */
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
#include <stdio.h>
-char *ctime PARAMS ((const time_t *));
-#include "gbl-ctors.h"
#include "gcov-io.h"
#include <string.h>
#ifdef TARGET_HAS_F_SETLKW
#include <errno.h>
#endif
+/* Chain of per-object file bb structures. */
static struct bb *bb_head;
-static int num_digits (long value, int base) __attribute__ ((const));
-
-/* Return the number of digits needed to print a value */
-/* __inline__ */ static int num_digits (long value, int base)
-{
- int minus = (value < 0 && base != 16);
- unsigned long v = (minus) ? -value : value;
- int ret = minus;
-
- do
- {
- v /= base;
- ret++;
- }
- while (v);
-
- return ret;
-}
+/* Dump the coverage counts. We merge with existing counts when
+ possible, to avoid growing the .da files ad infinitum. */
void
__bb_exit_func (void)
{
- FILE *da_file, *file;
- long time_value;
+ struct bb *ptr;
int i;
+ gcov_type program_sum = 0;
+ gcov_type program_max = 0;
+ long program_arcs = 0;
+ gcov_type merged_sum = 0;
+ gcov_type merged_max = 0;
+ long merged_arcs = 0;
+
+#if defined (TARGET_HAS_F_SETLKW)
+ struct flock s_flock;
- if (bb_head == 0)
- return;
-
- i = strlen (bb_head->filename) - 3;
+ s_flock.l_type = F_WRLCK;
+ s_flock.l_whence = SEEK_SET;
+ s_flock.l_start = 0;
+ s_flock.l_len = 0; /* Until EOF. */
+ s_flock.l_pid = getpid ();
+#endif
- if (!strcmp (bb_head->filename+i, ".da"))
+ /* Non-merged stats for this program. */
+ for (ptr = bb_head; ptr; ptr = ptr->next)
{
- /* Must be -fprofile-arcs not -a.
- Dump data in a form that gcov expects. */
-
- struct bb *ptr;
-
- for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
+ for (i = 0; i < ptr->ncounts; i++)
{
- int firstchar;
-
- /* Make sure the output file exists -
- but don't clobber exiting data. */
- if ((da_file = fopen (ptr->filename, "a")) != 0)
- fclose (da_file);
+ program_sum += ptr->counts[i];
- /* Need to re-open in order to be able to write from the start. */
- da_file = fopen (ptr->filename, "r+b");
+ if (ptr->counts[i] > program_max)
+ program_max = ptr->counts[i];
+ }
+ program_arcs += ptr->ncounts;
+ }
+
+ for (ptr = bb_head; ptr; ptr = ptr->next)
+ {
+ FILE *da_file;
+ gcov_type object_max = 0;
+ gcov_type object_sum = 0;
+ long object_functions = 0;
+ int merging = 0;
+ int error = 0;
+ struct bb_function_info *fn_info;
+ gcov_type *count_ptr;
+
+ /* Open for modification */
+ da_file = fopen (ptr->filename, "r+b");
+
+ if (da_file)
+ merging = 1;
+ else
+ {
+ /* Try for appending */
+ da_file = fopen (ptr->filename, "ab");
/* Some old systems might not allow the 'b' mode modifier.
- Therefore, try to open without it. This can lead to a race
- condition so that when you delete and re-create the file, the
- file might be opened in text mode, but then, you shouldn't
- delete the file in the first place. */
- if (da_file == 0)
- da_file = fopen (ptr->filename, "r+");
- if (da_file == 0)
- {
- fprintf (stderr, "arc profiling: Can't open output file %s.\n",
- ptr->filename);
- continue;
- }
+ Therefore, try to open without it. This can lead to a
+ race condition so that when you delete and re-create the
+ file, the file might be opened in text mode, but then,
+ you shouldn't delete the file in the first place. */
+ if (!da_file)
+ da_file = fopen (ptr->filename, "a");
+ }
+
+ if (!da_file)
+ {
+ fprintf (stderr, "arc profiling: Can't open output file %s.\n",
+ ptr->filename);
+ ptr->filename = 0;
+ continue;
+ }
- /* After a fork, another process might try to read and/or write
- the same file simultanously. So if we can, lock the file to
- avoid race conditions. */
#if defined (TARGET_HAS_F_SETLKW)
- {
- struct flock s_flock;
-
- s_flock.l_type = F_WRLCK;
- s_flock.l_whence = SEEK_SET;
- s_flock.l_start = 0;
- s_flock.l_len = 1;
- s_flock.l_pid = getpid ();
-
- while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
- && errno == EINTR);
- }
+ /* After a fork, another process might try to read and/or write
+ the same file simultanously. So if we can, lock the file to
+ avoid race conditions. */
+ while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
+ && errno == EINTR)
+ continue;
#endif
+ for (fn_info = ptr->function_infos; fn_info->arc_count != -1; fn_info++)
+ object_functions++;
- /* If the file is not empty, and the number of counts in it is the
- same, then merge them in. */
- firstchar = fgetc (da_file);
- if (firstchar == EOF)
+ if (merging)
+ {
+ /* Merge data from file. */
+ long tmp_long;
+ gcov_type tmp_gcov;
+
+ if (/* magic */
+ (__read_long (&tmp_long, da_file, 4) || tmp_long != -123l)
+ /* functions in object file. */
+ || (__read_long (&tmp_long, da_file, 4)
+ || tmp_long != object_functions)
+ /* extension block, skipped */
+ || (__read_long (&tmp_long, da_file, 4)
+ || fseek (da_file, tmp_long, SEEK_CUR)))
{
- if (ferror (da_file))
- {
- fprintf (stderr, "arc profiling: Can't read output file ");
- perror (ptr->filename);
- }
+ read_error:;
+ fprintf (stderr, "arc profiling: Error merging output file %s.\n",
+ ptr->filename);
+ clearerr (da_file);
}
else
{
- long n_counts = 0;
+ /* Merge execution counts for each function. */
+ count_ptr = ptr->counts;
- if (ungetc (firstchar, da_file) == EOF)
- rewind (da_file);
- if (__read_long (&n_counts, da_file, 8) != 0)
- {
- fprintf (stderr, "arc profiling: Can't read output file %s.\n",
- ptr->filename);
- continue;
- }
-
- if (n_counts == ptr->ncounts)
+ for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
+ fn_info++)
{
- int i;
-
- for (i = 0; i < n_counts; i++)
- {
- long v = 0;
-
- if (__read_long (&v, da_file, 8) != 0)
- {
- fprintf (stderr, "arc profiling: Can't read output file %s.\n",
- ptr->filename);
- break;
- }
- ptr->counts[i] += v;
- }
+ if (/* function name delim */
+ (__read_long (&tmp_long, da_file, 4)
+ || tmp_long != -1)
+ /* function name length */
+ || (__read_long (&tmp_long, da_file, 4)
+ || tmp_long != (long) strlen (fn_info->name))
+ /* skip string */
+ || fseek (da_file, ((tmp_long + 1) + 3) & ~3, SEEK_CUR)
+ /* function name delim */
+ || (__read_long (&tmp_long, da_file, 4)
+ || tmp_long != -1))
+ goto read_error;
+
+ if (/* function checksum */
+ (__read_long (&tmp_long, da_file, 4)
+ || tmp_long != fn_info->checksum)
+ /* arc count */
+ || (__read_long (&tmp_long, da_file, 4)
+ || tmp_long != fn_info->arc_count))
+ goto read_error;
+
+ for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
+ if (__read_gcov_type (&tmp_gcov, da_file, 8))
+ goto read_error;
+ else
+ *count_ptr += tmp_gcov;
}
-
}
+ fseek (da_file, 0, SEEK_SET);
+ }
+
+ /* Calculate the per-object statistics. */
+ for (i = 0; i < ptr->ncounts; i++)
+ {
+ object_sum += ptr->counts[i];
- rewind (da_file);
-
- /* ??? Should first write a header to the file. Preferably, a 4 byte
- magic number, 4 bytes containing the time the program was
- compiled, 4 bytes containing the last modification time of the
- source file, and 4 bytes indicating the compiler options used.
-
- That way we can easily verify that the proper source/executable/
- data file combination is being used from gcov. */
+ if (ptr->counts[i] > object_max)
+ object_max = ptr->counts[i];
+ }
+ merged_sum += object_sum;
+ if (merged_max < object_max)
+ merged_max = object_max;
+ merged_arcs += ptr->ncounts;
+
+ /* Write out the data. */
+ if (/* magic */
+ __write_long (-123, da_file, 4)
+ /* number of functions in object file. */
+ || __write_long (object_functions, da_file, 4)
+ /* length of extra data in bytes. */
+ || __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4)
+
+ /* whole program statistics. If merging write per-object
+ now, rewrite later */
+ /* number of instrumented arcs. */
+ || __write_long (merging ? ptr->ncounts : program_arcs, da_file, 4)
+ /* sum of counters. */
+ || __write_gcov_type (merging ? object_sum : program_sum, da_file, 8)
+ /* maximal counter. */
+ || __write_gcov_type (merging ? object_max : program_max, da_file, 8)
+
+ /* per-object statistics. */
+ /* number of counters. */
+ || __write_long (ptr->ncounts, da_file, 4)
+ /* sum of counters. */
+ || __write_gcov_type (object_sum, da_file, 8)
+ /* maximal counter. */
+ || __write_gcov_type (object_max, da_file, 8))
+ {
+ write_error:;
+ fprintf (stderr, "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ error = 1;
+ }
+ else
+ {
+ /* Write execution counts for each function. */
+ count_ptr = ptr->counts;
- if (__write_long (ptr->ncounts, da_file, 8) != 0)
+ for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
+ fn_info++)
{
+ if (__write_gcov_string (fn_info->name,
+ strlen (fn_info->name), da_file, -1)
+ || __write_long (fn_info->checksum, da_file, 4)
+ || __write_long (fn_info->arc_count, da_file, 4))
+ goto write_error;
- fprintf (stderr, "arc profiling: Error writing output file %s.\n",
- ptr->filename);
- }
- else
- {
- int j;
- long *count_ptr = ptr->counts;
- int ret = 0;
- for (j = ptr->ncounts; j > 0; j--)
- {
- if (__write_long (*count_ptr, da_file, 8) != 0)
- {
- ret=1;
- break;
- }
- count_ptr++;
- }
- if (ret)
- fprintf (stderr, "arc profiling: Error writing output file %s.\n",
- ptr->filename);
+ for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
+ if (__write_gcov_type (*count_ptr, da_file, 8))
+ goto write_error; /* RIP Edsger Dijkstra */
}
-
- if (fclose (da_file) == EOF)
- fprintf (stderr, "arc profiling: Error closing output file %s.\n",
- ptr->filename);
}
- return;
- }
-
- /* Must be basic block profiling. Emit a human readable output file. */
-
- file = fopen ("bb.out", "a");
-
- if (!file)
- perror ("bb.out");
-
- else
- {
- struct bb *ptr;
-
- /* This is somewhat type incorrect, but it avoids worrying about
- exactly where time.h is included from. It should be ok unless
- a void * differs from other pointer formats, or if sizeof (long)
- is < sizeof (time_t). It would be nice if we could assume the
- use of rationale standards here. */
-
- time ((void *) &time_value);
- fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
-
- /* We check the length field explicitly in order to allow compatibility
- with older GCC's which did not provide it. */
-
- for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
+ if (fclose (da_file))
{
- int i;
- int func_p = (ptr->nwords >= (long) sizeof (struct bb)
- && ptr->nwords <= 1000
- && ptr->functions);
- int line_p = (func_p && ptr->line_nums);
- int file_p = (func_p && ptr->filenames);
- int addr_p = (ptr->addresses != 0);
- long ncounts = ptr->ncounts;
- long cnt_max = 0;
- long line_max = 0;
- long addr_max = 0;
- int file_len = 0;
- int func_len = 0;
- int blk_len = num_digits (ncounts, 10);
- int cnt_len;
- int line_len;
- int addr_len;
-
- fprintf (file, "File %s, %ld basic blocks \n\n",
- ptr->filename, ncounts);
-
- /* Get max values for each field. */
- for (i = 0; i < ncounts; i++)
- {
- const char *p;
- int len;
-
- if (cnt_max < ptr->counts[i])
- cnt_max = ptr->counts[i];
-
- if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
- addr_max = ptr->addresses[i];
-
- if (line_p && line_max < ptr->line_nums[i])
- line_max = ptr->line_nums[i];
-
- if (func_p)
- {
- p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
- len = strlen (p);
- if (func_len < len)
- func_len = len;
- }
-
- if (file_p)
- {
- p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
- len = strlen (p);
- if (file_len < len)
- file_len = len;
- }
- }
-
- addr_len = num_digits (addr_max, 16);
- cnt_len = num_digits (cnt_max, 10);
- line_len = num_digits (line_max, 10);
-
- /* Now print out the basic block information. */
- for (i = 0; i < ncounts; i++)
- {
- fprintf (file,
- " Block #%*d: executed %*ld time(s)",
- blk_len, i+1,
- cnt_len, ptr->counts[i]);
-
- if (addr_p)
- fprintf (file, " address= 0x%.*lx", addr_len,
- ptr->addresses[i]);
-
- if (func_p)
- fprintf (file, " function= %-*s", func_len,
- (ptr->functions[i]) ? ptr->functions[i] : "<none>");
-
- if (line_p)
- fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
-
- if (file_p)
- fprintf (file, " file= %s",
- (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
-
- fprintf (file, "\n");
- }
-
- fprintf (file, "\n");
- fflush (file);
+ fprintf (stderr, "arc profiling: Error closing output file %s.\n",
+ ptr->filename);
+ error = 1;
}
-
- fprintf (file, "\n\n");
- fclose (file);
+ if (error || !merging)
+ ptr->filename = 0;
}
+
+ /* Upate whole program statistics. */
+ for (ptr = bb_head; ptr; ptr = ptr->next)
+ if (ptr->filename)
+ {
+ FILE *da_file;
+
+ da_file = fopen (ptr->filename, "r+b");
+ if (!da_file)
+ {
+ fprintf (stderr, "arc profiling: Cannot reopen %s.\n",
+ ptr->filename);
+ continue;
+ }
+
+#if defined (TARGET_HAS_F_SETLKW)
+ while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
+ && errno == EINTR)
+ continue;
+#endif
+
+ if (fseek (da_file, 4 * 3, SEEK_SET)
+ /* number of instrumented arcs. */
+ || __write_long (merged_arcs, da_file, 4)
+ /* sum of counters. */
+ || __write_gcov_type (merged_sum, da_file, 8)
+ /* maximal counter. */
+ || __write_gcov_type (merged_max, da_file, 8))
+ fprintf (stderr, "arc profiling: Error updating program header %s.\n",
+ ptr->filename);
+ if (fclose (da_file))
+ fprintf (stderr, "arc profiling: Error reclosing %s\n",
+ ptr->filename);
+ }
}
+/* Add a new object file onto the bb chain. Invoked automatically
+ when running an object file's global ctors. */
+
void
__bb_init_func (struct bb *blocks)
{
- /* User is supposed to check whether the first word is non-0,
- but just in case.... */
-
if (blocks->zero_word)
return;
- /* Initialize destructor. */
+ /* Initialize destructor and per-thread data. */
if (!bb_head)
atexit (__bb_exit_func);
/* Called before fork or exec - write out profile information gathered so
far and reset it to zero. This avoids duplication or loss of the
profile information gathered so far. */
+
void
__bb_fork_func (void)
{
}
}
-#ifndef MACHINE_STATE_SAVE
-#define MACHINE_STATE_SAVE(ID)
-#endif
-#ifndef MACHINE_STATE_RESTORE
-#define MACHINE_STATE_RESTORE(ID)
-#endif
-
-/* Number of buckets in hashtable of basic block addresses. */
-
-#define BB_BUCKETS 311
-
-/* Maximum length of string in file bb.in. */
-
-#define BBINBUFSIZE 500
-
-struct bb_edge
-{
- struct bb_edge *next;
- unsigned long src_addr;
- unsigned long dst_addr;
- unsigned long count;
-};
-
-enum bb_func_mode
-{
- TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
-};
-
-struct bb_func
-{
- struct bb_func *next;
- char *funcname;
- char *filename;
- enum bb_func_mode mode;
-};
-
-/* This is the connection to the outside world.
- The BLOCK_PROFILER macro must set __bb.blocks
- and __bb.blockno. */
-
-struct {
- unsigned long blockno;
- struct bb *blocks;
-} __bb;
-
-/* Vars to store addrs of source and destination basic blocks
- of a jump. */
-
-static unsigned long bb_src = 0;
-static unsigned long bb_dst = 0;
-
-static FILE *bb_tracefile = (FILE *) 0;
-static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
-static struct bb_func *bb_func_head = (struct bb_func *) 0;
-static unsigned long bb_callcount = 0;
-static int bb_mode = 0;
-
-static unsigned long *bb_stack = (unsigned long *) 0;
-static size_t bb_stacksize = 0;
-
-static int reported = 0;
-
-/* Trace modes:
-Always : Print execution frequencies of basic blocks
- to file bb.out.
-bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
-bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
-bb_mode & 4 != 0 : Cut call instructions from basic block flow.
-bb_mode & 8 != 0 : Insert return instructions in basic block flow.
-*/
-
-#ifdef HAVE_POPEN
-
-/*#include <sys/types.h>*/
-#include <sys/stat.h>
-/*#include <malloc.h>*/
-
-/* Commands executed by gopen. */
-
-#define GOPENDECOMPRESS "gzip -cd "
-#define GOPENCOMPRESS "gzip -c >"
-
-/* Like fopen but pipes through gzip. mode may only be "r" or "w".
- If it does not compile, simply replace gopen by fopen and delete
- '.gz' from any first parameter to gopen. */
-
-static FILE *
-gopen (char *fn, char *mode)
-{
- int use_gzip;
- char *p;
-
- if (mode[1])
- return (FILE *) 0;
-
- if (mode[0] != 'r' && mode[0] != 'w')
- return (FILE *) 0;
-
- p = fn + strlen (fn)-1;
- use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
- || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
-
- if (use_gzip)
- {
- if (mode[0]=='r')
- {
- FILE *f;
- char *s = (char *) malloc (sizeof (char) * strlen (fn)
- + sizeof (GOPENDECOMPRESS));
- strcpy (s, GOPENDECOMPRESS);
- strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
- f = popen (s, mode);
- free (s);
- return f;
- }
-
- else
- {
- FILE *f;
- char *s = (char *) malloc (sizeof (char) * strlen (fn)
- + sizeof (GOPENCOMPRESS));
- strcpy (s, GOPENCOMPRESS);
- strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
- if (!(f = popen (s, mode)))
- f = fopen (s, mode);
- free (s);
- return f;
- }
- }
-
- else
- return fopen (fn, mode);
-}
-
-static int
-gclose (FILE *f)
-{
- struct stat buf;
-
- if (f != 0)
- {
- if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
- return pclose (f);
-
- return fclose (f);
- }
- return 0;
-}
-
-#endif /* HAVE_POPEN */
-
-/* Called once per program. */
-
-static void
-__bb_exit_trace_func (void)
-{
- FILE *file = fopen ("bb.out", "a");
- struct bb_func *f;
- struct bb *b;
-
- if (!file)
- perror ("bb.out");
-
- if (bb_mode & 1)
- {
- if (!bb_tracefile)
- perror ("bbtrace");
- else
-#ifdef HAVE_POPEN
- gclose (bb_tracefile);
-#else
- fclose (bb_tracefile);
-#endif /* HAVE_POPEN */
- }
-
- /* Check functions in `bb.in'. */
-
- if (file)
- {
- long time_value;
- const struct bb_func *p;
- int printed_something = 0;
- struct bb *ptr;
- long blk;
-
- /* This is somewhat type incorrect. */
- time ((void *) &time_value);
-
- for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
- {
- for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
- {
- if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
- continue;
- for (blk = 0; blk < ptr->ncounts; blk++)
- {
- if (!strcmp (p->funcname, ptr->functions[blk]))
- goto found;
- }
- }
-
- if (!printed_something)
- {
- fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
- printed_something = 1;
- }
-
- fprintf (file, "\tFunction %s", p->funcname);
- if (p->filename)
- fprintf (file, " of file %s", p->filename);
- fprintf (file, "\n" );
-
-found: ;
- }
-
- if (printed_something)
- fprintf (file, "\n");
-
- }
-
- if (bb_mode & 2)
- {
- if (!bb_hashbuckets)
- {
- if (!reported)
- {
- fprintf (stderr, "Profiler: out of memory\n");
- reported = 1;
- }
- return;
- }
-
- else if (file)
- {
- long time_value;
- int i;
- unsigned long addr_max = 0;
- unsigned long cnt_max = 0;
- int cnt_len;
- int addr_len;
-
- /* This is somewhat type incorrect, but it avoids worrying about
- exactly where time.h is included from. It should be ok unless
- a void * differs from other pointer formats, or if sizeof (long)
- is < sizeof (time_t). It would be nice if we could assume the
- use of rationale standards here. */
-
- time ((void *) &time_value);
- fprintf (file, "Basic block jump tracing");
-
- switch (bb_mode & 12)
- {
- case 0:
- fprintf (file, " (with call)");
- break;
-
- case 4:
- /* Print nothing. */
- break;
-
- case 8:
- fprintf (file, " (with call & ret)");
- break;
-
- case 12:
- fprintf (file, " (with ret)");
- break;
- }
-
- fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
-
- for (i = 0; i < BB_BUCKETS; i++)
- {
- struct bb_edge *bucket = bb_hashbuckets[i];
- for ( ; bucket; bucket = bucket->next )
- {
- if (addr_max < bucket->src_addr)
- addr_max = bucket->src_addr;
- if (addr_max < bucket->dst_addr)
- addr_max = bucket->dst_addr;
- if (cnt_max < bucket->count)
- cnt_max = bucket->count;
- }
- }
- addr_len = num_digits (addr_max, 16);
- cnt_len = num_digits (cnt_max, 10);
-
- for ( i = 0; i < BB_BUCKETS; i++)
- {
- struct bb_edge *bucket = bb_hashbuckets[i];
- for ( ; bucket; bucket = bucket->next )
- {
- fprintf (file,
- "Jump from block 0x%.*lx to block 0x%.*lx executed %*lu time(s)\n",
- addr_len, bucket->src_addr,
- addr_len, bucket->dst_addr,
- cnt_len, bucket->count);
- }
- }
-
- fprintf (file, "\n");
-
- }
- }
-
- if (file)
- fclose (file);
-
- /* Free allocated memory. */
-
- f = bb_func_head;
- while (f)
- {
- struct bb_func *old = f;
-
- f = f->next;
- if (old->funcname) free (old->funcname);
- if (old->filename) free (old->filename);
- free (old);
- }
-
- if (bb_stack)
- free (bb_stack);
-
- if (bb_hashbuckets)
- {
- int i;
-
- for (i = 0; i < BB_BUCKETS; i++)
- {
- struct bb_edge *old, *bucket = bb_hashbuckets[i];
-
- while (bucket)
- {
- old = bucket;
- bucket = bucket->next;
- free (old);
- }
- }
- free (bb_hashbuckets);
- }
-
- for (b = bb_head; b; b = b->next)
- if (b->flags) free (b->flags);
-}
-
-/* Called once per program. */
-
-static void
-__bb_init_prg (void)
-{
- FILE *file;
- char buf[BBINBUFSIZE];
- const char *p;
- const char *pos;
- enum bb_func_mode m;
- int i;
-
- /* Initialize destructor. */
- atexit (__bb_exit_func);
-
- if (!(file = fopen ("bb.in", "r")))
- return;
-
- while(fgets (buf, BBINBUFSIZE, file) != 0)
- {
- i = strlen (buf);
- if (buf[i] == '\n')
- buf[i--] = '\0';
-
- p = buf;
- if (*p == '-')
- {
- m = TRACE_OFF;
- p++;
- }
- else
- {
- m = TRACE_ON;
- }
- if (!strcmp (p, "__bb_trace__"))
- bb_mode |= 1;
- else if (!strcmp (p, "__bb_jumps__"))
- bb_mode |= 2;
- else if (!strcmp (p, "__bb_hidecall__"))
- bb_mode |= 4;
- else if (!strcmp (p, "__bb_showret__"))
- bb_mode |= 8;
- else
- {
- struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
- if (f)
- {
- unsigned long l;
- f->next = bb_func_head;
- if ((pos = strchr (p, ':')))
- {
- if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
- continue;
- strcpy (f->funcname, pos+1);
- l = pos-p;
- if ((f->filename = (char *) malloc (l+1)))
- {
- strncpy (f->filename, p, l);
- f->filename[l] = '\0';
- }
- else
- f->filename = (char *) 0;
- }
- else
- {
- if (!(f->funcname = (char *) malloc (strlen (p)+1)))
- continue;
- strcpy (f->funcname, p);
- f->filename = (char *) 0;
- }
- f->mode = m;
- bb_func_head = f;
- }
- }
- }
- fclose (file);
-
-#ifdef HAVE_POPEN
-
- if (bb_mode & 1)
- bb_tracefile = gopen ("bbtrace.gz", "w");
-
-#else
-
- if (bb_mode & 1)
- bb_tracefile = fopen ("bbtrace", "w");
-
-#endif /* HAVE_POPEN */
-
- if (bb_mode & 2)
- {
- bb_hashbuckets = (struct bb_edge **)
- malloc (BB_BUCKETS * sizeof (struct bb_edge *));
- if (bb_hashbuckets)
- /* Use a loop here rather than calling bzero to avoid having to
- conditionalize its existance. */
- for (i = 0; i < BB_BUCKETS; i++)
- bb_hashbuckets[i] = 0;
- }
-
- if (bb_mode & 12)
- {
- bb_stacksize = 10;
- bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
- }
-
- /* Initialize destructor. */
- atexit (__bb_exit_trace_func);
-}
-
-/* Called upon entering a basic block. */
-
-void
-__bb_trace_func (void)
-{
- struct bb_edge *bucket;
-
- MACHINE_STATE_SAVE("1")
-
- if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
- goto skip;
-
- bb_dst = __bb.blocks->addresses[__bb.blockno];
- __bb.blocks->counts[__bb.blockno]++;
-
- if (bb_tracefile)
- {
- fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
- }
-
- if (bb_hashbuckets)
- {
- struct bb_edge **startbucket, **oldnext;
-
- oldnext = startbucket
- = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
- bucket = *startbucket;
-
- for (bucket = *startbucket; bucket;
- oldnext = &(bucket->next), bucket = *oldnext)
- {
- if (bucket->src_addr == bb_src
- && bucket->dst_addr == bb_dst)
- {
- bucket->count++;
- *oldnext = bucket->next;
- bucket->next = *startbucket;
- *startbucket = bucket;
- goto ret;
- }
- }
-
- bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
-
- if (!bucket)
- {
- if (!reported)
- {
- fprintf (stderr, "Profiler: out of memory\n");
- reported = 1;
- }
- }
-
- else
- {
- bucket->src_addr = bb_src;
- bucket->dst_addr = bb_dst;
- bucket->next = *startbucket;
- *startbucket = bucket;
- bucket->count = 1;
- }
- }
-
-ret:
- bb_src = bb_dst;
-
-skip:
- ;
-
- MACHINE_STATE_RESTORE("1")
-
-}
-
-/* Called when returning from a function and `__bb_showret__' is set. */
-
-static void
-__bb_trace_func_ret (void)
-{
- struct bb_edge *bucket;
-
- if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
- goto skip;
-
- if (bb_hashbuckets)
- {
- struct bb_edge **startbucket, **oldnext;
-
- oldnext = startbucket
- = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
- bucket = *startbucket;
-
- for (bucket = *startbucket; bucket;
- oldnext = &(bucket->next), bucket = *oldnext)
- {
- if (bucket->src_addr == bb_dst
- && bucket->dst_addr == bb_src)
- {
- bucket->count++;
- *oldnext = bucket->next;
- bucket->next = *startbucket;
- *startbucket = bucket;
- goto ret;
- }
- }
-
- bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
-
- if (!bucket)
- {
- if (!reported)
- {
- fprintf (stderr, "Profiler: out of memory\n");
- reported = 1;
- }
- }
-
- else
- {
- bucket->src_addr = bb_dst;
- bucket->dst_addr = bb_src;
- bucket->next = *startbucket;
- *startbucket = bucket;
- bucket->count = 1;
- }
- }
-
-ret:
- bb_dst = bb_src;
-
-skip:
- ;
-
-}
-
-/* Called upon entering the first function of a file. */
-
-static void
-__bb_init_file (struct bb *blocks)
-{
-
- const struct bb_func *p;
- long blk, ncounts = blocks->ncounts;
- const char **functions = blocks->functions;
-
- /* Set up linked list. */
- blocks->zero_word = 1;
- blocks->next = bb_head;
- bb_head = blocks;
-
- blocks->flags = 0;
- if (!bb_func_head
- || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
- return;
-
- for (blk = 0; blk < ncounts; blk++)
- blocks->flags[blk] = 0;
-
- for (blk = 0; blk < ncounts; blk++)
- {
- for (p = bb_func_head; p; p = p->next)
- {
- if (!strcmp (p->funcname, functions[blk])
- && (!p->filename || !strcmp (p->filename, blocks->filename)))
- {
- blocks->flags[blk] |= p->mode;
- }
- }
- }
-
-}
-
-/* Called when exiting from a function. */
-
-void
-__bb_trace_ret (void)
-{
-
- MACHINE_STATE_SAVE("2")
-
- if (bb_callcount)
- {
- if ((bb_mode & 12) && bb_stacksize > bb_callcount)
- {
- bb_src = bb_stack[bb_callcount];
- if (bb_mode & 8)
- __bb_trace_func_ret ();
- }
-
- bb_callcount -= 1;
- }
-
- MACHINE_STATE_RESTORE("2")
-
-}
-
-/* Called when entering a function. */
-
-void
-__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
-{
- static int trace_init = 0;
-
- MACHINE_STATE_SAVE("3")
-
- if (!blocks->zero_word)
- {
- if (!trace_init)
- {
- trace_init = 1;
- __bb_init_prg ();
- }
- __bb_init_file (blocks);
- }
-
- if (bb_callcount)
- {
-
- bb_callcount += 1;
-
- if (bb_mode & 12)
- {
- if (bb_callcount >= bb_stacksize)
- {
- size_t newsize = bb_callcount + 100;
-
- bb_stack = (unsigned long *) realloc (bb_stack, newsize);
- if (! bb_stack)
- {
- if (!reported)
- {
- fprintf (stderr, "Profiler: out of memory\n");
- reported = 1;
- }
- bb_stacksize = 0;
- goto stack_overflow;
- }
- bb_stacksize = newsize;
- }
- bb_stack[bb_callcount] = bb_src;
-
- if (bb_mode & 4)
- bb_src = 0;
-
- }
-
-stack_overflow:;
-
- }
-
- else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
- {
- bb_callcount = 1;
- bb_src = 0;
-
- if (bb_stack)
- bb_stack[bb_callcount] = bb_src;
- }
-
- MACHINE_STATE_RESTORE("3")
-}
-
#endif /* not inhibit_libc */
-#endif /* not BLOCK_PROFILER_CODE */
#endif /* L_bb */
\f
#ifdef L_clear_cache
__clear_cache (char *beg __attribute__((__unused__)),
char *end __attribute__((__unused__)))
{
-#ifdef CLEAR_INSN_CACHE
+#ifdef CLEAR_INSN_CACHE
CLEAR_INSN_CACHE (beg, end);
#else
#ifdef INSN_CACHE_SIZE
/* Compute the cache alignment of the place to stop clearing. */
#if 0 /* This is not needed for gcc's purposes. */
/* If the block to clear is bigger than a cache plane,
- we clear the entire cache, and OFFSET is already correct. */
+ we clear the entire cache, and OFFSET is already correct. */
if (end < beg + INSN_CACHE_PLANE_SIZE)
#endif
offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
-#ifdef TRANSFER_FROM_TRAMPOLINE
-TRANSFER_FROM_TRAMPOLINE
-#endif
-
-#if defined (NeXT) && defined (__MACH__)
-
-/* Make stack executable so we can call trampolines on stack.
- This is called from INITIALIZE_TRAMPOLINE in next.h. */
-#ifdef NeXTStep21
- #include <mach.h>
-#else
- #include <mach/mach.h>
-#endif
-
-void
-__enable_execute_stack (char *addr)
-{
- kern_return_t r;
- char *eaddr = addr + TRAMPOLINE_SIZE;
- vm_address_t a = (vm_address_t) addr;
-
- /* turn on execute access on stack */
- r = vm_protect (task_self (), a, TRAMPOLINE_SIZE, FALSE, VM_PROT_ALL);
- if (r != KERN_SUCCESS)
- {
- mach_error("vm_protect VM_PROT_ALL", r);
- exit(1);
- }
-
- /* We inline the i-cache invalidation for speed */
-
-#ifdef CLEAR_INSN_CACHE
- CLEAR_INSN_CACHE (addr, eaddr);
-#else
- __clear_cache ((int) addr, (int) eaddr);
+#ifdef TRANSFER_FROM_TRAMPOLINE
+TRANSFER_FROM_TRAMPOLINE
#endif
-}
-
-#endif /* defined (NeXT) && defined (__MACH__) */
-
-#ifdef __convex__
-
-/* Make stack executable so we can call trampolines on stack.
- This is called from INITIALIZE_TRAMPOLINE in convex.h. */
-
-#include <sys/mman.h>
-#include <sys/vmparam.h>
-#include <machine/machparam.h>
-
-void
-__enable_execute_stack (void)
-{
- int fp;
- static unsigned lowest = USRSTACK;
- unsigned current = (unsigned) &fp & -NBPG;
-
- if (lowest > current)
- {
- unsigned len = lowest - current;
- mremap (current, &len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
- lowest = current;
- }
-
- /* Clear instruction cache in case an old trampoline is in it. */
- asm ("pich");
-}
-#endif /* __convex__ */
-
-#ifdef __sysV88__
-
-/* Modified from the convex -code above. */
-
-#include <sys/param.h>
-#include <errno.h>
-#include <sys/m88kbcs.h>
-
-void
-__enable_execute_stack (void)
-{
- int save_errno;
- static unsigned long lowest = USRSTACK;
- unsigned long current = (unsigned long) &save_errno & -NBPC;
-
- /* Ignore errno being set. memctl sets errno to EINVAL whenever the
- address is seen as 'negative'. That is the case with the stack. */
-
- save_errno=errno;
- if (lowest > current)
- {
- unsigned len=lowest-current;
- memctl(current,len,MCT_TEXT);
- lowest = current;
- }
- else
- memctl(current,NBPC,MCT_TEXT);
- errno=save_errno;
-}
-
-#endif /* __sysV88__ */
#ifdef __sysV68__
int save_errno;
/* Preserve errno, because users would be surprised to have
- errno changing without explicitly calling any system-call. */
+ errno changing without explicitly calling any system-call. */
save_errno = errno;
- /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache.
- No need to use an address derived from _start or %sp, as 0 works also. */
+ /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache.
+ No need to use an address derived from _start or %sp, as 0 works also. */
memctl(0, 4096, MCT_TEXT);
errno = save_errno;
#endif
}
#endif /* __sysV68__ */
-
-#ifdef __pyr__
-
-#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
-#include <stdio.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/vmmac.h>
-
-/* Modified from the convex -code above.
- mremap promises to clear the i-cache. */
-
-void
-__enable_execute_stack (void)
-{
- int fp;
- if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ,
- PROT_READ|PROT_WRITE|PROT_EXEC))
- {
- perror ("mprotect in __enable_execute_stack");
- fflush (stderr);
- abort ();
- }
-}
-#endif /* __pyr__ */
-
-#if defined (sony_news) && defined (SYSTYPE_BSD)
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <syscall.h>
-#include <machine/sysnews.h>
-
-/* cacheflush function for NEWS-OS 4.2.
- This function is called from trampoline-initialize code
- defined in config/mips/mips.h. */
-
-void
-cacheflush (char *beg, int size, int flag)
-{
- if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
- {
- perror ("cache_flush");
- fflush (stderr);
- abort ();
- }
-}
-
-#endif /* sony_news */
#endif /* L_trampoline */
\f
#ifndef __CYGWIN__
/* Some ELF crosses use crtstuff.c to provide __CTOR_LIST__, but use this
code to run constructors. In that case, we need to handle EH here, too. */
-#ifdef EH_FRAME_SECTION
+#ifdef EH_FRAME_SECTION_NAME
#include "unwind-dw2-fde.h"
extern unsigned char __EH_FRAME_BEGIN__[];
#endif
(*(p-1)) ();
}
#endif
-#if defined (EH_FRAME_SECTION) && !defined (HAS_INIT_SECTION)
+#if defined (EH_FRAME_SECTION_NAME) && !defined (HAS_INIT_SECTION)
{
static int completed = 0;
if (! completed)
void
__do_global_ctors (void)
{
-#ifdef EH_FRAME_SECTION
+#ifdef EH_FRAME_SECTION_NAME
{
static struct object object;
__register_frame_info (__EH_FRAME_BEGIN__, &object);
Long term no port should use those extensions. But many still do. */
#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
-#if defined (ASM_OUTPUT_CONSTRUCTOR) || defined (USE_COLLECT2)
+#if defined (TARGET_ASM_CONSTRUCTOR) || defined (USE_COLLECT2)
func_ptr __CTOR_LIST__[2] = {0, 0};
func_ptr __DTOR_LIST__[2] = {0, 0};
#else
extern void _cleanup (void);
extern void _exit (int) __attribute__ ((__noreturn__));
-void
+void
exit (int status)
{
if (atexit_chain)