| //===-- ubsan_loop_detect.cpp ---------------------------------------------===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // Runtime support for -fsanitize-trap-loop. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include <sanitizer/ubsan_interface.h> | |
| #if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) | |
| #include <asm/processor-flags.h> | |
| #include <signal.h> | |
| #include <stdint.h> | |
| #include <sys/time.h> | |
| #include <sys/ucontext.h> | |
| int __ubsan_is_trap_loop(void *c) { | |
| auto *uc = reinterpret_cast<ucontext_t *>(c); | |
| #if defined(__x86_64__) | |
| auto *ip = reinterpret_cast<const uint8_t *>(uc->uc_mcontext.gregs[REG_RIP]); | |
| #else | |
| auto *ip = reinterpret_cast<const uint8_t *>(uc->uc_mcontext.gregs[REG_EIP]); | |
| #endif | |
| // Test whether IP is at a conditional branch to self instruction. | |
| if ((ip[0] & 0xf0) != 0x70 || ip[1] != 0xfe) | |
| return false; | |
| // If so, test whether the condition is satisfied, in case we happened to | |
| // receive the signal at a not-taken branch to self. | |
| uint64_t eflags = uc->uc_mcontext.gregs[REG_EFL]; | |
| switch (ip[0]) { | |
| case 0x70: // JO | |
| return eflags & X86_EFLAGS_OF; | |
| case 0x71: // JNO | |
| return !(eflags & X86_EFLAGS_OF); | |
| case 0x72: // JB | |
| return eflags & X86_EFLAGS_CF; | |
| case 0x73: // JAE | |
| return !(eflags & X86_EFLAGS_CF); | |
| case 0x74: // JE | |
| return eflags & X86_EFLAGS_ZF; | |
| case 0x75: // JNE | |
| return !(eflags & X86_EFLAGS_ZF); | |
| case 0x76: // JBE | |
| return (eflags & X86_EFLAGS_CF) || (eflags & X86_EFLAGS_ZF); | |
| case 0x77: // JA | |
| return !(eflags & X86_EFLAGS_CF) && !(eflags & X86_EFLAGS_ZF); | |
| case 0x78: // JS | |
| return eflags & X86_EFLAGS_SF; | |
| case 0x79: // JNS | |
| return !(eflags & X86_EFLAGS_SF); | |
| case 0x7A: // JP | |
| return eflags & X86_EFLAGS_PF; | |
| case 0x7B: // JNP | |
| return !(eflags & X86_EFLAGS_PF); | |
| case 0x7C: // JL | |
| return !!(eflags & X86_EFLAGS_SF) != !!(eflags & X86_EFLAGS_OF); | |
| case 0x7D: // JGE | |
| return !!(eflags & X86_EFLAGS_SF) == !!(eflags & X86_EFLAGS_OF); | |
| case 0x7E: // JLE | |
| return (eflags & X86_EFLAGS_ZF) || | |
| !!(eflags & X86_EFLAGS_SF) != !!(eflags & X86_EFLAGS_OF); | |
| case 0x7F: // JG | |
| return !(eflags & X86_EFLAGS_ZF) && | |
| !!(eflags & X86_EFLAGS_SF) == !!(eflags & X86_EFLAGS_OF); | |
| default: | |
| return false; | |
| } | |
| } | |
| static void SigprofHandler(int signo, siginfo_t *si, void *c) { | |
| if (__ubsan_is_trap_loop(c)) { | |
| __builtin_trap(); | |
| } | |
| } | |
| void __ubsan_install_trap_loop_detection(void) { | |
| struct sigaction sa; | |
| sa.sa_sigaction = SigprofHandler; | |
| sigaction(SIGPROF, &sa, nullptr); | |
| struct itimerval timer; | |
| timer.it_value.tv_sec = 0; | |
| timer.it_value.tv_usec = 100000; | |
| timer.it_interval = timer.it_value; | |
| setitimer(ITIMER_PROF, &timer, NULL); | |
| } | |
| #else | |
| int __ubsan_is_trap_loop(void *c) { return false; } | |
| void __ubsan_install_trap_loop_detection(void) {} | |
| #endif |