1712fc980SKostya Serebryany //===-- scudo_utils.cpp -----------------------------------------*- C++ -*-===//
2712fc980SKostya Serebryany //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6712fc980SKostya Serebryany //
7712fc980SKostya Serebryany //===----------------------------------------------------------------------===//
8712fc980SKostya Serebryany ///
9712fc980SKostya Serebryany /// Platform specific utility functions.
10712fc980SKostya Serebryany ///
11712fc980SKostya Serebryany //===----------------------------------------------------------------------===//
12712fc980SKostya Serebryany
13712fc980SKostya Serebryany #include "scudo_utils.h"
14712fc980SKostya Serebryany
152defe4d9SKostya Kortchinsky #if defined(__x86_64__) || defined(__i386__)
161148dc52SKostya Kortchinsky # include <cpuid.h>
170207b6fbSKostya Kortchinsky #elif defined(__arm__) || defined(__aarch64__)
180207b6fbSKostya Kortchinsky # include "sanitizer_common/sanitizer_getauxval.h"
195a8bdc81SKostya Kortchinsky # if SANITIZER_FUCHSIA
205a8bdc81SKostya Kortchinsky # include <zircon/syscalls.h>
215a8bdc81SKostya Kortchinsky # include <zircon/features.h>
225a8bdc81SKostya Kortchinsky # elif SANITIZER_POSIX
2373a80c54SKostya Kortchinsky # include "sanitizer_common/sanitizer_posix.h"
246bc7b26dSKostya Kortchinsky # include <fcntl.h>
25b39dff45SKostya Kortchinsky # endif
266bc7b26dSKostya Kortchinsky #endif
27712fc980SKostya Serebryany
280207b6fbSKostya Kortchinsky #include <stdarg.h>
290207b6fbSKostya Kortchinsky
30712fc980SKostya Serebryany // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
31712fc980SKostya Serebryany // complicated string formatting code. The following is a
32712fc980SKostya Serebryany // temporary workaround to be able to use __sanitizer::VSNPrintf.
33712fc980SKostya Serebryany namespace __sanitizer {
34712fc980SKostya Serebryany
35712fc980SKostya Serebryany extern int VSNPrintf(char *buff, int buff_length, const char *format,
36712fc980SKostya Serebryany va_list args);
37712fc980SKostya Serebryany
38712fc980SKostya Serebryany } // namespace __sanitizer
39712fc980SKostya Serebryany
40712fc980SKostya Serebryany namespace __scudo {
41712fc980SKostya Serebryany
dieWithMessage(const char * Format,...)42*036f9630SDmitry Vyukov void dieWithMessage(const char *Format, ...) {
43e245ec0cSKostya Kortchinsky static const char ScudoError[] = "Scudo ERROR: ";
44e245ec0cSKostya Kortchinsky static constexpr uptr PrefixSize = sizeof(ScudoError) - 1;
45ada27614SKostya Kortchinsky // Our messages are tiny, 256 characters is more than enough.
46ada27614SKostya Kortchinsky char Message[256];
47712fc980SKostya Serebryany va_list Args;
48712fc980SKostya Serebryany va_start(Args, Format);
49e245ec0cSKostya Kortchinsky internal_memcpy(Message, ScudoError, PrefixSize);
50e245ec0cSKostya Kortchinsky VSNPrintf(Message + PrefixSize, sizeof(Message) - PrefixSize, Format, Args);
51712fc980SKostya Serebryany va_end(Args);
522efb847bSKostya Kortchinsky LogMessageOnPrintf(Message);
532efb847bSKostya Kortchinsky if (common_flags()->abort_on_error)
542efb847bSKostya Kortchinsky SetAbortMessage(Message);
55712fc980SKostya Serebryany RawWrite(Message);
56712fc980SKostya Serebryany Die();
57712fc980SKostya Serebryany }
58712fc980SKostya Serebryany
591148dc52SKostya Kortchinsky #if defined(__x86_64__) || defined(__i386__)
601148dc52SKostya Kortchinsky // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
611148dc52SKostya Kortchinsky // CRC32 requires the SSE 4.2 instruction set.
621148dc52SKostya Kortchinsky # ifndef bit_SSE4_2
631148dc52SKostya Kortchinsky # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
641148dc52SKostya Kortchinsky # endif
659959eb91SKostya Kortchinsky
669959eb91SKostya Kortchinsky #ifndef signature_HYGON_ebx // They are not defined in gcc.
679959eb91SKostya Kortchinsky // HYGON: "HygonGenuine".
689959eb91SKostya Kortchinsky #define signature_HYGON_ebx 0x6f677948
699959eb91SKostya Kortchinsky #define signature_HYGON_edx 0x6e65476e
709959eb91SKostya Kortchinsky #define signature_HYGON_ecx 0x656e6975
719959eb91SKostya Kortchinsky #endif
729959eb91SKostya Kortchinsky
hasHardwareCRC32()730207b6fbSKostya Kortchinsky bool hasHardwareCRC32() {
740207b6fbSKostya Kortchinsky u32 Eax, Ebx, Ecx, Edx;
750207b6fbSKostya Kortchinsky __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx);
760207b6fbSKostya Kortchinsky const bool IsIntel = (Ebx == signature_INTEL_ebx) &&
770207b6fbSKostya Kortchinsky (Edx == signature_INTEL_edx) &&
780207b6fbSKostya Kortchinsky (Ecx == signature_INTEL_ecx);
790207b6fbSKostya Kortchinsky const bool IsAMD = (Ebx == signature_AMD_ebx) &&
800207b6fbSKostya Kortchinsky (Edx == signature_AMD_edx) &&
810207b6fbSKostya Kortchinsky (Ecx == signature_AMD_ecx);
829959eb91SKostya Kortchinsky const bool IsHygon = (Ebx == signature_HYGON_ebx) &&
839959eb91SKostya Kortchinsky (Edx == signature_HYGON_edx) &&
849959eb91SKostya Kortchinsky (Ecx == signature_HYGON_ecx);
859959eb91SKostya Kortchinsky if (!IsIntel && !IsAMD && !IsHygon)
86712fc980SKostya Serebryany return false;
870207b6fbSKostya Kortchinsky __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx);
880207b6fbSKostya Kortchinsky return !!(Ecx & bit_SSE4_2);
89712fc980SKostya Serebryany }
90b39dff45SKostya Kortchinsky #elif defined(__arm__) || defined(__aarch64__)
910207b6fbSKostya Kortchinsky // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWCAP
926bc7b26dSKostya Kortchinsky // auxiliary vector.
930207b6fbSKostya Kortchinsky # ifndef AT_HWCAP
940207b6fbSKostya Kortchinsky # define AT_HWCAP 16
950207b6fbSKostya Kortchinsky # endif
96b39dff45SKostya Kortchinsky # ifndef HWCAP_CRC32
97b39dff45SKostya Kortchinsky # define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms.
98b39dff45SKostya Kortchinsky # endif
990207b6fbSKostya Kortchinsky # if SANITIZER_POSIX
hasHardwareCRC32ARMPosix()1000207b6fbSKostya Kortchinsky bool hasHardwareCRC32ARMPosix() {
1010207b6fbSKostya Kortchinsky uptr F = internal_open("/proc/self/auxv", O_RDONLY);
1020207b6fbSKostya Kortchinsky if (internal_iserror(F))
1030207b6fbSKostya Kortchinsky return false;
1040207b6fbSKostya Kortchinsky struct { uptr Tag; uptr Value; } Entry = { 0, 0 };
1050207b6fbSKostya Kortchinsky for (;;) {
1060207b6fbSKostya Kortchinsky uptr N = internal_read(F, &Entry, sizeof(Entry));
1070207b6fbSKostya Kortchinsky if (internal_iserror(N) || N != sizeof(Entry) ||
1080207b6fbSKostya Kortchinsky (Entry.Tag == 0 && Entry.Value == 0) || Entry.Tag == AT_HWCAP)
109b39dff45SKostya Kortchinsky break;
110b39dff45SKostya Kortchinsky }
1110207b6fbSKostya Kortchinsky internal_close(F);
1120207b6fbSKostya Kortchinsky return (Entry.Tag == AT_HWCAP && (Entry.Value & HWCAP_CRC32) != 0);
113b39dff45SKostya Kortchinsky }
1141148dc52SKostya Kortchinsky # else
hasHardwareCRC32ARMPosix()1150207b6fbSKostya Kortchinsky bool hasHardwareCRC32ARMPosix() { return false; }
1160207b6fbSKostya Kortchinsky # endif // SANITIZER_POSIX
1170207b6fbSKostya Kortchinsky
11806b891f6SKostya Kortchinsky // Bionic doesn't initialize its globals early enough. This causes issues when
11906b891f6SKostya Kortchinsky // trying to access them from a preinit_array (b/25751302) or from another
12006b891f6SKostya Kortchinsky // constructor called before the libc one (b/68046352). __progname is
12106b891f6SKostya Kortchinsky // initialized after the other globals, so we can check its value to know if
12206b891f6SKostya Kortchinsky // calling getauxval is safe.
12306b891f6SKostya Kortchinsky extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
areBionicGlobalsInitialized()12485e578f5SKamil Rytarowski inline bool areBionicGlobalsInitialized() {
12506b891f6SKostya Kortchinsky return !SANITIZER_ANDROID || (&__progname && __progname);
12606b891f6SKostya Kortchinsky }
12706b891f6SKostya Kortchinsky
hasHardwareCRC32()1280207b6fbSKostya Kortchinsky bool hasHardwareCRC32() {
1295a8bdc81SKostya Kortchinsky #if SANITIZER_FUCHSIA
1305a8bdc81SKostya Kortchinsky u32 HWCap;
1315a8bdc81SKostya Kortchinsky zx_status_t Status = zx_system_get_features(ZX_FEATURE_KIND_CPU, &HWCap);
1325a8bdc81SKostya Kortchinsky if (Status != ZX_OK || (HWCap & ZX_ARM64_FEATURE_ISA_CRC32) == 0)
1335a8bdc81SKostya Kortchinsky return false;
1345a8bdc81SKostya Kortchinsky return true;
1355a8bdc81SKostya Kortchinsky #else
13606b891f6SKostya Kortchinsky if (&getauxval && areBionicGlobalsInitialized())
1370207b6fbSKostya Kortchinsky return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
1380207b6fbSKostya Kortchinsky return hasHardwareCRC32ARMPosix();
1395a8bdc81SKostya Kortchinsky #endif // SANITIZER_FUCHSIA
1401148dc52SKostya Kortchinsky }
1410207b6fbSKostya Kortchinsky #else
hasHardwareCRC32()1420207b6fbSKostya Kortchinsky bool hasHardwareCRC32() { return false; }
1431148dc52SKostya Kortchinsky #endif // defined(__x86_64__) || defined(__i386__)
144712fc980SKostya Serebryany
145712fc980SKostya Serebryany } // namespace __scudo
146