gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/util/signal_util.h (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef GVISOR_TEST_UTIL_SIGNAL_UTIL_H_ 16 #define GVISOR_TEST_UTIL_SIGNAL_UTIL_H_ 17 18 #include <signal.h> 19 #include <sys/syscall.h> 20 #include <unistd.h> 21 22 #include <ostream> 23 24 #include "gmock/gmock.h" 25 #include "test/util/cleanup.h" 26 #include "test/util/file_descriptor.h" 27 #include "test/util/posix_error.h" 28 29 // Format a sigset_t as a comma separated list of numeric ranges. 30 ::std::ostream& operator<<(::std::ostream& os, const sigset_t& sigset); 31 32 namespace gvisor { 33 namespace testing { 34 35 // The maximum signal number. 36 static constexpr int kMaxSignal = 64; 37 38 // Wrapper for the tgkill(2) syscall, which glibc does not provide. 39 inline int tgkill(pid_t tgid, pid_t tid, int sig) { 40 return syscall(__NR_tgkill, tgid, tid, sig); 41 } 42 43 // Installs the passed sigaction and returns a cleanup function to restore the 44 // previous handler when it goes out of scope. 45 PosixErrorOr<Cleanup> ScopedSigaction(int sig, struct sigaction const& sa); 46 47 // Updates the signal mask as per sigprocmask(2) and returns a cleanup function 48 // to restore the previous signal mask when it goes out of scope. 49 PosixErrorOr<Cleanup> ScopedSignalMask(int how, sigset_t const& set); 50 51 // ScopedSignalMask variant that creates a mask of the single signal 'sig'. 52 inline PosixErrorOr<Cleanup> ScopedSignalMask(int how, int sig) { 53 sigset_t set; 54 sigemptyset(&set); 55 sigaddset(&set, sig); 56 return ScopedSignalMask(how, set); 57 } 58 59 // Asserts equality of two sigset_t values. 60 MATCHER_P(EqualsSigset, value, "equals " + ::testing::PrintToString(value)) { 61 for (int sig = 1; sig <= kMaxSignal; ++sig) { 62 if (sigismember(&arg, sig) != sigismember(&value, sig)) { 63 return false; 64 } 65 } 66 return true; 67 } 68 69 #ifdef __x86_64__ 70 // Fault can be used to generate a synchronous SIGSEGV. 71 // 72 // This fault can be fixed up in a handler via fixup, below. 73 inline void Fault() { 74 // Zero and dereference %ax. 75 asm("movabs $0, %%rax\r\n" 76 "mov 0(%%rax), %%rax\r\n" 77 : 78 : 79 : "ax"); 80 } 81 82 // FixupFault fixes up a fault generated by fault, above. 83 inline void FixupFault(ucontext_t* ctx) { 84 // Skip the bad instruction above. 85 // 86 // The encoding is 0x48 0xab 0x00. 87 ctx->uc_mcontext.gregs[REG_RIP] += 3; 88 } 89 #elif __aarch64__ 90 inline void Fault() { 91 // Zero and dereference x0. 92 asm("mov x0, xzr\r\n" 93 "str xzr, [x0]\r\n" 94 : 95 : 96 : "x0"); 97 } 98 99 inline void FixupFault(ucontext_t* ctx) { 100 // Skip the bad instruction above. 101 ctx->uc_mcontext.pc += 4; 102 } 103 #endif 104 105 // Wrapper around signalfd(2) that returns a FileDescriptor. 106 PosixErrorOr<FileDescriptor> NewSignalFD(sigset_t* mask, int flags = 0); 107 108 } // namespace testing 109 } // namespace gvisor 110 111 #endif // GVISOR_TEST_UTIL_SIGNAL_UTIL_H_