blob: 9e6a3512e88d128f882044617909f5d513008166 [file] [log] [blame]
Kostya Serebryany712fc982016-06-07 01:20:26 +00001//===-- 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)
Kostya Serebryany707894b2016-08-02 22:25:38 +000036void NORETURN dieWithMessage(const char *Format, ...) {
Kostya Kortchinskyada27612016-09-30 19:57:21 +000037 // Our messages are tiny, 256 characters is more than enough.
38 char Message[256];
Kostya Serebryany712fc982016-06-07 01:20:26 +000039 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