ATLAS Offline Software
Debugging.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 
8 
9 __doc__ = """py-module to hold a few tools and utilities to help debugging
10 configurables and/or Athena application.
11 """
12 
13 import io
14 
15 class DbgStage:
16  """Class to hold the stage at which the user asked to hook the debugger
17  """
18  value = None
19  allowed_values = ( "conf", "init", "exec", "fini" )
20  pass # class DbgStage
21 
22 def hookDebugger(debugger='gdb'):
23  """debugging helper, hooks debugger to running interpreter process
24  """
25  import os
26  pid = os.spawnvp(os.P_NOWAIT,
27  debugger, [debugger, '-q', 'python', str(os.getpid())])
28 
29  # give debugger some time to attach to the python process
30  import time
31  time.sleep( 1 )
32 
33  # verify the process' existence (will raise OSError if failed)
34  os.waitpid( pid, os.WNOHANG )
35  os.kill( pid, 0 )
36  return
37 
38 def hookStrace(out=None):
39  """Same than for hookDebugger: spawn strace and attach to the running
40  interpreter process
41  """
42  import os
43  if out is None: out = 'athena.strace.log.%i' % os.getpid()
44  if isinstance(out, io.IOBase):
45  out = out.name
46  elif not isinstance(out,str):
47  raise TypeError('argument 0 needs to be either a file or a filename')
48 
49  pid = os.spawnvp(os.P_NOWAIT,
50  'strace', ['strace',
51  '-f', # follow children
52  '-p', str(os.getpid()),
53  '-o', out])
54 
55  # give strace some time to attach to the python process
56  import time
57  time.sleep( 1 )
58 
59  # verify the process' existence (will raise OSError if failed)
60  os.waitpid( pid, os.WNOHANG )
61  os.kill( pid, 0 )
62  return
63 
64 
66  """On kernels with Yama enabled, ptrace may not work by default on processes
67 which are not decendants of the tracing process. Among other things, that
68 causes the way we attach the debugger to fail. However, we can disable this
69 on a per-process basis. Do that here.
70 
71 See https://www.kernel.org/doc/Documentation/security/Yama.txt and prctl(2).
72 """
73 
74  # First test to see if ptrace restrictions are enabled.
75  import os
76  # Return if this kernel does not support ptrace restrictions.
77  if not os.path.exists ('/proc/sys/kernel/yama/ptrace_scope'): return
78 
79  # Return if ptrace restrictions are disabled.
80  with open('/proc/sys/kernel/yama/ptrace_scope') as f:
81  if f.readline().strip() == '0':
82  return
83 
84  # Use prctl to try to enable ptrace.
85  from ctypes import CDLL
86  libc = CDLL("libc.so.6")
87  # Args are PTRACE_SET_PTRACER (4HYama) and
88  # PR_SET_PTRACER_ANY ((unsigned long)-1).
89  libc.prctl (0x59616d61, 0xffffffffffffffff)
90 
91  return
92 
93 
94 def dumpPythonProfile(filename):
95  """Save python profile data of the default athena profiler instance
96  into filename (.txt or .pkl format).
97  """
98  from AthenaCommon.Logging import log
99  import cProfile
100  import pstats
101 
102  profiler = cProfile._athena_python_profiler
103  profiler.disable()
104  if filename.endswith(".txt"):
105  stats = pstats.Stats(profiler, stream=open(filename, 'w'))
106  stats.strip_dirs().sort_stats("time").print_stats()
107  log.info("Python profile summary stored in %s", filename)
108  else:
109  profiler.dump_stats(filename)
110  log.info("Python profile stored in %s", filename)
111 
112 
113 def traceExecution(script, level):
114  """Run script with the given trace level"""
115  import sys
116  import trace
117  ignore_dirs = []
118  ignore_mods = []
119 
120  # exclude system and root libraries
121  if level > 0:
122  ignore_dirs = [x for x in sys.path if x.find("ROOT")!=-1]
123  ignore_dirs.append(sys.prefix)
124  if level > 1:
125  ignore_mods += ['_db', '__init__', '_configurables', 'GaudiHandles', 'six']
126  if level > 2:
127  ignore_mods += [
128  # Legacy stuff we pull in b/c PythonAlgorithms and such still derive from old-style configurables
129  'Configurable','Configurables','PropertyProxy','DataHandle','ConfigurableDb',
130  'ConfigurableMeta', 'CfgMgr',
131  # Internals of the ComponentAccumulator
132  'ComponentAccumulator','Logging','AthConfigFlags','AllConfigFlags','Deduplication',
133  'semantics','AccumulatorCache','DebuggingContext','AtlasSemantics','ComponentFactory',
134  'LegacySupport','ItemListSemantics'
135  ]
136 
137  # taken from cpython/Lib/trace.py
138  tracer = trace.Trace(ignoredirs=ignore_dirs, ignoremods=ignore_mods)
139 
140  with io.open_code(script) as f:
141  code = compile(f.read(), script, 'exec')
142  tracer.run(code)
python.Debugging.traceExecution
def traceExecution(script, level)
Definition: Debugging.py:113
python.Debugging.DbgStage
Definition: Debugging.py:15
python.Debugging.dumpPythonProfile
def dumpPythonProfile(filename)
Definition: Debugging.py:94
python.Debugging.allowPtrace
def allowPtrace()
Definition: Debugging.py:65
python.Debugging.hookDebugger
def hookDebugger(debugger='gdb')
Definition: Debugging.py:22
Trk::open
@ open
Definition: BinningType.h:40
python.Debugging.hookStrace
def hookStrace(out=None)
Definition: Debugging.py:38
str
Definition: BTagTrackIpAccessor.cxx:11