PK!ch/__init__.pyPK!,nXg--ch/debug/__init__.pyfrom .gdb_get_trace import get_process_stack PK!RNQQch/debug/gdb_get_trace.pyimport os import subprocess import sys import tempfile from itertools import chain from pathlib import Path import requests from more_itertools import flatten python_gdb_url = os.environ.get( 'PYTHON_GDB_URL', 'https://raw.githubusercontent.com/python/cpython/master/Tools/gdb/libpython.py', ) def get_python_gdb(pid): """Get applicable python-gdb.py given a pid. """ python = Path(f'/proc/{pid}/exe').resolve() python_gdb = Path(f'{python}-gdb.py') if python_gdb.exists(): return python_gdb # Otherwise we need to retrieve it. response = requests.get(python_gdb_url) response.raise_for_status() fd, name = tempfile.mkstemp(suffix='.py', text=True) os.write(fd, response.content) os.fsync(fd) os.close(fd) return Path(name) def run_python_gdb(pid, commands): attach_args = [ ['-ex', f'attach {pid}'], ] python_gdb = get_python_gdb(pid) if python_gdb: attach_args.append(['-ex', f'source {python_gdb}']) command_args = [['-ex', c] for c in commands] args = [ 'gdb', # Use this as the executable file. '--exec', f'/proc/{pid}/exe', # No introductory message. '--batch', # No .gdbinit. '--nx', *flatten(attach_args), *flatten(command_args), # So we aren't prompted for confirmation. '-ex', 'set confirm off', '-ex', 'quit', ] result = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) return result.stdout.decode('utf-8') def get_process_stack(pid): commands = [ 'info threads', 'thread apply all bt', 'thread apply all py-bt', ] return run_python_gdb(pid, commands) def main(pid): stacks = get_process_stack(pid) print(stacks) if __name__ == '__main__': main(sys.argv[1]) PK!HڽTUch-0.1.1.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!H&[Kch-0.1.1.dist-info/METADATAMO0 f_HCц@ gi͚$.;.