diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc index 1f6531d50fb55..86ac4dd8f601d 100644 --- a/llvm/lib/Support/Unix/Signals.inc +++ b/llvm/lib/Support/Unix/Signals.inc @@ -80,6 +80,10 @@ #endif #endif +#if defined(__linux__) +#include +#endif + using namespace llvm; static void SignalHandler(int Sig, siginfo_t *Info, void *); @@ -411,10 +415,21 @@ static void SignalHandler(int Sig, siginfo_t *Info, void *) { raise(Sig); #endif - // Signal sent from another process, do not assume that continuing the - // execution would re-raise it. - if (Info->si_pid != getpid()) +#if defined(__linux__) + // Re-raising a signal via `raise` loses the original siginfo. Recent + // versions of linux (>= 3.9) support processes sending a signal to itself + // with arbitrary signal information using a syscall. If this syscall is + // unsupported, errno will be set to EPERM and `raise` will be used instead. + int retval = + syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), Sig, Info); + if (retval != 0 && errno == EPERM) raise(Sig); +#else + // Signal sent from another userspace process, do not assume that continuing + // the execution would re-raise it. + if (Info->si_pid != getpid() && Info->si_pid != 0) + raise(Sig); +#endif } static void InfoSignalHandler(int Sig) {