Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 1 | //===-- 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 Kortchinsky | 2defe4d | 2016-12-08 19:05:46 +0000 | [diff] [blame] | 20 | #if defined(__x86_64__) || defined(__i386__) |
| 21 | # include <cpuid.h> |
| 22 | #endif |
Kostya Kortchinsky | b39dff4 | 2017-01-18 17:11:17 +0000 | [diff] [blame] | 23 | #if defined(__arm__) || defined(__aarch64__) |
| 24 | # include <sys/auxv.h> |
| 25 | #endif |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 26 | |
| 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 { |
| 31 | |
| 32 | extern int VSNPrintf(char *buff, int buff_length, const char *format, |
| 33 | va_list args); |
| 34 | |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 35 | } // namespace __sanitizer |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 36 | |
| 37 | namespace __scudo { |
| 38 | |
| 39 | FORMAT(1, 2) |
Kostya Serebryany | 707894b | 2016-08-02 22:25:38 +0000 | [diff] [blame] | 40 | void NORETURN dieWithMessage(const char *Format, ...) { |
Kostya Kortchinsky | ada2761 | 2016-09-30 19:57:21 +0000 | [diff] [blame] | 41 | // Our messages are tiny, 256 characters is more than enough. |
| 42 | char Message[256]; |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 43 | 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 Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 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. |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 54 | typedef struct { |
| 55 | u32 Eax; |
| 56 | u32 Ebx; |
| 57 | u32 Ecx; |
| 58 | u32 Edx; |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 59 | } CPUIDRegs; |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 60 | |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 61 | static void getCPUID(CPUIDRegs *Regs, u32 Level) |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 62 | { |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 63 | __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx); |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 64 | } |
| 65 | |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 66 | CPUIDRegs 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 Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 81 | } |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 82 | return FeaturesRegs; |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 83 | } |
| 84 | |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 85 | #ifndef bit_SSE4_2 |
Kostya Kortchinsky | b39dff4 | 2017-01-18 17:11:17 +0000 | [diff] [blame] | 86 | # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines. |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 87 | #endif |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 88 | |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 89 | bool testCPUFeature(CPUFeature Feature) |
| 90 | { |
Petr Hosek | 97ab7fe | 2017-01-17 20:41:04 +0000 | [diff] [blame] | 91 | CPUIDRegs FeaturesRegs = getCPUFeatures(); |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 92 | |
| 93 | switch (Feature) { |
| 94 | case CRC32CPUFeature: // CRC32 is provided by SSE 4.2. |
| 95 | return !!(FeaturesRegs.Ecx & bit_SSE4_2); |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 96 | default: |
| 97 | break; |
| 98 | } |
| 99 | return false; |
| 100 | } |
Kostya Kortchinsky | b39dff4 | 2017-01-18 17:11:17 +0000 | [diff] [blame] | 101 | #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 | |
| 109 | bool 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 Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 120 | #else |
| 121 | bool testCPUFeature(CPUFeature Feature) { |
| 122 | return false; |
| 123 | } |
| 124 | #endif // defined(__x86_64__) || defined(__i386__) |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 125 | |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 126 | } // namespace __scudo |