X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Flibgcc2.c;h=a88c08df366b099978b4e7ba63c94942d0a1669b;hb=11aafc65723c2b05ae51ecb120ef1d2a47c763c5;hp=00a50e6b43efeba9bd3f760816aa5ba997d54582;hpb=bec2d4909566b67347a964a8e1eb1918f772f873;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index 00a50e6b43e..a88c08df366 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -1,14 +1,14 @@ /* More subroutines needed by GCC output code on some machines. */ /* Compile this one with gcc. */ -/* Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 1999, 2000 - Free Software Foundation, Inc. +/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001 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 @@ -19,15 +19,15 @@ do apply in other respects; for example, they cover modification of 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 @@ -37,7 +37,6 @@ Boston, MA 02111-1307, USA. */ #include "tsystem.h" #include "machmode.h" -#include "defaults.h" /* Don't use `fancy_abort' here even if config.h says to use it. */ #ifdef abort @@ -50,12 +49,26 @@ Boston, MA 02111-1307, USA. */ #if defined (L_divdi3) || defined (L_moddi3) static inline #endif +DWtype +__negdi2 (DWtype u) +{ + DWunion w; + DWunion uu; + + uu.ll = u; + + w.s.low = -uu.s.low; + w.s.high = -uu.s.high - ((UWtype) w.s.low > 0); + + return w.ll; +} +#endif #ifdef L_addvsi3 -SItype -__addvsi3 (SItype a, SItype b) +Wtype +__addvsi3 (Wtype a, Wtype b) { - SItype w, w1; + Wtype w; w = a + b; @@ -63,13 +76,14 @@ __addvsi3 (SItype a, SItype b) abort (); return w; -} +} +#endif #ifdef L_addvdi3 -DItype -__addvdi3 (DItype a, DItype b) +DWtype +__addvdi3 (DWtype a, DWtype b) { - DItype w; + DWtype w; w = a + b; @@ -81,13 +95,13 @@ __addvdi3 (DItype a, DItype b) #endif #ifdef L_subvsi3 -SItype -__subvsi3 (SItype a, SItype b) +Wtype +__subvsi3 (Wtype a, Wtype b) { #ifdef L_addvsi3 return __addvsi3 (a, (-b)); #else - DItype w; + DWtype w; w = a - b; @@ -100,13 +114,13 @@ __subvsi3 (SItype a, SItype b) #endif #ifdef L_subvdi3 -DItype -__subvdi3 (DItype a, DItype b) +DWtype +__subvdi3 (DWtype a, DWtype b) { #ifdef L_addvdi3 return (a, (-b)); #else - DItype w; + DWtype w; w = a - b; @@ -119,15 +133,14 @@ __subvdi3 (DItype a, DItype b) #endif #ifdef L_mulvsi3 -SItype -__mulvsi3 (SItype a, SItype b) +Wtype +__mulvsi3 (Wtype a, Wtype b) { - DItype w; + DWtype w; w = a * b; - if ((a >= 0 && b >= 0) ? w < 0 - : (a >= 0 || b >= 0) ? w > 0 : w < 0) + if (((a >= 0) == (b >= 0)) ? w < 0 : w > 0) abort (); return w; @@ -135,10 +148,10 @@ __mulvsi3 (SItype a, SItype b) #endif #ifdef L_negvsi2 -SItype -__negvsi2 (SItype a) +Wtype +__negvsi2 (Wtype a) { - SItype w; + Wtype w; w = -a; @@ -150,10 +163,10 @@ __negvsi2 (SItype a) #endif #ifdef L_negvdi2 -DItype -__negvdi2 (DItype a) +DWtype +__negvdi2 (DWtype a) { - DItype w; + DWtype w; w = -a; @@ -165,10 +178,10 @@ __negvdi2 (DItype a) #endif #ifdef L_absvsi2 -SItype -__absvsi2 (SItype a) +Wtype +__absvsi2 (Wtype a) { - SItype w = a; + Wtype w = a; if (a < 0) #ifdef L_negvsi2 @@ -185,10 +198,10 @@ __absvsi2 (SItype a) #endif #ifdef L_absvdi2 -DItype -__absvdi2 (DItype a) +DWtype +__absvdi2 (DWtype a) { - DItype w = a; + DWtype w = a; if (a < 0) #ifdef L_negvsi2 @@ -205,36 +218,21 @@ __absvdi2 (DItype a) #endif #ifdef L_mulvdi3 -DItype -__mulvdi3 (DItype u, DItype v) +DWtype +__mulvdi3 (DWtype u, DWtype v) { - DItype w; + DWtype w; w = u * v; - if ((u >= 0 && v >= 0) ? w < 0 - : (u >= 0 || v >= 0) ? w > 0 : w < 0) + if (((u >= 0) == (v >= 0)) ? w < 0 : w > 0) abort (); return w; } #endif -DWtype -__negdi2 (DWtype u) -{ - DWunion w; - DWunion uu; - - uu.ll = u; - w.s.low = -uu.s.low; - w.s.high = -uu.s.high - ((UWtype) w.s.low > 0); - - return w.ll; -} -#endif - /* Unless shift functions are defined whith full ANSI prototypes, parameter b will be promoted to int if word_type is smaller than an int. */ #ifdef L_lshrdi3 @@ -1067,35 +1065,10 @@ __floatdidf (DWtype u) #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) @@ -1147,8 +1120,8 @@ __floatdisf (DWtype u) UWtype __fixunsxfSI (XFtype a) { - if (a >= - (DFtype) LONG_MIN) - return (Wtype) (a + LONG_MIN) - LONG_MIN; + if (a >= - (DFtype) Wtype_MIN) + return (Wtype) (a + Wtype_MIN) - Wtype_MIN; return (Wtype) a; } #endif @@ -1169,8 +1142,8 @@ __fixunsxfSI (XFtype a) UWtype __fixunsdfSI (DFtype a) { - if (a >= - (DFtype) LONG_MIN) - return (Wtype) (a + LONG_MIN) - LONG_MIN; + if (a >= - (DFtype) Wtype_MIN) + return (Wtype) (a + Wtype_MIN) - Wtype_MIN; return (Wtype) a; } #endif @@ -1191,8 +1164,8 @@ __fixunsdfSI (DFtype a) UWtype __fixunssfSI (SFtype a) { - if (a >= - (SFtype) LONG_MIN) - return (Wtype) (a + LONG_MIN) - LONG_MIN; + if (a >= - (SFtype) Wtype_MIN) + return (Wtype) (a + Wtype_MIN) - Wtype_MIN; return (Wtype) a; } #endif @@ -1240,241 +1213,17 @@ __gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size) } #endif - -#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 (void) -{ - abort (); -} - -#endif /* not __mips__ */ -#endif /* not __sparc__ */ -#endif /* not __i860__ */ -#endif +/* __eprintf used to be used by GCC's private version of . + 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 -/* This is used by the `assert' macro. */ + void __eprintf (const char *string, const char *expression, unsigned int line, const char *filename) @@ -1489,27 +1238,26 @@ __eprintf (const char *string, const char *expression, #ifdef L_bb +struct bb_function_info { + long checksum; + int arc_count; + const char *name; +}; + /* Structure emitted by -a */ 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 @@ -1518,7 +1266,6 @@ BLOCK_PROFILER_CODE #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ #include -char *ctime (); #include "gbl-ctors.h" #include "gcov-io.h" @@ -1528,290 +1275,180 @@ char *ctime (); #include #endif -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; +#include - do - { - v /= base; - ret++; - } - while (v); +static struct bb *bb_head; - return ret; -} +int __global_counters = 0, __gthreads_active = 0; void __bb_exit_func (void) { - FILE *da_file, *file; - long time_value; - int i; + FILE *da_file; + struct bb *ptr; + long n_counters_p = 0; + gcov_type max_counter_p = 0; + gcov_type sum_counters_p = 0; if (bb_head == 0) return; - i = strlen (bb_head->filename) - 3; + /* Calculate overall "statistics". */ - if (!strcmp (bb_head->filename+i, ".da")) + for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) { - /* Must be -fprofile-arcs not -a. - Dump data in a form that gcov expects. */ + int i; - struct bb *ptr; + n_counters_p += ptr->ncounts; - 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); - - /* Need to re-open in order to be able to write from the start. */ - da_file = fopen (ptr->filename, "r+b"); - /* 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; - } - - /* 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); - } -#endif - - /* 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 (ferror (da_file)) - { - fprintf (stderr, "arc profiling: Can't read output file "); - perror (ptr->filename); - } - } - else - { - long n_counts = 0; - - 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) - { - 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; - } - } - - } + sum_counters_p += 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 (__write_long (ptr->ncounts, da_file, 8) != 0) - { - - 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); - } - - if (fclose (da_file) == EOF) - fprintf (stderr, "arc profiling: Error closing output file %s.\n", - ptr->filename); + if (ptr->counts[i] > max_counter_p) + max_counter_p = ptr->counts[i]; } - - return; } - /* Must be basic block profiling. Emit a human readable output file. */ - - file = fopen ("bb.out", "a"); - - if (!file) - perror ("bb.out"); - - else + for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) { - struct bb *ptr; + gcov_type max_counter_o = 0; + gcov_type sum_counters_o = 0; + int i; - /* 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. */ + /* Calculate the per-object statistics. */ - time ((void *) &time_value); - fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value)); + for (i = 0; i < ptr->ncounts; i++) + { + sum_counters_o += ptr->counts[i]; - /* We check the length field explicitly in order to allow compatibility - with older GCC's which did not provide it. */ + if (ptr->counts[i] > max_counter_o) + max_counter_o = ptr->counts[i]; + } - for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) + /* open the file for appending, creating it if necessary. */ + 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, "a"); + if (da_file == 0) { - 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; + fprintf (stderr, "arc profiling: Can't open output file %s.\n", + ptr->filename); + 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; - if (cnt_max < ptr->counts[i]) - cnt_max = ptr->counts[i]; + 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 (); - if (addr_p && (unsigned long) addr_max < ptr->addresses[i]) - addr_max = ptr->addresses[i]; + while (fcntl (fileno (da_file), F_SETLKW, &s_flock) + && errno == EINTR); + } +#endif - if (line_p && line_max < ptr->line_nums[i]) - line_max = ptr->line_nums[i]; + if (__write_long (-123, da_file, 4) != 0) /* magic */ + { + fprintf (stderr, "arc profiling: Error writing output file %s.\n", + ptr->filename); + } + else + { - if (func_p) + struct bb_function_info *fn_info; + gcov_type *count_ptr = ptr->counts; + int i; + int count_functions = 0; + + for (fn_info = ptr->function_infos; fn_info->arc_count != -1; + fn_info++) + count_functions++; + + /* number of functions in this block. */ + __write_long (count_functions, da_file, 4); + + /* length of extra data in bytes. */ + __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4); + + /* overall statistics. */ + /* number of counters. */ + __write_long (n_counters_p, da_file, 4); + /* sum of counters. */ + __write_gcov_type (sum_counters_p, da_file, 8); + /* maximal counter. */ + __write_gcov_type (max_counter_p, da_file, 8); + + /* per-object statistics. */ + /* number of counters. */ + __write_long (ptr->ncounts, da_file, 4); + /* sum of counters. */ + __write_gcov_type (sum_counters_o, da_file, 8); + /* maximal counter. */ + __write_gcov_type (max_counter_o, da_file, 8); + + /* write execution counts for each function. */ + + for (fn_info = ptr->function_infos; fn_info->arc_count != -1; + fn_info++) + { + /* new function. */ + if (__write_gcov_string + (fn_info->name, strlen (fn_info->name), da_file, -1) != 0) { - p = (ptr->functions[i]) ? (ptr->functions[i]) : ""; - len = strlen (p); - if (func_len < len) - func_len = len; + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; } - if (file_p) + if (__write_long (fn_info->checksum, da_file, 4) != 0) { - p = (ptr->filenames[i]) ? (ptr->filenames[i]) : ""; - len = strlen (p); - if (file_len < len) - file_len = len; + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; } - } - - 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] : ""); - - if (line_p) - fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]); + if (__write_long (fn_info->arc_count, da_file, 4) != 0) + { + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; + } - if (file_p) - fprintf (file, " file= %s", - (ptr->filenames[i]) ? ptr->filenames[i] : ""); + for (i = fn_info->arc_count; i > 0; i--, count_ptr++) + { + if (__write_gcov_type (*count_ptr, da_file, 8) != 0) + break; + } - fprintf (file, "\n"); + if (i) /* there was an error */ + { + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; + } } - - fprintf (file, "\n"); - fflush (file); } - fprintf (file, "\n\n"); - fclose (file); + if (fclose (da_file) != 0) + fprintf (stderr, "arc profiling: Error closing output file %s.\n", + ptr->filename); } } @@ -1823,8 +1460,8 @@ __bb_init_func (struct bb *blocks) if (blocks->zero_word) return; - - /* Initialize destructor. */ + + /* Initialize destructor and per-thread data. */ if (!bb_head) atexit (__bb_exit_func); @@ -1837,7 +1474,7 @@ __bb_init_func (struct bb *blocks) /* 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 +void __bb_fork_func (void) { struct bb *ptr; @@ -1851,845 +1488,114 @@ __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; -}; +#endif /* not inhibit_libc */ +#endif /* L_bb */ + +#ifdef L_clear_cache +/* Clear part of an instruction cache. */ -enum bb_func_mode -{ - TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2 -}; +#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH) -struct bb_func +void +__clear_cache (char *beg __attribute__((__unused__)), + char *end __attribute__((__unused__))) { - 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; +#ifdef CLEAR_INSN_CACHE + CLEAR_INSN_CACHE (beg, end); +#else +#ifdef INSN_CACHE_SIZE + static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH]; + static int initialized; + int offset; + void *start_addr + void *end_addr; + typedef (*function_ptr) (void); -/* Vars to store addrs of source and destination basic blocks - of a jump. */ +#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16 + /* It's cheaper to clear the whole cache. + Put in a series of jump instructions so that calling the beginning + of the cache will clear the whole thing. */ -static unsigned long bb_src = 0; -static unsigned long bb_dst = 0; + if (! initialized) + { + int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) + & -INSN_CACHE_LINE_WIDTH); + int end_ptr = ptr + INSN_CACHE_SIZE; -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; + while (ptr < end_ptr) + { + *(INSTRUCTION_TYPE *)ptr + = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH; + ptr += INSN_CACHE_LINE_WIDTH; + } + *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION; -static unsigned long *bb_stack = (unsigned long *) 0; -static size_t bb_stacksize = 0; + initialized = 1; + } -static int reported = 0; + /* Call the beginning of the sequence. */ + (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1) + & -INSN_CACHE_LINE_WIDTH)) + ()); -/* 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. -*/ +#else /* Cache is large. */ -#ifdef HAVE_POPEN + if (! initialized) + { + int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) + & -INSN_CACHE_LINE_WIDTH); -/*#include */ -#include -/*#include */ + while (ptr < (int) array + sizeof array) + { + *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION; + ptr += INSN_CACHE_LINE_WIDTH; + } -/* Commands executed by gopen. */ + initialized = 1; + } -#define GOPENDECOMPRESS "gzip -cd " -#define GOPENCOMPRESS "gzip -c >" + /* Find the location in array that occupies the same cache line as BEG. */ -/* 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. */ + offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1); + start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1) + & -INSN_CACHE_PLANE_SIZE) + + offset); -static FILE * -gopen (char *fn, char *mode) -{ - int use_gzip; - char *p; + /* 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. */ + if (end < beg + INSN_CACHE_PLANE_SIZE) +#endif + offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1) + & -INSN_CACHE_LINE_WIDTH) + & (INSN_CACHE_PLANE_SIZE - 1)); - if (mode[1]) - return (FILE *) 0; +#if INSN_CACHE_DEPTH > 1 + end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset; + if (end_addr <= start_addr) + end_addr += INSN_CACHE_PLANE_SIZE; - if (mode[0] != 'r' && mode[0] != 'w') - return (FILE *) 0; + for (plane = 0; plane < INSN_CACHE_DEPTH; plane++) + { + int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE; + int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE; - p = fn + strlen (fn)-1; - use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z')) - || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z')); + while (addr != stop) + { + /* Call the return instruction at ADDR. */ + ((function_ptr) addr) (); - if (use_gzip) + addr += INSN_CACHE_LINE_WIDTH; + } + } +#else /* just one plane */ + do { - 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; - } + /* Call the return instruction at START_ADDR. */ + ((function_ptr) start_addr) (); - 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 */ - -#ifdef L_shtab -unsigned int __shtab[] = { - 0x00000001, 0x00000002, 0x00000004, 0x00000008, - 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x00000100, 0x00000200, 0x00000400, 0x00000800, - 0x00001000, 0x00002000, 0x00004000, 0x00008000, - 0x00010000, 0x00020000, 0x00040000, 0x00080000, - 0x00100000, 0x00200000, 0x00400000, 0x00800000, - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000 - }; -#endif - -#ifdef L_clear_cache -/* Clear part of an instruction cache. */ - -#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH) - -void -__clear_cache (char *beg __attribute__((__unused__)), - char *end __attribute__((__unused__))) -{ -#ifdef CLEAR_INSN_CACHE - CLEAR_INSN_CACHE (beg, end); -#else -#ifdef INSN_CACHE_SIZE - static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH]; - static int initialized; - int offset; - void *start_addr - void *end_addr; - typedef (*function_ptr) (void); - -#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16 - /* It's cheaper to clear the whole cache. - Put in a series of jump instructions so that calling the beginning - of the cache will clear the whole thing. */ - - if (! initialized) - { - int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH); - int end_ptr = ptr + INSN_CACHE_SIZE; - - while (ptr < end_ptr) - { - *(INSTRUCTION_TYPE *)ptr - = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH; - ptr += INSN_CACHE_LINE_WIDTH; - } - *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION; - - initialized = 1; - } - - /* Call the beginning of the sequence. */ - (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH)) - ()); - -#else /* Cache is large. */ - - if (! initialized) - { - int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH); - - while (ptr < (int) array + sizeof array) - { - *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION; - ptr += INSN_CACHE_LINE_WIDTH; - } - - initialized = 1; - } - - /* Find the location in array that occupies the same cache line as BEG. */ - - offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1); - start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1) - & -INSN_CACHE_PLANE_SIZE) - + offset); - - /* 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. */ - if (end < beg + INSN_CACHE_PLANE_SIZE) -#endif - offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH) - & (INSN_CACHE_PLANE_SIZE - 1)); - -#if INSN_CACHE_DEPTH > 1 - end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset; - if (end_addr <= start_addr) - end_addr += INSN_CACHE_PLANE_SIZE; - - for (plane = 0; plane < INSN_CACHE_DEPTH; plane++) - { - int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE; - int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE; - - while (addr != stop) - { - /* Call the return instruction at ADDR. */ - ((function_ptr) addr) (); - - addr += INSN_CACHE_LINE_WIDTH; - } - } -#else /* just one plane */ - do - { - /* Call the return instruction at START_ADDR. */ - ((function_ptr) start_addr) (); - - start_addr += INSN_CACHE_LINE_WIDTH; + start_addr += INSN_CACHE_LINE_WIDTH; } while ((start_addr % INSN_CACHE_SIZE) != offset); #endif /* just one plane */ @@ -2746,8 +1652,8 @@ mprotect (char *addr, int len, int prot) #endif /* WINNT && ! __CYGWIN__ && ! _UWIN */ -#ifdef TRANSFER_FROM_TRAMPOLINE -TRANSFER_FROM_TRAMPOLINE +#ifdef TRANSFER_FROM_TRAMPOLINE +TRANSFER_FROM_TRAMPOLINE #endif #if defined (NeXT) && defined (__MACH__) @@ -2782,7 +1688,7 @@ __enable_execute_stack (char *addr) #else __clear_cache ((int) addr, (int) eaddr); #endif -} +} #endif /* defined (NeXT) && defined (__MACH__) */ @@ -2828,9 +1734,9 @@ __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. */ + address is seen as 'negative'. That is the case with the stack. */ save_errno=errno; if (lowest > current) @@ -2879,11 +1785,11 @@ __clear_insn_cache (void) 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 @@ -2966,8 +1872,8 @@ cacheflush (char *beg, int size, int flag) /* 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 -#include "frame.h" +#ifdef EH_FRAME_SECTION_NAME +#include "unwind-dw2-fde.h" extern unsigned char __EH_FRAME_BEGIN__[]; #endif @@ -2986,7 +1892,7 @@ __do_global_dtors (void) (*(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) @@ -3005,7 +1911,7 @@ __do_global_dtors (void) 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); @@ -3059,7 +1965,7 @@ SYMBOL__MAIN () 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 @@ -3110,7 +2016,7 @@ atexit (func_ptr func) extern void _cleanup (void); extern void _exit (int) __attribute__ ((__noreturn__)); -void +void exit (int status) { if (atexit_chain) @@ -3144,1210 +2050,3 @@ atexit (func_ptr func) #endif /* NEED_ATEXIT */ #endif /* L_exit */ - -#ifdef L_eh - -#include "gthr.h" - -/* Shared exception handling support routines. */ - -void -__default_terminate (void) -{ - abort (); -} - -void (*__terminate_func)(void) __attribute__ ((__noreturn__)) = - __default_terminate; - -void __attribute__((__noreturn__)) -__terminate (void) -{ - (*__terminate_func)(); -} - -void * -__throw_type_match (void *catch_type, void *throw_type, void *obj) -{ -#if 0 - printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n", - catch_type, throw_type); -#endif - if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0) - return obj; - return 0; -} - -void -__empty (void) -{ -} - - -/* Include definitions of EH context and table layout */ - -#include "eh-common.h" -#ifndef inhibit_libc -#include -#endif - -/* Allocate and return a new EH context structure. */ - -#if __GTHREADS -static void * -new_eh_context (void) -{ - struct eh_full_context { - struct eh_context c; - void *top_elt[2]; - } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc); - - if (! ehfc) - __terminate (); - - memset (ehfc, 0, sizeof *ehfc); - - ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt; - - /* This should optimize out entirely. This should always be true, - but just in case it ever isn't, don't allow bogus code to be - generated. */ - - if ((void*)(&ehfc->c) != (void*)ehfc) - __terminate (); - - return &ehfc->c; -} - -static __gthread_key_t eh_context_key; - -/* Destructor for struct eh_context. */ -static void -eh_context_free (void *ptr) -{ - __gthread_key_dtor (eh_context_key, ptr); - if (ptr) - free (ptr); -} -#endif - -/* Pointer to function to return EH context. */ - -static struct eh_context *eh_context_initialize (void); -static struct eh_context *eh_context_static (void); -#if __GTHREADS -static struct eh_context *eh_context_specific (void); -#endif - -static struct eh_context *(*get_eh_context) (void) = &eh_context_initialize; - -/* Routine to get EH context. - This one will simply call the function pointer. */ - -void * -__get_eh_context (void) -{ - return (void *) (*get_eh_context) (); -} - -/* Get and set the language specific info pointer. */ - -void ** -__get_eh_info (void) -{ - struct eh_context *eh = (*get_eh_context) (); - return &eh->info; -} - -#ifdef DWARF2_UNWIND_INFO -static int dwarf_reg_size_table_initialized = 0; -static char dwarf_reg_size_table[DWARF_FRAME_REGISTERS]; - -static void -init_reg_size_table (void) -{ - __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table); - dwarf_reg_size_table_initialized = 1; -} -#endif - -#if __GTHREADS -static void -eh_threads_initialize (void) -{ - /* Try to create the key. If it fails, revert to static method, - otherwise start using thread specific EH contexts. */ - if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0) - get_eh_context = &eh_context_specific; - else - get_eh_context = &eh_context_static; -} -#endif /* no __GTHREADS */ - -/* Initialize EH context. - This will be called only once, since we change GET_EH_CONTEXT - pointer to another routine. */ - -static struct eh_context * -eh_context_initialize (void) -{ -#if __GTHREADS - - static __gthread_once_t once = __GTHREAD_ONCE_INIT; - /* Make sure that get_eh_context does not point to us anymore. - Some systems have dummy thread routines in their libc that - return a success (Solaris 2.6 for example). */ - if (__gthread_once (&once, eh_threads_initialize) != 0 - || get_eh_context == &eh_context_initialize) - { - /* Use static version of EH context. */ - get_eh_context = &eh_context_static; - } -#ifdef DWARF2_UNWIND_INFO - { - static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT; - if (__gthread_once (&once_regsizes, init_reg_size_table) != 0 - || ! dwarf_reg_size_table_initialized) - init_reg_size_table (); - } -#endif - -#else /* no __GTHREADS */ - - /* Use static version of EH context. */ - get_eh_context = &eh_context_static; - -#ifdef DWARF2_UNWIND_INFO - init_reg_size_table (); -#endif - -#endif /* no __GTHREADS */ - - return (*get_eh_context) (); -} - -/* Return a static EH context. */ - -static struct eh_context * -eh_context_static (void) -{ - static struct eh_context eh; - static int initialized; - static void *top_elt[2]; - - if (! initialized) - { - initialized = 1; - memset (&eh, 0, sizeof eh); - eh.dynamic_handler_chain = top_elt; - } - return &eh; -} - -#if __GTHREADS -/* Return a thread specific EH context. */ - -static struct eh_context * -eh_context_specific (void) -{ - struct eh_context *eh; - eh = (struct eh_context *) __gthread_getspecific (eh_context_key); - if (! eh) - { - eh = new_eh_context (); - if (__gthread_setspecific (eh_context_key, (void *) eh) != 0) - __terminate (); - } - - return eh; -} -#endif /* __GTHREADS */ - -/* Support routines for alloc/free during exception handling */ - -/* __eh_alloc and __eh_free attempt allocation using malloc, but fall back to - the small arena in the eh_context. This is needed because throwing an - out-of-memory exception would fail otherwise. The emergency space is - allocated in blocks of size EH_ALLOC_ALIGN, the - minimum allocation being two blocks. A bitmask indicates which blocks - have been allocated. To indicate the size of an allocation, the bit for - the final block is not set. Hence each allocation is a run of 1s followed - by a zero. */ -void * -__eh_alloc (size_t size) -{ - void *p; - - if (!size) - abort(); - p = malloc (size); - if (p == 0) - { - struct eh_context *eh = __get_eh_context (); - unsigned blocks = (size + EH_ALLOC_ALIGN - 1) / EH_ALLOC_ALIGN; - unsigned real_mask = eh->alloc_mask | (eh->alloc_mask << 1); - unsigned our_mask; - unsigned ix; - - if (blocks > EH_ALLOC_SIZE / EH_ALLOC_ALIGN) - __terminate (); - blocks += blocks == 1; - our_mask = (1 << blocks) - 1; - - for (ix = EH_ALLOC_SIZE / EH_ALLOC_ALIGN - blocks; ix; ix--) - if (! ((real_mask >> ix) & our_mask)) - { - /* found some space */ - p = &eh->alloc_buffer[ix * EH_ALLOC_ALIGN]; - eh->alloc_mask |= (our_mask >> 1) << ix; - return p; - } - __terminate (); - } - return p; -} - -/* Free the memory for an cp_eh_info and associated exception, given - a pointer to the cp_eh_info. */ -void -__eh_free (void *p) -{ - struct eh_context *eh = __get_eh_context (); - - ptrdiff_t diff = (char *)p - &eh->alloc_buffer[0]; - if (diff >= 0 && diff < EH_ALLOC_SIZE) - { - unsigned mask = eh->alloc_mask; - unsigned bit = 1 << (diff / EH_ALLOC_ALIGN); - - do - { - mask ^= bit; - bit <<= 1; - } - while (mask & bit); - eh->alloc_mask = mask; - } - else - free (p); -} - -/* Support routines for setjmp/longjmp exception handling. */ - -/* Calls to __sjthrow are generated by the compiler when an exception - is raised when using the setjmp/longjmp exception handling codegen - method. */ - -#ifdef DONT_USE_BUILTIN_SETJMP -extern void longjmp (void *, int); -#endif - -/* Routine to get the head of the current thread's dynamic handler chain - use for exception handling. */ - -void *** -__get_dynamic_handler_chain (void) -{ - struct eh_context *eh = (*get_eh_context) (); - return &eh->dynamic_handler_chain; -} - -/* This is used to throw an exception when the setjmp/longjmp codegen - method is used for exception handling. - - We call __terminate if there are no handlers left. Otherwise we run the - cleanup actions off the dynamic cleanup stack, and pop the top of the - dynamic handler chain, and use longjmp to transfer back to the associated - handler. */ - -void -__sjthrow (void) -{ - struct eh_context *eh = (*get_eh_context) (); - void ***dhc = &eh->dynamic_handler_chain; - void *jmpbuf; - void (*func)(void *, int); - void *arg; - /* The cleanup chain is one word into the buffer. Get the cleanup chain. */ - void ***cleanup = (void***)&(*dhc)[1]; - - /* If there are any cleanups in the chain, run them now. */ - if (cleanup[0]) - { - double store[200]; - void **buf = (void**)store; - buf[1] = 0; - buf[0] = (*dhc); - - /* try { */ -#ifdef DONT_USE_BUILTIN_SETJMP - if (! setjmp (&buf[2])) -#else - if (! __builtin_setjmp (&buf[2])) -#endif - { - *dhc = buf; - while (cleanup[0]) - { - func = (void(*)(void*, int))cleanup[0][1]; - arg = (void*)cleanup[0][2]; - - /* Update this before running the cleanup. */ - cleanup[0] = (void **)cleanup[0][0]; - - (*func)(arg, 2); - } - *dhc = buf[0]; - } - /* catch (...) */ - else - { - __terminate (); - } - } - - /* We must call terminate if we try and rethrow an exception, when - there is no exception currently active and when there are no - handlers left. */ - if (! eh->info || (*dhc)[0] == 0) - __terminate (); - - /* Find the jmpbuf associated with the top element of the dynamic - handler chain. The jumpbuf starts two words into the buffer. */ - jmpbuf = &(*dhc)[2]; - - /* Then we pop the top element off the dynamic handler chain. */ - *dhc = (void**)(*dhc)[0]; - - /* And then we jump to the handler. */ - -#ifdef DONT_USE_BUILTIN_SETJMP - longjmp (jmpbuf, 1); -#else - __builtin_longjmp (jmpbuf, 1); -#endif -} - -/* Run cleanups on the dynamic cleanup stack for the current dynamic - handler, then pop the handler off the dynamic handler stack, and - then throw. This is used to skip the first handler, and transfer - control to the next handler in the dynamic handler stack. */ - -void -__sjpopnthrow (void) -{ - struct eh_context *eh = (*get_eh_context) (); - void ***dhc = &eh->dynamic_handler_chain; - void (*func)(void *, int); - void *arg; - /* The cleanup chain is one word into the buffer. Get the cleanup chain. */ - void ***cleanup = (void***)&(*dhc)[1]; - - /* If there are any cleanups in the chain, run them now. */ - if (cleanup[0]) - { - double store[200]; - void **buf = (void**)store; - buf[1] = 0; - buf[0] = (*dhc); - - /* try { */ -#ifdef DONT_USE_BUILTIN_SETJMP - if (! setjmp (&buf[2])) -#else - if (! __builtin_setjmp (&buf[2])) -#endif - { - *dhc = buf; - while (cleanup[0]) - { - func = (void(*)(void*, int))cleanup[0][1]; - arg = (void*)cleanup[0][2]; - - /* Update this before running the cleanup. */ - cleanup[0] = (void **)cleanup[0][0]; - - (*func)(arg, 2); - } - *dhc = buf[0]; - } - /* catch (...) */ - else - { - __terminate (); - } - } - - /* Then we pop the top element off the dynamic handler chain. */ - *dhc = (void**)(*dhc)[0]; - - __sjthrow (); -} - -/* Support code for all exception region-based exception handling. */ - -int -__eh_rtime_match (void *rtime) -{ - void *info; - __eh_matcher matcher; - void *ret; - - info = *(__get_eh_info ()); - matcher = ((__eh_info *)info)->match_function; - if (! matcher) - { -#ifndef inhibit_libc - fprintf (stderr, "Internal Compiler Bug: No runtime type matcher."); -#endif - return 0; - } - ret = (*matcher) (info, rtime, (void *)0); - return (ret != NULL); -} - -/* This value identifies the place from which an exception is being - thrown. */ - -#ifdef EH_TABLE_LOOKUP - -EH_TABLE_LOOKUP - -#else - -#ifdef DWARF2_UNWIND_INFO - -/* Return the table version of an exception descriptor */ - -short -__get_eh_table_version (exception_descriptor *table) -{ - return table->lang.version; -} - -/* Return the originating table language of an exception descriptor */ - -short -__get_eh_table_language (exception_descriptor *table) -{ - return table->lang.language; -} - -/* This routine takes a PC and a pointer to the exception region TABLE for - its translation unit, and returns the address of the exception handler - associated with the closest exception table handler entry associated - with that PC, or 0 if there are no table entries the PC fits in. - - In the advent of a tie, we have to give the last entry, as it represents - an inner block. */ - -static void * -old_find_exception_handler (void *pc, old_exception_table *table) -{ - if (table) - { - int pos; - int best = -1; - - /* We can't do a binary search because the table isn't guaranteed - to be sorted from function to function. */ - for (pos = 0; table[pos].start_region != (void *) -1; ++pos) - { - if (table[pos].start_region <= pc && table[pos].end_region > pc) - { - /* This can apply. Make sure it is at least as small as - the previous best. */ - if (best == -1 || (table[pos].end_region <= table[best].end_region - && table[pos].start_region >= table[best].start_region)) - best = pos; - } - /* But it is sorted by starting PC within a function. */ - else if (best >= 0 && table[pos].start_region > pc) - break; - } - if (best != -1) - return table[best].exception_handler; - } - - return (void *) 0; -} - -/* find_exception_handler finds the correct handler, if there is one, to - handle an exception. - returns a pointer to the handler which controlled should be transferred - to, or NULL if there is nothing left. - Parameters: - PC - pc where the exception originates. If this is a rethrow, - then this starts out as a pointer to the exception table - entry we wish to rethrow out of. - TABLE - exception table for the current module. - EH_INFO - eh info pointer for this exception. - RETHROW - 1 if this is a rethrow. (see incoming value of PC). - CLEANUP - returned flag indicating whether this is a cleanup handler. -*/ -static void * -find_exception_handler (void *pc, exception_descriptor *table, - __eh_info *eh_info, int rethrow, int *cleanup) -{ - - void *retval = NULL; - *cleanup = 1; - if (table) - { - int pos = 0; - /* The new model assumed the table is sorted inner-most out so the - first region we find which matches is the correct one */ - - exception_table *tab = &(table->table[0]); - - /* Subtract 1 from the PC to avoid hitting the next region */ - if (rethrow) - { - /* pc is actually the region table entry to rethrow out of */ - pos = ((exception_table *) pc) - tab; - pc = ((exception_table *) pc)->end_region - 1; - - /* The label is always on the LAST handler entry for a region, - so we know the next entry is a different region, even if the - addresses are the same. Make sure its not end of table tho. */ - if (tab[pos].start_region != (void *) -1) - pos++; - } - else - pc--; - - /* We can't do a binary search because the table is in inner-most - to outermost address ranges within functions */ - for ( ; tab[pos].start_region != (void *) -1; pos++) - { - if (tab[pos].start_region <= pc && tab[pos].end_region > pc) - { - if (tab[pos].match_info) - { - __eh_matcher matcher = eh_info->match_function; - /* match info but no matcher is NOT a match */ - if (matcher) - { - void *ret = (*matcher)((void *) eh_info, - tab[pos].match_info, table); - if (ret) - { - if (retval == NULL) - retval = tab[pos].exception_handler; - *cleanup = 0; - break; - } - } - } - else - { - if (retval == NULL) - retval = tab[pos].exception_handler; - } - } - } - } - return retval; -} -#endif /* DWARF2_UNWIND_INFO */ -#endif /* EH_TABLE_LOOKUP */ - -#ifdef DWARF2_UNWIND_INFO -/* Support code for exception handling using static unwind information. */ - -#include "frame.h" - -/* This type is used in get_reg and put_reg to deal with ABIs where a void* - is smaller than a word, such as the Irix 6 n32 ABI. We cast twice to - avoid a warning about casting between int and pointer of different - sizes. */ - -typedef int ptr_type __attribute__ ((mode (pointer))); - -#ifdef INCOMING_REGNO -/* Is the saved value for register REG in frame UDATA stored in a register - window in the previous frame? */ - -/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT. This allows us - to use the macro here. One wonders, though, that perhaps TARGET_FLAT - compiled functions won't work with the frame-unwind stuff here. - Perhaps the entireity of in_reg_window should be conditional on having - seen a DW_CFA_GNU_window_save? */ -#define target_flags 0 - -static int -in_reg_window (int reg, frame_state *udata) -{ - if (udata->saved[reg] == REG_SAVED_REG) - return INCOMING_REGNO (reg) == reg; - if (udata->saved[reg] != REG_SAVED_OFFSET) - return 0; - -#ifdef STACK_GROWS_DOWNWARD - return udata->reg_or_offset[reg] > 0; -#else - return udata->reg_or_offset[reg] < 0; -#endif -} -#else -static inline int -in_reg_window (int reg __attribute__ ((__unused__)), - frame_state *udata __attribute__ ((__unused__))) -{ - return 0; -} -#endif /* INCOMING_REGNO */ - -/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a - frame called by UDATA or 0. */ - -static word_type * -get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata) -{ - while (udata->saved[reg] == REG_SAVED_REG) - { - reg = udata->reg_or_offset[reg]; - if (in_reg_window (reg, udata)) - { - udata = sub_udata; - sub_udata = NULL; - } - } - if (udata->saved[reg] == REG_SAVED_OFFSET) - return (word_type *)(udata->cfa + udata->reg_or_offset[reg]); - else - abort (); -} - -/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a - frame called by UDATA or 0. */ - -static inline void * -get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata) -{ - return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata); -} - -/* Overwrite the saved value for register REG in frame UDATA with VAL. */ - -static inline void -put_reg (unsigned reg, void *val, frame_state *udata) -{ - *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val; -} - -/* Copy the saved value for register REG from frame UDATA to frame - TARGET_UDATA. Unlike the previous two functions, this can handle - registers that are not one word large. */ - -static void -copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata) -{ - word_type *preg = get_reg_addr (reg, udata, NULL); - word_type *ptreg = get_reg_addr (reg, target_udata, NULL); - - memcpy (ptreg, preg, dwarf_reg_size_table [reg]); -} - -/* Retrieve the return address for frame UDATA. */ - -static inline void * -get_return_addr (frame_state *udata, frame_state *sub_udata) -{ - return __builtin_extract_return_addr - (get_reg (udata->retaddr_column, udata, sub_udata)); -} - -/* Overwrite the return address for frame UDATA with VAL. */ - -static inline void -put_return_addr (void *val, frame_state *udata) -{ - val = __builtin_frob_return_addr (val); - put_reg (udata->retaddr_column, val, udata); -} - -/* Given the current frame UDATA and its return address PC, return the - information about the calling frame in CALLER_UDATA. */ - -static void * -next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata) -{ - caller_udata = __frame_state_for (pc, caller_udata); - if (! caller_udata) - return 0; - - /* Now go back to our caller's stack frame. If our caller's CFA register - was saved in our stack frame, restore it; otherwise, assume the CFA - register is SP and restore it to our CFA value. */ - if (udata->saved[caller_udata->cfa_reg]) - caller_udata->cfa = get_reg (caller_udata->cfa_reg, udata, 0); - else - caller_udata->cfa = udata->cfa; - if (caller_udata->indirect) - caller_udata->cfa = * (void **) ((unsigned char *)caller_udata->cfa - + caller_udata->base_offset); - caller_udata->cfa += caller_udata->cfa_offset; - - return caller_udata; -} - -/* Hook to call before __terminate if only cleanup handlers remain. */ -void -__unwinding_cleanup (void) -{ -} - -/* throw_helper performs some of the common grunt work for a throw. This - routine is called by throw and rethrows. This is pretty much split - out from the old __throw routine. An addition has been added which allows - for a dummy call to a routine __unwinding_cleanup() when there are nothing - but cleanups remaining. This allows a debugger to examine the state - at which the throw was executed, before any cleanups, rather than - at the terminate point after the stack has been unwound. - - EH is the current eh_context structure. - PC is the address of the call to __throw. - MY_UDATA is the unwind information for __throw. - OFFSET_P is where we return the SP adjustment offset. */ - -static void * -throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata, - long *offset_p) -{ - frame_state ustruct2, *udata = &ustruct2; - frame_state ustruct; - frame_state *sub_udata = &ustruct; - void *saved_pc = pc; - void *handler; - void *handler_p = 0; - void *pc_p = 0; - frame_state saved_ustruct; - int new_eh_model; - int cleanup = 0; - int only_cleanup = 0; - int rethrow = 0; - int saved_state = 0; - long args_size; - __eh_info *eh_info = (__eh_info *)eh->info; - - /* Do we find a handler based on a re-throw PC? */ - if (eh->table_index != (void *) 0) - rethrow = 1; - - memcpy (udata, my_udata, sizeof (*udata)); - - handler = (void *) 0; - for (;;) - { - frame_state *p = udata; - udata = next_stack_level (pc, udata, sub_udata); - sub_udata = p; - - /* If we couldn't find the next frame, we lose. */ - if (! udata) - break; - - if (udata->eh_ptr == NULL) - new_eh_model = 0; - else - new_eh_model = (((exception_descriptor *)(udata->eh_ptr))-> - runtime_id_field == NEW_EH_RUNTIME); - - if (rethrow) - { - rethrow = 0; - handler = find_exception_handler (eh->table_index, udata->eh_ptr, - eh_info, 1, &cleanup); - eh->table_index = (void *)0; - } - else - if (new_eh_model) - handler = find_exception_handler (pc, udata->eh_ptr, eh_info, - 0, &cleanup); - else - handler = old_find_exception_handler (pc, udata->eh_ptr); - - /* If we found one, we can stop searching, if its not a cleanup. - for cleanups, we save the state, and keep looking. This allows - us to call a debug hook if there are nothing but cleanups left. */ - if (handler) - { - if (cleanup) - { - if (!saved_state) - { - saved_ustruct = *udata; - handler_p = handler; - pc_p = pc; - saved_state = 1; - only_cleanup = 1; - } - } - else - { - only_cleanup = 0; - break; - } - } - - /* Otherwise, we continue searching. We subtract 1 from PC to avoid - hitting the beginning of the next region. */ - pc = get_return_addr (udata, sub_udata) - 1; - } - - if (saved_state) - { - udata = &saved_ustruct; - handler = handler_p; - pc = pc_p; - if (only_cleanup) - __unwinding_cleanup (); - } - - /* If we haven't found a handler by now, this is an unhandled - exception. */ - if (! handler) - __terminate(); - - eh->handler_label = handler; - - args_size = udata->args_size; - - if (pc == saved_pc) - /* We found a handler in the throw context, no need to unwind. */ - udata = my_udata; - else - { - int i; - - /* Unwind all the frames between this one and the handler by copying - their saved register values into our register save slots. */ - - /* Remember the PC where we found the handler. */ - void *handler_pc = pc; - - /* Start from the throw context again. */ - pc = saved_pc; - memcpy (udata, my_udata, sizeof (*udata)); - - while (pc != handler_pc) - { - frame_state *p = udata; - udata = next_stack_level (pc, udata, sub_udata); - sub_udata = p; - - for (i = 0; i < DWARF_FRAME_REGISTERS; ++i) - if (i != udata->retaddr_column && udata->saved[i]) - { - /* If you modify the saved value of the return address - register on the SPARC, you modify the return address for - your caller's frame. Don't do that here, as it will - confuse get_return_addr. */ - if (in_reg_window (i, udata) - && udata->saved[udata->retaddr_column] == REG_SAVED_REG - && udata->reg_or_offset[udata->retaddr_column] == i) - continue; - copy_reg (i, udata, my_udata); - } - - pc = get_return_addr (udata, sub_udata) - 1; - } - - /* But we do need to update the saved return address register from - the last frame we unwind, or the handler frame will have the wrong - return address. */ - if (udata->saved[udata->retaddr_column] == REG_SAVED_REG) - { - i = udata->reg_or_offset[udata->retaddr_column]; - if (in_reg_window (i, udata)) - copy_reg (i, udata, my_udata); - } - } - /* udata now refers to the frame called by the handler frame. */ - - /* We adjust SP by the difference between __throw's CFA and the CFA for - the frame called by the handler frame, because those CFAs correspond - to the SP values at the two call sites. We need to further adjust by - the args_size of the handler frame itself to get the handler frame's - SP from before the args were pushed for that call. */ -#ifdef STACK_GROWS_DOWNWARD - *offset_p = udata->cfa - my_udata->cfa + args_size; -#else - *offset_p = my_udata->cfa - udata->cfa - args_size; -#endif - - return handler; -} - - -/* We first search for an exception handler, and if we don't find - it, we call __terminate on the current stack frame so that we may - use the debugger to walk the stack and understand why no handler - was found. - - If we find one, then we unwind the frames down to the one that - has the handler and transfer control into the handler. */ - -/*extern void __throw(void) __attribute__ ((__noreturn__));*/ - -void -__throw (void) -{ - struct eh_context *eh = (*get_eh_context) (); - void *pc, *handler; - long offset; - - /* XXX maybe make my_ustruct static so we don't have to look it up for - each throw. */ - frame_state my_ustruct, *my_udata = &my_ustruct; - - /* This is required for C++ semantics. We must call terminate if we - try and rethrow an exception, when there is no exception currently - active. */ - if (! eh->info) - __terminate (); - - /* Start at our stack frame. */ -label: - my_udata = __frame_state_for (&&label, my_udata); - if (! my_udata) - __terminate (); - - /* We need to get the value from the CFA register. */ - my_udata->cfa = __builtin_dwarf_cfa (); - - /* Do any necessary initialization to access arbitrary stack frames. - On the SPARC, this means flushing the register windows. */ - __builtin_unwind_init (); - - /* Now reset pc to the right throw point. */ - pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1; - - handler = throw_helper (eh, pc, my_udata, &offset); - - /* Now go! */ - - __builtin_eh_return ((void *)eh, offset, handler); - - /* Epilogue: restore the handler frame's register values and return - to the stub. */ -} - -/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/ - -void -__rethrow (void *index) -{ - struct eh_context *eh = (*get_eh_context) (); - void *pc, *handler; - long offset; - - /* XXX maybe make my_ustruct static so we don't have to look it up for - each throw. */ - frame_state my_ustruct, *my_udata = &my_ustruct; - - /* This is required for C++ semantics. We must call terminate if we - try and rethrow an exception, when there is no exception currently - active. */ - if (! eh->info) - __terminate (); - - /* This is the table index we want to rethrow from. The value of - the END_REGION label is used for the PC of the throw, and the - search begins with the next table entry. */ - eh->table_index = index; - - /* Start at our stack frame. */ -label: - my_udata = __frame_state_for (&&label, my_udata); - if (! my_udata) - __terminate (); - - /* We need to get the value from the CFA register. */ - my_udata->cfa = __builtin_dwarf_cfa (); - - /* Do any necessary initialization to access arbitrary stack frames. - On the SPARC, this means flushing the register windows. */ - __builtin_unwind_init (); - - /* Now reset pc to the right throw point. */ - pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1; - - handler = throw_helper (eh, pc, my_udata, &offset); - - /* Now go! */ - - __builtin_eh_return ((void *)eh, offset, handler); - - /* Epilogue: restore the handler frame's register values and return - to the stub. */ -} -#endif /* DWARF2_UNWIND_INFO */ - -#ifdef IA64_UNWIND_INFO -#include "frame.h" - -/* Return handler to which we want to transfer control, NULL if we don't - intend to handle this exception here. */ -void * -__ia64_personality_v1 (void *pc, old_exception_table *table) -{ - if (table) - { - int pos; - int best = -1; - - for (pos = 0; table[pos].start_region != (void *) -1; ++pos) - { - if (table[pos].start_region <= pc && table[pos].end_region > pc) - { - /* This can apply. Make sure it is at least as small as - the previous best. */ - if (best == -1 || (table[pos].end_region <= table[best].end_region - && table[pos].start_region >= table[best].start_region)) - best = pos; - } - /* It is sorted by starting PC within a function. */ - else if (best >= 0 && table[pos].start_region > pc) - break; - } - if (best != -1) - return table[best].exception_handler; - } - return (void *) 0; -} - -static void -ia64_throw_helper (ia64_frame_state *throw_frame, ia64_frame_state *caller, - void *throw_bsp, void *throw_sp) -{ - void *throw_pc = __builtin_return_address (0); - unwind_info_ptr *info; - void *pc, *handler = NULL; - void *pc_base; - int frame_count; - void *bsp; - - __builtin_ia64_flushrs (); /* Make the local register stacks available. */ - - /* Start at our stack frame, get our state. */ - __build_ia64_frame_state (throw_pc, throw_frame, throw_bsp, throw_sp, - &pc_base); - - /* Now we have to find the proper frame for pc, and see if there - is a handler for it. if not, we keep going back frames until - we do find one. Otherwise we call uncaught (). */ - - frame_count = 0; - memcpy (caller, throw_frame, sizeof (*caller)); - while (!handler) - { - void *(*personality) (); - void *eh_table; - - frame_count++; - /* We only care about the RP right now, so we dont need to keep - any other information about a call frame right now. */ - pc = __get_real_reg_value (&caller->rp) - 1; - bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs), - caller->my_bsp); - info = __build_ia64_frame_state (pc, caller, bsp, caller->my_psp, - &pc_base); - - /* If we couldn't find the next frame, we lose. */ - if (! info) - break; - - personality = __get_personality (info); - /* TODO Haven't figured out how to actually load the personality address - yet, so just always default to the one we expect for now. */ - if (personality != 0) - personality = __ia64_personality_v1; - eh_table = __get_except_table (info); - /* If there is no personality routine, we'll keep unwinding. */ - if (personality) - /* Pass a segment relative PC address to the personality routine, - because the unwind_info section uses segrel relocs. */ - handler = personality (pc - pc_base, eh_table); - } - - if (!handler) - __terminate (); - - /* Handler is a segment relative address, so we must adjust it here. */ - handler += (long) pc_base; - - /* If we found a handler, we need to unwind the stack to that point. - We do this by copying saved values from previous frames into the - save slot for the throw_frame saved slots. when __throw returns, - it'll pickup the correct values. */ - - /* Start with where __throw saved things, and copy each saved register - of each previous frame until we get to the one before we're - throwing back to. */ - memcpy (caller, throw_frame, sizeof (*caller)); - for ( ; frame_count > 0; frame_count--) - { - pc = __get_real_reg_value (&caller->rp) - 1; - bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs), - caller->my_bsp); - __build_ia64_frame_state (pc, caller, bsp, caller->my_psp, &pc_base); - /* Any regs that were saved can be put in the throw frame now. */ - /* We don't want to copy any saved register from the - target destination, but we do want to load up it's frame. */ - if (frame_count > 1) - __copy_saved_reg_state (throw_frame, caller); - } - - /* Set return address of the throw frame to the handler. */ - __set_real_reg_value (&throw_frame->rp, handler); - - /* TODO, do we need to do anything to make the values we wrote 'stick'? */ - /* DO we need to go through the whole loadrs seqeunce? */ -} - - -void -__throw () -{ - register void *stack_pointer __asm__("r12"); - struct eh_context *eh = (*get_eh_context) (); - ia64_frame_state my_frame; - ia64_frame_state originator; /* For the context handler is in. */ - void *bsp, *tmp_bsp; - long offset; - - /* This is required for C++ semantics. We must call terminate if we - try and rethrow an exception, when there is no exception currently - active. */ - if (! eh->info) - __terminate (); - - __builtin_unwind_init (); - - /* We have to call another routine to actually process the frame - information, which will force all of __throw's local registers into - backing store. */ - - /* Get the value of ar.bsp while we're here. */ - - bsp = __builtin_ia64_bsp (); - ia64_throw_helper (&my_frame, &originator, bsp, stack_pointer); - - /* Now we have to fudge the bsp by the amount in our (__throw) - frame marker, since the return is going to adjust it by that much. */ - - tmp_bsp = __calc_caller_bsp ((long)__get_real_reg_value (&my_frame.pfs), - my_frame.my_bsp); - offset = (char *)my_frame.my_bsp - (char *)tmp_bsp; - tmp_bsp = (char *)originator.my_bsp + offset; - - __builtin_eh_return (tmp_bsp, offset, originator.my_sp); - - /* The return address was already set by throw_helper. */ -} - -#endif /* IA64_UNWIND_INFO */ - -#endif /* L_eh */