Skip to content

Omega493/cpp-panic-handler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Panic Handler

Two small helper functions (wrapper around the write function) and a panic handler for both Linux and Windows. What the panic handler does is to print out the values in the 16 GPRs + the RIP register whenever a crash occurs. The print occurs to stderr, while an equivalent stdout function is present as well.

How to Use

Just drag and drop the include/panic_handler directory in your project, include include/panic_handler/panic_handler.hpp in your source file (ideally, the same file where your main() is located), add "include/panic_handler/panic_handler.cpp" in your CMakeLists.txt file and call it a day!

Your main() must be of the following way to reasonably use the provided functions:

// Other includes...

#include "include/panic_handler/panic_handler.hpp"

// ...

int main(int argc, char* argv[]) { // or int main()
  std::signal(SIGINT, [](const int signum_) {
    stderr_write("SIGINT (external interrupt) sent to program.");
    std::_Exit(signum_);
  });

  std::signal(SIGTERM, [](const int signum_) {
    stderr_write("SIGTERM (termination request) sent to program.");
    std::_Exit(signum_);
  });

#ifdef _WIN32
  LPTOP_LEVEL_EXCEPTION_FILTER prev_handler_{ SetUnhandledExceptionFilter(panic_handler) };
#elifdef __linux__ // ^^^ _WIN32 || __linux__ vvv
  struct sigaction signal_action_{};
  signal_action_.sa_sigaction = panic_handler;
  signal_action_.sa_flags = SA_SIGINFO;
  sigemptyset(&signal_action_.sa_mask);
  sigaction(SIGSEGV, &signal_action_, nullptr);
  sigaction(SIGABRT, &signal_action_, nullptr);
  sigaction(SIGILL, &signal_action_, nullptr);
  sigaction(SIGFPE, &signal_action_, nullptr);
  // Ignore SIGINT and SIGTERM
  // SIGINT is initiated by user
  // SIGTERM is sent to the program
  // Neither of the two are caused by the program itself
#endif // ^^^ _WIN32 ^^^

  // ... Your own logic
}

As is evident, the panic handlers must be the first thing to be setup in main. You could also follow the main.cpp provided in this repo to know more.

Example - 1

An example is provided in the repo itself, via the src/main.cpp:

// ... in main()...
int* ptr{ nullptr };
*ptr = 2;

I deliberately dereference the null pointer for this example.

1. Windows

On Windows, the example will write to stderr something similar to:

Process ID: 26408
Exception at address 0x00007FF7E6E11037: EXCEPTION_ACCESS_VIOLATION - a thread attempted to read from an address it doesn't have access to.

Registers:
RAX: 0x0000000000000000  RCX: 0xFFFFFFFFFFFFFFFF
RDX: 0x0000000000000000  RBX: 0x000001E1E09AF2B0
RSP: 0x00000030412FFA70  RBP: 0x0000000000000000
RSI: 0x0000000000000000  RDI: 0x000001E1E09B6510
RIP: 0x00007FF7E6E11037
R8:  0x00000030412FF748  R9:  0x0000000000000000
R10: 0x0000000000000000  R11: 0x00000030412FFA60
R12: 0x0000000000000000  R13: 0x0000000000000000
R14: 0x0000000000000000  R15: 0x0000000000000000

2. Linux

On a Linux system, the example will write to stderr something similar to:

Process ID: 444
Exception at address 0x0000000000000000: SIGSEGV (segment violation).

Registers:
RAX: 0x0000000000000000  RCX: 0x0000779148C3E3B6
RDX: 0x0000000000000000  RBX: 0x0000000000000000
RSP: 0x00007FFF8839A640  RBP: 0x00007FFF8839A6F0
RSI: 0x00007FFF8839A4F0  RDI: 0x0000000000000008
RIP: 0x0000625730CEA178
R8:  0x0000000000000000  R9:  0x0000000000000000
R10: 0x0000000000000008  R11: 0x0000000000000246
R12: 0x0000000000000000  R13: 0x0000000000000001
R14: 0x000077914935E000  R15: 0x0000625730CECDA8

Example - 2

Now, let us do...

std::cout << 10 / 0;

1. Windows

On Windows, this writes something similar to stderr:

Process ID: 2728
Exception at address 0x00007FF62A451509: EXCEPTION_INT_DIVIDE_BY_ZERO - division by zero.

Registers:
RAX: 0x000000000000000A  RCX: 0x0000000000000000
RDX: 0x0000000000000000  RBX: 0x0000025F9222DB10
RSP: 0x00000074B6BCF990  RBP: 0x0000000000000000
RSI: 0x0000000000000000  RDI: 0x0000025F9222CDD0
RIP: 0x00007FF62A451509
R8:  0x7FFFFFFFFFFFFFFC  R9:  0x00000074B6BCF814
R10: 0x00000FFF3B0FCD80  R11: 0x00000074B6BCF950
R12: 0x0000000000000000  R13: 0x0000000000000000
R14: 0x0000000000000000  R15: 0x0000000000000000

2. Linux

On Linux, it writes the following to stderr:

Process ID: 526
Exception at address 0x000056C5D1CF628C: SIGFPE (floating point exception - erroneous arithmatic operation, maybe division by zero?).

Registers:
RAX: 0x000000000000000A  RCX: 0x0000000000000000
RDX: 0x0000000000000000  RBX: 0x0000000000000000
RSP: 0x00007FFFD7FECEF0  RBP: 0x00007FFFD7FECFA0
RSI: 0x00007FFFD7FECDA0  RDI: 0x0000000000000008
RIP: 0x000056C5D1CF628C
R8:  0x0000000000000000  R9:  0x0000000000000000
R10: 0x0000000000000008  R11: 0x0000000000000246
R12: 0x00007FFFD7FED0D8  R13: 0x0000000000000001
R14: 0x00007946C68D4000  R15: 0x000056C5D1CF8DA8

Contributors