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__ < 18 22 // getauxval() was introduced with API level 18 on Android. Emulate it using 23 // /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 { 95 __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx); 96 } 97 98 CPUIDRegs getCPUFeatures() { 99 CPUIDRegs VendorRegs = {}; 100 getCPUID(&VendorRegs, 0); 101 bool IsIntel = 102 (VendorRegs.Ebx == signature_INTEL_ebx) && 103 (VendorRegs.Edx == signature_INTEL_edx) && 104 (VendorRegs.Ecx == signature_INTEL_ecx); 105 bool IsAMD = 106 (VendorRegs.Ebx == signature_AMD_ebx) && 107 (VendorRegs.Edx == signature_AMD_edx) && 108 (VendorRegs.Ecx == signature_AMD_ecx); 109 // Default to an empty feature set if not on a supported CPU. 110 CPUIDRegs FeaturesRegs = {}; 111 if (IsIntel || IsAMD) { 112 getCPUID(&FeaturesRegs, 1); 113 } 114 return FeaturesRegs; 115 } 116 117 # ifndef bit_SSE4_2 118 # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines. 119 # endif 120 121 bool testCPUFeature(CPUFeature Feature) 122 { 123 CPUIDRegs FeaturesRegs = getCPUFeatures(); 124 125 switch (Feature) { 126 case CRC32CPUFeature: // CRC32 is provided by SSE 4.2. 127 return !!(FeaturesRegs.Ecx & bit_SSE4_2); 128 default: 129 break; 130 } 131 return false; 132 } 133 #elif defined(__arm__) || defined(__aarch64__) 134 // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWVAL 135 // auxiliary vector. 136 137 # ifndef HWCAP_CRC32 138 # define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms. 139 # endif 140 141 bool testCPUFeature(CPUFeature Feature) { 142 uptr HWCap = getauxval(AT_HWCAP); 143 144 switch (Feature) { 145 case CRC32CPUFeature: 146 return !!(HWCap & HWCAP_CRC32); 147 default: 148 break; 149 } 150 return false; 151 } 152 #else 153 bool testCPUFeature(CPUFeature Feature) { 154 return false; 155 } 156 #endif // defined(__x86_64__) || defined(__i386__) 157 158 } // namespace __scudo 159