1 //===-- scudo_utils.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// Platform specific utility functions.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "scudo_utils.h"
15 
16 #if defined(__x86_64__) || defined(__i386__)
17 # include <cpuid.h>
18 #elif defined(__arm__) || defined(__aarch64__)
19 # include "sanitizer_common/sanitizer_getauxval.h"
20 # if SANITIZER_FUCHSIA
21 #  include <zircon/syscalls.h>
22 #  include <zircon/features.h>
23 # elif SANITIZER_POSIX
24 #  include "sanitizer_common/sanitizer_posix.h"
25 #  include <fcntl.h>
26 # endif
27 #endif
28 
29 #include <stdarg.h>
30 
31 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
32 //                complicated string formatting code. The following is a
33 //                temporary workaround to be able to use __sanitizer::VSNPrintf.
34 namespace __sanitizer {
35 
36 extern int VSNPrintf(char *buff, int buff_length, const char *format,
37                      va_list args);
38 
39 }  // namespace __sanitizer
40 
41 namespace __scudo {
42 
43 FORMAT(1, 2) void NORETURN dieWithMessage(const char *Format, ...) {
44   static const char ScudoError[] = "Scudo ERROR: ";
45   static constexpr uptr PrefixSize = sizeof(ScudoError) - 1;
46   // Our messages are tiny, 256 characters is more than enough.
47   char Message[256];
48   va_list Args;
49   va_start(Args, Format);
50   internal_memcpy(Message, ScudoError, PrefixSize);
51   VSNPrintf(Message + PrefixSize, sizeof(Message) - PrefixSize, Format, Args);
52   va_end(Args);
53   RawWrite(Message);
54   Die();
55 }
56 
57 #if defined(__x86_64__) || defined(__i386__)
58 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
59 // CRC32 requires the SSE 4.2 instruction set.
60 # ifndef bit_SSE4_2
61 #  define bit_SSE4_2 bit_SSE42  // clang and gcc have different defines.
62 # endif
63 bool hasHardwareCRC32() {
64   u32 Eax, Ebx, Ecx, Edx;
65   __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx);
66   const bool IsIntel = (Ebx == signature_INTEL_ebx) &&
67                        (Edx == signature_INTEL_edx) &&
68                        (Ecx == signature_INTEL_ecx);
69   const bool IsAMD = (Ebx == signature_AMD_ebx) &&
70                      (Edx == signature_AMD_edx) &&
71                      (Ecx == signature_AMD_ecx);
72   if (!IsIntel && !IsAMD)
73     return false;
74   __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx);
75   return !!(Ecx & bit_SSE4_2);
76 }
77 #elif defined(__arm__) || defined(__aarch64__)
78 // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWCAP
79 // auxiliary vector.
80 # ifndef AT_HWCAP
81 #  define AT_HWCAP 16
82 # endif
83 # ifndef HWCAP_CRC32
84 #  define HWCAP_CRC32 (1 << 7)  // HWCAP_CRC32 is missing on older platforms.
85 # endif
86 # if SANITIZER_POSIX
87 bool hasHardwareCRC32ARMPosix() {
88   uptr F = internal_open("/proc/self/auxv", O_RDONLY);
89   if (internal_iserror(F))
90     return false;
91   struct { uptr Tag; uptr Value; } Entry = { 0, 0 };
92   for (;;) {
93     uptr N = internal_read(F, &Entry, sizeof(Entry));
94     if (internal_iserror(N) || N != sizeof(Entry) ||
95         (Entry.Tag == 0 && Entry.Value == 0) || Entry.Tag == AT_HWCAP)
96       break;
97   }
98   internal_close(F);
99   return (Entry.Tag == AT_HWCAP && (Entry.Value & HWCAP_CRC32) != 0);
100 }
101 # else
102 bool hasHardwareCRC32ARMPosix() { return false; }
103 # endif  // SANITIZER_POSIX
104 
105 // Bionic doesn't initialize its globals early enough. This causes issues when
106 // trying to access them from a preinit_array (b/25751302) or from another
107 // constructor called before the libc one (b/68046352). __progname is
108 // initialized after the other globals, so we can check its value to know if
109 // calling getauxval is safe.
110 extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
111 INLINE bool areBionicGlobalsInitialized() {
112   return !SANITIZER_ANDROID || (&__progname && __progname);
113 }
114 
115 bool hasHardwareCRC32() {
116 #if SANITIZER_FUCHSIA
117   u32 HWCap;
118   zx_status_t Status = zx_system_get_features(ZX_FEATURE_KIND_CPU, &HWCap);
119   if (Status != ZX_OK || (HWCap & ZX_ARM64_FEATURE_ISA_CRC32) == 0)
120     return false;
121   return true;
122 #else
123   if (&getauxval && areBionicGlobalsInitialized())
124     return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
125   return hasHardwareCRC32ARMPosix();
126 #endif  // SANITIZER_FUCHSIA
127 }
128 #else
129 bool hasHardwareCRC32() { return false; }
130 #endif  // defined(__x86_64__) || defined(__i386__)
131 
132 }  // namespace __scudo
133