aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKostya Kortchinsky <kostyak@google.com>2017-11-22 18:30:44 +0000
committerKostya Kortchinsky <kostyak@google.com>2017-11-22 18:30:44 +0000
commit0207b6fbbfc1922e5acf51110a604ebb36fe48b6 (patch)
treecf97106d7cfa13c721503a3867307bf7b90d2eec /compiler-rt/lib/scudo/scudo_utils.cpp
parentCachePruning: Allow limiting the number of files in the cache directory. (diff)
downloadllvm-project-0207b6fbbfc1922e5acf51110a604ebb36fe48b6.tar.gz
llvm-project-0207b6fbbfc1922e5acf51110a604ebb36fe48b6.tar.bz2
llvm-project-0207b6fbbfc1922e5acf51110a604ebb36fe48b6.zip
[scudo] Overhaul hardware CRC32 feature detection
Summary: This patch aims at condensing the hardware CRC32 feature detection and making it slightly more effective on Android. The following changes are included: - remove the `CPUFeature` enum, and get rid of one level of nesting of functions: we only used CRC32, so we just implement and use `hasHardwareCRC32`; - allow for a weak `getauxval`: the Android toolchain is compiled at API level 14 for Android ARM, meaning no `getauxval` at compile time, yet we will run on API level 27+ devices. The `/proc/self/auxv` fallback can work but is worthless for a process like `init` where the proc filesystem doesn't exist yet. If a weak `getauxval` doesn't exist, then fallback. - couple of extra corrections. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: kubamracek, aemerson, srhines, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D40322 llvm-svn: 318859
Diffstat (limited to 'compiler-rt/lib/scudo/scudo_utils.cpp')
-rw-r--r--compiler-rt/lib/scudo/scudo_utils.cpp140
1 files changed, 46 insertions, 94 deletions
diff --git a/compiler-rt/lib/scudo/scudo_utils.cpp b/compiler-rt/lib/scudo/scudo_utils.cpp
index fb082a475bab..75be2fc73ec2 100644
--- a/compiler-rt/lib/scudo/scudo_utils.cpp
+++ b/compiler-rt/lib/scudo/scudo_utils.cpp
@@ -13,49 +13,18 @@
#include "scudo_utils.h"
-#include <stdarg.h>
#if defined(__x86_64__) || defined(__i386__)
# include <cpuid.h>
-#endif
-#if defined(__arm__) || defined(__aarch64__)
-# if SANITIZER_ANDROID && __ANDROID_API__ < 21
-// getauxval() was introduced with API level 18 for ARM and 21 for AArch64.
-// Emulate it using /proc/self/auxv for lower API levels.
+#elif defined(__arm__) || defined(__aarch64__)
+# include "sanitizer_common/sanitizer_getauxval.h"
+# if SANITIZER_POSIX
# include "sanitizer_common/sanitizer_posix.h"
-
# include <fcntl.h>
-
-# define AT_HWCAP 16
-
-namespace __sanitizer {
-
-uptr getauxval(uptr Type) {
- uptr F = internal_open("/proc/self/auxv", O_RDONLY);
- if (internal_iserror(F))
- return 0;
- struct { uptr Tag; uptr Value; } Entry;
- uptr Result = 0;
- for (;;) {
- uptr N = internal_read(F, &Entry, sizeof(Entry));
- if (internal_iserror(N))
- break;
- if (N == 0 || N != sizeof(Entry) || (Entry.Tag == 0 && Entry.Value == 0))
- break;
- if (Entry.Tag == Type) {
- Result = Entry.Value;
- break;
- }
- }
- internal_close(F);
- return Result;
-}
-
-} // namespace __sanitizer
-# else
-# include <sys/auxv.h>
# endif
#endif
+#include <stdarg.h>
+
// TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
// complicated string formatting code. The following is a
// temporary workaround to be able to use __sanitizer::VSNPrintf.
@@ -68,13 +37,12 @@ extern int VSNPrintf(char *buff, int buff_length, const char *format,
namespace __scudo {
-FORMAT(1, 2)
-void NORETURN dieWithMessage(const char *Format, ...) {
+FORMAT(1, 2) void NORETURN dieWithMessage(const char *Format, ...) {
// Our messages are tiny, 256 characters is more than enough.
char Message[256];
va_list Args;
va_start(Args, Format);
- __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args);
+ VSNPrintf(Message, sizeof(Message), Format, Args);
va_end(Args);
RawWrite(Message);
Die();
@@ -83,74 +51,58 @@ void NORETURN dieWithMessage(const char *Format, ...) {
#if defined(__x86_64__) || defined(__i386__)
// i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
// CRC32 requires the SSE 4.2 instruction set.
-typedef struct {
- u32 Eax;
- u32 Ebx;
- u32 Ecx;
- u32 Edx;
-} CPUIDRegs;
-
-static void getCPUID(CPUIDRegs *Regs, u32 Level) {
- __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
-}
-
-CPUIDRegs getCPUFeatures() {
- CPUIDRegs VendorRegs = {};
- getCPUID(&VendorRegs, 0);
- bool IsIntel =
- (VendorRegs.Ebx == signature_INTEL_ebx) &&
- (VendorRegs.Edx == signature_INTEL_edx) &&
- (VendorRegs.Ecx == signature_INTEL_ecx);
- bool IsAMD =
- (VendorRegs.Ebx == signature_AMD_ebx) &&
- (VendorRegs.Edx == signature_AMD_edx) &&
- (VendorRegs.Ecx == signature_AMD_ecx);
- // Default to an empty feature set if not on a supported CPU.
- CPUIDRegs FeaturesRegs = {};
- if (IsIntel || IsAMD) {
- getCPUID(&FeaturesRegs, 1);
- }
- return FeaturesRegs;
-}
-
# ifndef bit_SSE4_2
# define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
# endif
-
-bool testCPUFeature(CPUFeature Feature) {
- CPUIDRegs FeaturesRegs = getCPUFeatures();
-
- switch (Feature) {
- case CRC32CPUFeature: // CRC32 is provided by SSE 4.2.
- return !!(FeaturesRegs.Ecx & bit_SSE4_2);
- default:
- break;
- }
- return false;
+bool hasHardwareCRC32() {
+ u32 Eax, Ebx, Ecx, Edx;
+ __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx);
+ const bool IsIntel = (Ebx == signature_INTEL_ebx) &&
+ (Edx == signature_INTEL_edx) &&
+ (Ecx == signature_INTEL_ecx);
+ const bool IsAMD = (Ebx == signature_AMD_ebx) &&
+ (Edx == signature_AMD_edx) &&
+ (Ecx == signature_AMD_ecx);
+ if (!IsIntel && !IsAMD)
+ return false;
+ __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx);
+ return !!(Ecx & bit_SSE4_2);
}
#elif defined(__arm__) || defined(__aarch64__)
-// For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWVAL
+// For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWCAP
// auxiliary vector.
-
+# ifndef AT_HWCAP
+# define AT_HWCAP 16
+# endif
# ifndef HWCAP_CRC32
# define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms.
# endif
-
-bool testCPUFeature(CPUFeature Feature) {
- uptr HWCap = getauxval(AT_HWCAP);
-
- switch (Feature) {
- case CRC32CPUFeature:
- return !!(HWCap & HWCAP_CRC32);
- default:
+# if SANITIZER_POSIX
+bool hasHardwareCRC32ARMPosix() {
+ uptr F = internal_open("/proc/self/auxv", O_RDONLY);
+ if (internal_iserror(F))
+ return false;
+ struct { uptr Tag; uptr Value; } Entry = { 0, 0 };
+ for (;;) {
+ uptr N = internal_read(F, &Entry, sizeof(Entry));
+ if (internal_iserror(N) || N != sizeof(Entry) ||
+ (Entry.Tag == 0 && Entry.Value == 0) || Entry.Tag == AT_HWCAP)
break;
}
- return false;
+ internal_close(F);
+ return (Entry.Tag == AT_HWCAP && (Entry.Value & HWCAP_CRC32) != 0);
}
-#else
-bool testCPUFeature(CPUFeature Feature) {
- return false;
+# else
+bool hasHardwareCRC32ARMPosix() { return false; }
+# endif // SANITIZER_POSIX
+
+bool hasHardwareCRC32() {
+ if (&getauxval)
+ return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
+ return hasHardwareCRC32ARMPosix();
}
+#else
+bool hasHardwareCRC32() { return false; }
#endif // defined(__x86_64__) || defined(__i386__)
} // namespace __scudo