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>
This commit is contained in:
parent
b7dbeeac49
commit
c077579240
|
@ -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
|
Loading…
Reference in New Issue