|
34 | 34 | # functions below. It also doesn't work once we add the exception handling |
35 | 35 | # we see below. So for now, we'll live with the code duplication. |
36 | 36 |
|
| 37 | +import os |
37 | 38 | import sys |
38 | | -from typing import Callable, Optional |
| 39 | +from typing import Callable, Literal, Optional |
39 | 40 |
|
40 | 41 | from trepan.debugger import Trepan, debugger_obj |
| 42 | +from trepan.interfaces.server import ServerInterface |
41 | 43 | from trepan.post_mortem import post_mortem_excepthook, uncaught_exception |
42 | 44 |
|
43 | | - |
44 | | -def debugger_on_post_mortem(): |
45 | | - """Call debugger on an exception that terminates a program""" |
46 | | - sys.excepthook = post_mortem_excepthook |
47 | | - return |
48 | | - |
49 | | - |
50 | | -def run_eval( |
51 | | - expression, |
52 | | - debug_opts: Optional[dict] = None, |
53 | | - start_opts: Optional[dict] = None, |
54 | | - globals_: Optional[dict] = None, |
55 | | - locals_: Optional[dict] = None, |
56 | | - tb_fn: Optional[Callable] = None, |
57 | | -): |
58 | | - """Evaluate the expression (given as a string) under debugger |
59 | | - control starting with the statement after the place that |
60 | | - this appears in your program. |
61 | | -
|
62 | | - This is a wrapper to Debugger.run_eval(), so see that. |
63 | | -
|
64 | | - When run_eval() returns, it returns the value of the expression. |
65 | | - Otherwise, this function is similar to run(). |
66 | | - """ |
67 | | - |
68 | | - dbg = Trepan(opts=debug_opts) |
69 | | - try: |
70 | | - return dbg.run_eval( |
71 | | - expression, start_opts=start_opts, globals_=globals_, locals_=locals_ |
72 | | - ) |
73 | | - except Exception: |
74 | | - dbg.core.trace_hook_suspend = True |
75 | | - if start_opts and "tb_fn" in start_opts: |
76 | | - tb_fn = start_opts["tb_fn"] |
77 | | - uncaught_exception(dbg, tb_fn) |
78 | | - finally: |
79 | | - dbg.core.trace_hook_suspend = False |
80 | | - return |
81 | | - |
82 | | - |
83 | | -def run_call( |
84 | | - func: Callable, |
85 | | - *args, |
86 | | - debug_opts: Optional[dict] = None, |
87 | | - start_opts: Optional[dict] = None, |
88 | | - **kwds, |
89 | | -): |
90 | | - """Call the function (a function or method object, not a string) |
91 | | - with the given arguments starting with the statement after |
92 | | - the place that this appears in your program. |
93 | | -
|
94 | | - When run_call() returns, it returns whatever the function call |
95 | | - returned. The debugger prompt appears as soon as the function is |
96 | | - entered.""" |
97 | | - |
98 | | - dbg = Trepan(opts=debug_opts) |
99 | | - try: |
100 | | - return dbg.run_call(func, *args, **kwds) |
101 | | - except Exception: |
102 | | - uncaught_exception(dbg) |
103 | | - pass |
104 | | - return |
105 | | - |
106 | | - |
107 | | -def run_exec(statement, debug_opts=None, start_opts=None, globals_=None, locals_=None): |
108 | | - """Execute the statement (given as a string) under debugger |
109 | | - control starting with the statement subsequent to the place that |
110 | | - this run_call appears in your program. |
111 | | -
|
112 | | - This is a wrapper to Debugger.run_exec(), so see that. |
113 | | -
|
114 | | - The debugger prompt appears before any code is executed; |
115 | | - you can set breakpoints and type 'continue', or you can step |
116 | | - through the statement using 'step' or 'next' |
117 | | -
|
118 | | - The optional globals_ and locals_ arguments specify the environment |
119 | | - in which the code is executed; by default the dictionary of the |
120 | | - module __main__ is used.""" |
121 | | - |
122 | | - dbg = Trepan(opts=debug_opts) |
123 | | - try: |
124 | | - return dbg.run_exec( |
125 | | - statement, start_opts=start_opts, globals_=globals_, locals_=locals_ |
126 | | - ) |
127 | | - except Exception: |
128 | | - uncaught_exception(dbg) |
129 | | - pass |
130 | | - return |
131 | | - |
| 45 | +DEFAULT_DEBUG_PORT: Literal = 1955 |
132 | 46 |
|
133 | 47 | def debug( |
134 | 48 | dbg_opts={}, |
@@ -276,6 +190,107 @@ def debug( |
276 | 190 | return |
277 | 191 |
|
278 | 192 |
|
| 193 | +def debug_for_remote_access(): |
| 194 | + """Enter the debugger in a mode that allows connection to it |
| 195 | + outside of the process being debugged. |
| 196 | + """ |
| 197 | + connection_opts = {'IO': 'TCP', 'PORT': os.getenv('TREPAN3K_TCP_PORT', DEFAULT_DEBUG_PORT)} |
| 198 | + intf = ServerInterface(connection_opts=connection_opts) |
| 199 | + dbg_opts = {'interface': intf} |
| 200 | + print(f'Starting {connection_opts["IO"]} server listening on {connection_opts["PORT"]}.', file=sys.stderr) |
| 201 | + print(f'Use `python3 -m trepan.client --port {connection_opts["PORT"]}` to enter debugger.', file=sys.stderr) |
| 202 | + debug(dbg_opts=dbg_opts, step_ignore=0, level=1) |
| 203 | + |
| 204 | + |
| 205 | +def debugger_on_post_mortem(): |
| 206 | + """Call debugger on an exception that terminates a program""" |
| 207 | + sys.excepthook = post_mortem_excepthook |
| 208 | + return |
| 209 | + |
| 210 | + |
| 211 | +def run_eval( |
| 212 | + expression, |
| 213 | + debug_opts: Optional[dict] = None, |
| 214 | + start_opts: Optional[dict] = None, |
| 215 | + globals_: Optional[dict] = None, |
| 216 | + locals_: Optional[dict] = None, |
| 217 | + tb_fn: Optional[Callable] = None, |
| 218 | +): |
| 219 | + """Evaluate the expression (given as a string) under debugger |
| 220 | + control starting with the statement after the place that |
| 221 | + this appears in your program. |
| 222 | +
|
| 223 | + This is a wrapper to Debugger.run_eval(), so see that. |
| 224 | +
|
| 225 | + When run_eval() returns, it returns the value of the expression. |
| 226 | + Otherwise, this function is similar to run(). |
| 227 | + """ |
| 228 | + |
| 229 | + dbg = Trepan(opts=debug_opts) |
| 230 | + try: |
| 231 | + return dbg.run_eval( |
| 232 | + expression, start_opts=start_opts, globals_=globals_, locals_=locals_ |
| 233 | + ) |
| 234 | + except Exception: |
| 235 | + dbg.core.trace_hook_suspend = True |
| 236 | + if start_opts and "tb_fn" in start_opts: |
| 237 | + tb_fn = start_opts["tb_fn"] |
| 238 | + uncaught_exception(dbg, tb_fn) |
| 239 | + finally: |
| 240 | + dbg.core.trace_hook_suspend = False |
| 241 | + return |
| 242 | + |
| 243 | + |
| 244 | +def run_call( |
| 245 | + func: Callable, |
| 246 | + *args, |
| 247 | + debug_opts: Optional[dict] = None, |
| 248 | + start_opts: Optional[dict] = None, |
| 249 | + **kwds, |
| 250 | +): |
| 251 | + """Call the function (a function or method object, not a string) |
| 252 | + with the given arguments starting with the statement after |
| 253 | + the place that this appears in your program. |
| 254 | +
|
| 255 | + When run_call() returns, it returns whatever the function call |
| 256 | + returned. The debugger prompt appears as soon as the function is |
| 257 | + entered.""" |
| 258 | + |
| 259 | + dbg = Trepan(opts=debug_opts) |
| 260 | + try: |
| 261 | + return dbg.run_call(func, *args, **kwds) |
| 262 | + except Exception: |
| 263 | + uncaught_exception(dbg) |
| 264 | + pass |
| 265 | + return |
| 266 | + |
| 267 | + |
| 268 | +def run_exec(statement, debug_opts=None, start_opts=None, globals_=None, locals_=None): |
| 269 | + """Execute the statement (given as a string) under debugger |
| 270 | + control starting with the statement subsequent to the place that |
| 271 | + this run_call appears in your program. |
| 272 | +
|
| 273 | + This is a wrapper to Debugger.run_exec(), so see that. |
| 274 | +
|
| 275 | + The debugger prompt appears before any code is executed; |
| 276 | + you can set breakpoints and type 'continue', or you can step |
| 277 | + through the statement using 'step' or 'next' |
| 278 | +
|
| 279 | + The optional globals_ and locals_ arguments specify the environment |
| 280 | + in which the code is executed; by default the dictionary of the |
| 281 | + module __main__ is used.""" |
| 282 | + |
| 283 | + dbg = Trepan(opts=debug_opts) |
| 284 | + try: |
| 285 | + return dbg.run_exec( |
| 286 | + statement, start_opts=start_opts, globals_=globals_, locals_=locals_ |
| 287 | + ) |
| 288 | + except Exception: |
| 289 | + uncaught_exception(dbg) |
| 290 | + pass |
| 291 | + return |
| 292 | + |
| 293 | + |
279 | 294 | def stop(opts=None): |
280 | 295 | if isinstance(debugger_obj, Trepan): |
281 | 296 | return debugger_obj.stop(opts) |
|
0 commit comments