diff options
-rw-r--r-- | compiler-rt/lib/profile/InstrProfiling.h | 14 | ||||
-rw-r--r-- | compiler-rt/lib/profile/InstrProfilingMerge.c | 42 | ||||
-rw-r--r-- | compiler-rt/test/profile/Inputs/instrprof-merge-match-lib.c | 39 | ||||
-rw-r--r-- | compiler-rt/test/profile/Inputs/instrprof-merge-match.c | 54 | ||||
-rw-r--r-- | compiler-rt/test/profile/instrprof-merge-match.test | 5 |
5 files changed, 153 insertions, 1 deletions
diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h index fe6ec36e426..6ee54c51cb6 100644 --- a/compiler-rt/lib/profile/InstrProfiling.h +++ b/compiler-rt/lib/profile/InstrProfiling.h @@ -63,7 +63,9 @@ uint64_t *__llvm_profile_end_counters(void); void __llvm_profile_reset_counters(void); /*! - * \brief Read profile data form buffer and merge with + * \brief Merge profile data from buffer. + * + * Read profile data form buffer \p Profile and merge with * in-process profile counters. The client is expected to * have checked or already knows the profile data in the * buffer matches the in-process counter structure before @@ -71,6 +73,16 @@ void __llvm_profile_reset_counters(void); */ void __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size); +/*! \brief Check if profile in buffer matches the current binary. + * + * Returns 0 (success) if the profile data in buffer \p Profile with size + * \p Size was generated by the same binary and therefore matches + * structurally the in-process counters. If the profile data in buffer is + * not compatible, the interface returns 1 (failure). + */ +int __llvm_profile_check_compatibility(const char *Profile, + uint64_t Size); + /*! * \brief Counts the number of times a target value is seen. * diff --git a/compiler-rt/lib/profile/InstrProfilingMerge.c b/compiler-rt/lib/profile/InstrProfilingMerge.c index b2f13340976..17cffc7523f 100644 --- a/compiler-rt/lib/profile/InstrProfilingMerge.c +++ b/compiler-rt/lib/profile/InstrProfilingMerge.c @@ -20,6 +20,48 @@ COMPILER_RT_WEAK void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *) = NULL; +/* Returns 1 if profile is not structurally compatible. */ +COMPILER_RT_VISIBILITY +int __llvm_profile_check_compatibility(const char *ProfileData, + uint64_t ProfileSize) { + /* Check profile header only for now */ + __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData; + __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData; + SrcDataStart = + (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header)); + SrcDataEnd = SrcDataStart + Header->DataSize; + + /* Check the header first. */ + if (Header->Magic != __llvm_profile_get_magic() || + Header->Version != __llvm_profile_get_version() || + Header->DataSize != + (uint64_t)(__llvm_profile_end_data() - __llvm_profile_begin_data()) || + Header->CountersSize != (uint64_t)(__llvm_profile_end_counters() - + __llvm_profile_begin_counters()) || + Header->NamesSize != (uint64_t)(__llvm_profile_end_names() - + __llvm_profile_begin_names()) || + Header->ValueKindLast != IPVK_Last) + return 1; + + if (ProfileSize < sizeof(__llvm_profile_header) + + Header->DataSize * sizeof(__llvm_profile_data) + + Header->NamesSize + Header->CountersSize + + Header->ValueDataSize) + return 1; + + for (SrcData = SrcDataStart, + DstData = (__llvm_profile_data *)__llvm_profile_begin_data(); + SrcData < SrcDataEnd; ++SrcData, ++DstData) { + if (SrcData->NameRef != DstData->NameRef || + SrcData->FuncHash != DstData->FuncHash || + SrcData->NumCounters != DstData->NumCounters) + return 1; + } + + /* Matched! */ + return 0; +} + COMPILER_RT_VISIBILITY void __llvm_profile_merge_from_buffer(const char *ProfileData, uint64_t ProfileSize) { diff --git a/compiler-rt/test/profile/Inputs/instrprof-merge-match-lib.c b/compiler-rt/test/profile/Inputs/instrprof-merge-match-lib.c new file mode 100644 index 00000000000..e251fd20526 --- /dev/null +++ b/compiler-rt/test/profile/Inputs/instrprof-merge-match-lib.c @@ -0,0 +1,39 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +int __llvm_profile_runtime = 0; +uint64_t __llvm_profile_get_size_for_buffer(void); +int __llvm_profile_write_buffer(char *); +void __llvm_profile_reset_counters(void); +int __llvm_profile_check_compatibility(const char *, uint64_t); + +int gg = 0; +void bar(char c) { + if (c == '1') + gg++; + else + gg--; +} + +/* Returns 0 (size) when an error occurs. */ +uint64_t libEntry(char *Buffer, uint64_t MaxSize) { + + uint64_t Size = __llvm_profile_get_size_for_buffer(); + if (Size > MaxSize) + return 1; + + __llvm_profile_reset_counters(); + + bar('1'); + + if (__llvm_profile_write_buffer(Buffer)) + return 0; + + /* Now check compatibility. Should return 0. */ + if (__llvm_profile_check_compatibility(Buffer, Size)) + return 0; + + return Size; +} + diff --git a/compiler-rt/test/profile/Inputs/instrprof-merge-match.c b/compiler-rt/test/profile/Inputs/instrprof-merge-match.c new file mode 100644 index 00000000000..6e29e4a4e51 --- /dev/null +++ b/compiler-rt/test/profile/Inputs/instrprof-merge-match.c @@ -0,0 +1,54 @@ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +int __llvm_profile_runtime = 0; +uint64_t __llvm_profile_get_size_for_buffer(void); +int __llvm_profile_write_buffer(char *); +void __llvm_profile_reset_counters(void); +int __llvm_profile_check_compatibility(const char *, uint64_t); + +int g = 0; +void foo(char c) { + if (c == '1') + g++; + else + g--; +} + +extern uint64_t libEntry(char *Buffer, uint64_t MaxSize); + +int main(int argc, const char *argv[]) { + const uint64_t MaxSize = 10000; + static char Buffer[MaxSize]; + + uint64_t Size = __llvm_profile_get_size_for_buffer(); + if (Size > MaxSize) + return 1; + + __llvm_profile_reset_counters(); + foo('0'); + + if (__llvm_profile_write_buffer(Buffer)) + return 1; + + /* Now check compatibility. Should return 0. */ + if (__llvm_profile_check_compatibility(Buffer, Size)) + return 1; + + /* Clear the buffer. */ + memset(Buffer, 0, MaxSize); + + /* Collect profile from shared library. */ + Size = libEntry(Buffer, MaxSize); + + if (!Size) + return 1; + + /* Shared library's profile should not match main executable's. */ + if (!__llvm_profile_check_compatibility(Buffer, Size)) + return 1; + + return 0; +} + diff --git a/compiler-rt/test/profile/instrprof-merge-match.test b/compiler-rt/test/profile/instrprof-merge-match.test new file mode 100644 index 00000000000..8345620dcf0 --- /dev/null +++ b/compiler-rt/test/profile/instrprof-merge-match.test @@ -0,0 +1,5 @@ +// RUN: mkdir -p %t.d +// RUN: %clang_profgen -o %t.d/libt.so -fPIC -shared %S/Inputs/instrprof-merge-match-lib.c +// RUN: %clang_profgen -o %t -L %t.d -rpath %t.d %S/Inputs/instrprof-merge-match.c -lt +// RUN: %run %t + |