]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/scudo/scudo_utils.cpp
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r304149, and update
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / scudo / scudo_utils.cpp
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 <errno.h>
17 #include <fcntl.h>
18 #include <stdarg.h>
19 #include <unistd.h>
20 #if defined(__x86_64__) || defined(__i386__)
21 # include <cpuid.h>
22 #endif
23 #if defined(__arm__) || defined(__aarch64__)
24 # include <sys/auxv.h>
25 #endif
26
27 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
28 //                complicated string formatting code. The following is a
29 //                temporary workaround to be able to use __sanitizer::VSNPrintf.
30 namespace __sanitizer {
31
32 extern int VSNPrintf(char *buff, int buff_length, const char *format,
33                      va_list args);
34
35 }  // namespace __sanitizer
36
37 namespace __scudo {
38
39 FORMAT(1, 2)
40 void NORETURN dieWithMessage(const char *Format, ...) {
41   // Our messages are tiny, 256 characters is more than enough.
42   char Message[256];
43   va_list Args;
44   va_start(Args, Format);
45   __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args);
46   va_end(Args);
47   RawWrite(Message);
48   Die();
49 }
50
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.
54 typedef struct {
55   u32 Eax;
56   u32 Ebx;
57   u32 Ecx;
58   u32 Edx;
59 } CPUIDRegs;
60
61 static void getCPUID(CPUIDRegs *Regs, u32 Level)
62 {
63   __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
64 }
65
66 CPUIDRegs getCPUFeatures() {
67   CPUIDRegs VendorRegs = {};
68   getCPUID(&VendorRegs, 0);
69   bool IsIntel =
70       (VendorRegs.Ebx == signature_INTEL_ebx) &&
71       (VendorRegs.Edx == signature_INTEL_edx) &&
72       (VendorRegs.Ecx == signature_INTEL_ecx);
73   bool IsAMD =
74       (VendorRegs.Ebx == signature_AMD_ebx) &&
75       (VendorRegs.Edx == signature_AMD_edx) &&
76       (VendorRegs.Ecx == signature_AMD_ecx);
77   // Default to an empty feature set if not on a supported CPU.
78   CPUIDRegs FeaturesRegs = {};
79   if (IsIntel || IsAMD) {
80     getCPUID(&FeaturesRegs, 1);
81   }
82   return FeaturesRegs;
83 }
84
85 #ifndef bit_SSE4_2
86 # define bit_SSE4_2 bit_SSE42  // clang and gcc have different defines.
87 #endif
88
89 bool testCPUFeature(CPUFeature Feature)
90 {
91   CPUIDRegs FeaturesRegs = getCPUFeatures();
92
93   switch (Feature) {
94     case CRC32CPUFeature:  // CRC32 is provided by SSE 4.2.
95       return !!(FeaturesRegs.Ecx & bit_SSE4_2);
96     default:
97       break;
98   }
99   return false;
100 }
101 #elif defined(__arm__) || defined(__aarch64__)
102 // For ARM and AArch64, hardware CRC32 support is indicated in the
103 // AT_HWVAL auxiliary vector.
104
105 #ifndef HWCAP_CRC32
106 # define HWCAP_CRC32 (1<<7)  // HWCAP_CRC32 is missing on older platforms.
107 #endif
108
109 bool testCPUFeature(CPUFeature Feature) {
110   uptr HWCap = getauxval(AT_HWCAP);
111
112   switch (Feature) {
113     case CRC32CPUFeature:
114       return !!(HWCap & HWCAP_CRC32);
115     default:
116       break;
117   }
118   return false;
119 }
120 #else
121 bool testCPUFeature(CPUFeature Feature) {
122   return false;
123 }
124 #endif  // defined(__x86_64__) || defined(__i386__)
125
126 // readRetry will attempt to read Count bytes from the Fd specified, and if
127 // interrupted will retry to read additional bytes to reach Count.
128 static ssize_t readRetry(int Fd, u8 *Buffer, size_t Count) {
129   ssize_t AmountRead = 0;
130   while (static_cast<size_t>(AmountRead) < Count) {
131     ssize_t Result = read(Fd, Buffer + AmountRead, Count - AmountRead);
132     if (Result > 0)
133       AmountRead += Result;
134     else if (!Result)
135       break;
136     else if (errno != EINTR) {
137       AmountRead = -1;
138       break;
139     }
140   }
141   return AmountRead;
142 }
143
144 static void fillRandom(u8 *Data, ssize_t Size) {
145   int Fd = open("/dev/urandom", O_RDONLY);
146   if (Fd < 0) {
147     dieWithMessage("ERROR: failed to open /dev/urandom.\n");
148   }
149   bool Success = readRetry(Fd, Data, Size) == Size;
150   close(Fd);
151   if (!Success) {
152     dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n");
153   }
154 }
155
156 // Seeds the xorshift state with /dev/urandom.
157 // TODO(kostyak): investigate using getrandom() if available.
158 void Xorshift128Plus::initFromURandom() {
159   fillRandom(reinterpret_cast<u8 *>(State), sizeof(State));
160 }
161
162 }  // namespace __scudo