blob: f7903ff34c73c32165bc53e980c11b1e1689238f [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>
Kostya Kortchinsky2defe4d2016-12-08 19:05:46 +000020#if defined(__x86_64__) || defined(__i386__)
21# include <cpuid.h>
22#endif
Kostya Kortchinskyb39dff42017-01-18 17:11:17 +000023#if defined(__arm__) || defined(__aarch64__)
24# include <sys/auxv.h>
25#endif
Kostya Serebryany712fc982016-06-07 01:20:26 +000026
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.
30namespace __sanitizer {
31
32extern int VSNPrintf(char *buff, int buff_length, const char *format,
33 va_list args);
34
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000035} // namespace __sanitizer
Kostya Serebryany712fc982016-06-07 01:20:26 +000036
37namespace __scudo {
38
39FORMAT(1, 2)
Kostya Serebryany707894b2016-08-02 22:25:38 +000040void NORETURN dieWithMessage(const char *Format, ...) {
Kostya Kortchinskyada27612016-09-30 19:57:21 +000041 // Our messages are tiny, 256 characters is more than enough.
42 char Message[256];
Kostya Serebryany712fc982016-06-07 01:20:26 +000043 va_list Args;
44 va_start(Args, Format);
45 __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args);
46 va_end(Args);
47 RawWrite(Message);
48 Die();
49}
50
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000051#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.
Kostya Serebryany712fc982016-06-07 01:20:26 +000054typedef struct {
55 u32 Eax;
56 u32 Ebx;
57 u32 Ecx;
58 u32 Edx;
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000059} CPUIDRegs;
Kostya Serebryany712fc982016-06-07 01:20:26 +000060
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000061static void getCPUID(CPUIDRegs *Regs, u32 Level)
Kostya Serebryany712fc982016-06-07 01:20:26 +000062{
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000063 __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
Kostya Serebryany712fc982016-06-07 01:20:26 +000064}
65
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000066CPUIDRegs getCPUFeatures() {
67 CPUIDRegs VendorRegs = {};
68 getCPUID(&VendorRegs, 0);
69 bool IsIntel =
70 (VendorRegs.Ebx == signature_INTEL_ebx) &&
71 (VendorRegs.Edx == signature_INTEL_edx) &&
72 (VendorRegs.Ecx == signature_INTEL_ecx);
73 bool IsAMD =
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);
Kostya Serebryany712fc982016-06-07 01:20:26 +000081 }
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000082 return FeaturesRegs;
Kostya Serebryany712fc982016-06-07 01:20:26 +000083}
84
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000085#ifndef bit_SSE4_2
Kostya Kortchinskyb39dff42017-01-18 17:11:17 +000086# define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000087#endif
Kostya Serebryany712fc982016-06-07 01:20:26 +000088
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000089bool testCPUFeature(CPUFeature Feature)
90{
Petr Hosek97ab7fe2017-01-17 20:41:04 +000091 CPUIDRegs FeaturesRegs = getCPUFeatures();
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +000092
93 switch (Feature) {
94 case CRC32CPUFeature: // CRC32 is provided by SSE 4.2.
95 return !!(FeaturesRegs.Ecx & bit_SSE4_2);
Kostya Serebryany712fc982016-06-07 01:20:26 +000096 default:
97 break;
98 }
99 return false;
100}
Kostya Kortchinskyb39dff42017-01-18 17:11:17 +0000101#elif defined(__arm__) || defined(__aarch64__)
102// For ARM and AArch64, hardware CRC32 support is indicated in the
103// AT_HWVAL auxiliary vector.
104
105#ifndef HWCAP_CRC32
106# define HWCAP_CRC32 (1<<7) // HWCAP_CRC32 is missing on older platforms.
107#endif
108
109bool testCPUFeature(CPUFeature Feature) {
110 uptr HWCap = getauxval(AT_HWCAP);
111
112 switch (Feature) {
113 case CRC32CPUFeature:
114 return !!(HWCap & HWCAP_CRC32);
115 default:
116 break;
117 }
118 return false;
119}
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +0000120#else
121bool testCPUFeature(CPUFeature Feature) {
122 return false;
123}
124#endif // defined(__x86_64__) || defined(__i386__)
Kostya Serebryany712fc982016-06-07 01:20:26 +0000125
Kostya Kortchinsky1148dc52016-11-30 17:32:20 +0000126} // namespace __scudo