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 21#include <cstring> 22 23// TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less 24// complicated string formatting code. The following is a 25// temporary workaround to be able to use __sanitizer::VSNPrintf. 26namespace __sanitizer { 27 28extern int VSNPrintf(char *buff, int buff_length, const char *format, 29 va_list args); 30 31} // namespace __sanitizer 32 33namespace __scudo { 34 35FORMAT(1, 2) 36void dieWithMessage(const char *Format, ...) { 37 // Our messages are tiny, 128 characters is more than enough. 38 char Message[128]; 39 va_list Args; 40 va_start(Args, Format); 41 __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args); 42 va_end(Args); 43 RawWrite(Message); 44 Die(); 45} 46 47typedef struct { 48 u32 Eax; 49 u32 Ebx; 50 u32 Ecx; 51 u32 Edx; 52} CPUIDInfo; 53 54static void getCPUID(CPUIDInfo *info, u32 leaf, u32 subleaf) 55{ 56 asm volatile("cpuid" 57 : "=a" (info->Eax), "=b" (info->Ebx), "=c" (info->Ecx), "=d" (info->Edx) 58 : "a" (leaf), "c" (subleaf) 59 ); 60} 61 62// Returns true is the CPU is a "GenuineIntel" or "AuthenticAMD" 63static bool isSupportedCPU() 64{ 65 CPUIDInfo Info; 66 67 getCPUID(&Info, 0, 0); 68 if (memcmp(reinterpret_cast<char *>(&Info.Ebx), "Genu", 4) == 0 && 69 memcmp(reinterpret_cast<char *>(&Info.Edx), "ineI", 4) == 0 && 70 memcmp(reinterpret_cast<char *>(&Info.Ecx), "ntel", 4) == 0) { 71 return true; 72 } 73 if (memcmp(reinterpret_cast<char *>(&Info.Ebx), "Auth", 4) == 0 && 74 memcmp(reinterpret_cast<char *>(&Info.Edx), "enti", 4) == 0 && 75 memcmp(reinterpret_cast<char *>(&Info.Ecx), "cAMD", 4) == 0) { 76 return true; 77 } 78 return false; 79} 80 81bool testCPUFeature(CPUFeature feature) 82{ 83 static bool InfoInitialized = false; 84 static CPUIDInfo CPUInfo = {}; 85 86 if (InfoInitialized == false) { 87 if (isSupportedCPU() == true) 88 getCPUID(&CPUInfo, 1, 0); 89 else 90 UNIMPLEMENTED(); 91 InfoInitialized = true; 92 } 93 switch (feature) { 94 case SSE4_2: 95 return ((CPUInfo.Ecx >> 20) & 0x1) != 0; 96 default: 97 break; 98 } 99 return false; 100} 101 102// readRetry will attempt to read Count bytes from the Fd specified, and if 103// interrupted will retry to read additional bytes to reach Count. 104static ssize_t readRetry(int Fd, u8 *Buffer, size_t Count) { 105 ssize_t AmountRead = 0; 106 while (static_cast<size_t>(AmountRead) < Count) { 107 ssize_t Result = read(Fd, Buffer + AmountRead, Count - AmountRead); 108 if (Result > 0) 109 AmountRead += Result; 110 else if (!Result) 111 break; 112 else if (errno != EINTR) { 113 AmountRead = -1; 114 break; 115 } 116 } 117 return AmountRead; 118} 119 120// Default constructor for Xorshift128Plus seeds the state with /dev/urandom 121Xorshift128Plus::Xorshift128Plus() { 122 int Fd = open("/dev/urandom", O_RDONLY); 123 bool Success = readRetry(Fd, reinterpret_cast<u8 *>(&State_0_), 124 sizeof(State_0_)) == sizeof(State_0_); 125 Success &= readRetry(Fd, reinterpret_cast<u8 *>(&State_1_), 126 sizeof(State_1_)) == sizeof(State_1_); 127 close(Fd); 128 if (!Success) { 129 dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n"); 130 } 131} 132 133} // namespace __scudo 134