diff options
Diffstat (limited to 'contrib/compiler-rt/lib/scudo/scudo_utils.cpp')
-rw-r--r-- | contrib/compiler-rt/lib/scudo/scudo_utils.cpp | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/contrib/compiler-rt/lib/scudo/scudo_utils.cpp b/contrib/compiler-rt/lib/scudo/scudo_utils.cpp new file mode 100644 index 0000000..6b96e84 --- /dev/null +++ b/contrib/compiler-rt/lib/scudo/scudo_utils.cpp @@ -0,0 +1,133 @@ +//===-- scudo_utils.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Platform specific utility functions. +/// +//===----------------------------------------------------------------------===// + +#include "scudo_utils.h" + +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <unistd.h> + +#include <cstring> + +// TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less +// complicated string formatting code. The following is a +// temporary workaround to be able to use __sanitizer::VSNPrintf. +namespace __sanitizer { + +extern int VSNPrintf(char *buff, int buff_length, const char *format, + va_list args); + +} // namespace __sanitizer + +namespace __scudo { + +FORMAT(1, 2) +void dieWithMessage(const char *Format, ...) { + // Our messages are tiny, 128 characters is more than enough. + char Message[128]; + va_list Args; + va_start(Args, Format); + __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args); + va_end(Args); + RawWrite(Message); + Die(); +} + +typedef struct { + u32 Eax; + u32 Ebx; + u32 Ecx; + u32 Edx; +} CPUIDInfo; + +static void getCPUID(CPUIDInfo *info, u32 leaf, u32 subleaf) +{ + asm volatile("cpuid" + : "=a" (info->Eax), "=b" (info->Ebx), "=c" (info->Ecx), "=d" (info->Edx) + : "a" (leaf), "c" (subleaf) + ); +} + +// Returns true is the CPU is a "GenuineIntel" or "AuthenticAMD" +static bool isSupportedCPU() +{ + CPUIDInfo Info; + + getCPUID(&Info, 0, 0); + if (memcmp(reinterpret_cast<char *>(&Info.Ebx), "Genu", 4) == 0 && + memcmp(reinterpret_cast<char *>(&Info.Edx), "ineI", 4) == 0 && + memcmp(reinterpret_cast<char *>(&Info.Ecx), "ntel", 4) == 0) { + return true; + } + if (memcmp(reinterpret_cast<char *>(&Info.Ebx), "Auth", 4) == 0 && + memcmp(reinterpret_cast<char *>(&Info.Edx), "enti", 4) == 0 && + memcmp(reinterpret_cast<char *>(&Info.Ecx), "cAMD", 4) == 0) { + return true; + } + return false; +} + +bool testCPUFeature(CPUFeature feature) +{ + static bool InfoInitialized = false; + static CPUIDInfo CPUInfo = {}; + + if (InfoInitialized == false) { + if (isSupportedCPU() == true) + getCPUID(&CPUInfo, 1, 0); + else + UNIMPLEMENTED(); + InfoInitialized = true; + } + switch (feature) { + case SSE4_2: + return ((CPUInfo.Ecx >> 20) & 0x1) != 0; + default: + break; + } + return false; +} + +// readRetry will attempt to read Count bytes from the Fd specified, and if +// interrupted will retry to read additional bytes to reach Count. +static ssize_t readRetry(int Fd, u8 *Buffer, size_t Count) { + ssize_t AmountRead = 0; + while (static_cast<size_t>(AmountRead) < Count) { + ssize_t Result = read(Fd, Buffer + AmountRead, Count - AmountRead); + if (Result > 0) + AmountRead += Result; + else if (!Result) + break; + else if (errno != EINTR) { + AmountRead = -1; + break; + } + } + return AmountRead; +} + +// Default constructor for Xorshift128Plus seeds the state with /dev/urandom +Xorshift128Plus::Xorshift128Plus() { + int Fd = open("/dev/urandom", O_RDONLY); + bool Success = readRetry(Fd, reinterpret_cast<u8 *>(&State_0_), + sizeof(State_0_)) == sizeof(State_0_); + Success &= readRetry(Fd, reinterpret_cast<u8 *>(&State_1_), + sizeof(State_1_)) == sizeof(State_1_); + close(Fd); + if (!Success) { + dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n"); + } +} + +} // namespace __scudo |