PK!ch/__init__.pyPK!..ch/debug/__init__.pyfrom .gdb_get_trace import get_process_stacks PK!8uuch/debug/gdb_get_trace.pyimport os import subprocess import sys import tempfile from itertools import chain from pathlib import Path import requests python_gdb_url = os.environ.get( 'PYTHON_GDB_URL', 'https://raw.githubusercontent.com/python/cpython/master/Tools/gdb/libpython.py', ) def flatten(iterable): return list(chain.from_iterable(iterable)) 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.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!H&1I ch-0.1.0.dist-info/METADATAQN1 +,q"ZʡCm=ݚ]&Y/'=5[c PXR}wzj8gckaYm u2~A\6;hƳjI9$F]6\h`VFJ0g+CgEej EL]+L14YT\*=O!0n ^paz5rCs XZ_4P%6bH(9g!