Reviewers: fmayer, vitalybuka Reviewed By: vitalybuka, fmayer Pull Request: https://github.com/llvm/llvm-project/pull/179011
101 lines
3.0 KiB
C++
101 lines
3.0 KiB
C++
//===-- 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
|