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