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_