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