forked from OSchip/llvm-project
134 lines
3.6 KiB
C++
134 lines
3.6 KiB
C++
//===-- 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
|