]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/scudo/scudo_utils.cpp
Merge compiler-rt r291274.
[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
24 #include <cstring>
25
26 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
27 //                complicated string formatting code. The following is a
28 //                temporary workaround to be able to use __sanitizer::VSNPrintf.
29 namespace __sanitizer {
30
31 extern int VSNPrintf(char *buff, int buff_length, const char *format,
32                      va_list args);
33
34 }  // namespace __sanitizer
35
36 namespace __scudo {
37
38 FORMAT(1, 2)
39 void NORETURN dieWithMessage(const char *Format, ...) {
40   // Our messages are tiny, 256 characters is more than enough.
41   char Message[256];
42   va_list Args;
43   va_start(Args, Format);
44   __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args);
45   va_end(Args);
46   RawWrite(Message);
47   Die();
48 }
49
50 #if defined(__x86_64__) || defined(__i386__)
51 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
52 // CRC32 requires the SSE 4.2 instruction set.
53 typedef struct {
54   u32 Eax;
55   u32 Ebx;
56   u32 Ecx;
57   u32 Edx;
58 } CPUIDRegs;
59
60 static void getCPUID(CPUIDRegs *Regs, u32 Level)
61 {
62   __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
63 }
64
65 CPUIDRegs getCPUFeatures() {
66   CPUIDRegs VendorRegs = {};
67   getCPUID(&VendorRegs, 0);
68   bool IsIntel =
69       (VendorRegs.Ebx == signature_INTEL_ebx) &&
70       (VendorRegs.Edx == signature_INTEL_edx) &&
71       (VendorRegs.Ecx == signature_INTEL_ecx);
72   bool IsAMD =
73       (VendorRegs.Ebx == signature_AMD_ebx) &&
74       (VendorRegs.Edx == signature_AMD_edx) &&
75       (VendorRegs.Ecx == signature_AMD_ecx);
76   // Default to an empty feature set if not on a supported CPU.
77   CPUIDRegs FeaturesRegs = {};
78   if (IsIntel || IsAMD) {
79     getCPUID(&FeaturesRegs, 1);
80   }
81   return FeaturesRegs;
82 }
83
84 #ifndef bit_SSE4_2
85 #define bit_SSE4_2 bit_SSE42  // clang and gcc have different defines.
86 #endif
87
88 bool testCPUFeature(CPUFeature Feature)
89 {
90   static CPUIDRegs FeaturesRegs = getCPUFeatures();
91
92   switch (Feature) {
93     case CRC32CPUFeature:  // CRC32 is provided by SSE 4.2.
94       return !!(FeaturesRegs.Ecx & bit_SSE4_2);
95     default:
96       break;
97   }
98   return false;
99 }
100 #else
101 bool testCPUFeature(CPUFeature Feature) {
102   return false;
103 }
104 #endif  // defined(__x86_64__) || defined(__i386__)
105
106 // readRetry will attempt to read Count bytes from the Fd specified, and if
107 // interrupted will retry to read additional bytes to reach Count.
108 static ssize_t readRetry(int Fd, u8 *Buffer, size_t Count) {
109   ssize_t AmountRead = 0;
110   while (static_cast<size_t>(AmountRead) < Count) {
111     ssize_t Result = read(Fd, Buffer + AmountRead, Count - AmountRead);
112     if (Result > 0)
113       AmountRead += Result;
114     else if (!Result)
115       break;
116     else if (errno != EINTR) {
117       AmountRead = -1;
118       break;
119     }
120   }
121   return AmountRead;
122 }
123
124 static void fillRandom(u8 *Data, ssize_t Size) {
125   int Fd = open("/dev/urandom", O_RDONLY);
126   if (Fd < 0) {
127     dieWithMessage("ERROR: failed to open /dev/urandom.\n");
128   }
129   bool Success = readRetry(Fd, Data, Size) == Size;
130   close(Fd);
131   if (!Success) {
132     dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n");
133   }
134 }
135
136 // Default constructor for Xorshift128Plus seeds the state with /dev/urandom.
137 // TODO(kostyak): investigate using getrandom() if available.
138 Xorshift128Plus::Xorshift128Plus() {
139   fillRandom(reinterpret_cast<u8 *>(State), sizeof(State));
140 }
141
142 const static u32 CRC32Table[] = {
143   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
144   0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
145   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
146   0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
147   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
148   0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
149   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
150   0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
151   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
152   0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
153   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
154   0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
155   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
156   0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
157   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
158   0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
159   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
160   0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
161   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
162   0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
163   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
164   0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
165   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
166   0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
167   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
168   0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
169   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
170   0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
171   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
172   0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
173   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
174   0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
175   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
176   0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
177   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
178   0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
179   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
180   0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
181   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
182   0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
183   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
184   0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
185   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
186 };
187
188 u32 computeCRC32(u32 Crc, uptr Data)
189 {
190   for (uptr i = 0; i < sizeof(Data); i++) {
191     Crc = CRC32Table[(Crc ^ Data) & 0xff] ^ (Crc >> 8);
192     Data >>= 8;
193   }
194   return Crc;
195 }
196
197 }  // namespace __scudo