xref: /netbsd-src/external/bsd/openldap/dist/tests/scripts/gdb.py (revision e670fd5c413e99c2f6a37901bb21c537fcd322d2)
1# $OpenLDAP$
2## This work is part of OpenLDAP Software <http://www.openldap.org/>.
3##
4## Copyright 2020-2021 The OpenLDAP Foundation.
5## All rights reserved.
6##
7## Redistribution and use in source and binary forms, with or without
8## modification, are permitted only as authorized by the OpenLDAP
9## Public License.
10##
11## A copy of this license is available in the file LICENSE in the
12## top-level directory of the distribution or, alternatively, at
13## <http://www.OpenLDAP.org/license.html>.
14"""
15This GDB script sets up the debugger to run the program and see if it finishes
16of its own accord or is terminated by a signal (like SIGABRT/SIGSEGV). In the
17latter case, it saves a full backtrace and core file.
18
19These signals are considered part of normal operation and will not trigger the
20above handling:
21- SIGPIPE: normal in a networked environment
22- SIGHUP: normally used to tell a process to shut down
23"""
24
25import os
26import os.path
27
28import gdb
29
30
31def format_program(inferior=None, thread=None):
32    "Format program name and p(t)id"
33
34    if thread:
35        inferior = thread.inferior
36    elif inferior is None:
37        inferior = gdb.selected_inferior()
38
39    try:
40        name = os.path.basename(inferior.progspace.filename)
41    except AttributeError:  # inferior has died already
42        name = "unknown"
43
44    if thread:
45        pid = ".".join(tid for tid in thread.ptid if tid)
46    else:
47        pid = inferior.pid
48
49    return "{}.{}".format(name, pid)
50
51
52def stop_handler(event):
53    "Inferior stopped on a signal, record core, backtrace and exit"
54
55    if not isinstance(event, gdb.SignalEvent):
56        # Ignore breakpoints
57        return
58
59    thread = event.inferior_thread
60
61    identifier = format_program(thread=thread)
62    prefix = os.path.expandvars("${TESTDIR}/") + identifier
63
64    if event.stop_signal == "SIGHUP":
65        # TODO: start a timer to catch shutdown issues/deadlocks
66        gdb.execute("continue")
67        return
68
69    gdb.execute('generate-core-file {}.core'.format(prefix))
70
71    with open(prefix + ".backtrace", "w") as bt_file:
72        backtrace = gdb.execute("thread apply all backtrace full",
73                                to_string=True)
74        bt_file.write(backtrace)
75
76    gdb.execute("continue")
77
78
79# We or we could allow the runner to disable randomisation
80gdb.execute("set disable-randomization off")
81
82gdb.execute("handle SIGPIPE noprint")
83gdb.execute("handle SIGINT pass")
84gdb.events.stop.connect(stop_handler)
85gdb.execute("run")
86