diff options
author | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2018-07-10 16:08:27 +0000 |
---|---|---|
committer | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2018-07-10 16:08:27 +0000 |
commit | cd7171e060afecc9f1754264e56078f69b5b245c (patch) | |
tree | c36de547adc3d17d546af03fa7cd1ca6dc2e4e11 /lib | |
parent | 3e66332edd4c8d6c85f9b3d0d8c042be99df8bcc (diff) |
[gcov] Fix gcov profiling on big-endian machines
Two fixes required to handle big-endian systems:
- 64-bit counter values are stored in a mixed-endian format in the
gcov files: a 32-bit low-part followed by a 32-bit high part. Note that
this is already implemented correctly on the LLVM side, see
GCOVBuffer::readInt64.
- The tag values (e.g. arcs tag, object summary tag, ...) are aways
written as the same sequence of bytes independent of byte order. But
when *reading* them back in, the code reads them as 32-bit values in
host byte order. For the comparisons to work correctly, this should
instead always read them as little-endian values.
Fixes PR 38121.
Reviewed By: marco-c
Differential Revision: https://reviews.llvm.org/D49132
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@336693 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/profile/GCDAProfiling.c | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c index ad58db4c4..9e9c60e80 100644 --- a/lib/profile/GCDAProfiling.c +++ b/lib/profile/GCDAProfiling.c @@ -178,7 +178,12 @@ static void write_32bit_value(uint32_t i) { } static void write_64bit_value(uint64_t i) { - write_bytes((char*)&i, 8); + // GCOV uses a lo-/hi-word format even on big-endian systems. + // See also GCOVBuffer::readInt64 in LLVM. + uint32_t lo = (uint32_t) i; + uint32_t hi = (uint32_t) (i >> 32); + write_32bit_value(lo); + write_32bit_value(hi); } static uint32_t length_of_string(const char *s) { @@ -203,17 +208,25 @@ static uint32_t read_32bit_value() { return val; } -static uint64_t read_64bit_value() { - uint64_t val; +static uint32_t read_le_32bit_value() { + uint32_t val = 0; if (new_file) - return (uint64_t)-1; + return (uint32_t)-1; - val = *(uint64_t*)&write_buffer[cur_pos]; - cur_pos += 8; + for (int i = 0; i < 4; i++) + val |= write_buffer[cur_pos++] << (8*i); return val; } +static uint64_t read_64bit_value() { + // GCOV uses a lo-/hi-word format even on big-endian systems. + // See also GCOVBuffer::readInt64 in LLVM. + uint32_t lo = read_32bit_value(); + uint32_t hi = read_32bit_value(); + return ((uint64_t)hi << 32) | ((uint64_t)lo); +} + static char *mangle_filename(const char *orig_filename) { char *new_filename; size_t prefix_len; @@ -400,7 +413,7 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { if (!output_file) return; - val = read_32bit_value(); + val = read_le_32bit_value(); if (val != (uint32_t)-1) { /* There are counters present in the file. Merge them. */ @@ -454,7 +467,7 @@ void llvm_gcda_summary_info() { if (!output_file) return; - val = read_32bit_value(); + val = read_le_32bit_value(); if (val != (uint32_t)-1) { /* There are counters present in the file. Merge them. */ |