diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2018-01-05 11:46:53 +0100 |
---|---|---|
committer | Patrick Ohly <patrick.ohly@intel.com> | 2018-01-09 07:53:28 -0800 |
commit | c0775792409b108125ec15edca9089b5bf5258bd (patch) | |
tree | dbe7aca6b56042c82cda68943956209fc21b2b09 | |
parent | b7dbeeac49eeb52bcb843d4625d25c12644d43c0 (diff) |
gdb-dump-stack: automatic stack dumps
This is meant to be used by automated testing, with gdb acting as
wrapper around a command so that stack traces are created
automatically when something goes wrong.
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
-rw-r--r-- | test/gdb-dump-stack | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/test/gdb-dump-stack b/test/gdb-dump-stack new file mode 100644 index 00000000..b6205ec2 --- /dev/null +++ b/test/gdb-dump-stack @@ -0,0 +1,79 @@ +# Use this file with +# gdb --batch --return-child-result -x gdb-dump-stack <some command> +# to get full stack backtraces when the command or any of its +# children fails. + +# It is important that we keep processes running in parallel, +# otherwise we risk deadlocks once multiple processes are involved. +set non-stop on + +# Keep track also of child processes. +set detach-on-fork off +set follow-fork-mode parent + +python +class Exited (gdb.Function): + """Return 1 if current threat has exited, else 0.""" + + def __init__ (self): + super (Exited, self).__init__("exited") + + def invoke (self): + thread = gdb.selected_thread() + if thread is None or thread.is_exited(): + return 1 + else: + return 0 + +class FindStopped (gdb.Function): + """Dump stack backtrace of all stopped threads and continue them.""" + + def __init__ (self): + super (FindStopped, self).__init__("find_stopped") + + def invoke (self): + for inferior in gdb.inferiors(): + if inferior.is_valid(): + for thread in inferior.threads(): + if thread.is_valid() and thread.is_stopped(): + thread.switch() + return 1 + return 0 + +Exited() +FindStopped() +end + +# Start the command. Returns once something needs our attention. +run + +# Continously deal with events that normally require user intervention: +# - a process was stopped because of something (like a segfault) +# - a process has quit +while 1 + if $find_stopped() + # The stopped thread is now selected, so we can dump some information about + # it, then continue it. + info inferiors + bt + continue + else + inferior 1 + if $exited() + # No stopped thread, current thread has quit -> we are done. + loop_break + else + # We need to do something, otherwise we would busy-loop + # while all threads are running. Therefore we interrupt + # and restart the main thread. + # + # In (unlikely?) case that some other thread stops by + # itself while we do that, we continue all threads to + # avoid potential deadlocks (main thread running again but + # waiting for stopped thread that we don't know about). + # The downside is that we don't print a stack backtrace + # of such a thread. + interrupt + continue -a + end +end |