1
0
Fork
You've already forked tracecrash
0
Display a backtrace when a crashing signal occurs in a child process.
  • C 97.9%
  • Makefile 2.1%
2024年03月04日 12:36:59 +03:00
.gitignore Add .gitignore 2024年03月01日 23:24:17 +03:00
GNUmakefile Optional stack dump 2024年03月02日 14:59:47 +03:00
hexdump.c Tweaks, warning fixes 2024年03月02日 17:14:24 +03:00
hexdump.h Optional stack dump 2024年03月02日 14:59:47 +03:00
LICENCE README and LICENCE 2024年03月02日 11:49:08 +03:00
README.md README tweaks 2024年03月04日 12:36:59 +03:00
tracecrash.c Tweaks 2024年03月02日 11:24:33 +03:00
unwind.c Optional stack dump 2024年03月02日 14:59:47 +03:00
unwind.h Unwinding using libunwind-ptrace now works 2024年03月01日 23:23:02 +03:00

tracecrash

What is it?

tracecrash is a just-in-time debugger. For most of the process lifetime, it does as little as possible, only attaching to child threads and processes as they are created. If one of them receives a "crashing" signal (currently chosen as SIGSEGV, SIGBUS, SIGILL, or SIGTRAP), tracecrash produces a backtrace on the standard output.

What does it look like?

$ cat crash.c
void crash(void) { *(double*)42 = 42; }
$ R CMD SHLIB crash.c
<compiler output omitted>
$ ./tracecrash R -q -s -e 'dyn.load("crash.so"); .C("crash")'
-----------------------------------8<-----------------------------------
PID 8864 received crashing signal 11
rax=4045000000000000 rbx=000056166e1a12a8 rcx=00005616701178b0 rdx=00007f39740acc1c
rsi=000056166e169440 rdi=0000000000000000 rbp=00005616701179c8 rsp=00007ffee4c9b218
 r8=0000000000000007 r9=0000000000000001 r10=0000000000000000 r11=0000000000000000
r12=00007ffee4c9b3e0 r13=000056166e169440 r14=0000561670117958 r15=000056166e169440
ip = 7f396f01c107, sp = 7ffee4c9b218 [crash+7]
ip = 7f3973f023e9, sp = 7ffee4c9b220 [Rf_NewFrameConfirm+26969]
ip = 7f3973f5809d, sp = 7ffee4c9b830 [Rf_eval+2013]
ip = 7f3973f8c161, sp = 7ffee4c9ba80 [Rf_ReplIteration+513]
ip = 7f3973f8c4d0, sp = 7ffee4c9bac0 [Rf_ReplIteration+1392]
ip = 7f3973f8c588, sp = 7ffee4c9cb10 [run_Rmainloop+72]
ip = 56166dca907b, sp = 7ffee4c9cb20 [main+27]
ip = 7f3973c4624a, sp = 7ffee4c9cb30 [__libc_init_first+138]
ip = 7f3973c46305, sp = 7ffee4c9cbd0 [__libc_start_main+133]
ip = 56166dca90b1, sp = 7ffee4c9cc20 [_start+33]
-----------------------------------8<-----------------------------------
 *** caught segfault ***
address 0x2a, cause 'memory not mapped'
Traceback:
 1: .C("crash")
An irrecoverable exception occurred. R is aborting now ...
<R raises the signal again, so the output is duplicated>

There is an optional stack dump feature. If the program is compiled with a positive -DHEXDUMP_LIMIT, up to this many bytes from the stack are dumped together with the call frames:

ip = 7f1b6bb8c4d0, sp = 7ffe45118da0 [Rf_ReplIteration+1392]
7ffe45118da0 01 00 00 00 01 00 00 00 00 00 00 00 64 79 6e 2e dyn.
7ffe45118db0 6c 6f 61 64 28 22 63 72 61 73 68 2e 73 6f 22 29 load("crash.so")
7ffe45118dc0 3b 20 2e 43 28 22 63 72 61 73 68 22 29 0a 00 00 ; .C("crash")
7ffe45118dd0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Any problems with this approach?

  • For now, tracecrash only supports amd64 Linux. Support for other architectures is easy to add as long as it exists in libunwind. Support for other Unix-like operating systems will require separating the ptrace() interface due to it being not portable. On Windows, better use catchsegv from Dr. Mingw, which served as the inspiration for this program.
  • Since tracecrash uses ptrace(), it will prevent other processes from attaching to the target process or any of its children. If another tracer attaches to a child first, it will prevent tracecrash from handling its crashes or its children.
  • tracecrash will wait for all tracees to terminate, not only the target program. This includes any background processes created during the lifetime of the process tree: the tracer may terminate much later than the traced child.
  • tracecrash will forward the exit code of the target program. If the target program is terminated by a signal, tracecrash will exit with code 0x80 | signal. If the parent cares about WIFEXITED vs. WIFSIGNALED, it will notice the difference.

How do I build the program?

Make sure that libunwind is installed, including the development headers and pkg-config files, and type make.

Patches?

Welcome.

Licence

Copyright 2024 Ivan Krylov

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.