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 #include <stdarg.h>
17 #if defined(__x86_64__) || defined(__i386__)
18 # include <cpuid.h>
19 #endif
20 #if defined(__arm__) || defined(__aarch64__)
21 # if SANITIZER_ANDROID && __ANDROID_API__ < 21
22 // getauxval() was introduced with API level 18 for ARM and 21 for AArch64.
23 // Emulate it using /proc/self/auxv for lower API levels.
24 #  include "sanitizer_common/sanitizer_posix.h"
25 
26 #  include <fcntl.h>
27 
28 #  define AT_HWCAP 16
29 
30 namespace __sanitizer {
31 
32 uptr getauxval(uptr Type) {
33   uptr F = internal_open("/proc/self/auxv", O_RDONLY);
34   if (internal_iserror(F))
35     return 0;
36   struct { uptr Tag; uptr Value; } Entry;
37   uptr Result = 0;
38   for (;;) {
39     uptr N = internal_read(F, &Entry, sizeof(Entry));
40     if (internal_iserror(N))
41       break;
42     if (N == 0 || N != sizeof(Entry) || (Entry.Tag == 0 && Entry.Value == 0))
43       break;
44     if (Entry.Tag == Type) {
45       Result =  Entry.Value;
46       break;
47     }
48   }
49   internal_close(F);
50   return Result;
51 }
52 
53 }  // namespace __sanitizer
54 # else
55 #  include <sys/auxv.h>
56 # endif
57 #endif
58 
59 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
60 //                complicated string formatting code. The following is a
61 //                temporary workaround to be able to use __sanitizer::VSNPrintf.
62 namespace __sanitizer {
63 
64 extern int VSNPrintf(char *buff, int buff_length, const char *format,
65                      va_list args);
66 
67 }  // namespace __sanitizer
68 
69 namespace __scudo {
70 
71 FORMAT(1, 2)
72 void NORETURN dieWithMessage(const char *Format, ...) {
73   // Our messages are tiny, 256 characters is more than enough.
74   char Message[256];
75   va_list Args;
76   va_start(Args, Format);
77   __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args);
78   va_end(Args);
79   RawWrite(Message);
80   Die();
81 }
82 
83 #if defined(__x86_64__) || defined(__i386__)
84 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
85 // CRC32 requires the SSE 4.2 instruction set.
86 typedef struct {
87   u32 Eax;
88   u32 Ebx;
89   u32 Ecx;
90   u32 Edx;
91 } CPUIDRegs;
92 
93 static void getCPUID(CPUIDRegs *Regs, u32 Level) {
94   __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
95 }
96 
97 CPUIDRegs getCPUFeatures() {
98   CPUIDRegs VendorRegs = {};
99   getCPUID(&VendorRegs, 0);
100   bool IsIntel =
101       (VendorRegs.Ebx == signature_INTEL_ebx) &&
102       (VendorRegs.Edx == signature_INTEL_edx) &&
103       (VendorRegs.Ecx == signature_INTEL_ecx);
104   bool IsAMD =
105       (VendorRegs.Ebx == signature_AMD_ebx) &&
106       (VendorRegs.Edx == signature_AMD_edx) &&
107       (VendorRegs.Ecx == signature_AMD_ecx);
108   // Default to an empty feature set if not on a supported CPU.
109   CPUIDRegs FeaturesRegs = {};
110   if (IsIntel || IsAMD) {
111     getCPUID(&FeaturesRegs, 1);
112   }
113   return FeaturesRegs;
114 }
115 
116 # ifndef bit_SSE4_2
117 #  define bit_SSE4_2 bit_SSE42  // clang and gcc have different defines.
118 # endif
119 
120 bool testCPUFeature(CPUFeature Feature) {
121   CPUIDRegs FeaturesRegs = getCPUFeatures();
122 
123   switch (Feature) {
124     case CRC32CPUFeature:  // CRC32 is provided by SSE 4.2.
125       return !!(FeaturesRegs.Ecx & bit_SSE4_2);
126     default:
127       break;
128   }
129   return false;
130 }
131 #elif defined(__arm__) || defined(__aarch64__)
132 // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWVAL
133 // auxiliary vector.
134 
135 # ifndef HWCAP_CRC32
136 #  define HWCAP_CRC32 (1 << 7)  // HWCAP_CRC32 is missing on older platforms.
137 # endif
138 
139 bool testCPUFeature(CPUFeature Feature) {
140   uptr HWCap = getauxval(AT_HWCAP);
141 
142   switch (Feature) {
143     case CRC32CPUFeature:
144       return !!(HWCap & HWCAP_CRC32);
145     default:
146       break;
147   }
148   return false;
149 }
150 #else
151 bool testCPUFeature(CPUFeature Feature) {
152   return false;
153 }
154 #endif  // defined(__x86_64__) || defined(__i386__)
155 
156 }  // namespace __scudo
157