1 //===-- scudo_utils.cpp -----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 /// Platform specific utility functions.
12 //===----------------------------------------------------------------------===//
14 #include "scudo_utils.h"
20 #if defined(__x86_64__) || defined(__i386__)
23 #if defined(__arm__) || defined(__aarch64__)
24 # include <sys/auxv.h>
27 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
28 // complicated string formatting code. The following is a
29 // temporary workaround to be able to use __sanitizer::VSNPrintf.
30 namespace __sanitizer {
32 extern int VSNPrintf(char *buff, int buff_length, const char *format,
35 } // namespace __sanitizer
40 void NORETURN dieWithMessage(const char *Format, ...) {
41 // Our messages are tiny, 256 characters is more than enough.
44 va_start(Args, Format);
45 __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args);
51 #if defined(__x86_64__) || defined(__i386__)
52 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
53 // CRC32 requires the SSE 4.2 instruction set.
61 static void getCPUID(CPUIDRegs *Regs, u32 Level)
63 __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
66 CPUIDRegs getCPUFeatures() {
67 CPUIDRegs VendorRegs = {};
68 getCPUID(&VendorRegs, 0);
70 (VendorRegs.Ebx == signature_INTEL_ebx) &&
71 (VendorRegs.Edx == signature_INTEL_edx) &&
72 (VendorRegs.Ecx == signature_INTEL_ecx);
74 (VendorRegs.Ebx == signature_AMD_ebx) &&
75 (VendorRegs.Edx == signature_AMD_edx) &&
76 (VendorRegs.Ecx == signature_AMD_ecx);
77 // Default to an empty feature set if not on a supported CPU.
78 CPUIDRegs FeaturesRegs = {};
79 if (IsIntel || IsAMD) {
80 getCPUID(&FeaturesRegs, 1);
86 # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
89 bool testCPUFeature(CPUFeature Feature)
91 CPUIDRegs FeaturesRegs = getCPUFeatures();
94 case CRC32CPUFeature: // CRC32 is provided by SSE 4.2.
95 return !!(FeaturesRegs.Ecx & bit_SSE4_2);
101 #elif defined(__arm__) || defined(__aarch64__)
102 // For ARM and AArch64, hardware CRC32 support is indicated in the
103 // AT_HWVAL auxiliary vector.
106 # define HWCAP_CRC32 (1<<7) // HWCAP_CRC32 is missing on older platforms.
109 bool testCPUFeature(CPUFeature Feature) {
110 uptr HWCap = getauxval(AT_HWCAP);
113 case CRC32CPUFeature:
114 return !!(HWCap & HWCAP_CRC32);
121 bool testCPUFeature(CPUFeature Feature) {
124 #endif // defined(__x86_64__) || defined(__i386__)
126 // readRetry will attempt to read Count bytes from the Fd specified, and if
127 // interrupted will retry to read additional bytes to reach Count.
128 static ssize_t readRetry(int Fd, u8 *Buffer, size_t Count) {
129 ssize_t AmountRead = 0;
130 while (static_cast<size_t>(AmountRead) < Count) {
131 ssize_t Result = read(Fd, Buffer + AmountRead, Count - AmountRead);
133 AmountRead += Result;
136 else if (errno != EINTR) {
144 static void fillRandom(u8 *Data, ssize_t Size) {
145 int Fd = open("/dev/urandom", O_RDONLY);
147 dieWithMessage("ERROR: failed to open /dev/urandom.\n");
149 bool Success = readRetry(Fd, Data, Size) == Size;
152 dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n");
156 // Seeds the xorshift state with /dev/urandom.
157 // TODO(kostyak): investigate using getrandom() if available.
158 void Xorshift128Plus::initFromURandom() {
159 fillRandom(reinterpret_cast<u8 *>(State), sizeof(State));
162 } // namespace __scudo