1 //===-- scudo_utils.cpp -----------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 /// Platform specific utility functions.
11 //===----------------------------------------------------------------------===//
13 #include "scudo_utils.h"
15 #if defined(__x86_64__) || defined(__i386__)
17 #elif defined(__arm__) || defined(__aarch64__)
18 # include "sanitizer_common/sanitizer_getauxval.h"
19 # if SANITIZER_FUCHSIA
20 # include <zircon/syscalls.h>
21 # include <zircon/features.h>
22 # elif SANITIZER_POSIX
23 # include "sanitizer_common/sanitizer_posix.h"
30 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
31 // complicated string formatting code. The following is a
32 // temporary workaround to be able to use __sanitizer::VSNPrintf.
33 namespace __sanitizer {
35 extern int VSNPrintf(char *buff, int buff_length, const char *format,
38 } // namespace __sanitizer
42 FORMAT(1, 2) void NORETURN dieWithMessage(const char *Format, ...) {
43 static const char ScudoError[] = "Scudo ERROR: ";
44 static constexpr uptr PrefixSize = sizeof(ScudoError) - 1;
45 // Our messages are tiny, 256 characters is more than enough.
48 va_start(Args, Format);
49 internal_memcpy(Message, ScudoError, PrefixSize);
50 VSNPrintf(Message + PrefixSize, sizeof(Message) - PrefixSize, Format, Args);
52 LogMessageOnPrintf(Message);
53 if (common_flags()->abort_on_error)
54 SetAbortMessage(Message);
59 #if defined(__x86_64__) || defined(__i386__)
60 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
61 // CRC32 requires the SSE 4.2 instruction set.
63 # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
65 bool hasHardwareCRC32() {
66 u32 Eax, Ebx, Ecx, Edx;
67 __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx);
68 const bool IsIntel = (Ebx == signature_INTEL_ebx) &&
69 (Edx == signature_INTEL_edx) &&
70 (Ecx == signature_INTEL_ecx);
71 const bool IsAMD = (Ebx == signature_AMD_ebx) &&
72 (Edx == signature_AMD_edx) &&
73 (Ecx == signature_AMD_ecx);
74 if (!IsIntel && !IsAMD)
76 __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx);
77 return !!(Ecx & bit_SSE4_2);
79 #elif defined(__arm__) || defined(__aarch64__)
80 // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWCAP
86 # define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms.
89 bool hasHardwareCRC32ARMPosix() {
90 uptr F = internal_open("/proc/self/auxv", O_RDONLY);
91 if (internal_iserror(F))
93 struct { uptr Tag; uptr Value; } Entry = { 0, 0 };
95 uptr N = internal_read(F, &Entry, sizeof(Entry));
96 if (internal_iserror(N) || N != sizeof(Entry) ||
97 (Entry.Tag == 0 && Entry.Value == 0) || Entry.Tag == AT_HWCAP)
101 return (Entry.Tag == AT_HWCAP && (Entry.Value & HWCAP_CRC32) != 0);
104 bool hasHardwareCRC32ARMPosix() { return false; }
105 # endif // SANITIZER_POSIX
107 // Bionic doesn't initialize its globals early enough. This causes issues when
108 // trying to access them from a preinit_array (b/25751302) or from another
109 // constructor called before the libc one (b/68046352). __progname is
110 // initialized after the other globals, so we can check its value to know if
111 // calling getauxval is safe.
112 extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
113 INLINE bool areBionicGlobalsInitialized() {
114 return !SANITIZER_ANDROID || (&__progname && __progname);
117 bool hasHardwareCRC32() {
118 #if SANITIZER_FUCHSIA
120 zx_status_t Status = zx_system_get_features(ZX_FEATURE_KIND_CPU, &HWCap);
121 if (Status != ZX_OK || (HWCap & ZX_ARM64_FEATURE_ISA_CRC32) == 0)
125 if (&getauxval && areBionicGlobalsInitialized())
126 return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
127 return hasHardwareCRC32ARMPosix();
128 #endif // SANITIZER_FUCHSIA
131 bool hasHardwareCRC32() { return false; }
132 #endif // defined(__x86_64__) || defined(__i386__)
134 } // namespace __scudo