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