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__ < 18
22 // getauxval() was introduced with API level 18 on Android. Emulate it using
23 // /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 {
95   __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
96 }
97 
98 CPUIDRegs getCPUFeatures() {
99   CPUIDRegs VendorRegs = {};
100   getCPUID(&VendorRegs, 0);
101   bool IsIntel =
102       (VendorRegs.Ebx == signature_INTEL_ebx) &&
103       (VendorRegs.Edx == signature_INTEL_edx) &&
104       (VendorRegs.Ecx == signature_INTEL_ecx);
105   bool IsAMD =
106       (VendorRegs.Ebx == signature_AMD_ebx) &&
107       (VendorRegs.Edx == signature_AMD_edx) &&
108       (VendorRegs.Ecx == signature_AMD_ecx);
109   // Default to an empty feature set if not on a supported CPU.
110   CPUIDRegs FeaturesRegs = {};
111   if (IsIntel || IsAMD) {
112     getCPUID(&FeaturesRegs, 1);
113   }
114   return FeaturesRegs;
115 }
116 
117 # ifndef bit_SSE4_2
118 #  define bit_SSE4_2 bit_SSE42  // clang and gcc have different defines.
119 # endif
120 
121 bool testCPUFeature(CPUFeature Feature)
122 {
123   CPUIDRegs FeaturesRegs = getCPUFeatures();
124 
125   switch (Feature) {
126     case CRC32CPUFeature:  // CRC32 is provided by SSE 4.2.
127       return !!(FeaturesRegs.Ecx & bit_SSE4_2);
128     default:
129       break;
130   }
131   return false;
132 }
133 #elif defined(__arm__) || defined(__aarch64__)
134 // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWVAL
135 // auxiliary vector.
136 
137 # ifndef HWCAP_CRC32
138 #  define HWCAP_CRC32 (1 << 7)  // HWCAP_CRC32 is missing on older platforms.
139 # endif
140 
141 bool testCPUFeature(CPUFeature Feature) {
142   uptr HWCap = getauxval(AT_HWCAP);
143 
144   switch (Feature) {
145     case CRC32CPUFeature:
146       return !!(HWCap & HWCAP_CRC32);
147     default:
148       break;
149   }
150   return false;
151 }
152 #else
153 bool testCPUFeature(CPUFeature Feature) {
154   return false;
155 }
156 #endif  // defined(__x86_64__) || defined(__i386__)
157 
158 }  // namespace __scudo
159