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