aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/libgcc
diff options
context:
space:
mode:
authorYiran Wang <yiran@google.com>2015-06-23 15:33:17 -0700
committerYiran Wang <yiran@google.com>2015-06-29 10:56:28 -0700
commit1d9fec7937f45dde5e04cac966a2d9a12f2fc15a (patch)
tree3fbcd18a379a05fd6d43491a107e1f36bc61b185 /gcc-4.9/libgcc
parentf378ebf14df0952eae870c9865bab8326aa8f137 (diff)
downloadtoolchain_gcc-1d9fec7937f45dde5e04cac966a2d9a12f2fc15a.tar.gz
toolchain_gcc-1d9fec7937f45dde5e04cac966a2d9a12f2fc15a.tar.bz2
toolchain_gcc-1d9fec7937f45dde5e04cac966a2d9a12f2fc15a.zip
Synchronize with google/gcc-4_9 to r224707 (from r214835)
Change-Id: I3d6f06fc613c8f8b6a82143dc44b7338483aac5d
Diffstat (limited to 'gcc-4.9/libgcc')
-rw-r--r--gcc-4.9/libgcc/ChangeLog79
-rw-r--r--gcc-4.9/libgcc/Makefile.in12
-rw-r--r--gcc-4.9/libgcc/config/avr/lib1funcs.S229
-rw-r--r--gcc-4.9/libgcc/config/avr/t-avr3
-rw-r--r--gcc-4.9/libgcc/config/i386/sfp-machine.h2
-rw-r--r--gcc-4.9/libgcc/config/libbid/ChangeLog4
-rw-r--r--gcc-4.9/libgcc/config/nios2/linux-unwind.h3
-rw-r--r--gcc-4.9/libgcc/config/pa/linux-atomic.c304
-rw-r--r--gcc-4.9/libgcc/config/pa/linux-unwind.h34
-rw-r--r--gcc-4.9/libgcc/config/sh/lib1funcs.S18
-rw-r--r--gcc-4.9/libgcc/dyn-ipa.c111
-rw-r--r--gcc-4.9/libgcc/libgcov-driver-kernel.c203
-rw-r--r--gcc-4.9/libgcc/libgcov-driver-system.c23
-rw-r--r--gcc-4.9/libgcc/libgcov-driver.c469
-rw-r--r--gcc-4.9/libgcc/libgcov-kernel.h121
-rw-r--r--gcc-4.9/libgcc/libgcov-merge.c2
-rw-r--r--gcc-4.9/libgcc/libgcov-profiler.c136
-rw-r--r--gcc-4.9/libgcc/libgcov-util.c684
-rw-r--r--gcc-4.9/libgcc/libgcov.h40
19 files changed, 1950 insertions, 527 deletions
diff --git a/gcc-4.9/libgcc/ChangeLog b/gcc-4.9/libgcc/ChangeLog
index d17c8c8a9..44b3f37e1 100644
--- a/gcc-4.9/libgcc/ChangeLog
+++ b/gcc-4.9/libgcc/ChangeLog
@@ -1,3 +1,76 @@
+2015-01-20 Chung-Lin Tang <cltang@codesourcery.com>
+
+ Backport from mainline
+ * config/nios2/linux-unwind.h (nios2_fallback_frame_state):
+ Update rt_sigframe format and address for current Nios II
+ Linux conventions.
+
+2014-12-09 John David Anglin <danglin@gcc.gnu.org>
+
+ Backport from mainline
+ 2014-11-24 John David Anglin <danglin@gcc.gnu.org>
+
+ * config/pa/linux-atomic.c (ABORT_INSTRUCTION): Use __builtin_trap()
+ instead.
+
+ 2014-11-21 Guy Martin <gmsoft@tuxicoman.be>
+ John David Anglin <danglin@gcc.gnu.org>
+
+ * config/pa/linux-atomic.c (__kernel_cmpxchg2): New.
+ (FETCH_AND_OP_2): New. Use for subword and double word operations.
+ (OP_AND_FETCH_2): Likewise.
+ (COMPARE_AND_SWAP_2): Likewise.
+ (SYNC_LOCK_TEST_AND_SET_2): Likewise.
+ (SYNC_LOCK_RELEASE_2): Likewise.
+ (SUBWORD_SYNC_OP): Remove.
+ (SUBWORD_VAL_CAS): Likewise.
+ (SUBWORD_BOOL_CAS): Likewise.
+ (FETCH_AND_OP_WORD): Update.
+ Consistently use signed types.
+
+2014-12-09 Oleg Endo <olegendo@gcc.gnu.org>
+
+ Backport from mainline
+ 2014-11-30 Oleg Endo <olegendo@gcc.gnu.org>
+
+ PR target/55351
+ * config/sh/lib1funcs.S: Check value of __SHMEDIA__ instead of checking
+ whether it's defined.
+
+2014-10-30 Release Manager
+
+ * GCC 4.9.2 released.
+
+2014-10-26 John David Anglin <danglin@gcc.gnu.org>
+
+ * config/pa/linux-unwind.h (pa32_read_access_ok): New function.
+ (pa32_fallback_frame_state): Use pa32_read_access_ok to check if
+ memory read accesses are ok.
+
+2014-10-22 Georg-Johann Lay <avr@gjlay.de>
+
+ PR target/63223
+ * config/avr/lib1funcs.S (__do_global_dtors): Reverse execution
+ order to first...last.
+
+2014-09-18 Joseph Myers <joseph@codesourcery.com>
+
+ * config/i386/sfp-machine.h (FP_TRAPPING_EXCEPTIONS): Treat clear
+ bits not set bits as indicating trapping exceptions.
+
+2014-09-11 Georg-Johann Lay <avr@gjlay.de>
+
+ Backport from 2014-09-11 trunk r215152.
+
+ PR target/63223
+ * config/avr/libgcc.S (__tablejump2__): Rewrite to use RAMPZ, ELPM
+ and R24 as needed. Make work for all devices and .text locations.
+ (__do_global_ctors, __do_global_dtors): Use word addresses.
+ (__tablejump__, __tablejump_elpm__): Remove functions.
+ * t-avr (LIB1ASMFUNCS): Remove _tablejump, _tablejump_elpm.
+ Add _tablejump2.
+ (XICALL, XIJMP): New macros.
+
2014-08-04 Rohit <rohitarulraj@freescale.com>
PR target/60102
@@ -57,7 +130,7 @@
(__gcov_delta_counter_op): Process delta profile counter values.
(__gcov_single_counter_op): Process single profile counter values.
(fp_scale): Callback function for float-point scaling.
- (int_scale): Callback function for integer fraction scaling.
+ (int_scale): Callback function for integer fraction scaling.
(gcov_profile_scale): Scaling profile counters.
(gcov_profile_normalize): Normalize profile counters.
* libgcov.h: Add headers and functions for gcov-tool use.
@@ -458,7 +531,7 @@
(gcov_exit_merge_summary): Ditto.
(gcov_exit_dump_gcov): Ditto.
-2014-01-08 Rong Xu <xur@google.com>
+2014-01-08 Rong Xu <xur@google.com>
* libgcov-driver.c: Use libgcov.h.
(buffer_fn_data): Use xmalloc instead of malloc.
@@ -1348,7 +1421,7 @@
* config/mips/crtn.S (fini, init): New labels.
2012-02-19 Edgar E. Iglesias <edgar.iglesias@gmail.com>
- * config/microblaze/modsi3.S (modsi3): Fix case with 0x80000000
+ * config/microblaze/modsi3.S (modsi3): Fix case with 0x80000000
as dividend.
2013-02-16 Alan Modra <amodra@gmail.com>
diff --git a/gcc-4.9/libgcc/Makefile.in b/gcc-4.9/libgcc/Makefile.in
index 1e941f29f..a8122c1bb 100644
--- a/gcc-4.9/libgcc/Makefile.in
+++ b/gcc-4.9/libgcc/Makefile.in
@@ -1147,10 +1147,14 @@ install-leaf: $(install-shared) $(install-libunwind)
cp ../../gcc/gcov-iov.h $$gcov_src_dest; \
cp $(srcdir)/../gcc/gcov-io.h $$gcov_src_dest; \
cp $(srcdir)/../gcc/gcov-io.c $$gcov_src_dest; \
- cp $(srcdir)/libgcov-driver.c $$gcov_src_dest; \
- chmod 644 $$gcov_src_dest/gcov-iov.h \
- $$gcov_src_dest/gcov-io.h $$gcov_src_dest/gcov-io.c \
- $$gcov_src_dest/libgcov-driver.c; \
+ cp $(srcdir)/../gcc/gcov-counter.def $$gcov_src_dest; \
+ cp $(srcdir)/libgcov-driver.c $$gcov_src_dest; \
+ cp $(srcdir)/libgcov-driver-kernel.c $$gcov_src_dest; \
+ cp $(srcdir)/libgcov.h $$gcov_src_dest; \
+ cp $(srcdir)/libgcov-kernel.h $$gcov_src_dest; \
+ cp $(srcdir)/libgcov-profiler.c $$gcov_src_dest; \
+ cp $(srcdir)/libgcov-merge.c $$gcov_src_dest; \
+ chmod 644 $$gcov_src_dest/*.[ch]; \
fi
install: install-leaf install-unwind_h
diff --git a/gcc-4.9/libgcc/config/avr/lib1funcs.S b/gcc-4.9/libgcc/config/avr/lib1funcs.S
index 6f1c77edb..5ad1e93f1 100644
--- a/gcc-4.9/libgcc/config/avr/lib1funcs.S
+++ b/gcc-4.9/libgcc/config/avr/lib1funcs.S
@@ -46,6 +46,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
input sections together are small enough to reach every
location with a RCALL/RJMP instruction. */
+#if defined (__AVR_HAVE_EIJMP_EICALL__) && !defined (__AVR_HAVE_ELPMX__)
+#error device not supported
+#endif
+
.macro mov_l r_dest, r_src
#if defined (__AVR_HAVE_MOVW__)
movw \r_dest, \r_src
@@ -79,6 +83,14 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define XJMP rjmp
#endif
+#if defined (__AVR_HAVE_EIJMP_EICALL__)
+#define XICALL eicall
+#define XIJMP eijmp
+#else
+#define XICALL icall
+#define XIJMP ijmp
+#endif
+
;; Prologue stuff
.macro do_prologue_saves n_pushed n_frame=0
@@ -2127,11 +2139,7 @@ DEFUN __prologue_saves__
out __SP_L__,r28
#endif /* #SP = 8/16 */
-#if defined (__AVR_HAVE_EIJMP_EICALL__)
- eijmp
-#else
- ijmp
-#endif
+ XIJMP
ENDF __prologue_saves__
#endif /* defined (L_prologue) */
@@ -2213,38 +2221,54 @@ _cleanup:
.section .text.libgcc, "ax", @progbits
-#ifdef L_tablejump
+#ifdef L_tablejump2
DEFUN __tablejump2__
- lsl r30
- rol r31
- ;; FALLTHRU
-ENDF __tablejump2__
-
-DEFUN __tablejump__
-#if defined (__AVR_HAVE_LPMX__)
- lpm __tmp_reg__, Z+
- lpm r31, Z
- mov r30, __tmp_reg__
+ lsl r30
+ rol r31
#if defined (__AVR_HAVE_EIJMP_EICALL__)
- eijmp
-#else
- ijmp
+ ;; Word address of gs() jumptable entry in R24:Z
+ rol r24
+ out __RAMPZ__, r24
+#elif defined (__AVR_HAVE_ELPM__)
+ ;; Word address of jumptable entry in Z
+ clr __tmp_reg__
+ rol __tmp_reg__
+ out __RAMPZ__, __tmp_reg__
#endif
-#else /* !HAVE_LPMX */
- lpm
- adiw r30, 1
- push r0
- lpm
- push r0
-#if defined (__AVR_HAVE_EIJMP_EICALL__)
- in __tmp_reg__, __EIND__
- push __tmp_reg__
+ ;; Read word address from jumptable and jump
+
+#if defined (__AVR_HAVE_ELPMX__)
+ elpm __tmp_reg__, Z+
+ elpm r31, Z
+ mov r30, __tmp_reg__
+#ifdef __AVR_HAVE_RAMPD__
+ ;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM
+ out __RAMPZ__, __zero_reg__
+#endif /* RAMPD */
+ XIJMP
+#elif defined (__AVR_HAVE_ELPM__)
+ elpm
+ push r0
+ adiw r30, 1
+ elpm
+ push r0
+ ret
+#elif defined (__AVR_HAVE_LPMX__)
+ lpm __tmp_reg__, Z+
+ lpm r31, Z
+ mov r30, __tmp_reg__
+ ijmp
+#else
+ lpm
+ push r0
+ adiw r30, 1
+ lpm
+ push r0
+ ret
#endif
- ret
-#endif /* !HAVE_LPMX */
-ENDF __tablejump__
-#endif /* defined (L_tablejump) */
+ENDF __tablejump2__
+#endif /* L_tablejump2 */
#ifdef L_copy_data
.section .init4,"ax",@progbits
@@ -2336,116 +2360,67 @@ ENDF __do_clear_bss
#ifdef L_ctors
.section .init6,"ax",@progbits
DEFUN __do_global_ctors
-#if defined(__AVR_HAVE_ELPM__)
- ldi r17, hi8(__ctors_start)
- ldi r28, lo8(__ctors_end)
- ldi r29, hi8(__ctors_end)
- ldi r16, hh8(__ctors_end)
- rjmp .L__do_global_ctors_start
+ ldi r17, pm_hi8(__ctors_start)
+ ldi r28, pm_lo8(__ctors_end)
+ ldi r29, pm_hi8(__ctors_end)
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ ldi r16, pm_hh8(__ctors_end)
+#endif /* HAVE_EIJMP */
+ rjmp .L__do_global_ctors_start
.L__do_global_ctors_loop:
- sbiw r28, 2
- sbc r16, __zero_reg__
- mov_h r31, r29
- mov_l r30, r28
- out __RAMPZ__, r16
- XCALL __tablejump_elpm__
+ sbiw r28, 1
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ sbc r16, __zero_reg__
+ mov r24, r16
+#endif /* HAVE_EIJMP */
+ mov_h r31, r29
+ mov_l r30, r28
+ XCALL __tablejump2__
.L__do_global_ctors_start:
- cpi r28, lo8(__ctors_start)
- cpc r29, r17
- ldi r24, hh8(__ctors_start)
- cpc r16, r24
- brne .L__do_global_ctors_loop
-#else
- ldi r17, hi8(__ctors_start)
- ldi r28, lo8(__ctors_end)
- ldi r29, hi8(__ctors_end)
- rjmp .L__do_global_ctors_start
-.L__do_global_ctors_loop:
- sbiw r28, 2
- mov_h r31, r29
- mov_l r30, r28
- XCALL __tablejump__
-.L__do_global_ctors_start:
- cpi r28, lo8(__ctors_start)
- cpc r29, r17
- brne .L__do_global_ctors_loop
-#endif /* defined(__AVR_HAVE_ELPM__) */
+ cpi r28, pm_lo8(__ctors_start)
+ cpc r29, r17
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ ldi r24, pm_hh8(__ctors_start)
+ cpc r16, r24
+#endif /* HAVE_EIJMP */
+ brne .L__do_global_ctors_loop
ENDF __do_global_ctors
#endif /* L_ctors */
#ifdef L_dtors
.section .fini6,"ax",@progbits
DEFUN __do_global_dtors
-#if defined(__AVR_HAVE_ELPM__)
- ldi r17, hi8(__dtors_end)
- ldi r28, lo8(__dtors_start)
- ldi r29, hi8(__dtors_start)
- ldi r16, hh8(__dtors_start)
- rjmp .L__do_global_dtors_start
+ ldi r17, pm_hi8(__dtors_end)
+ ldi r28, pm_lo8(__dtors_start)
+ ldi r29, pm_hi8(__dtors_start)
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ ldi r16, pm_hh8(__dtors_start)
+#endif /* HAVE_EIJMP */
+ rjmp .L__do_global_dtors_start
.L__do_global_dtors_loop:
- sbiw r28, 2
- sbc r16, __zero_reg__
- mov_h r31, r29
- mov_l r30, r28
- out __RAMPZ__, r16
- XCALL __tablejump_elpm__
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ mov r24, r16
+#endif /* HAVE_EIJMP */
+ mov_h r31, r29
+ mov_l r30, r28
+ XCALL __tablejump2__
+ adiw r28, 1
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ adc r16, __zero_reg__
+#endif /* HAVE_EIJMP */
.L__do_global_dtors_start:
- cpi r28, lo8(__dtors_end)
- cpc r29, r17
- ldi r24, hh8(__dtors_end)
- cpc r16, r24
- brne .L__do_global_dtors_loop
-#else
- ldi r17, hi8(__dtors_end)
- ldi r28, lo8(__dtors_start)
- ldi r29, hi8(__dtors_start)
- rjmp .L__do_global_dtors_start
-.L__do_global_dtors_loop:
- mov_h r31, r29
- mov_l r30, r28
- XCALL __tablejump__
- adiw r28, 2
-.L__do_global_dtors_start:
- cpi r28, lo8(__dtors_end)
- cpc r29, r17
- brne .L__do_global_dtors_loop
-#endif /* defined(__AVR_HAVE_ELPM__) */
+ cpi r28, pm_lo8(__dtors_end)
+ cpc r29, r17
+#ifdef __AVR_HAVE_EIJMP_EICALL__
+ ldi r24, pm_hh8(__dtors_end)
+ cpc r16, r24
+#endif /* HAVE_EIJMP */
+ brne .L__do_global_dtors_loop
ENDF __do_global_dtors
#endif /* L_dtors */
.section .text.libgcc, "ax", @progbits
-#ifdef L_tablejump_elpm
-DEFUN __tablejump_elpm__
-#if defined (__AVR_HAVE_ELPMX__)
- elpm __tmp_reg__, Z+
- elpm r31, Z
- mov r30, __tmp_reg__
-#if defined (__AVR_HAVE_RAMPD__)
- ;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM
- out __RAMPZ__, __zero_reg__
-#endif /* RAMPD */
-#if defined (__AVR_HAVE_EIJMP_EICALL__)
- eijmp
-#else
- ijmp
-#endif
-
-#elif defined (__AVR_HAVE_ELPM__)
- elpm
- adiw r30, 1
- push r0
- elpm
- push r0
-#if defined (__AVR_HAVE_EIJMP_EICALL__)
- in __tmp_reg__, __EIND__
- push __tmp_reg__
-#endif
- ret
-#endif
-ENDF __tablejump_elpm__
-#endif /* defined (L_tablejump_elpm) */
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Loading n bytes from Flash; n = 3,4
;; R22... = Flash[Z]
diff --git a/gcc-4.9/libgcc/config/avr/t-avr b/gcc-4.9/libgcc/config/avr/t-avr
index 461304706..1f7356968 100644
--- a/gcc-4.9/libgcc/config/avr/t-avr
+++ b/gcc-4.9/libgcc/config/avr/t-avr
@@ -26,8 +26,7 @@ LIB1ASMFUNCS = \
_epilogue \
_exit \
_cleanup \
- _tablejump \
- _tablejump_elpm \
+ _tablejump2 \
_load_3 _load_4 \
_xload_1 _xload_2 _xload_3 _xload_4 \
_movmemx \
diff --git a/gcc-4.9/libgcc/config/i386/sfp-machine.h b/gcc-4.9/libgcc/config/i386/sfp-machine.h
index 148044a69..8a1923b6c 100644
--- a/gcc-4.9/libgcc/config/i386/sfp-machine.h
+++ b/gcc-4.9/libgcc/config/i386/sfp-machine.h
@@ -60,7 +60,7 @@ void __sfp_handle_exceptions (int);
__sfp_handle_exceptions (_fex); \
} while (0);
-#define FP_TRAPPING_EXCEPTIONS ((_fcw >> FP_EX_SHIFT) & FP_EX_ALL)
+#define FP_TRAPPING_EXCEPTIONS ((~_fcw >> FP_EX_SHIFT) & FP_EX_ALL)
#define FP_ROUNDMODE (_fcw & FP_RND_MASK)
#endif
diff --git a/gcc-4.9/libgcc/config/libbid/ChangeLog b/gcc-4.9/libgcc/config/libbid/ChangeLog
index c3f83862a..68d46d29f 100644
--- a/gcc-4.9/libgcc/config/libbid/ChangeLog
+++ b/gcc-4.9/libgcc/config/libbid/ChangeLog
@@ -1,3 +1,7 @@
+2014-10-30 Release Manager
+
+ * GCC 4.9.2 released.
+
2014-07-16 Release Manager
* GCC 4.9.1 released.
diff --git a/gcc-4.9/libgcc/config/nios2/linux-unwind.h b/gcc-4.9/libgcc/config/nios2/linux-unwind.h
index 92ff1f629..ba4bd801d 100644
--- a/gcc-4.9/libgcc/config/nios2/linux-unwind.h
+++ b/gcc-4.9/libgcc/config/nios2/linux-unwind.h
@@ -67,10 +67,9 @@ nios2_fallback_frame_state (struct _Unwind_Context *context,
if (pc[0] == (0x00800004 | (__NR_rt_sigreturn << 6)))
{
struct rt_sigframe {
- char retcode[12];
siginfo_t info;
struct nios2_ucontext uc;
- } *rt_ = context->ra;
+ } *rt_ = context->cfa;
struct nios2_mcontext *regs = &rt_->uc.uc_mcontext;
int i;
diff --git a/gcc-4.9/libgcc/config/pa/linux-atomic.c b/gcc-4.9/libgcc/config/pa/linux-atomic.c
index d92d6ef79..19e37b6f3 100644
--- a/gcc-4.9/libgcc/config/pa/linux-atomic.c
+++ b/gcc-4.9/libgcc/config/pa/linux-atomic.c
@@ -41,11 +41,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
using the kernel helper defined below. There is no support for
64-bit operations yet. */
-/* A privileged instruction to crash a userspace program with SIGILL. */
-#define ABORT_INSTRUCTION asm ("iitlbp %r0,(%sr0, %r0)")
-
/* Determine kernel LWS function call (0=32-bit, 1=64-bit userspace). */
-#define LWS_CAS (sizeof(unsigned long) == 4 ? 0 : 1)
+#define LWS_CAS (sizeof(long) == 4 ? 0 : 1)
/* Kernel helper for compare-and-exchange a 32-bit value. */
static inline long
@@ -64,7 +61,7 @@ __kernel_cmpxchg (int oldval, int newval, int *mem)
: "r1", "r20", "r22", "r23", "r29", "r31", "memory"
);
if (__builtin_expect (lws_errno == -EFAULT || lws_errno == -ENOSYS, 0))
- ABORT_INSTRUCTION;
+ __builtin_trap ();
/* If the kernel LWS call succeeded (lws_errno == 0), lws_ret contains
the old value from memory. If this value is equal to OLDVAL, the
@@ -75,6 +72,30 @@ __kernel_cmpxchg (int oldval, int newval, int *mem)
return lws_errno;
}
+static inline long
+__kernel_cmpxchg2 (void * oldval, void * newval, void *mem, int val_size)
+{
+ register unsigned long lws_mem asm("r26") = (unsigned long) (mem);
+ register long lws_ret asm("r28");
+ register long lws_errno asm("r21");
+ register unsigned long lws_old asm("r25") = (unsigned long) oldval;
+ register unsigned long lws_new asm("r24") = (unsigned long) newval;
+ register int lws_size asm("r23") = val_size;
+ asm volatile ( "ble 0xb0(%%sr2, %%r0) \n\t"
+ "ldi %2, %%r20 \n\t"
+ : "=r" (lws_ret), "=r" (lws_errno)
+ : "i" (2), "r" (lws_mem), "r" (lws_old), "r" (lws_new), "r" (lws_size)
+ : "r1", "r20", "r22", "r29", "r31", "fr4", "memory"
+ );
+ if (__builtin_expect (lws_errno == -EFAULT || lws_errno == -ENOSYS, 0))
+ __builtin_trap ();
+
+ /* If the kernel LWS call fails, retrun EBUSY */
+ if (!lws_errno && lws_ret)
+ lws_errno = -EBUSY;
+
+ return lws_errno;
+}
#define HIDDEN __attribute__ ((visibility ("hidden")))
/* Big endian masks */
@@ -84,6 +105,80 @@ __kernel_cmpxchg (int oldval, int newval, int *mem)
#define MASK_1 0xffu
#define MASK_2 0xffffu
+#define FETCH_AND_OP_2(OP, PFX_OP, INF_OP, TYPE, WIDTH, INDEX) \
+ TYPE HIDDEN \
+ __sync_fetch_and_##OP##_##WIDTH (TYPE *ptr, TYPE val) \
+ { \
+ TYPE tmp, newval; \
+ int failure; \
+ \
+ do { \
+ tmp = *ptr; \
+ newval = PFX_OP (tmp INF_OP val); \
+ failure = __kernel_cmpxchg2 (&tmp, &newval, ptr, INDEX); \
+ } while (failure != 0); \
+ \
+ return tmp; \
+ }
+
+FETCH_AND_OP_2 (add, , +, long long, 8, 3)
+FETCH_AND_OP_2 (sub, , -, long long, 8, 3)
+FETCH_AND_OP_2 (or, , |, long long, 8, 3)
+FETCH_AND_OP_2 (and, , &, long long, 8, 3)
+FETCH_AND_OP_2 (xor, , ^, long long, 8, 3)
+FETCH_AND_OP_2 (nand, ~, &, long long, 8, 3)
+
+FETCH_AND_OP_2 (add, , +, short, 2, 1)
+FETCH_AND_OP_2 (sub, , -, short, 2, 1)
+FETCH_AND_OP_2 (or, , |, short, 2, 1)
+FETCH_AND_OP_2 (and, , &, short, 2, 1)
+FETCH_AND_OP_2 (xor, , ^, short, 2, 1)
+FETCH_AND_OP_2 (nand, ~, &, short, 2, 1)
+
+FETCH_AND_OP_2 (add, , +, signed char, 1, 0)
+FETCH_AND_OP_2 (sub, , -, signed char, 1, 0)
+FETCH_AND_OP_2 (or, , |, signed char, 1, 0)
+FETCH_AND_OP_2 (and, , &, signed char, 1, 0)
+FETCH_AND_OP_2 (xor, , ^, signed char, 1, 0)
+FETCH_AND_OP_2 (nand, ~, &, signed char, 1, 0)
+
+#define OP_AND_FETCH_2(OP, PFX_OP, INF_OP, TYPE, WIDTH, INDEX) \
+ TYPE HIDDEN \
+ __sync_##OP##_and_fetch_##WIDTH (TYPE *ptr, TYPE val) \
+ { \
+ TYPE tmp, newval; \
+ int failure; \
+ \
+ do { \
+ tmp = *ptr; \
+ newval = PFX_OP (tmp INF_OP val); \
+ failure = __kernel_cmpxchg2 (&tmp, &newval, ptr, INDEX); \
+ } while (failure != 0); \
+ \
+ return PFX_OP (tmp INF_OP val); \
+ }
+
+OP_AND_FETCH_2 (add, , +, long long, 8, 3)
+OP_AND_FETCH_2 (sub, , -, long long, 8, 3)
+OP_AND_FETCH_2 (or, , |, long long, 8, 3)
+OP_AND_FETCH_2 (and, , &, long long, 8, 3)
+OP_AND_FETCH_2 (xor, , ^, long long, 8, 3)
+OP_AND_FETCH_2 (nand, ~, &, long long, 8, 3)
+
+OP_AND_FETCH_2 (add, , +, short, 2, 1)
+OP_AND_FETCH_2 (sub, , -, short, 2, 1)
+OP_AND_FETCH_2 (or, , |, short, 2, 1)
+OP_AND_FETCH_2 (and, , &, short, 2, 1)
+OP_AND_FETCH_2 (xor, , ^, short, 2, 1)
+OP_AND_FETCH_2 (nand, ~, &, short, 2, 1)
+
+OP_AND_FETCH_2 (add, , +, signed char, 1, 0)
+OP_AND_FETCH_2 (sub, , -, signed char, 1, 0)
+OP_AND_FETCH_2 (or, , |, signed char, 1, 0)
+OP_AND_FETCH_2 (and, , &, signed char, 1, 0)
+OP_AND_FETCH_2 (xor, , ^, signed char, 1, 0)
+OP_AND_FETCH_2 (nand, ~, &, signed char, 1, 0)
+
#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \
int HIDDEN \
__sync_fetch_and_##OP##_4 (int *ptr, int val) \
@@ -105,48 +200,6 @@ FETCH_AND_OP_WORD (and, , &)
FETCH_AND_OP_WORD (xor, , ^)
FETCH_AND_OP_WORD (nand, ~, &)
-#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
-#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
-
-/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
- subword-sized quantities. */
-
-#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \
- TYPE HIDDEN \
- NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \
- { \
- int *wordptr = (int *) ((unsigned long) ptr & ~3); \
- unsigned int mask, shift, oldval, newval; \
- int failure; \
- \
- shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
- mask = MASK_##WIDTH << shift; \
- \
- do { \
- oldval = *wordptr; \
- newval = ((PFX_OP (((oldval & mask) >> shift) \
- INF_OP (unsigned int) val)) << shift) & mask; \
- newval |= oldval & ~mask; \
- failure = __kernel_cmpxchg (oldval, newval, wordptr); \
- } while (failure != 0); \
- \
- return (RETURN & mask) >> shift; \
- }
-
-SUBWORD_SYNC_OP (add, , +, unsigned short, 2, oldval)
-SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, oldval)
-SUBWORD_SYNC_OP (or, , |, unsigned short, 2, oldval)
-SUBWORD_SYNC_OP (and, , &, unsigned short, 2, oldval)
-SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, oldval)
-SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, oldval)
-
-SUBWORD_SYNC_OP (add, , +, unsigned char, 1, oldval)
-SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, oldval)
-SUBWORD_SYNC_OP (or, , |, unsigned char, 1, oldval)
-SUBWORD_SYNC_OP (and, , &, unsigned char, 1, oldval)
-SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, oldval)
-SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, oldval)
-
#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \
int HIDDEN \
__sync_##OP##_and_fetch_4 (int *ptr, int val) \
@@ -168,19 +221,41 @@ OP_AND_FETCH_WORD (and, , &)
OP_AND_FETCH_WORD (xor, , ^)
OP_AND_FETCH_WORD (nand, ~, &)
-SUBWORD_SYNC_OP (add, , +, unsigned short, 2, newval)
-SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, newval)
-SUBWORD_SYNC_OP (or, , |, unsigned short, 2, newval)
-SUBWORD_SYNC_OP (and, , &, unsigned short, 2, newval)
-SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, newval)
-SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, newval)
+typedef unsigned char bool;
+
+#define COMPARE_AND_SWAP_2(TYPE, WIDTH, INDEX) \
+ TYPE HIDDEN \
+ __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
+ TYPE newval) \
+ { \
+ TYPE actual_oldval; \
+ int fail; \
+ \
+ while (1) \
+ { \
+ actual_oldval = *ptr; \
+ \
+ if (__builtin_expect (oldval != actual_oldval, 0)) \
+ return actual_oldval; \
+ \
+ fail = __kernel_cmpxchg2 (&actual_oldval, &newval, ptr, INDEX); \
+ \
+ if (__builtin_expect (!fail, 1)) \
+ return actual_oldval; \
+ } \
+ } \
+ \
+ bool HIDDEN \
+ __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
+ TYPE newval) \
+ { \
+ int failure = __kernel_cmpxchg2 (&oldval, &newval, ptr, INDEX); \
+ return (failure != 0); \
+ }
-SUBWORD_SYNC_OP (add, , +, unsigned char, 1, newval)
-SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, newval)
-SUBWORD_SYNC_OP (or, , |, unsigned char, 1, newval)
-SUBWORD_SYNC_OP (and, , &, unsigned char, 1, newval)
-SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, newval)
-SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, newval)
+COMPARE_AND_SWAP_2 (long long, 8, 3)
+COMPARE_AND_SWAP_2 (short, 2, 1)
+COMPARE_AND_SWAP_2 (char, 1, 0)
int HIDDEN
__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
@@ -201,41 +276,6 @@ __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
}
}
-#define SUBWORD_VAL_CAS(TYPE, WIDTH) \
- TYPE HIDDEN \
- __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
- TYPE newval) \
- { \
- int *wordptr = (int *)((unsigned long) ptr & ~3), fail; \
- unsigned int mask, shift, actual_oldval, actual_newval; \
- \
- shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
- mask = MASK_##WIDTH << shift; \
- \
- while (1) \
- { \
- actual_oldval = *wordptr; \
- \
- if (__builtin_expect (((actual_oldval & mask) >> shift) \
- != (unsigned int) oldval, 0)) \
- return (actual_oldval & mask) >> shift; \
- \
- actual_newval = (actual_oldval & ~mask) \
- | (((unsigned int) newval << shift) & mask); \
- \
- fail = __kernel_cmpxchg (actual_oldval, actual_newval, \
- wordptr); \
- \
- if (__builtin_expect (!fail, 1)) \
- return (actual_oldval & mask) >> shift; \
- } \
- }
-
-SUBWORD_VAL_CAS (unsigned short, 2)
-SUBWORD_VAL_CAS (unsigned char, 1)
-
-typedef unsigned char bool;
-
bool HIDDEN
__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
{
@@ -243,18 +283,24 @@ __sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
return (failure == 0);
}
-#define SUBWORD_BOOL_CAS(TYPE, WIDTH) \
- bool HIDDEN \
- __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
- TYPE newval) \
+#define SYNC_LOCK_TEST_AND_SET_2(TYPE, WIDTH, INDEX) \
+TYPE HIDDEN \
+ __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \
{ \
- TYPE actual_oldval \
- = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \
- return (oldval == actual_oldval); \
+ TYPE oldval; \
+ int failure; \
+ \
+ do { \
+ oldval = *ptr; \
+ failure = __kernel_cmpxchg2 (&oldval, &val, ptr, INDEX); \
+ } while (failure != 0); \
+ \
+ return oldval; \
}
-SUBWORD_BOOL_CAS (unsigned short, 2)
-SUBWORD_BOOL_CAS (unsigned char, 1)
+SYNC_LOCK_TEST_AND_SET_2 (long long, 8, 3)
+SYNC_LOCK_TEST_AND_SET_2 (short, 2, 1)
+SYNC_LOCK_TEST_AND_SET_2 (signed char, 1, 0)
int HIDDEN
__sync_lock_test_and_set_4 (int *ptr, int val)
@@ -269,37 +315,29 @@ __sync_lock_test_and_set_4 (int *ptr, int val)
return oldval;
}
-#define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \
- TYPE HIDDEN \
- __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \
- { \
- int failure; \
- unsigned int oldval, newval, shift, mask; \
- int *wordptr = (int *) ((unsigned long) ptr & ~3); \
- \
- shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
- mask = MASK_##WIDTH << shift; \
- \
- do { \
- oldval = *wordptr; \
- newval = (oldval & ~mask) \
- | (((unsigned int) val << shift) & mask); \
- failure = __kernel_cmpxchg (oldval, newval, wordptr); \
- } while (failure != 0); \
- \
- return (oldval & mask) >> shift; \
+#define SYNC_LOCK_RELEASE_2(TYPE, WIDTH, INDEX) \
+ void HIDDEN \
+ __sync_lock_release_##WIDTH (TYPE *ptr) \
+ { \
+ TYPE failure, oldval, zero = 0; \
+ \
+ do { \
+ oldval = *ptr; \
+ failure = __kernel_cmpxchg2 (&oldval, &zero, ptr, INDEX); \
+ } while (failure != 0); \
}
-SUBWORD_TEST_AND_SET (unsigned short, 2)
-SUBWORD_TEST_AND_SET (unsigned char, 1)
+SYNC_LOCK_RELEASE_2 (long long, 8, 3)
+SYNC_LOCK_RELEASE_2 (short, 2, 1)
+SYNC_LOCK_RELEASE_2 (signed char, 1, 0)
-#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \
- void HIDDEN \
- __sync_lock_release_##WIDTH (TYPE *ptr) \
- { \
- *ptr = 0; \
- }
+void HIDDEN
+__sync_lock_release_4 (int *ptr)
+{
+ int failure, oldval;
-SYNC_LOCK_RELEASE (int, 4)
-SYNC_LOCK_RELEASE (short, 2)
-SYNC_LOCK_RELEASE (char, 1)
+ do {
+ oldval = *ptr;
+ failure = __kernel_cmpxchg (oldval, 0, ptr);
+ } while (failure != 0);
+}
diff --git a/gcc-4.9/libgcc/config/pa/linux-unwind.h b/gcc-4.9/libgcc/config/pa/linux-unwind.h
index 485f2d98e..4a3cfffd1 100644
--- a/gcc-4.9/libgcc/config/pa/linux-unwind.h
+++ b/gcc-4.9/libgcc/config/pa/linux-unwind.h
@@ -32,6 +32,17 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include <signal.h>
#include <sys/ucontext.h>
+/* Return TRUE if read access to *P is allowed. */
+
+static inline long
+pa32_read_access_ok (void *p)
+{
+ long ret;
+
+ __asm__ ("proberi (%1),3,%0" : "=r" (ret) : "r" (p) :);
+ return ret;
+}
+
/* Unfortunately, because of various bugs and changes to the kernel,
we have several cases to deal with.
@@ -48,7 +59,12 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
tell us how to locate the sigcontext structure.
Note that with a 2.4 64-bit kernel, the signal context is not properly
- passed back to userspace so the unwind will not work correctly. */
+ passed back to userspace so the unwind will not work correctly.
+
+ There is also a bug in various glibc versions. The (CONTEXT)->ra
+ for the outermost frame is not marked as undefined, so we need to
+ check whether read access is allowed for all the accesses used in
+ searching for the signal trampoline. */
#define MD_FALLBACK_FRAME_STATE_FOR pa32_fallback_frame_state
@@ -73,14 +89,17 @@ pa32_fallback_frame_state (struct _Unwind_Context *context,
e4008200 be,l 0x100(%sr2, %r0), %sr0, %r31
08000240 nop */
- if (pc[0] == 0x34190000 || pc[0] == 0x34190002)
+ if (pa32_read_access_ok (pc)
+ && (pc[0] == 0x34190000 || pc[0] == 0x34190002))
off = 4*4;
- else if (pc[4] == 0x34190000 || pc[4] == 0x34190002)
+ else if (pa32_read_access_ok (&pc[4])
+ && (pc[4] == 0x34190000 || pc[4] == 0x34190002))
{
pc += 4;
off = 10 * 4;
}
- else if (pc[5] == 0x34190000 || pc[5] == 0x34190002)
+ else if (pa32_read_access_ok (&pc[5])
+ && (pc[5] == 0x34190000 || pc[5] == 0x34190002))
{
pc += 5;
off = 10 * 4;
@@ -96,13 +115,16 @@ pa32_fallback_frame_state (struct _Unwind_Context *context,
word boundary and we can then determine the frame offset. */
sp = (unsigned long)context->ra;
pc = (unsigned int *)sp;
- if ((pc[0] == 0x34190000 || pc[0] == 0x34190002) && (sp & 4))
+ if ((sp & 4)
+ && pa32_read_access_ok (pc)
+ && (pc[0] == 0x34190000 || pc[0] == 0x34190002))
off = 5 * 4;
else
return _URC_END_OF_STACK;
}
- if (pc[1] != 0x3414015a
+ if (!pa32_read_access_ok (&pc[3])
+ || pc[1] != 0x3414015a
|| pc[2] != 0xe4008200
|| pc[3] != 0x08000240)
return _URC_END_OF_STACK;
diff --git a/gcc-4.9/libgcc/config/sh/lib1funcs.S b/gcc-4.9/libgcc/config/sh/lib1funcs.S
index 3410cf7c1..cfd6dc2a2 100644
--- a/gcc-4.9/libgcc/config/sh/lib1funcs.S
+++ b/gcc-4.9/libgcc/config/sh/lib1funcs.S
@@ -1278,7 +1278,7 @@ GLOBAL(sdivsi3_2):
#endif
ENDFUNC(GLOBAL(sdivsi3_2))
#endif
-#elif defined __SHMEDIA__
+#elif __SHMEDIA__
/* m5compact-nofpu */
// clobbered: r18,r19,r20,r21,r25,tr0,tr1,tr2
.mode SHmedia
@@ -1683,7 +1683,7 @@ GLOBAL(udivsi3):
add.l r18,r25,r0
blink tr0,r63
#endif
-#elif defined (__SHMEDIA__)
+#elif __SHMEDIA__
/* m5compact-nofpu - more emphasis on code size than on speed, but don't
ignore speed altogether - div1 needs 9 cycles, subc 7 and rotcl 4.
So use a short shmedia loop. */
@@ -1707,7 +1707,7 @@ LOCAL(udivsi3_dontsub):
bnei r25,-32,tr1
add.l r20,r63,r0
blink tr2,r63
-#else /* ! defined (__SHMEDIA__) */
+#else /* ! __SHMEDIA__ */
LOCAL(div8):
div1 r5,r4
LOCAL(div7):
@@ -1773,7 +1773,7 @@ LOCAL(large_divisor):
#endif /* L_udivsi3 */
#ifdef L_udivdi3
-#ifdef __SHMEDIA__
+#if __SHMEDIA__
.mode SHmedia
.section .text..SHmedia32,"ax"
.align 2
@@ -1901,7 +1901,7 @@ LOCAL(no_lo_adj):
#endif /* L_udivdi3 */
#ifdef L_divdi3
-#ifdef __SHMEDIA__
+#if __SHMEDIA__
.mode SHmedia
.section .text..SHmedia32,"ax"
.align 2
@@ -1925,7 +1925,7 @@ GLOBAL(divdi3):
#endif /* L_divdi3 */
#ifdef L_umoddi3
-#ifdef __SHMEDIA__
+#if __SHMEDIA__
.mode SHmedia
.section .text..SHmedia32,"ax"
.align 2
@@ -2054,7 +2054,7 @@ LOCAL(no_lo_adj):
#endif /* L_umoddi3 */
#ifdef L_moddi3
-#ifdef __SHMEDIA__
+#if __SHMEDIA__
.mode SHmedia
.section .text..SHmedia32,"ax"
.align 2
@@ -3142,7 +3142,7 @@ GLOBAL(GCC_pop_shmedia_regs_nofpu):
#ifdef L_div_table
#if __SH5__
-#if defined(__pic__) && defined(__SHMEDIA__)
+#if defined(__pic__) && __SHMEDIA__
.global GLOBAL(sdivsi3)
FUNC(GLOBAL(sdivsi3))
#if __SH5__ == 32
@@ -3215,7 +3215,7 @@ Defects for bias -330:
#else /* ! __pic__ || ! __SHMEDIA__ */
.section .rodata
#endif /* __pic__ */
-#if defined(TEXT_DATA_BUG) && defined(__pic__) && defined(__SHMEDIA__)
+#if defined(TEXT_DATA_BUG) && defined(__pic__) && __SHMEDIA__
.balign 2
.type Local_div_table,@object
.size Local_div_table,128
diff --git a/gcc-4.9/libgcc/dyn-ipa.c b/gcc-4.9/libgcc/dyn-ipa.c
index e66b02bbc..ef6da8db8 100644
--- a/gcc-4.9/libgcc/dyn-ipa.c
+++ b/gcc-4.9/libgcc/dyn-ipa.c
@@ -107,8 +107,9 @@ struct checksum_alias
struct checksum_alias *next_alias;
gcov_type guid;
const struct gcov_fn_info *fi_ptr;
- /* Does this function have all-zero arc counts? */
- int zero_counts;
+ /* Non-NULL pointer to flag if this function has all-zero arc counts, to be
+ set if we perform fixup. */
+ char *zero_count_fixup;
};
/* Module info is stored in dyn_caph->sup_modules
@@ -178,10 +179,10 @@ extern gcov_unsigned_t __gcov_lipo_merge_modu_edges;
extern gcov_unsigned_t __gcov_lipo_weak_inclusion;
#if defined(inhibit_libc)
-void __gcov_build_callgraph (void) {}
+void __gcov_build_callgraph (char **zero_counts) {}
#else
-int __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN;
+int __gcov_compute_module_groups (char **zero_counts) ATTRIBUTE_HIDDEN;
void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN;
static void gcov_dump_callgraph (gcov_type);
static void gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node);
@@ -378,18 +379,19 @@ lineno_checksum_get_key (const void *p)
}
/* Create a new checksum_alias struct for function with GUID, FI_PTR,
- and ZERO_COUNTS flag. Prepends to list NEXT and returns new struct. */
+ and ZERO_COUNT_FIXUP flag pointer. Prepends to list NEXT and returns
+ new struct. */
static struct checksum_alias *
new_checksum_alias (gcov_type guid, const struct gcov_fn_info *fi_ptr,
- int zero_counts,
+ char *zero_count_fixup,
struct checksum_alias *next)
{
struct checksum_alias *alias = XNEW (struct checksum_alias);
alias->next_alias = next;
alias->fi_ptr = fi_ptr;
alias->guid = guid;
- alias->zero_counts = zero_counts;
+ alias->zero_count_fixup = zero_count_fixup;
return alias;
}
@@ -407,11 +409,12 @@ find_cfg_checksum (struct checksum_alias_info *list, unsigned cfg_checksum)
}
/* Insert a new checksum_alias struct into LIST for function with
- CFG_CHECKSUM and associated GUID, FI_PTR, and ZERO_COUNTS flag. */
+ CFG_CHECKSUM and associated GUID, FI_PTR, and ZERO_COUNT_FIXUP
+ flag pointer. */
static struct checksum_alias_info *
cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid,
- const struct gcov_fn_info *fi_ptr, int zero_counts,
+ const struct gcov_fn_info *fi_ptr, char *zero_count_fixup,
struct checksum_alias_info *list)
{
struct checksum_alias_info *alias_info;
@@ -419,7 +422,8 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid,
if (alias_info)
{
gcc_assert (alias_info->alias_list);
- alias_info->alias_list = new_checksum_alias (guid, fi_ptr, zero_counts,
+ alias_info->alias_list = new_checksum_alias (guid, fi_ptr,
+ zero_count_fixup,
alias_info->alias_list);
return list;
}
@@ -428,7 +432,8 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid,
alias_info = XNEW (struct checksum_alias_info);
alias_info->next_cfg_checksum = list;
alias_info->cfg_checksum = cfg_checksum;
- alias_info->alias_list = new_checksum_alias (guid, fi_ptr, zero_counts,
+ alias_info->alias_list = new_checksum_alias (guid, fi_ptr,
+ zero_count_fixup,
NULL);
return alias_info;
}
@@ -436,12 +441,12 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid,
/* Insert a new checksum_alias struct into lineno_pointer_sets for function with
LINENO_CHECKSUM and CFG_CHECKSUM with associated GUID, FI_PTR, and
- ZERO_COUNTS flag. */
+ ZERO_COUNT_FIXUP flag pointer. */
static void
checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum,
gcov_type guid, const struct gcov_fn_info *fi_ptr,
- int zero_counts)
+ char *zero_count_fixup)
{
struct dyn_pointer_set *p = the_dyn_call_graph.lineno_pointer_sets;
if (!p)
@@ -452,7 +457,7 @@ checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum,
if (*m)
{
(*m)->cfg_checksum_list = cfg_checksum_insert (cfg_checksum, guid,
- fi_ptr, zero_counts,
+ fi_ptr, zero_count_fixup,
(*m)->cfg_checksum_list);
}
else
@@ -460,7 +465,8 @@ checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum,
*m = XNEW (struct lineno_checksum_alias);
(*m)->lineno_checksum = lineno_checksum;
(*m)->cfg_checksum_list = cfg_checksum_insert (cfg_checksum, guid,
- fi_ptr, zero_counts, NULL);
+ fi_ptr, zero_count_fixup,
+ NULL);
p->n_elements++;
}
}
@@ -801,10 +807,10 @@ gcov_build_callgraph_ic_fn (struct dyn_cgraph_node *caller,
}
}
-/* Build the dynamic call graph. */
+/* Build the dynamic call graph and update ZERO_COUNTS flags. */
static void
-gcov_build_callgraph (void)
+gcov_build_callgraph (char **zero_counts)
{
struct gcov_info *gi_ptr;
unsigned m_ix;
@@ -852,9 +858,19 @@ gcov_build_callgraph (void)
if (total_arc_count != 0)
the_dyn_call_graph.num_nodes_executed++;
if (fixup_type)
- checksum_set_insert (fi_ptr->lineno_checksum,
- fi_ptr->cfg_checksum, caller->guid,
- fi_ptr, total_arc_count == 0);
+ {
+ char *zero_count_fixup = NULL;
+ /* Passing in a non-NULL zero_count_fixup pointer
+ indicates that the counts were all zero for this
+ function, and the fixup routine will set the flag
+ if the function's counters are updated to non-zero
+ values. */
+ if (total_arc_count == 0)
+ zero_count_fixup = &zero_counts[m_ix][f_ix];
+ checksum_set_insert (fi_ptr->lineno_checksum,
+ fi_ptr->cfg_checksum, caller->guid,
+ fi_ptr, zero_count_fixup);
+ }
}
ci_ptr++;
}
@@ -1251,7 +1267,14 @@ gcov_collect_imported_modules (const void *value,
out_array = (struct gcov_import_mod_array *) data1;
if (m->imp_mod != out_array->importing_module)
+ {
out_array->imported_modules[out_array->len++] = m;
+ /* Sanity check that the importing (primary) module is not
+ actually the same as the new aux module. This could happen if
+ we accidentally read in the same gcda file twice. */
+ gcc_assert (m->imp_mod->mod_info->ident !=
+ out_array->importing_module->mod_info->ident);
+ }
return 1;
}
@@ -2234,6 +2257,7 @@ gcov_compute_random_module_groups (unsigned max_group_size)
}
}
+#if 0
/* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag
indicating if the module is the primary module in the group. */
@@ -2241,7 +2265,7 @@ static void
gcov_write_module_info (const struct gcov_info *mod_info,
unsigned is_primary)
{
- gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i, j;
+ gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i;
gcov_unsigned_t num_strings;
gcov_unsigned_t *aligned_fname;
struct gcov_module_info *module_info = mod_info->mod_info;
@@ -2256,14 +2280,8 @@ gcov_write_module_info (const struct gcov_info *mod_info,
+ module_info->num_system_paths
+ module_info->num_cpp_defines + module_info->num_cpp_includes
+ module_info->num_cl_args;
- for (i = 0; i < num_strings; i++)
- {
- gcov_unsigned_t string_len
- = (strlen (module_info->string_array[i]) + sizeof (gcov_unsigned_t))
- / sizeof (gcov_unsigned_t);
- len += string_len;
- len += 1; /* Each string is lead by a length. */
- }
+ len += gcov_compute_string_array_len (module_info->string_array,
+ num_strings);
len += 11; /* 11 more fields */
@@ -2296,21 +2314,9 @@ gcov_write_module_info (const struct gcov_info *mod_info,
gcov_write_unsigned (aligned_fname[i]);
/* Now write the string array. */
- for (j = 0; j < num_strings; j++)
- {
- gcov_unsigned_t *aligned_string;
- gcov_unsigned_t string_len =
- (strlen (module_info->string_array[j]) + sizeof (gcov_unsigned_t)) /
- sizeof (gcov_unsigned_t);
- aligned_string = (gcov_unsigned_t *)
- alloca ((string_len + 1) * sizeof (gcov_unsigned_t));
- memset (aligned_string, 0, (string_len + 1) * sizeof (gcov_unsigned_t));
- aligned_string[0] = string_len;
- strcpy ((char*) (aligned_string + 1), module_info->string_array[j]);
- for (i = 0; i < (string_len + 1); i++)
- gcov_write_unsigned (aligned_string[i]);
- }
+ gcov_write_string_array (module_info->string_array, num_strings);
}
+#endif
/* Write out MOD_INFO and its imported modules into gcda file. */
@@ -2320,6 +2326,8 @@ gcov_write_module_infos (struct gcov_info *mod_info)
unsigned imp_len = 0;
const struct dyn_imp_mod **imp_mods;
+ if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM)
+ SET_MODULE_INCLUDE_ALL_AUX (mod_info->mod_info);
gcov_write_module_info (mod_info, 1);
imp_mods = gcov_get_sorted_import_module_array (mod_info, &imp_len);
@@ -2976,7 +2984,7 @@ gcov_fixup_counters_checksum (const struct checksum_alias_info *info,
for (alias = info->alias_list; alias;
alias = alias->next_alias)
{
- if (alias->zero_counts)
+ if (alias->zero_count_fixup)
{
found = 1;
break;
@@ -2991,7 +2999,7 @@ gcov_fixup_counters_checksum (const struct checksum_alias_info *info,
for (alias = info->alias_list; alias;
alias = alias->next_alias)
{
- if (alias->zero_counts)
+ if (alias->zero_count_fixup)
continue;
merge_ctrs (merged_ctrs, alias->fi_ptr->ctrs, alias->guid);
found = 1;
@@ -3009,9 +3017,10 @@ gcov_fixup_counters_checksum (const struct checksum_alias_info *info,
for (alias = info->alias_list; alias;
alias = alias->next_alias)
{
- if (!alias->zero_counts)
+ if (!alias->zero_count_fixup)
continue;
copy_ctrs (alias->fi_ptr->ctrs, alias->guid, merged_ctrs);
+ *alias->zero_count_fixup = 1;
}
return 1;
@@ -3059,11 +3068,13 @@ gcov_fixup_zero_counters (void)
return changed;
}
-/* Compute module groups needed for L-IPO compilation. Returns 1 if any
- counter fixups were applied, requiring a profile rewrite, 0 otherwise. */
+/* Compute module groups needed for L-IPO compilation. The ZERO_COUNTS
+ flags are set for functions with zero count fixups applied. Returns 1
+ if any counter fixups were applied, requiring a profile rewrite,
+ 0 otherwise. */
int
-__gcov_compute_module_groups (void)
+__gcov_compute_module_groups (char **zero_counts)
{
gcov_type cut_off_count;
char *seed = getenv ("LIPO_RANDOM_GROUPING");
@@ -3110,7 +3121,7 @@ __gcov_compute_module_groups (void)
fixup_type = atoi (do_fixup);
/* First compute dynamic call graph. */
- gcov_build_callgraph ();
+ gcov_build_callgraph (zero_counts);
cut_off_count = gcov_compute_cutoff_count ();
diff --git a/gcc-4.9/libgcc/libgcov-driver-kernel.c b/gcc-4.9/libgcc/libgcov-driver-kernel.c
new file mode 100644
index 000000000..34298ed69
--- /dev/null
+++ b/gcc-4.9/libgcc/libgcov-driver-kernel.c
@@ -0,0 +1,203 @@
+/* Routines required for instrumenting a program. */
+/* Compile this one with gcc. */
+/* Copyright (C) 1989-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+
+/* A utility function for outputing errors. */
+
+static int __attribute__((format(printf, 1, 2)))
+gcov_error (const char *fmt, ...)
+{
+ int ret;
+ va_list argp;
+ va_start (argp, fmt);
+ ret = vprintk (fmt, argp);
+ va_end (argp);
+ return ret;
+}
+
+static void
+allocate_filename_struct (struct gcov_filename_aux *gf)
+{
+ const char *gcov_prefix;
+ int gcov_prefix_strip = 0;
+ size_t prefix_length = 0;
+ char *gi_filename_up;
+
+ /* Allocate and initialize the filename scratch space plus one. */
+ gi_filename = (char *) xmalloc (prefix_length + gcov_max_filename + 2);
+ if (prefix_length)
+ memcpy (gi_filename, gcov_prefix, prefix_length);
+ gi_filename_up = gi_filename + prefix_length;
+
+ gf->gi_filename_up = gi_filename_up;
+ gf->prefix_length = prefix_length;
+ gf->gcov_prefix_strip = gcov_prefix_strip;
+}
+
+static int
+gcov_open_by_filename (char *gi_filename)
+{
+ gcov_open (gi_filename);
+ return 0;
+}
+
+
+/* Strip GCOV_PREFIX_STRIP levels of leading '/' from FILENAME and
+ put the result into GI_FILENAME_UP. */
+
+static void
+gcov_strip_leading_dirs (int prefix_length, int gcov_prefix_strip,
+ const char *filename, char *gi_filename_up)
+{
+ strcpy (gi_filename_up, filename);
+}
+
+/* Current virual gcda file. This is for kernel use only. */
+gcov_kernel_vfile *gcov_current_file;
+
+/* Set current virutal gcda file. It needs to be set before dumping
+ profile data. */
+
+void
+gcov_set_vfile (gcov_kernel_vfile *file)
+{
+ gcov_current_file = file;
+}
+
+/* File fclose operation in kernel mode. */
+
+int
+kernel_file_fclose (gcov_kernel_vfile *fp)
+{
+ return 0;
+}
+
+/* File ftell operation in kernel mode. It currently should not
+ be called. */
+
+long
+kernel_file_ftell (gcov_kernel_vfile *fp)
+{
+ return 0;
+}
+
+/* File fseek operation in kernel mode. It should only be called
+ with OFFSET==0 and WHENCE==0 to a freshly opened file. */
+
+int
+kernel_file_fseek (gcov_kernel_vfile *fp, long offset, int whence)
+{
+ gcc_assert (offset == 0 && whence == 0 && fp->count == 0);
+ return 0;
+}
+
+/* File ftruncate operation in kernel mode. It currently should not
+ be called. */
+
+int
+kernel_file_ftruncate (gcov_kernel_vfile *fp, off_t value)
+{
+ gcc_assert (0); /* should not reach here */
+ return 0;
+}
+
+/* File fread operation in kernel mode. It currently should not
+ be called. */
+
+int
+kernel_file_fread (void *ptr, size_t size, size_t nitems,
+ gcov_kernel_vfile *fp)
+{
+ gcc_assert (0); /* should not reach here */
+ return 0;
+}
+
+/* File fwrite operation in kernel mode. It outputs the data
+ to a buffer in the virual file. */
+
+int
+kernel_file_fwrite (const void *ptr, size_t size,
+ size_t nitems, gcov_kernel_vfile *fp)
+{
+ char *vbuf;
+ unsigned vsize, vpos;
+ unsigned len;
+
+ if (!fp) return 0;
+
+ vbuf = fp->buf;
+ vsize = fp->size;
+ vpos = fp->count;
+
+
+ if (vsize < vpos)
+ {
+ printk (KERN_ERR
+ "GCOV_KERNEL: something wrong in file %s: vbuf=%p vsize=%u"
+ " vpos=%u\n",
+ fp->info->filename, vbuf, vsize, vpos);
+ return 0;
+ }
+
+ len = vsize - vpos;
+ len /= size;
+
+ /* Increase the virtual file size if it is not suffcient. */
+ while (len < nitems)
+ {
+ vsize *= 2;
+ len = vsize - vpos;
+ len /= size;
+ }
+
+ if (vsize != fp->size)
+ {
+ vbuf = fp->buf = (char *) gcov_realloc_file_buf(vsize, vpos);
+ fp->size = vsize;
+ }
+
+ if (len > nitems)
+ len = nitems;
+
+ memcpy (vbuf+vpos, ptr, size*len);
+ fp->count += len*size;
+
+ if (len != nitems)
+ printk (KERN_ERR
+ "GCOV_KERNEL: something wrong in file %s: size=%lu nitems=%lu"
+ " len=%d vsize=%u vpos=%u \n",
+ fp->info->filename, size, nitems, len, vsize, vpos);
+ return len;
+}
+
+/* File fileno operation in kernel mode. It currently should not
+ be called. */
+
+int
+kernel_file_fileno (gcov_kernel_vfile *fp)
+{
+ gcc_assert (0); /* should not reach here */
+ return 0;
+}
diff --git a/gcc-4.9/libgcc/libgcov-driver-system.c b/gcc-4.9/libgcc/libgcov-driver-system.c
index d0bed4975..109547420 100644
--- a/gcc-4.9/libgcc/libgcov-driver-system.c
+++ b/gcc-4.9/libgcc/libgcov-driver-system.c
@@ -156,8 +156,6 @@ gcov_open_by_filename (char *gi_filename)
}
-#define GCOV_GET_FILENAME gcov_strip_leading_dirs
-
/* Strip GCOV_PREFIX_STRIP levels of leading '/' from FILENAME and
put the result into GI_FILENAME_UP. */
@@ -197,24 +195,3 @@ gcov_strip_leading_dirs (int prefix_length, int gcov_prefix_strip,
else
strcpy (gi_filename_up, filename);
}
-
-
-/* Open a gcda file specified by GI_FILENAME.
- Return -1 on error. Return 0 on success. */
-
-static int
-gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
-{
- int gcov_prefix_strip;
- size_t prefix_length;
- char *gi_filename_up;
-
- gcov_prefix_strip = gf->gcov_prefix_strip;
- gi_filename_up = gf->gi_filename_up;
- prefix_length = gf->prefix_length;
-
- GCOV_GET_FILENAME (prefix_length, gcov_prefix_strip, gi_ptr->filename,
- gi_filename_up);
-
- return gcov_open_by_filename (gi_filename);
-}
diff --git a/gcc-4.9/libgcc/libgcov-driver.c b/gcc-4.9/libgcc/libgcov-driver.c
index dc8cf362b..3c569f171 100644
--- a/gcc-4.9/libgcc/libgcov-driver.c
+++ b/gcc-4.9/libgcc/libgcov-driver.c
@@ -34,28 +34,24 @@ void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
#else /* inhibit_libc */
+#if !defined(__KERNEL__)
#include <string.h>
#if GCOV_LOCKED
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#endif
+#endif /* __KERNEL__ */
#ifdef L_gcov
#include "gcov-io.c"
-#ifndef IN_GCOV_TOOL
-extern gcov_unsigned_t __gcov_sampling_period;
-extern gcov_unsigned_t __gcov_has_sampling;
-static int gcov_sampling_period_initialized = 0;
-#endif
-
/* Unique identifier assigned to each module (object file). */
static gcov_unsigned_t gcov_cur_module_id = 0;
/* Dynamic call graph build and form module groups. */
-int __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN;
+int __gcov_compute_module_groups (char **zero_counts) ATTRIBUTE_HIDDEN;
void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN;
/* The following functions can be called from outside of this file. */
@@ -67,7 +63,11 @@ extern int get_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
extern void set_gcov_list (struct gcov_info *) ATTRIBUTE_HIDDEN;
__attribute__((weak)) void __coverage_callback (gcov_type, int);
-#ifndef IN_GCOV_TOOL
+#if !defined(IN_GCOV_TOOL) && !defined(__KERNEL__)
+extern gcov_unsigned_t __gcov_sampling_period;
+extern gcov_unsigned_t __gcov_has_sampling;
+static int gcov_sampling_period_initialized = 0;
+
/* Create a strong reference to these symbols so that they are
unconditionally pulled into the instrumented binary, even when
the only reference is a weak reference. This is necessary because
@@ -129,6 +129,24 @@ set_gcov_list (struct gcov_info *head)
__gcov_list = head;
}
+/* Flag if the current function being read was marked as having fixed-up
+ zero counters. */
+static int __gcov_curr_fn_fixed_up;
+
+/* Set function fixed up flag. */
+void
+set_gcov_fn_fixed_up (int fixed_up)
+{
+ __gcov_curr_fn_fixed_up = fixed_up;
+}
+
+/* Return function fixed up flag. */
+int
+get_gcov_fn_fixed_up (void)
+{
+ return __gcov_curr_fn_fixed_up;
+}
+
/* Size of the longest file name. */
/* We need to expose this static variable when compiling for gcov-tool. */
#ifndef IN_GCOV_TOOL
@@ -181,8 +199,8 @@ free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
for (ix = 0; ix != limit; ix++)
if (gi_ptr->merge[ix])
- free (buffer->info.ctrs[n_ctr++].values);
- free (buffer);
+ xfree (buffer->info.ctrs[n_ctr++].values);
+ xfree (buffer);
return next;
}
@@ -386,7 +404,10 @@ static int run_accounted = 0;
/* This funtions computes the program level summary and the histo-gram.
It computes and returns CRC32 and stored summary in THIS_PRG. */
-static gcov_unsigned_t
+#if !IN_GCOV_TOOL
+static
+#endif
+gcov_unsigned_t
gcov_exit_compute_summary (struct gcov_summary *this_prg)
{
struct gcov_info *gi_ptr;
@@ -451,14 +472,58 @@ struct gcov_filename_aux{
};
/* Including system dependent components. */
+#if !defined (__KERNEL__)
#include "libgcov-driver-system.c"
+#else
+#include "libgcov-driver-kernel.c"
+#endif
+
+static int
+scan_build_info (struct gcov_info *gi_ptr)
+{
+ gcov_unsigned_t i, length;
+ gcov_unsigned_t num_strings = 0;
+ char **build_info_strings;
+ length = gcov_read_unsigned ();
+ build_info_strings = gcov_read_build_info (length, &num_strings);
+ if (!build_info_strings)
+ {
+ gcov_error ("profiling:%s:Error reading build info\n", gi_filename);
+ return -1;
+ }
+ if (!gi_ptr->build_info)
+ {
+ gcov_error ("profiling:%s:Mismatched build info sections, expected "
+ "none, found %u strings)\n", gi_filename, num_strings);
+ return -1;
+ }
+
+ for (i = 0; i < num_strings; i++)
+ {
+ if (strcmp (build_info_strings[i], gi_ptr->build_info[i]))
+ {
+ gcov_error ("profiling:%s:Mismatched build info string "
+ "(expected %s, read %s)\n",
+ gi_filename, gi_ptr->build_info[i],
+ build_info_strings[i]);
+ return -1;
+ }
+ xfree (build_info_strings[i]);
+ }
+ xfree (build_info_strings);
+ return 0;
+}
+
+#if !defined(__KERNEL__)
/* Scan through the current open gcda file corresponding to GI_PTR
- to locate the end position of the last summary, returned in
- SUMMARY_END_POS_P. Return 0 on success, -1 on error. */
+ to locate the end position just before function data should be rewritten,
+ returned in SUMMARY_END_POS_P. E.g. scan past the last summary and other
+ sections that won't be rewritten, like the build info. Return 0 on success,
+ -1 on error. */
static int
-gcov_scan_summary_end (struct gcov_info *gi_ptr,
- gcov_position_t *summary_end_pos_p)
+gcov_scan_to_function_data (struct gcov_info *gi_ptr,
+ gcov_position_t *summary_end_pos_p)
{
gcov_unsigned_t tag, version, stamp;
tag = gcov_read_unsigned ();
@@ -493,8 +558,21 @@ gcov_scan_summary_end (struct gcov_info *gi_ptr,
return -1;
}
+ /* If there is a build info section, scan past it as well. */
+ if (tag == GCOV_TAG_BUILD_INFO)
+ {
+ if (scan_build_info (gi_ptr) < 0)
+ return -1;
+
+ *summary_end_pos_p = gcov_position ();
+ tag = gcov_read_unsigned ();
+ }
+ /* The next section should be the function counters. */
+ gcc_assert (tag == GCOV_TAG_FUNCTION);
+
return 0;
}
+#endif /* __KERNEL__ */
/* This function merges counters in GI_PTR to an existing gcda file.
Return 0 on success.
@@ -514,6 +592,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
int error = 0;
struct gcov_fn_buffer **fn_tail = &fn_buffer;
struct gcov_summary_buffer **sum_tail = &sum_buffer;
+ int *zero_fixup_flags = NULL;
length = gcov_read_unsigned ();
if (!gcov_version (gi_ptr, length, gi_filename))
@@ -565,6 +644,31 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
next_summary:;
}
+ if (tag == GCOV_TAG_BUILD_INFO)
+ {
+ if (scan_build_info (gi_ptr) < 0)
+ return -1;
+
+ /* Since the stamps matched if we got here, this should be from
+ the same compilation and the build info strings should match. */
+ tag = gcov_read_unsigned ();
+ }
+
+ if (tag == GCOV_TAG_COMDAT_ZERO_FIXUP)
+ {
+ gcov_unsigned_t num_fns = 0;
+ length = gcov_read_unsigned ();
+ zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns);
+ if (!zero_fixup_flags)
+ {
+ gcov_error ("profiling:%s:Error reading zero fixup flags\n",
+ gi_filename);
+ return -1;
+ }
+
+ tag = gcov_read_unsigned ();
+ }
+
/* Merge execution counts for each function. */
for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
f_ix++, tag = gcov_read_unsigned ())
@@ -598,6 +702,9 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
continue;
}
+ if (zero_fixup_flags)
+ set_gcov_fn_fixed_up (zero_fixup_flags[f_ix]);
+
length = gcov_read_unsigned ();
if (length != gfi_ptr->ident)
goto read_mismatch;
@@ -629,6 +736,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
if ((error = gcov_is_error ()))
goto read_error;
}
+ xfree (zero_fixup_flags);
if (tag && tag != GCOV_TAG_MODULE_INFO)
{
@@ -646,6 +754,57 @@ read_error:
return -1;
}
+#if !defined(__KERNEL__)
+/* Write NUM_FNS ZERO_COUNTS fixup flags to a gcda file starting from its
+ current location. */
+
+static void
+gcov_write_comdat_zero_fixup (char *zero_counts, unsigned num_fns)
+{
+ unsigned f_ix;
+ gcov_unsigned_t len = GCOV_TAG_COMDAT_ZERO_FIXUP_LENGTH (num_fns);
+ gcov_unsigned_t bitvector = 0, b_ix = 0;
+ gcov_write_tag_length (GCOV_TAG_COMDAT_ZERO_FIXUP, len);
+
+ gcov_write_unsigned (num_fns);
+ for (f_ix = 0; f_ix != num_fns; f_ix++)
+ {
+ if (zero_counts[f_ix])
+ bitvector |= 1 << b_ix;
+ if (++b_ix == 32)
+ {
+ gcov_write_unsigned (bitvector);
+ b_ix = 0;
+ bitvector = 0;
+ }
+ }
+ if (b_ix > 0)
+ gcov_write_unsigned (bitvector);
+}
+#endif /* __KERNEL__ */
+
+/* Write build_info strings from GI_PTR to a gcda file starting from its current
+ location. */
+
+static void
+gcov_write_build_info (struct gcov_info *gi_ptr)
+{
+ gcov_unsigned_t num = 0;
+ gcov_unsigned_t len = 1;
+
+ if (!gi_ptr->build_info)
+ return;
+
+ /* Count the number of strings, which is terminated with an empty string. */
+ while (gi_ptr->build_info[num][0])
+ num++;
+
+ len += gcov_compute_string_array_len (gi_ptr->build_info, num);
+ gcov_write_tag_length (GCOV_TAG_BUILD_INFO, len);
+ gcov_write_unsigned (num);
+ gcov_write_string_array (gi_ptr->build_info, num);
+}
+
/* Write counters in GI_PTR to a gcda file starting from its current
location. */
@@ -676,7 +835,7 @@ gcov_write_func_counters (struct gcov_info *gi_ptr)
if (gfi_ptr && gfi_ptr->key == gi_ptr)
length = GCOV_TAG_FUNCTION_LENGTH;
else
- length = 0;
+ length = 0;
}
gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
@@ -704,8 +863,10 @@ gcov_write_func_counters (struct gcov_info *gi_ptr)
gcov_write_counter (*c_ptr++);
ci_ptr++;
}
+#if !defined(__KERNEL__)
if (buffered)
fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
+#endif /* __KERNEL__ */
}
gi_ptr->eof_pos = gcov_position ();
@@ -748,10 +909,12 @@ gcov_exit_write_gcda (struct gcov_info *gi_ptr,
{
gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary);
next_sum_buffer = sum_buffer->next;
- free (sum_buffer);
+ xfree (sum_buffer);
sum_buffer = next_sum_buffer;
}
+ gcov_write_build_info (gi_ptr);
+
/* Write the counters. */
gcov_write_func_counters (gi_ptr);
}
@@ -835,6 +998,8 @@ gcov_exit_merge_summary (const struct gcov_info *gi_ptr, struct gcov_summary *pr
return 0;
}
+__attribute__((weak)) gcov_unsigned_t __gcov_lipo_sampling_period;
+
/* Sort N entries in VALUE_ARRAY in descending order.
Each entry in VALUE_ARRAY has two values. The sorting
is based on the second value. */
@@ -906,6 +1071,62 @@ gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
}
}
+/* Scaling LIPO sampled profile counters. */
+static void
+gcov_scaling_lipo_counters (const struct gcov_info *gi_ptr)
+{
+ unsigned int i,j,k;
+ int f_ix;
+ const struct gcov_fn_info *gfi_ptr;
+ const struct gcov_ctr_info *ci_ptr;
+
+ if (__gcov_lipo_sampling_period <= 1)
+ return;
+
+ for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
+ {
+ gfi_ptr = gi_ptr->functions[f_ix];
+ ci_ptr = gfi_ptr->ctrs;
+ for (i = 0; i < GCOV_COUNTERS; i++)
+ {
+ if (!gcov_counter_active (gi_ptr, i))
+ continue;
+ if (i == GCOV_COUNTER_ICALL_TOPNV)
+ {
+ for (j = 0; j < ci_ptr->num; j += GCOV_ICALL_TOPN_NCOUNTS)
+ for (k = 2; k < GCOV_ICALL_TOPN_NCOUNTS; k += 2)
+ ci_ptr->values[j+k] *= __gcov_lipo_sampling_period;
+ }
+ if (i == GCOV_COUNTER_DIRECT_CALL)
+ {
+ for (j = 0; j < ci_ptr->num; j += 2)
+ ci_ptr->values[j+1] *= __gcov_lipo_sampling_period;
+ }
+ ci_ptr++;
+ }
+ }
+}
+
+/* Open a gcda file specified by GI_FILENAME.
+ Return -1 on error. Return 0 on success. */
+
+static int
+gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
+{
+ int gcov_prefix_strip;
+ size_t prefix_length;
+ char *gi_filename_up;
+
+ gcov_prefix_strip = gf->gcov_prefix_strip;
+ gi_filename_up = gf->gi_filename_up;
+ prefix_length = gf->prefix_length;
+
+ gcov_strip_leading_dirs (prefix_length, gcov_prefix_strip, gi_ptr->filename,
+ gi_filename_up);
+
+ return gcov_open_by_filename (gi_filename);
+}
+
/* Dump the coverage counts for one gcov_info object. We merge with existing
counts when possible, to avoid growing the .da files ad infinitum. We use
this program's checksum to make sure we only accumulate whole program
@@ -918,9 +1139,14 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf,
gcov_unsigned_t crc32, struct gcov_summary *all_prg,
struct gcov_summary *this_prg)
{
+/* We have to make the decl static as kernel has limited stack size.
+ If we put prg to stack, we will running into nasty stack overflow. */
+#if defined(__KERNEL__)
+ static
+#endif
struct gcov_summary prg; /* summary for this object over all program. */
int error;
- gcov_unsigned_t tag;
+ gcov_unsigned_t tag = 0;
gcov_position_t summary_pos = 0;
gcov_position_t eof_pos = 0;
@@ -928,12 +1154,15 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf,
sum_buffer = 0;
gcov_sort_topn_counter_arrays (gi_ptr);
+ gcov_scaling_lipo_counters (gi_ptr);
error = gcov_exit_open_gcda_file (gi_ptr, gf);
if (error == -1)
return;
+#if !defined(__KERNEL__)
tag = gcov_read_unsigned ();
+#endif
if (tag)
{
/* Merge data from file. */
@@ -964,8 +1193,21 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf,
/* fall through */
read_fatal:;
+#if !defined(__KERNEL__)
while (fn_buffer)
fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
+#else
+
+ /* In LIPO mode, dump the primary module info. */
+ if (gi_ptr->mod_info && gi_ptr->mod_info->is_primary)
+ {
+ /* Overwrite the zero word at the of the file. */
+ gcov_seek (gi_ptr->eof_pos);
+ gcov_write_module_info (gi_ptr, 1);
+ /* Write the end marker */
+ gcov_write_unsigned (0);
+ }
+#endif
if ((error = gcov_close ()))
gcov_error (error < 0 ?
@@ -974,6 +1216,7 @@ read_fatal:;
gi_filename);
}
+#if !defined (__KERNEL__)
/* Write imported files (auxiliary modules) for primary module GI_PTR
into file GI_FILENAME. */
@@ -1009,7 +1252,7 @@ gcov_write_import_file (char *gi_filename, struct gcov_info *gi_ptr)
fprintf (imports_file, "%s%s\n",
imp_mods[i]->imp_mod->mod_info->da_filename, GCOV_DATA_SUFFIX);
}
- free (imp_mods);
+ xfree (imp_mods);
}
fclose (imports_file);
}
@@ -1020,9 +1263,24 @@ gcov_dump_module_info (struct gcov_filename_aux *gf)
{
struct gcov_info *gi_ptr;
+ unsigned max_module_id = 0;
+ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+ {
+ unsigned mod_id = gi_ptr->mod_info->ident;
+ if (max_module_id < mod_id)
+ max_module_id = mod_id;
+ }
+ char **zero_counts = (char **) xcalloc (max_module_id, sizeof (char *));
+ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+ {
+ unsigned mod_id = gi_ptr->mod_info->ident;
+ zero_counts[mod_id-1] = (char *) xcalloc (gi_ptr->n_functions,
+ sizeof (char));
+ }
+
/* Compute the module groups and record whether there were any
counter fixups applied that require rewriting the counters. */
- int changed = __gcov_compute_module_groups ();
+ int changed = __gcov_compute_module_groups (zero_counts);
/* Now write out module group info. */
for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
@@ -1034,10 +1292,10 @@ gcov_dump_module_info (struct gcov_filename_aux *gf)
if (changed)
{
- /* Scan file to find the end of the summary section, which is
+ /* Scan file to find the start of the function section, which is
where we will start re-writing the counters. */
gcov_position_t summary_end_pos;
- if (gcov_scan_summary_end (gi_ptr, &summary_end_pos) == -1)
+ if (gcov_scan_to_function_data (gi_ptr, &summary_end_pos) == -1)
gcov_error ("profiling:%s:Error scanning summaries\n",
gi_filename);
else
@@ -1045,8 +1303,15 @@ gcov_dump_module_info (struct gcov_filename_aux *gf)
gcov_position_t eof_pos = gi_ptr->eof_pos;
gcov_rewrite ();
gcov_seek (summary_end_pos);
+
+ unsigned mod_id = gi_ptr->mod_info->ident;
+ gcov_write_comdat_zero_fixup (zero_counts[mod_id-1],
+ gi_ptr->n_functions);
+ gcov_position_t zero_fixup_eof_pos = gcov_position ();
+
gcov_write_func_counters (gi_ptr);
- gcc_assert (eof_pos == gi_ptr->eof_pos);
+ gcc_assert (eof_pos + (zero_fixup_eof_pos - summary_end_pos)
+ == gi_ptr->eof_pos);
}
}
else
@@ -1065,7 +1330,11 @@ gcov_dump_module_info (struct gcov_filename_aux *gf)
"profiling:%s:Error writing\n",
gi_filename);
gcov_write_import_file (gi_filename, gi_ptr);
+ free (zero_counts[gi_ptr->mod_info->ident-1]);
}
+
+ free (zero_counts);
+
__gcov_finalize_dyn_callgraph ();
}
@@ -1102,7 +1371,8 @@ gcov_exit (void)
/* The IS_PRIMARY field is overloaded to indicate if this module
is FDO/LIPO. */
- dump_module_info |= gi_ptr->mod_info->is_primary;
+ if (gi_ptr->mod_info)
+ dump_module_info |= gi_ptr->mod_info->is_primary;
}
run_accounted = 1;
@@ -1110,38 +1380,7 @@ gcov_exit (void)
gcov_dump_module_info (&gf);
if (gi_filename)
- free (gi_filename);
-}
-
-/* Reset all counters to zero. */
-
-void
-gcov_clear (void)
-{
- const struct gcov_info *gi_ptr;
-
- for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
- {
- unsigned f_ix;
-
- for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
- {
- unsigned t_ix;
- const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
-
- if (!gfi_ptr || gfi_ptr->key != gi_ptr)
- continue;
- const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
- for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
- {
- if (!gi_ptr->merge[t_ix])
- continue;
-
- memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
- ci_ptr++;
- }
- }
- }
+ xfree (gi_filename);
}
/* Add a new object file onto the bb chain. Invoked automatically
@@ -1160,6 +1399,13 @@ __gcov_init (struct gcov_info *info)
if (env_value_int >= 1)
__gcov_sampling_period = env_value_int;
}
+ env_value_str = getenv ("GCOV_LIPO_SAMPLING_PERIOD");
+ if (env_value_str)
+ {
+ int env_value_int = atoi(env_value_str);
+ if (env_value_int >= 0)
+ __gcov_lipo_sampling_period = env_value_int;
+ }
gcov_sampling_period_initialized = 1;
}
#endif
@@ -1189,5 +1435,116 @@ __gcov_init (struct gcov_info *info)
info->version = 0;
}
+#else /* __KERNEL__ */
+
+static struct gcov_filename_aux gf;
+static gcov_unsigned_t crc32;
+static struct gcov_summary all_prg;
+static struct gcov_summary this_prg;
+void
+gcov_kernel_dump_gcov_init (void)
+{
+ crc32 = gcov_exit_compute_summary (&this_prg);
+ allocate_filename_struct (&gf);
+ memset (&all_prg, 0, sizeof (all_prg));
+}
+
+void
+gcov_kernel_dump_one_gcov(struct gcov_info *info)
+{
+ gcov_exit_dump_gcov (info, &gf, crc32, &all_prg, &this_prg);
+}
+
+#endif /* __KERNEL__ */
+
+/* Reset all counters to zero. */
+
+void
+gcov_clear (void)
+{
+ const struct gcov_info *gi_ptr;
+
+ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+ {
+ unsigned f_ix;
+
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ unsigned t_ix;
+ const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+ const struct gcov_ctr_info *ci_ptr;
+
+ if (!gfi_ptr || gfi_ptr->key != gi_ptr)
+ continue;
+ ci_ptr = gfi_ptr->ctrs;
+ for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+ {
+ if (!gi_ptr->merge[t_ix])
+ continue;
+
+ memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
+ ci_ptr++;
+ }
+ }
+ }
+}
+
+/* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag
+ indicating if the module is the primary module in the group. */
+
+void
+gcov_write_module_info (const struct gcov_info *mod_info,
+ unsigned is_primary)
+{
+ gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i;
+ gcov_unsigned_t num_strings;
+ gcov_unsigned_t *aligned_fname;
+ struct gcov_module_info *module_info = mod_info->mod_info;
+ filename_len = (strlen (module_info->da_filename) +
+ sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t);
+ src_filename_len = (strlen (module_info->source_filename) +
+ sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t);
+ len = filename_len + src_filename_len;
+ len += 2; /* each name string is led by a length. */
+
+ num_strings = module_info->num_quote_paths + module_info->num_bracket_paths
+ + module_info->num_system_paths
+ + module_info->num_cpp_defines + module_info->num_cpp_includes
+ + module_info->num_cl_args;
+ len += gcov_compute_string_array_len (module_info->string_array,
+ num_strings);
+
+ len += 11; /* 11 more fields */
+
+ gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len);
+ gcov_write_unsigned (module_info->ident);
+ gcov_write_unsigned (is_primary);
+ gcov_write_unsigned (module_info->flags);
+ gcov_write_unsigned (module_info->lang);
+ gcov_write_unsigned (module_info->ggc_memory);
+ gcov_write_unsigned (module_info->num_quote_paths);
+ gcov_write_unsigned (module_info->num_bracket_paths);
+ gcov_write_unsigned (module_info->num_system_paths);
+ gcov_write_unsigned (module_info->num_cpp_defines);
+ gcov_write_unsigned (module_info->num_cpp_includes);
+ gcov_write_unsigned (module_info->num_cl_args);
+
+ /* Now write the filenames */
+ aligned_fname = (gcov_unsigned_t *) alloca ((filename_len + src_filename_len + 2) *
+ sizeof (gcov_unsigned_t));
+ memset (aligned_fname, 0,
+ (filename_len + src_filename_len + 2) * sizeof (gcov_unsigned_t));
+ aligned_fname[0] = filename_len;
+ strcpy ((char*) (aligned_fname + 1), module_info->da_filename);
+ aligned_fname[filename_len + 1] = src_filename_len;
+ strcpy ((char*) (aligned_fname + filename_len + 2), module_info->source_filename);
+
+ for (i = 0; i < (filename_len + src_filename_len + 2); i++)
+ gcov_write_unsigned (aligned_fname[i]);
+
+ /* Now write the string array. */
+ gcov_write_string_array (module_info->string_array, num_strings);
+}
+
#endif /* L_gcov */
#endif /* inhibit_libc */
diff --git a/gcc-4.9/libgcc/libgcov-kernel.h b/gcc-4.9/libgcc/libgcov-kernel.h
new file mode 100644
index 000000000..b44af53c7
--- /dev/null
+++ b/gcc-4.9/libgcc/libgcov-kernel.h
@@ -0,0 +1,121 @@
+/* Header file for libgcov-*.c.
+ Copyright (C) 1996-2014 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_LIBGCOV_KERNEL_H
+#define GCC_LIBGCOV_KERNEL_H
+
+/* work around the poisoned malloc/calloc in system.h. */
+#ifndef xmalloc
+#define xmalloc vmalloc
+#endif
+#ifndef xcalloc
+#define xcalloc vcalloc
+#endif
+#ifndef xrealloc
+#define xrealloc vrealloc
+#endif
+#ifndef xfree
+#define xfree vfree
+#endif
+#ifndef alloca
+#define alloca __builtin_alloca
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+ /* Define MACROs to be used by kernel compilation. */
+# define L_gcov
+# define L_gcov_interval_profiler
+# define L_gcov_pow2_profiler
+# define L_gcov_one_value_profiler
+# define L_gcov_indirect_call_profiler_v2
+# define L_gcov_direct_call_profiler
+# define L_gcov_indirect_call_profiler
+# define L_gcov_indirect_call_topn_profiler
+# define L_gcov_time_profiler
+# define L_gcov_average_profiler
+# define L_gcov_ior_profiler
+# define L_gcov_merge_add
+# define L_gcov_merge_single
+# define L_gcov_merge_delta
+# define L_gcov_merge_ior
+# define L_gcov_merge_time_profile
+# define L_gcov_merge_icall_topn
+# define L_gcov_merge_dc
+
+# define IN_LIBGCOV 1
+# define IN_GCOV 0
+#define THREAD_PREFIX
+#define GCOV_LINKAGE /* nothing */
+#define BITS_PER_UNIT 8
+#define LONG_LONG_TYPE_SIZE 64
+#define MEMMODEL_RELAXED 0
+
+#define ENABLE_ASSERT_CHECKING 1
+
+/* gcc_assert() prints out a warning if the check fails. It
+ will not abort. */
+#if ENABLE_ASSERT_CHECKING
+# define gcc_assert(EXPR) \
+ ((void)(!(EXPR) ? printk (KERN_WARNING \
+ "GCOV assertion fails: func=%s line=%d\n", \
+ __FUNCTION__, __LINE__), 0 : 0))
+#else
+# define gcc_assert(EXPR) ((void)(0 && (EXPR)))
+#endif
+
+/* In Linux kernel mode, a virtual file is used for file operations. */
+struct gcov_info;
+typedef struct {
+ long size; /* size of buf */
+ long count; /* element written into buf */
+ struct gcov_info *info;
+ char *buf;
+} gcov_kernel_vfile;
+
+#define _GCOV_FILE gcov_kernel_vfile
+
+/* Wrappers to the file operations. */
+#define _GCOV_fclose kernel_file_fclose
+#define _GCOV_ftell kernel_file_ftell
+#define _GCOV_fseek kernel_file_fseek
+#define _GCOV_ftruncate kernel_file_ftruncate
+#define _GCOV_fread kernel_file_fread
+#define _GCOV_fwrite kernel_file_fwrite
+#define _GCOV_fileno kernel_file_fileno
+
+/* Declarations for virtual files operations. */
+extern int kernel_file_fclose (gcov_kernel_vfile *);
+extern long kernel_file_ftell (gcov_kernel_vfile *);
+extern int kernel_file_fseek (gcov_kernel_vfile *, long, int);
+extern int kernel_file_ftruncate (gcov_kernel_vfile *, off_t);
+extern int kernel_file_fread (void *, size_t, size_t,
+ gcov_kernel_vfile *);
+extern int kernel_file_fwrite (const void *, size_t, size_t,
+ gcov_kernel_vfile *);
+extern int kernel_file_fileno (gcov_kernel_vfile *);
+
+#endif /* GCC_LIBGCOV_KERNEL_H */
diff --git a/gcc-4.9/libgcc/libgcov-merge.c b/gcc-4.9/libgcc/libgcov-merge.c
index ddbf06aaf..997dab3e9 100644
--- a/gcc-4.9/libgcc/libgcov-merge.c
+++ b/gcc-4.9/libgcc/libgcov-merge.c
@@ -108,10 +108,12 @@ __gcov_merge_dc (gcov_type *counters, unsigned n_counters)
else if (__gcov_is_gid_insane (global_id))
global_id = counters[i];
+#if !defined(__KERNEL__)
/* In the case of inconsistency, use the src's target. */
if (counters[i] != global_id)
fprintf (stderr, "Warning: Inconsistent call targets in"
" direct-call profile.\n");
+#endif
}
else if (global_id)
counters[i] = global_id;
diff --git a/gcc-4.9/libgcc/libgcov-profiler.c b/gcc-4.9/libgcc/libgcov-profiler.c
index 3057b6157..7552adac8 100644
--- a/gcc-4.9/libgcc/libgcov-profiler.c
+++ b/gcc-4.9/libgcc/libgcov-profiler.c
@@ -221,13 +221,29 @@ __gcov_indirect_call_profiler_atomic_v2 (gcov_type value, void* cur_func)
the descriptors to see if they point to the same function. */
if (cur_func == __gcov_indirect_call_callee
|| (VTABLE_USES_DESCRIPTORS && __gcov_indirect_call_callee
- && *(void **) cur_func == *(void **) __gcov_indirect_call_callee))
+ && *(void **) cur_func == *(void **) __gcov_indirect_call_callee))
__gcov_one_value_profiler_body_atomic (__gcov_indirect_call_counters, value);
}
#endif
+/*
+#if defined(L_gcov_direct_call_profiler) || defined(L_gcov_indirect_call_topn_profiler)
+__attribute__ ((weak)) gcov_unsigned_t __gcov_lipo_sampling_period;
+#endif
+*/
+
+extern gcov_unsigned_t __gcov_lipo_sampling_period;
+
#ifdef L_gcov_indirect_call_topn_profiler
+
+#include "gthr.h"
+
+#ifdef __GTHREAD_MUTEX_INIT
+__thread int in_profiler;
+ATTRIBUTE_HIDDEN __gthread_mutex_t __indir_topn_val_mx = __GTHREAD_MUTEX_INIT;
+#endif
+
/* Tries to keep track the most frequent N values in the counters where
N is specified by parameter TOPN_VAL. To track top N values, 2*N counter
entries are used.
@@ -252,10 +268,18 @@ __gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value,
/* There are 2*topn_val values tracked, each value takes two slots in the
counter array */
- for ( i = 0; i < (topn_val << 2); i += 2)
+#ifdef __GTHREAD_MUTEX_INIT
+ /* If this is reentry, return. */
+ if (in_profiler == 1)
+ return;
+
+ in_profiler = 1;
+ __gthread_mutex_lock (&__indir_topn_val_mx);
+#endif
+ for (i = 0; i < topn_val << 2; i += 2)
{
entry = &value_array[i];
- if ( entry[0] == value)
+ if (entry[0] == value)
{
entry[1]++ ;
found = 1;
@@ -271,7 +295,13 @@ __gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value,
}
if (found)
- return;
+ {
+ in_profiler = 0;
+#ifdef __GTHREAD_MUTEX_INIT
+ __gthread_mutex_unlock (&__indir_topn_val_mx);
+#endif
+ return;
+ }
/* lfu_entry is either an empty entry or an entry
with lowest count, which will be evicted. */
@@ -280,56 +310,49 @@ __gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value,
#define GCOV_ICALL_COUNTER_CLEAR_THRESHOLD 3000
- /* Too many evictions -- time to clear bottom entries to
+ /* Too many evictions -- time to clear bottom entries to
avoid hot values bumping each other out. */
- if ( !have_zero_count
- && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD)
+ if (!have_zero_count
+ && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD)
{
unsigned i, j;
- gcov_type *p, minv;
- gcov_type* tmp_cnts
- = (gcov_type *)alloca (topn_val * sizeof(gcov_type));
+ gcov_type **p;
+ gcov_type **tmp_cnts
+ = (gcov_type **)alloca (topn_val * sizeof(gcov_type *));
*num_eviction = 0;
- for ( i = 0; i < topn_val; i++ )
- tmp_cnts[i] = 0;
-
/* Find the largest topn_val values from the group of
- 2*topn_val values and put them into tmp_cnts. */
+ 2*topn_val values and put the addresses into tmp_cnts. */
+ for (i = 0; i < topn_val; i++)
+ tmp_cnts[i] = &value_array[i * 2 + 1];
- for ( i = 0; i < 2 * topn_val; i += 2 )
+ for (i = topn_val * 2; i < topn_val << 2; i += 2)
{
- p = 0;
- for ( j = 0; j < topn_val; j++ )
- {
- if ( !p || tmp_cnts[j] < *p )
- p = &tmp_cnts[j];
- }
- if ( value_array[i + 1] > *p )
- *p = value_array[i + 1];
+ p = &tmp_cnts[0];
+ for (j = 1; j < topn_val; j++)
+ if (*tmp_cnts[j] > **p)
+ p = &tmp_cnts[j];
+ if (value_array[i + 1] < **p)
+ *p = &value_array[i + 1];
}
- minv = tmp_cnts[0];
- for ( j = 1; j < topn_val; j++ )
- {
- if (tmp_cnts[j] < minv)
- minv = tmp_cnts[j];
- }
- /* Zero out low value entries */
- for ( i = 0; i < 2 * topn_val; i += 2 )
+ /* Zero out low value entries. */
+ for (i = 0; i < topn_val; i++)
{
- if (value_array[i + 1] < minv)
- {
- value_array[i] = 0;
- value_array[i + 1] = 0;
- }
+ *tmp_cnts[i] = 0;
+ *(tmp_cnts[i] - 1) = 0;
}
}
+
+#ifdef __GTHREAD_MUTEX_INIT
+ in_profiler = 0;
+ __gthread_mutex_unlock (&__indir_topn_val_mx);
+#endif
}
#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
-__thread
+__thread
#endif
gcov_type *__gcov_indirect_call_topn_counters ATTRIBUTE_HIDDEN;
@@ -338,6 +361,11 @@ __thread
#endif
void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN;
+#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
+__thread
+#endif
+gcov_unsigned_t __gcov_indirect_call_sampling_counter ATTRIBUTE_HIDDEN;
+
#ifdef TARGET_VTABLE_USES_DESCRIPTORS
#define VTABLE_USES_DESCRIPTORS 1
#else
@@ -355,12 +383,16 @@ __gcov_indirect_call_topn_profiler (void *cur_func,
the descriptors to see if they point to the same function. */
if (cur_func == callee_func
|| (VTABLE_USES_DESCRIPTORS && callee_func
- && *(void **) cur_func == *(void **) callee_func))
+ && *(void **) cur_func == *(void **) callee_func))
{
- gcov_type global_id
- = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
- global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
- __gcov_topn_value_profiler_body (counter, global_id, GCOV_ICALL_TOPN_VAL);
+ if (++__gcov_indirect_call_sampling_counter >= __gcov_lipo_sampling_period)
+ {
+ __gcov_indirect_call_sampling_counter = 0;
+ gcov_type global_id
+ = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
+ global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
+ __gcov_topn_value_profiler_body (counter, global_id, GCOV_ICALL_TOPN_VAL);
+ }
__gcov_indirect_call_topn_callee = 0;
}
}
@@ -376,7 +408,13 @@ gcov_type *__gcov_direct_call_counters ATTRIBUTE_HIDDEN;
__thread
#endif
void *__gcov_direct_call_callee ATTRIBUTE_HIDDEN;
+#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
+__thread
+#endif
+gcov_unsigned_t __gcov_direct_call_sampling_counter ATTRIBUTE_HIDDEN;
+
/* Direct call profiler. */
+
void
__gcov_direct_call_profiler (void *cur_func,
void *cur_module_gcov_info,
@@ -384,11 +422,15 @@ __gcov_direct_call_profiler (void *cur_func,
{
if (cur_func == __gcov_direct_call_callee)
{
- gcov_type global_id
- = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
- global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
- __gcov_direct_call_counters[0] = global_id;
- __gcov_direct_call_counters[1]++;
+ if (++__gcov_direct_call_sampling_counter >= __gcov_lipo_sampling_period)
+ {
+ __gcov_direct_call_sampling_counter = 0;
+ gcov_type global_id
+ = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
+ global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
+ __gcov_direct_call_counters[0] = global_id;
+ __gcov_direct_call_counters[1]++;
+ }
__gcov_direct_call_callee = 0;
}
}
diff --git a/gcc-4.9/libgcc/libgcov-util.c b/gcc-4.9/libgcc/libgcov-util.c
index 09d588675..4435cff4f 100644
--- a/gcc-4.9/libgcc/libgcov-util.c
+++ b/gcc-4.9/libgcc/libgcov-util.c
@@ -66,6 +66,7 @@ static void tag_lines (unsigned, unsigned);
static void tag_counters (unsigned, unsigned);
static void tag_summary (unsigned, unsigned);
static void tag_module_info (unsigned, unsigned);
+static void tag_zero_fixup (unsigned, unsigned);
/* The gcov_info for the first module. */
static struct gcov_info *curr_gcov_info;
@@ -88,6 +89,8 @@ static int k_ctrs_types;
/* The longest length of all the filenames. */
static int max_filename_len;
+static int *zero_fixup_flags = NULL;
+
/* Merge functions for counters. Similar to __gcov_dyn_ipa_merge_*
functions in dyn-ipa.c, which were derived from these, except
the versions in dyn-ipa are used when merging from another array. */
@@ -143,6 +146,7 @@ static const tag_format_t tag_table[] =
{GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
{GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
{GCOV_TAG_MODULE_INFO, "MODULE INFO", tag_module_info},
+ {GCOV_TAG_COMDAT_ZERO_FIXUP, "ZERO FIXUP", tag_zero_fixup},
{0, NULL, NULL}
};
@@ -169,14 +173,18 @@ tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
k_ctrs[i].num = 0;
k_ctrs_types = 0;
+ if (zero_fixup_flags)
+ {
+ set_gcov_fn_fixed_up (zero_fixup_flags[num_fn_info]);
+ if (get_gcov_fn_fixed_up () && verbose)
+ fprintf (stderr, "Function id=%d fixed up\n", curr_fn_info->ident);
+ }
+
curr_fn_info->key = curr_gcov_info;
curr_fn_info->ident = gcov_read_unsigned ();
curr_fn_info->lineno_checksum = gcov_read_unsigned ();
curr_fn_info->cfg_checksum = gcov_read_unsigned ();
num_fn_info++;
-
- if (verbose)
- fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
}
/* Handler for reading block tag. */
@@ -226,7 +234,13 @@ tag_counters (unsigned tag, unsigned length)
gcc_assert (values);
for (ix = 0; ix != n_counts; ix++)
- values[ix] = gcov_read_counter ();
+ {
+ gcov_type val = gcov_read_counter ();
+ if (!get_gcov_fn_fixed_up ())
+ values[ix] = val;
+ else
+ values[ix] = 0;
+ }
}
/* Handler for reading summary tag. */
@@ -323,7 +337,7 @@ lipo_process_substitute_string_1 (char *input_str,
char *t;
if (verbose)
- printf ("Substitute: %s \n", input_str);
+ fprintf (stderr, "Substitute: %s \n", input_str);
t = (char*) xmalloc (strlen (input_str) + 1
+ strlen (new_str) - strlen (cur_str));
*p = 0;
@@ -332,7 +346,7 @@ lipo_process_substitute_string_1 (char *input_str,
strcat (t, new_str);
strcat (t, p + strlen (cur_str));
if (verbose)
- printf (" --> %s\n", t);
+ fprintf (stderr, " --> %s\n", t);
return t;
}
@@ -397,6 +411,16 @@ tag_module_info (unsigned tag ATTRIBUTE_UNUSED, unsigned length)
free (mod_info);
}
+/* Handler for reading the COMDAT zero-profile fixup section. */
+
+static void
+tag_zero_fixup (unsigned tag ATTRIBUTE_UNUSED, unsigned length)
+{
+ gcov_unsigned_t num_fns = 0;
+ zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns);
+ gcc_assert (zero_fixup_flags);
+}
+
/* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
Program level summary CURRENT_SUMMARY will also be updated. */
@@ -464,62 +488,63 @@ read_gcda_file (const char *filename)
tag = gcov_read_unsigned ();
if (!tag)
- break;
+ break;
length = gcov_read_unsigned ();
base = gcov_position ();
mask = GCOV_TAG_MASK (tag) >> 1;
for (tag_depth = 4; mask; mask >>= 8)
- {
- if (((mask & 0xff) != 0xff))
- {
- warning (0, "%s:tag `%x' is invalid\n", filename, tag);
- break;
- }
- tag_depth--;
- }
+ {
+ if (((mask & 0xff) != 0xff))
+ {
+ warning (0, "%s:tag `%x' is invalid\n", filename, tag);
+ break;
+ }
+ tag_depth--;
+ }
for (format = tag_table; format->name; format++)
- if (format->tag == tag)
- goto found;
+ if (format->tag == tag)
+ goto found;
format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
found:;
if (tag)
- {
- if (depth && depth < tag_depth)
- {
- if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
- warning (0, "%s:tag `%x' is incorrectly nested\n",
- filename, tag);
- }
- depth = tag_depth;
- tags[depth - 1] = tag;
- }
+ {
+ if (depth && depth < tag_depth)
+ {
+ if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
+ warning (0, "%s:tag `%x' is incorrectly nested\n",
+ filename, tag);
+ }
+ depth = tag_depth;
+ tags[depth - 1] = tag;
+ }
if (format->proc)
{
- unsigned long actual_length;
+ unsigned long actual_length;
- (*format->proc) (tag, length);
+ (*format->proc) (tag, length);
- actual_length = gcov_position () - base;
- if (actual_length > length)
- warning (0, "%s:record size mismatch %lu bytes overread\n",
- filename, actual_length - length);
- else if (length > actual_length)
- warning (0, "%s:record size mismatch %lu bytes unread\n",
- filename, length - actual_length);
- }
+ actual_length = gcov_position () - base;
+ if (actual_length > length)
+ warning (0, "%s:record size mismatch %lu bytes overread\n",
+ filename, actual_length - length);
+ else if (length > actual_length)
+ warning (0, "%s:record size mismatch %lu bytes unread\n",
+ filename, length - actual_length);
+ }
gcov_sync (base, length);
if ((error = gcov_is_error ()))
- {
- warning (0, error < 0 ? "%s:counter overflow at %lu\n" :
- "%s:read error at %lu\n", filename,
- (long unsigned) gcov_position ());
- break;
- }
+ {
+ warning (0, error < 0 ? "%s:counter overflow at %lu\n" :
+ "%s:read error at %lu\n", filename,
+ (long unsigned) gcov_position ());
+ break;
+ }
}
read_gcda_finalize (obj_info);
+ free (zero_fixup_flags);
gcov_close ();
return obj_info;
@@ -539,6 +564,18 @@ set_use_modu_list (void)
flag_use_modu_list = 1;
}
+/* Source profile directory name. */
+
+static const char *source_profile_dir;
+
+/* Return Source profile directory name. */
+
+const char *
+get_source_profile_dir (void)
+{
+ return source_profile_dir;
+}
+
/* Handler to open and read a gcda file FILENAME. */
static int
@@ -569,6 +606,20 @@ read_file_handler (const char *filename)
unsigned mod_id = obj_info->mod_info->ident;
int create = (flag_use_modu_list ? 0 : 1);
+ if (!source_profile_dir)
+ {
+ static char resolved_path[PATH_MAX + 1];
+ char *abs_path = realpath (filename, resolved_path);
+
+ if (abs_path)
+ {
+ char *p = strstr (abs_path, obj_info->mod_info->da_filename);
+ gcc_assert (p);
+ *p = 0;
+ source_profile_dir = abs_path;
+ }
+ }
+
if (!is_module_available (obj_info->mod_info->source_filename,
&mod_id, create))
{
@@ -605,6 +656,7 @@ ftw_read_file (const char *filename,
#else /* _WIN32 */
/* Funtion to find all the gcda files recursively in DIR. */
+
static void
myftw (char *dir, char* pattern, int (*handler)(const char *))
{
@@ -648,18 +700,6 @@ myftw (char *dir, char* pattern, int (*handler)(const char *))
}
#endif
-/* Source profile directory name. */
-
-static const char *source_profile_dir;
-
-/* Return Source profile directory name. */
-
-const char *
-get_source_profile_dir (void)
-{
- return source_profile_dir;
-}
-
/* Initializer for reading a profile dir. */
static inline void
@@ -694,7 +734,6 @@ gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNU
fnotice (stderr, "%s is not a directory\n", dir_name);
return NULL;
}
- source_profile_dir = getcwd (NULL, 0);
#if !defined(_WIN32)
ftw (".", ftw_read_file, 50);
@@ -831,7 +870,8 @@ gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
Return NULL if there is no match. */
static struct gcov_info *
-find_match_gcov_info (struct gcov_info **array, int size, struct gcov_info *info)
+find_match_gcov_info (struct gcov_info **array, int size,
+ struct gcov_info *info)
{
struct gcov_info *gi_ptr;
struct gcov_info *ret = NULL;
@@ -935,6 +975,7 @@ gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile
tgt_tail->next = gi_ptr;
tgt_tail = gi_ptr;
}
+ tgt_tail->next = 0;
return 0;
}
@@ -1085,7 +1126,7 @@ gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
unsigned f_ix;
if (verbose)
- fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
+ fnotice (stderr, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
/* Scaling the counters. */
for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
@@ -1153,8 +1194,533 @@ gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
scale_factor = (float)max_val / curr_max_val;
#if !defined (_WIN32)
if (verbose)
- fnotice (stdout, "max_val is %lld\n", (long long) curr_max_val);
+ fnotice (stdout, "max_val is %lld\n", curr_max_val);
#endif
return gcov_profile_scale (profile, scale_factor, 0, 0);
}
+
+/* The following variables are defined in gcc/gcov-tool.c. */
+extern int overlap_func_level;
+extern int overlap_obj_level;
+extern int overlap_hot_only;
+extern int overlap_use_fullname;
+extern double overlap_hot_threshold;
+
+/* Compute the overlap score of two values. The score is defined as:
+ min (V1/SUM_1, V2/SUM_2) */
+
+static double
+calculate_2_entries (const unsigned long v1, const unsigned long v2,
+ const double sum_1, const double sum_2)
+{
+ double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
+ double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
+
+ if (val2 < val1)
+ val1 = val2;
+
+ return val1;
+}
+
+/* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
+ SUM_1 is the sum_all for profile1 where GCOV_INFO1 belongs.
+ SUM_2 is the sum_all for profile2 where GCOV_INFO2 belongs.
+ This function also updates cumulative score CUM_1_RESULT and
+ CUM_2_RESULT. */
+
+static double
+compute_one_gcov (const struct gcov_info *gcov_info1,
+ const struct gcov_info *gcov_info2,
+ const double sum_1, const double sum_2,
+ double *cum_1_result, double *cum_2_result)
+{
+ unsigned f_ix;
+ double ret = 0;
+ double cum_1 = 0, cum_2 = 0;
+ const struct gcov_info *gcov_info = 0;
+ double *cum_p;
+ double sum;
+
+ gcc_assert (gcov_info1 || gcov_info2);
+ if (!gcov_info1)
+ {
+ gcov_info = gcov_info2;
+ cum_p = cum_2_result;
+ sum = sum_2;
+ *cum_1_result = 0;
+ } else
+ if (!gcov_info2)
+ {
+ gcov_info = gcov_info1;
+ cum_p = cum_1_result;
+ sum = sum_1;
+ *cum_2_result = 0;
+ }
+
+ if (gcov_info)
+ {
+ for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
+ {
+ unsigned t_ix;
+ const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
+ if (!gfi_ptr || gfi_ptr->key != gcov_info)
+ continue;
+ const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
+ for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
+ {
+ unsigned c_num;
+
+ if (!gcov_info->merge[t_ix])
+ continue;
+
+ for (c_num = 0; c_num < ci_ptr->num; c_num++)
+ {
+ cum_1 += ci_ptr->values[c_num] / sum;
+ }
+ ci_ptr++;
+ }
+ }
+ *cum_p = cum_1;
+ return 0.0;
+ }
+
+ for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
+ {
+ unsigned t_ix;
+ double func_cum_1 = 0.0;
+ double func_cum_2 = 0.0;
+ double func_val = 0.0;
+ int nonzero = 0;
+ int hot = 0;
+ const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
+ const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
+
+ if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
+ continue;
+ if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
+ continue;
+
+ const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
+ const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
+ for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
+ {
+ unsigned c_num;
+
+ if (!gcov_info1->merge[t_ix])
+ continue;
+
+ for (c_num = 0; c_num < ci_ptr1->num; c_num++)
+ {
+ if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
+ {
+ func_val += calculate_2_entries (ci_ptr1->values[c_num],
+ ci_ptr2->values[c_num],
+ sum_1, sum_2);
+
+ func_cum_1 += ci_ptr1->values[c_num] / sum_1;
+ func_cum_2 += ci_ptr2->values[c_num] / sum_2;
+ nonzero = 1;
+ if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold ||
+ ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
+ hot = 1;
+ }
+ }
+ ci_ptr1++;
+ ci_ptr2++;
+ }
+ ret += func_val;
+ cum_1 += func_cum_1;
+ cum_2 += func_cum_2;
+ if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
+ {
+ printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
+ gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
+ }
+ }
+ *cum_1_result = cum_1;
+ *cum_2_result = cum_2;
+ return ret;
+}
+
+/* Test if all counter values in this GCOV_INFO are cold.
+ "Cold" is defined as the counter value being less than
+ or equal to THRESHOLD. */
+
+static bool
+gcov_info_count_all_cold (const struct gcov_info *gcov_info,
+ gcov_type threshold)
+{
+ unsigned f_ix;
+
+ for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
+ {
+ unsigned t_ix;
+ const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
+
+ if (!gfi_ptr || gfi_ptr->key != gcov_info)
+ continue;
+ const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
+ for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
+ {
+ unsigned c_num;
+
+ if (!gcov_info->merge[t_ix])
+ continue;
+
+ for (c_num = 0; c_num < ci_ptr->num; c_num++)
+ {
+ if (ci_ptr->values[c_num] > threshold)
+ return false;
+ }
+ ci_ptr++;
+ }
+ }
+
+ return true;
+}
+
+/* Test if all counter values in this GCOV_INFO are 0. */
+
+static bool
+gcov_info_count_all_zero (const struct gcov_info *gcov_info)
+{
+ return gcov_info_count_all_cold (gcov_info, 0);
+}
+
+/* A pair of matched GCOV_INFO.
+ The flag is a bitvector:
+ b0: obj1's all counts are 0;
+ b1: obj1's all counts are cold (but no 0);
+ b2: obj1 is hot;
+ b3: no obj1 to match obj2;
+ b4: obj2's all counts are 0;
+ b5: obj2's all counts are cold (but no 0);
+ b6: obj2 is hot;
+ b7: no obj2 to match obj1;
+ */
+struct overlap_t {
+ const struct gcov_info *obj1;
+ const struct gcov_info *obj2;
+ char flag;
+};
+
+#define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
+#define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
+#define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
+
+/* Cumlative overlap dscore for profile1 and profile2. */
+static double overlap_sum_1, overlap_sum_2;
+
+/* sum_all for profile1 and profile2. */
+static gcov_type p1_sum_all, p2_sum_all;
+
+/* run_max for profile1 and profile2. */
+static gcov_type p1_run_max, p2_run_max;
+
+/* The number of gcda files in the profiles. */
+static unsigned gcda_files[2];
+
+/* The number of unique gcda files in the profiles
+ (not existing in the other profile). */
+static unsigned unique_gcda_files[2];
+
+/* The number of gcda files that all counter values are 0. */
+static unsigned zero_gcda_files[2];
+
+/* The number of gcda files that all counter values are cold (but not 0). */
+static unsigned cold_gcda_files[2];
+
+/* The number of gcda files that includes hot counter values. */
+static unsigned hot_gcda_files[2];
+
+/* The number of gcda files with hot count value in either profiles. */
+static unsigned both_hot_cnt;
+
+/* The number of gcda files with all counts cold (but not 0) in
+ both profiles. */
+static unsigned both_cold_cnt;
+
+/* The number of gcda files with all counts 0 in both profiles. */
+static unsigned both_zero_cnt;
+
+/* Extract the basename of the filename NAME. */
+
+static char *
+extract_file_basename (const char *name)
+{
+ char *str;
+ int len = 0;
+ char *path = xstrdup (name);
+ char sep_str[2];
+
+ sep_str[0] = DIR_SEPARATOR;
+ sep_str[1] = 0;
+ str = strstr(path, sep_str);
+ do{
+ len = strlen(str) + 1;
+ path = &path[strlen(path) - len + 2];
+ str = strstr(path, sep_str);
+ } while(str);
+
+ return path;
+}
+
+/* Utility function to get the filename. */
+
+static const char *
+get_file_basename (const char *name)
+{
+ if (overlap_use_fullname)
+ return name;
+ return extract_file_basename (name);
+}
+
+/* A utility function to set the flag for the gcda files. */
+
+static void
+set_flag (struct overlap_t *e)
+{
+ char flag = 0;
+
+ if (!e->obj1)
+ {
+ unique_gcda_files[1]++;
+ flag = 0x8;
+ }
+ else
+ {
+ gcda_files[0]++;
+ if (gcov_info_count_all_zero (e->obj1))
+ {
+ zero_gcda_files[0]++;
+ flag = 0x1;
+ }
+ else
+ if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
+ * overlap_hot_threshold))
+ {
+ cold_gcda_files[0]++;
+ flag = 0x2;
+ }
+ else
+ {
+ hot_gcda_files[0]++;
+ flag = 0x4;
+ }
+ }
+
+ if (!e->obj2)
+ {
+ unique_gcda_files[0]++;
+ flag |= (0x8 << 4);
+ }
+ else
+ {
+ gcda_files[1]++;
+ if (gcov_info_count_all_zero (e->obj2))
+ {
+ zero_gcda_files[1]++;
+ flag |= (0x1 << 4);
+ }
+ else
+ if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
+ * overlap_hot_threshold))
+ {
+ cold_gcda_files[1]++;
+ flag |= (0x2 << 4);
+ }
+ else
+ {
+ hot_gcda_files[1]++;
+ flag |= (0x4 << 4);
+ }
+ }
+
+ gcc_assert (flag);
+ e->flag = flag;
+}
+
+/* Test if INFO1 and INFO2 are from the matched source file.
+ Return 1 if they match; return 0 otherwise. */
+
+static int
+matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
+{
+ /* For FDO, we have to match the name. This can be expensive.
+ Maybe we should use hash here. */
+ if (strcmp (info1->filename, info2->filename))
+ return 0;
+
+ if (info1->n_functions != info2->n_functions)
+ {
+ fnotice (stderr, "mismatched profiles in %s (%d functions"
+ " vs %d functions)\n",
+ info1->filename,
+ info1->n_functions,
+ info2->n_functions);
+ return 0;
+ }
+ return 1;
+}
+
+/* Defined in libgcov-driver.c. */
+extern gcov_unsigned_t gcov_exit_compute_summary (struct gcov_summary *);
+extern void set_gcov_list (struct gcov_info*);
+
+/* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
+ GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
+ match and 1.0 meaning a perfect match. */
+
+static double
+calculate_overlap (struct gcov_info *gcov_list1,
+ struct gcov_info *gcov_list2)
+{
+ struct gcov_summary this_prg;
+ unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
+ unsigned int i, j;
+ size_t max_length;
+ const struct gcov_info *gi_ptr;
+ struct overlap_t *all_infos;
+
+ set_gcov_list (gcov_list1);
+ gcov_exit_compute_summary (&this_prg);
+ overlap_sum_1 = (double) (this_prg.ctrs[0].sum_all);
+ p1_sum_all = this_prg.ctrs[0].sum_all;
+ p1_run_max = this_prg.ctrs[0].run_max;
+ set_gcov_list (gcov_list2);
+ gcov_exit_compute_summary (&this_prg);
+ overlap_sum_2 = (double) (this_prg.ctrs[0].sum_all);
+ p2_sum_all = this_prg.ctrs[0].sum_all;
+ p2_run_max = this_prg.ctrs[0].run_max;
+
+ for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
+ list1_cnt++;
+ for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
+ list2_cnt++;
+ all_cnt = list1_cnt + list2_cnt;
+ all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
+ * all_cnt * 2);
+ gcc_assert (all_infos);
+
+ i = 0;
+ for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
+ {
+ all_infos[i].obj1 = gi_ptr;
+ all_infos[i].obj2 = 0;
+ }
+
+ for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
+ {
+ all_infos[i].obj1 = 0;
+ all_infos[i].obj2 = gi_ptr;
+ }
+
+ for (i = list1_cnt; i < all_cnt; i++)
+ {
+ if (all_infos[i].obj2 == 0)
+ continue;
+ for (j = 0; j < list1_cnt; j++)
+ {
+ if (all_infos[j].obj2 != 0)
+ continue;
+ if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
+ {
+ all_infos[j].obj2 = all_infos[i].obj2;
+ all_infos[i].obj2 = 0;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < all_cnt; i++)
+ if (all_infos[i].obj1 || all_infos[i].obj2)
+ {
+ set_flag (all_infos + i);
+ if (FLAG_ONE_HOT (all_infos[i].flag))
+ both_hot_cnt++;
+ if (FLAG_BOTH_COLD(all_infos[i].flag))
+ both_cold_cnt++;
+ if (FLAG_BOTH_ZERO(all_infos[i].flag))
+ both_zero_cnt++;
+ }
+
+ double prg_val = 0;
+ double sum_val = 0;
+ double sum_cum_1 = 0;
+ double sum_cum_2 = 0;
+
+ for (i = 0; i < all_cnt; i++)
+ {
+ double val;
+ double cum_1, cum_2;
+ const char *filename;
+
+ if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
+ continue;
+ if (FLAG_BOTH_ZERO (all_infos[i].flag))
+ continue;
+
+ if (all_infos[i].obj1)
+ filename = get_file_basename (all_infos[i].obj1->filename);
+ else
+ filename = get_file_basename (all_infos[i].obj2->filename);
+
+ if (overlap_func_level)
+ printf("\n processing %36s:\n", filename);
+
+ val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
+ overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
+
+ if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
+ {
+ printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
+ filename, val*100, cum_1*100, cum_2*100);
+ sum_val += val;
+ sum_cum_1 += cum_1;
+ sum_cum_2 += cum_2;
+ }
+
+ prg_val += val;
+
+ }
+
+ if (overlap_obj_level)
+ printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
+ "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
+
+ printf (" Statistics:\n"
+ " profile1_# profile2_# overlap_#\n");
+ printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
+ gcda_files[0]-unique_gcda_files[0]);
+ printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
+ unique_gcda_files[1]);
+ printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
+ hot_gcda_files[1], both_hot_cnt);
+ printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
+ cold_gcda_files[1], both_cold_cnt);
+ printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
+ zero_gcda_files[1], both_zero_cnt);
+ printf (" sum_all: %12lld \t%12lld\n", p1_sum_all, p2_sum_all);
+ printf (" run_max: %12lld \t%12lld\n", p1_run_max, p2_run_max);
+
+ return prg_val;
+}
+
+/* Computer the overlap score of two lists of gcov_info objects PROFILE1 and PROFILE2.
+ Return 0 on success: without mismatch. Reutrn 1 on error. */
+
+int
+gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
+{
+ double result;
+
+ result = calculate_overlap (profile1, profile2);
+
+ if (result > 0)
+ {
+ printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
+ return 0;
+ }
+ return 1;
+}
diff --git a/gcc-4.9/libgcc/libgcov.h b/gcc-4.9/libgcc/libgcov.h
index fdfb6502e..c1ebe6e92 100644
--- a/gcc-4.9/libgcc/libgcov.h
+++ b/gcc-4.9/libgcc/libgcov.h
@@ -25,6 +25,7 @@
#ifndef GCC_LIBGCOV_H
#define GCC_LIBGCOV_H
+#ifndef __KERNEL__
/* work around the poisoned malloc/calloc in system.h. */
#ifndef xmalloc
#define xmalloc malloc
@@ -35,16 +36,24 @@
#ifndef xrealloc
#define xrealloc realloc
#endif
+#ifndef xfree
+#define xfree free
+#endif
+#else /* __KERNEL__ */
+#include "libgcov-kernel.h"
+#endif /* __KERNEL__ */
#ifndef IN_GCOV_TOOL
/* About the target. */
/* This path will be used by libgcov runtime. */
+#ifndef __KERNEL__
#include "tconfig.h"
#include "tsystem.h"
#include "coretypes.h"
#include "tm.h"
#include "libgcc_tm.h"
+#endif /* __KERNEL__ */
#undef FUNC_ID_WIDTH
#undef FUNC_ID_MASK
@@ -128,7 +137,6 @@ typedef unsigned gcov_position_t;
#define GCOV_LOCKED 0
#endif
-/* xur??? */
#define FUNC_ID_WIDTH 32
#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
@@ -189,6 +197,7 @@ extern unsigned gcov_get_merge_weight ();
#define gcov_read_unsigned __gcov_read_unsigned
#define gcov_read_counter __gcov_read_counter
#define gcov_read_summary __gcov_read_summary
+#define gcov_read_buildinfo __gcov_read_buildinfo
#define gcov_read_module_info __gcov_read_module_info
#define gcov_sort_n_vals __gcov_sort_n_vals
@@ -246,12 +255,16 @@ struct gcov_info
unsigned n_functions; /* number of functions */
-#ifndef IN_GCOV_TOOL
+#if !defined (IN_GCOV_TOOL) && !defined (__KERNEL__)
const struct gcov_fn_info *const *functions; /* pointer to pointers
to function information */
-#else
+#elif defined (IN_GCOV_TOOL)
const struct gcov_fn_info **functions;
+#else
+ struct gcov_fn_info **functions;
#endif /* !IN_GCOV_TOOL */
+ char **build_info; /* strings to include in BUILD_INFO
+ section of gcda file. */
};
/* Information about a single imported module. */
@@ -339,6 +352,8 @@ GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
ATTRIBUTE_HIDDEN;
GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN;
GCOV_LINKAGE void gcov_truncate (void) ATTRIBUTE_HIDDEN;
+void gcov_write_module_info (const struct gcov_info *, unsigned)
+ ATTRIBUTE_HIDDEN;
GCOV_LINKAGE void gcov_write_module_infos (struct gcov_info *mod_info)
ATTRIBUTE_HIDDEN;
GCOV_LINKAGE const struct dyn_imp_mod **
@@ -346,6 +361,9 @@ gcov_get_sorted_import_module_array (struct gcov_info *mod_info, unsigned *len)
ATTRIBUTE_HIDDEN;
GCOV_LINKAGE inline void gcov_rewrite (void);
+extern void set_gcov_fn_fixed_up (int fixed_up);
+extern int get_gcov_fn_fixed_up (void);
+
/* "Counts" stored in gcda files can be a real counter value, or
an target address. When differentiate these two types because
when manipulating counts, we should only change real counter values,
@@ -358,7 +376,13 @@ gcov_get_counter (void)
/* This version is for reading count values in libgcov runtime:
we read from gcda files. */
- return gcov_read_counter ();
+ if (get_gcov_fn_fixed_up ())
+ {
+ gcov_read_counter ();
+ return 0;
+ }
+ else
+ return gcov_read_counter ();
#else
/* This version is for gcov-tool. We read the value from memory and
multiply it by the merge weight. */
@@ -377,7 +401,13 @@ gcov_get_counter_target (void)
/* This version is for reading count target values in libgcov runtime:
we read from gcda files. */
- return gcov_read_counter ();
+ if (get_gcov_fn_fixed_up ())
+ {
+ gcov_read_counter ();
+ return 0;
+ }
+ else
+ return gcov_read_counter ();
#else
/* This version is for gcov-tool. We read the value from memory and we do NOT
multiply it by the merge weight. */