blob: ffa65b219fd16a56e3884775aeef313432cbe17d [file] [log] [blame]
Kostya Serebryany712fc982016-06-07 01:20:26 +00001//===-- 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>
Kostya Kortchinsky2defe4d2016-12-08 19:05:46 +000020#if defined(__x86_64__) || defined(__i386__)
21# include <cpuid.h>
22#endif
Kostya Serebryany712fc982016-06-07 01:20:26 +000023
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.
29namespace __sanitizer {
30
31extern int VSNPrintf(char *buff, int buff_length, const char *format,
32 va_list args);
33
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000034} // namespace __sanitizer
Kostya Serebryany712fc982016-06-07 01:20:26 +000035
36namespace __scudo {
37
38FORMAT(1, 2)
Kostya Serebryany707894b2016-08-02 22:25:38 +000039void NORETURN dieWithMessage(const char *Format, ...) {
Kostya Kortchinskyada27612016-09-30 19:57:21 +000040 // Our messages are tiny, 256 characters is more than enough.
41 char Message[256];
Kostya Serebryany712fc982016-06-07 01:20:26 +000042 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
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000050#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.
Kostya Serebryany712fc982016-06-07 01:20:26 +000053typedef struct {
54 u32 Eax;
55 u32 Ebx;
56 u32 Ecx;
57 u32 Edx;
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000058} CPUIDRegs;
Kostya Serebryany712fc982016-06-07 01:20:26 +000059
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000060static void getCPUID(CPUIDRegs *Regs, u32 Level)
Kostya Serebryany712fc982016-06-07 01:20:26 +000061{
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000062 __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
Kostya Serebryany712fc982016-06-07 01:20:26 +000063}
64
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000065CPUIDRegs 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);
Kostya Serebryany712fc982016-06-07 01:20:26 +000080 }
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000081 return FeaturesRegs;
Kostya Serebryany712fc982016-06-07 01:20:26 +000082}
83
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000084#ifndef bit_SSE4_2
85#define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
86#endif
Kostya Serebryany712fc982016-06-07 01:20:26 +000087
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000088bool 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);
Kostya Serebryany712fc982016-06-07 01:20:26 +000095 default:
96 break;
97 }
98 return false;
99}
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +0000100#else
101bool testCPUFeature(CPUFeature Feature) {
102 return false;
103}
104#endif // defined(__x86_64__) || defined(__i386__)
Kostya Serebryany712fc982016-06-07 01:20:26 +0000105
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.
108static 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
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +0000124static void fillRandom(u8 *Data, ssize_t Size) {
Kostya Serebryany712fc982016-06-07 01:20:26 +0000125 int Fd = open("/dev/urandom", O_RDONLY);
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +0000126 if (Fd < 0) {
127 dieWithMessage("ERROR: failed to open /dev/urandom.\n");
128 }
129 bool Success = readRetry(Fd, Data, Size) == Size;
Kostya Serebryany712fc982016-06-07 01:20:26 +0000130 close(Fd);
131 if (!Success) {
132 dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n");
133 }
134}
135
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +0000136// Default constructor for Xorshift128Plus seeds the state with /dev/urandom.
137// TODO(kostyak): investigate using getrandom() if available.
138Xorshift128Plus::Xorshift128Plus() {
139 fillRandom(reinterpret_cast<u8 *>(State), sizeof(State));
140}
141
142const 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
Kostya Kortchinskyc4d6c932017-01-10 16:39:36 +0000188u32 computeSoftwareCRC32(u32 Crc, uptr Data) {
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +0000189 for (uptr i = 0; i < sizeof(Data); i++) {
190 Crc = CRC32Table[(Crc ^ Data) & 0xff] ^ (Crc >> 8);
191 Data >>= 8;
192 }
193 return Crc;
194}
195
196} // namespace __scudo