123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- //===-- scudo_utils.cpp -----------------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- ///
- /// Platform specific utility functions.
- ///
- //===----------------------------------------------------------------------===//
- #include "scudo_utils.h"
- #if defined(__x86_64__) || defined(__i386__)
- # include <cpuid.h>
- #elif defined(__arm__) || defined(__aarch64__)
- # include "sanitizer_common/sanitizer_getauxval.h"
- # if SANITIZER_FUCHSIA
- # error #include <zircon/syscalls.h>
- # error #include <zircon/features.h>
- # elif SANITIZER_POSIX
- # include "sanitizer_common/sanitizer_posix.h"
- # include <fcntl.h>
- # endif
- #endif
- #include <stdarg.h>
- // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
- // complicated string formatting code. The following is a
- // temporary workaround to be able to use __sanitizer::VSNPrintf.
- namespace __sanitizer {
- extern int VSNPrintf(char *buff, int buff_length, const char *format,
- va_list args);
- } // namespace __sanitizer
- namespace __scudo {
- void dieWithMessage(const char *Format, ...) {
- static const char ScudoError[] = "Scudo ERROR: ";
- static constexpr uptr PrefixSize = sizeof(ScudoError) - 1;
- // Our messages are tiny, 256 characters is more than enough.
- char Message[256];
- va_list Args;
- va_start(Args, Format);
- internal_memcpy(Message, ScudoError, PrefixSize);
- VSNPrintf(Message + PrefixSize, sizeof(Message) - PrefixSize, Format, Args);
- va_end(Args);
- LogMessageOnPrintf(Message);
- if (common_flags()->abort_on_error)
- SetAbortMessage(Message);
- RawWrite(Message);
- Die();
- }
- #if defined(__x86_64__) || defined(__i386__)
- // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
- // CRC32 requires the SSE 4.2 instruction set.
- # ifndef bit_SSE4_2
- # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
- # endif
- #ifndef signature_HYGON_ebx // They are not defined in gcc.
- // HYGON: "HygonGenuine".
- #define signature_HYGON_ebx 0x6f677948
- #define signature_HYGON_edx 0x6e65476e
- #define signature_HYGON_ecx 0x656e6975
- #endif
- bool hasHardwareCRC32() {
- u32 Eax, Ebx, Ecx, Edx;
- __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx);
- const bool IsIntel = (Ebx == signature_INTEL_ebx) &&
- (Edx == signature_INTEL_edx) &&
- (Ecx == signature_INTEL_ecx);
- const bool IsAMD = (Ebx == signature_AMD_ebx) &&
- (Edx == signature_AMD_edx) &&
- (Ecx == signature_AMD_ecx);
- const bool IsHygon = (Ebx == signature_HYGON_ebx) &&
- (Edx == signature_HYGON_edx) &&
- (Ecx == signature_HYGON_ecx);
- if (!IsIntel && !IsAMD && !IsHygon)
- return false;
- __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx);
- return !!(Ecx & bit_SSE4_2);
- }
- #elif defined(__arm__) || defined(__aarch64__)
- // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWCAP
- // auxiliary vector.
- # ifndef AT_HWCAP
- # define AT_HWCAP 16
- # endif
- # ifndef HWCAP_CRC32
- # define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms.
- # endif
- # if SANITIZER_POSIX
- bool hasHardwareCRC32ARMPosix() {
- uptr F = internal_open("/proc/self/auxv", O_RDONLY);
- if (internal_iserror(F))
- return false;
- struct { uptr Tag; uptr Value; } Entry = { 0, 0 };
- for (;;) {
- uptr N = internal_read(F, &Entry, sizeof(Entry));
- if (internal_iserror(N) || N != sizeof(Entry) ||
- (Entry.Tag == 0 && Entry.Value == 0) || Entry.Tag == AT_HWCAP)
- break;
- }
- internal_close(F);
- return (Entry.Tag == AT_HWCAP && (Entry.Value & HWCAP_CRC32) != 0);
- }
- # else
- bool hasHardwareCRC32ARMPosix() { return false; }
- # endif // SANITIZER_POSIX
- // Bionic doesn't initialize its globals early enough. This causes issues when
- // trying to access them from a preinit_array (b/25751302) or from another
- // constructor called before the libc one (b/68046352). __progname is
- // initialized after the other globals, so we can check its value to know if
- // calling getauxval is safe.
- extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
- inline bool areBionicGlobalsInitialized() {
- return !SANITIZER_ANDROID || (&__progname && __progname);
- }
- bool hasHardwareCRC32() {
- #if SANITIZER_FUCHSIA
- u32 HWCap;
- zx_status_t Status = zx_system_get_features(ZX_FEATURE_KIND_CPU, &HWCap);
- if (Status != ZX_OK || (HWCap & ZX_ARM64_FEATURE_ISA_CRC32) == 0)
- return false;
- return true;
- #else
- if (&getauxval && areBionicGlobalsInitialized())
- return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
- return hasHardwareCRC32ARMPosix();
- #endif // SANITIZER_FUCHSIA
- }
- #else
- bool hasHardwareCRC32() { return false; }
- #endif // defined(__x86_64__) || defined(__i386__)
- } // namespace __scudo
|