summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2018-01-05 11:46:53 +0100
committerPatrick Ohly <patrick.ohly@intel.com>2018-01-09 07:53:28 -0800
commitc0775792409b108125ec15edca9089b5bf5258bd (patch)
treedbe7aca6b56042c82cda68943956209fc21b2b09
parentb7dbeeac49eeb52bcb843d4625d25c12644d43c0 (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-stack79
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