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 <stdarg.h> 17 #if defined(__x86_64__) || defined(__i386__) 18 # include <cpuid.h> 19 #endif 20 #if defined(__arm__) || defined(__aarch64__) 21 # if SANITIZER_ANDROID && __ANDROID_API__ < 21 22 // getauxval() was introduced with API level 18 for ARM and 21 for AArch64. 23 // Emulate it using /proc/self/auxv for lower API levels. 24 # include "sanitizer_common/sanitizer_posix.h" 25 26 # include <fcntl.h> 27 28 # define AT_HWCAP 16 29 30 namespace __sanitizer { 31 32 uptr getauxval(uptr Type) { 33 uptr F = internal_open("/proc/self/auxv", O_RDONLY); 34 if (internal_iserror(F)) 35 return 0; 36 struct { uptr Tag; uptr Value; } Entry; 37 uptr Result = 0; 38 for (;;) { 39 uptr N = internal_read(F, &Entry, sizeof(Entry)); 40 if (internal_iserror(N)) 41 break; 42 if (N == 0 || N != sizeof(Entry) || (Entry.Tag == 0 && Entry.Value == 0)) 43 break; 44 if (Entry.Tag == Type) { 45 Result = Entry.Value; 46 break; 47 } 48 } 49 internal_close(F); 50 return Result; 51 } 52 53 } // namespace __sanitizer 54 # else 55 # include <sys/auxv.h> 56 # endif 57 #endif 58 59 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less 60 // complicated string formatting code. The following is a 61 // temporary workaround to be able to use __sanitizer::VSNPrintf. 62 namespace __sanitizer { 63 64 extern int VSNPrintf(char *buff, int buff_length, const char *format, 65 va_list args); 66 67 } // namespace __sanitizer 68 69 namespace __scudo { 70 71 FORMAT(1, 2) 72 void NORETURN dieWithMessage(const char *Format, ...) { 73 // Our messages are tiny, 256 characters is more than enough. 74 char Message[256]; 75 va_list Args; 76 va_start(Args, Format); 77 __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args); 78 va_end(Args); 79 RawWrite(Message); 80 Die(); 81 } 82 83 #if defined(__x86_64__) || defined(__i386__) 84 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID. 85 // CRC32 requires the SSE 4.2 instruction set. 86 typedef struct { 87 u32 Eax; 88 u32 Ebx; 89 u32 Ecx; 90 u32 Edx; 91 } CPUIDRegs; 92 93 static void getCPUID(CPUIDRegs *Regs, u32 Level) { 94 __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx); 95 } 96 97 CPUIDRegs getCPUFeatures() { 98 CPUIDRegs VendorRegs = {}; 99 getCPUID(&VendorRegs, 0); 100 bool IsIntel = 101 (VendorRegs.Ebx == signature_INTEL_ebx) && 102 (VendorRegs.Edx == signature_INTEL_edx) && 103 (VendorRegs.Ecx == signature_INTEL_ecx); 104 bool IsAMD = 105 (VendorRegs.Ebx == signature_AMD_ebx) && 106 (VendorRegs.Edx == signature_AMD_edx) && 107 (VendorRegs.Ecx == signature_AMD_ecx); 108 // Default to an empty feature set if not on a supported CPU. 109 CPUIDRegs FeaturesRegs = {}; 110 if (IsIntel || IsAMD) { 111 getCPUID(&FeaturesRegs, 1); 112 } 113 return FeaturesRegs; 114 } 115 116 # ifndef bit_SSE4_2 117 # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines. 118 # endif 119 120 bool testCPUFeature(CPUFeature Feature) { 121 CPUIDRegs FeaturesRegs = getCPUFeatures(); 122 123 switch (Feature) { 124 case CRC32CPUFeature: // CRC32 is provided by SSE 4.2. 125 return !!(FeaturesRegs.Ecx & bit_SSE4_2); 126 default: 127 break; 128 } 129 return false; 130 } 131 #elif defined(__arm__) || defined(__aarch64__) 132 // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWVAL 133 // auxiliary vector. 134 135 # ifndef HWCAP_CRC32 136 # define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms. 137 # endif 138 139 bool testCPUFeature(CPUFeature Feature) { 140 uptr HWCap = getauxval(AT_HWCAP); 141 142 switch (Feature) { 143 case CRC32CPUFeature: 144 return !!(HWCap & HWCAP_CRC32); 145 default: 146 break; 147 } 148 return false; 149 } 150 #else 151 bool testCPUFeature(CPUFeature Feature) { 152 return false; 153 } 154 #endif // defined(__x86_64__) || defined(__i386__) 155 156 } // namespace __scudo 157