#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
# include <zircon/syscalls.h>
# include <zircon/features.h>
# elif SANITIZER_POSIX
# include "sanitizer_common/sanitizer_posix.h"
# include <fcntl.h>
# endif
#endif
#include <stdarg.h>
namespace __sanitizer {
extern int VSNPrintf(char *buff, int buff_length, const char *format,
va_list args);
}
namespace __scudo {
void dieWithMessage(const char *Format, ...) {
static const char ScudoError[] = "Scudo ERROR: ";
static constexpr uptr PrefixSize = sizeof(ScudoError) - 1;
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__)
# ifndef bit_SSE4_2
# define bit_SSE4_2 bit_SSE42
# endif
#ifndef signature_HYGON_ebx
#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__)
# ifndef AT_HWCAP
# define AT_HWCAP 16
# endif
# ifndef HWCAP_CRC32
# define HWCAP_CRC32 (1 << 7)
# 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
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
}
#else
bool hasHardwareCRC32() { return false; }
#endif
}