1 //===-- scudo_utils.cpp -----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 /// Platform specific utility functions.
12 //===----------------------------------------------------------------------===//
14 #include "scudo_utils.h"
16 #if defined(__x86_64__) || defined(__i386__)
18 #elif defined(__arm__) || defined(__aarch64__)
19 # include "sanitizer_common/sanitizer_getauxval.h"
21 # include "sanitizer_common/sanitizer_posix.h"
28 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
29 // complicated string formatting code. The following is a
30 // temporary workaround to be able to use __sanitizer::VSNPrintf.
31 namespace __sanitizer {
33 extern int VSNPrintf(char *buff, int buff_length, const char *format,
36 } // namespace __sanitizer
40 FORMAT(1, 2) void NORETURN dieWithMessage(const char *Format, ...) {
41 // Our messages are tiny, 256 characters is more than enough.
44 va_start(Args, Format);
45 VSNPrintf(Message, sizeof(Message), Format, Args);
51 #if defined(__x86_64__) || defined(__i386__)
52 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
53 // CRC32 requires the SSE 4.2 instruction set.
55 # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
57 bool hasHardwareCRC32() {
58 u32 Eax, Ebx, Ecx, Edx;
59 __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx);
60 const bool IsIntel = (Ebx == signature_INTEL_ebx) &&
61 (Edx == signature_INTEL_edx) &&
62 (Ecx == signature_INTEL_ecx);
63 const bool IsAMD = (Ebx == signature_AMD_ebx) &&
64 (Edx == signature_AMD_edx) &&
65 (Ecx == signature_AMD_ecx);
66 if (!IsIntel && !IsAMD)
68 __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx);
69 return !!(Ecx & bit_SSE4_2);
71 #elif defined(__arm__) || defined(__aarch64__)
72 // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWCAP
78 # define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms.
81 bool hasHardwareCRC32ARMPosix() {
82 uptr F = internal_open("/proc/self/auxv", O_RDONLY);
83 if (internal_iserror(F))
85 struct { uptr Tag; uptr Value; } Entry = { 0, 0 };
87 uptr N = internal_read(F, &Entry, sizeof(Entry));
88 if (internal_iserror(N) || N != sizeof(Entry) ||
89 (Entry.Tag == 0 && Entry.Value == 0) || Entry.Tag == AT_HWCAP)
93 return (Entry.Tag == AT_HWCAP && (Entry.Value & HWCAP_CRC32) != 0);
96 bool hasHardwareCRC32ARMPosix() { return false; }
97 # endif // SANITIZER_POSIX
99 // Bionic doesn't initialize its globals early enough. This causes issues when
100 // trying to access them from a preinit_array (b/25751302) or from another
101 // constructor called before the libc one (b/68046352). __progname is
102 // initialized after the other globals, so we can check its value to know if
103 // calling getauxval is safe.
104 extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
105 INLINE bool areBionicGlobalsInitialized() {
106 return !SANITIZER_ANDROID || (&__progname && __progname);
109 bool hasHardwareCRC32() {
110 if (&getauxval && areBionicGlobalsInitialized())
111 return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
112 return hasHardwareCRC32ARMPosix();
115 bool hasHardwareCRC32() { return false; }
116 #endif // defined(__x86_64__) || defined(__i386__)
118 } // namespace __scudo