summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2003-04-09 19:06:21 (GMT)
committerGuido van Rossum <guido@python.org>2003-04-09 19:06:21 (GMT)
commita12fe4e81fa3221458e16225e76ec7b8a05820ee (patch)
tree05f9ba6e5dab68aa1627e340aa1b6f2437c8e302
parent12dd7b12c6bce882a7e789173760abab62c80304 (diff)
downloadcpython-a12fe4e81fa3221458e16225e76ec7b8a05820ee.zip
cpython-a12fe4e81fa3221458e16225e76ec7b8a05820ee.tar.gz
cpython-a12fe4e81fa3221458e16225e76ec7b8a05820ee.tar.bz2
- New function sys.call_tracing() allows pdb to debug code
recursively. - pdb has a new command, "debug", which lets you step through arbitrary code from the debugger's (pdb) prompt.
-rw-r--r--Include/eval.h2
-rwxr-xr-xLib/pdb.py33
-rw-r--r--Misc/NEWS6
-rw-r--r--Python/ceval.c18
-rw-r--r--Python/sysmodule.c19
5 files changed, 78 insertions, 0 deletions
diff --git a/Include/eval.h b/Include/eval.h
index 66638e7..b78dfe0 100644
--- a/Include/eval.h
+++ b/Include/eval.h
@@ -17,6 +17,8 @@ PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co,
PyObject **defs, int defc,
PyObject *closure);
+PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args);
+
#ifdef __cplusplus
}
#endif
diff --git a/Lib/pdb.py b/Lib/pdb.py
index d7215cf..46dff55 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -523,6 +523,33 @@ class Pdb(bdb.Bdb, cmd.Cmd):
print '*** Jump failed:', e
do_j = do_jump
+ def do_debug(self, arg):
+ sys.settrace(None)
+ globals = self.curframe.f_globals
+ locals = self.curframe.f_locals
+ p = Pdb()
+ p.prompt = "(%s) " % self.prompt.strip()
+ print "ENTERING RECURSIVE DEBUGGER"
+ sys.call_tracing(p.run, (arg, globals, locals))
+ print "LEAVING RECURSIVE DEBUGGER"
+ sys.settrace(self.trace_dispatch)
+ self.lastcmd = p.lastcmd
+
+ def dont_debug(self, arg):
+ locals = self.curframe.f_locals
+ globals = self.curframe.f_globals
+ try:
+ r = sys.call_tracing(eval, (arg, globals, locals))
+ print "--- DEBUG RETURNED ---"
+ if r is not None:
+ print repr(r)
+ except:
+ t, v = sys.exc_info()[:2]
+ if type(t) == type(''):
+ exc_type_name = t
+ else: exc_type_name = t.__name__
+ print '***', exc_type_name + ':', v
+
def do_quit(self, arg):
self.set_quit()
return 1
@@ -834,6 +861,12 @@ Continue execution, only stop when a breakpoint is encountered."""
print """j(ump) lineno
Set the next line that will be executed."""
+ def help_debug(self):
+ print """debug code
+Enter a recursive debugger that steps through the code argument
+(which is an arbitrary expression or statement to be executed
+in the current environment)."""
+
def help_list(self):
self.help_l()
diff --git a/Misc/NEWS b/Misc/NEWS
index 3ded09e..661c2ca 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -49,6 +49,9 @@ Core and builtins
Extension modules
-----------------
+- New function sys.call_tracing() allows pdb to debug code
+ recursively.
+
- New function gc.get_referents(obj) returns a list of objects
directly referenced by obj. In effect, it exposes what the object's
tp_traverse slot does, and can be helpful when debugging memory
@@ -86,6 +89,9 @@ Extension modules
Library
-------
+- pdb has a new command, "debug", which lets you step through
+ arbitrary code from the debugger's (pdb) prompt.
+
- unittest.failUnlessEqual and its equivalent unittest.assertEqual now
return 'not a == b' rather than 'a != b'. This gives the desired
result for classes that define __eq__ without defining __ne__.
diff --git a/Python/ceval.c b/Python/ceval.c
index f965d38..080b3c1 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3024,6 +3024,24 @@ call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame,
return result;
}
+PyObject *
+_PyEval_CallTracing(PyObject *func, PyObject *args)
+{
+ PyFrameObject *frame = PyEval_GetFrame();
+ PyThreadState *tstate = frame->f_tstate;
+ int save_tracing = tstate->tracing;
+ int save_use_tracing = tstate->use_tracing;
+ PyObject *result;
+
+ tstate->tracing = 0;
+ tstate->use_tracing = ((tstate->c_tracefunc != NULL)
+ || (tstate->c_profilefunc != NULL));
+ result = PyObject_Call(func, args, NULL);
+ tstate->tracing = save_tracing;
+ tstate->use_tracing = save_use_tracing;
+ return result;
+}
+
static int
maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
PyFrameObject *frame, int *instr_lb, int *instr_ub)
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index fa7f3c4..50b9912 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -17,6 +17,7 @@ Data members:
#include "Python.h"
#include "compile.h"
#include "frameobject.h"
+#include "eval.h"
#include "osdefs.h"
@@ -609,6 +610,23 @@ sys_getframe(PyObject *self, PyObject *args)
return (PyObject*)f;
}
+PyDoc_STRVAR(call_tracing_doc,
+"call_tracing(func, args) -> object\n\
+\n\
+Call func(*args), while tracing is enabled. The tracing state is\n\
+saved, and restored afterwards. This is intended to be called from\n\
+a debugger from a checkpoint, to recursively debug some other code."
+);
+
+static PyObject *
+sys_call_tracing(PyObject *self, PyObject *args)
+{
+ PyObject *func, *funcargs;
+ if (!PyArg_ParseTuple(args, "OO:call_tracing", &func, &funcargs))
+ return NULL;
+ return _PyEval_CallTracing(func, funcargs);
+}
+
PyDoc_STRVAR(callstats_doc,
"callstats() -> tuple of integers\n\
\n\
@@ -700,6 +718,7 @@ static PyMethodDef sys_methods[] = {
{"setrecursionlimit", sys_setrecursionlimit, METH_VARARGS,
setrecursionlimit_doc},
{"settrace", sys_settrace, METH_O, settrace_doc},
+ {"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
{NULL, NULL} /* sentinel */
};