summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
diff options
context:
space:
mode:
authorDennis Sweeney <36520290+sweeneyde@users.noreply.github.com>2022-04-16 21:36:29 (GMT)
committerGitHub <noreply@github.com>2022-04-16 21:36:29 (GMT)
commit8560f4a0f288fec33ba49f85bb872353d631a4dc (patch)
treebde96f3f8e2e1efefd8810d7ec48714567696fc3 /Python/ceval.c
parent25af5ea40f286df0a578c738c67ab54faceda90a (diff)
downloadcpython-8560f4a0f288fec33ba49f85bb872353d631a4dc.zip
cpython-8560f4a0f288fec33ba49f85bb872353d631a4dc.tar.gz
cpython-8560f4a0f288fec33ba49f85bb872353d631a4dc.tar.bz2
gh-91462: Make lltrace output human-readable. (GH-91463)
* Transform opcodes into opnames * Print the whole stack at each opcode, and eliminate prtrace output at each (push/pop/stackadj) * Display info about the function at each resume_frame
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c118
1 files changed, 83 insertions, 35 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index 66856e5..d6f11d8 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -54,15 +54,77 @@ static PyObject * do_call_core(
#ifdef LLTRACE
static int lltrace;
-static int prtrace(PyThreadState *, PyObject *, const char *);
-static void lltrace_instruction(_PyInterpreterFrame *frame, int opcode, int oparg)
+static void
+dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer)
+{
+ PyObject **stack_base = _PyFrame_Stackbase(frame);
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
+ printf(" stack=[");
+ for (PyObject **ptr = stack_base; ptr < stack_pointer; ptr++) {
+ if (ptr != stack_base) {
+ printf(", ");
+ }
+ if (PyObject_Print(*ptr, stdout, 0) != 0) {
+ PyErr_Clear();
+ printf("<%s object at %p>",
+ Py_TYPE(*ptr)->tp_name, (void *)(*ptr));
+ }
+ }
+ printf("]\n");
+ fflush(stdout);
+ PyErr_Restore(type, value, traceback);
+}
+
+static void
+lltrace_instruction(_PyInterpreterFrame *frame,
+ PyObject **stack_pointer,
+ _Py_CODEUNIT *next_instr)
{
+ dump_stack(frame, stack_pointer);
+ int oparg = _Py_OPARG(*next_instr);
+ int opcode = _Py_OPCODE(*next_instr);
+ const char *opname = _PyOpcode_OpName[opcode];
+ assert(opname != NULL);
+ int offset = (int)(next_instr - _PyCode_CODE(frame->f_code));
if (HAS_ARG(opcode)) {
- printf("%d: %d, %d\n", _PyInterpreterFrame_LASTI(frame), opcode, oparg);
+ printf("%d: %s %d\n", offset * 2, opname, oparg);
}
else {
- printf("%d: %d\n", _PyInterpreterFrame_LASTI(frame), opcode);
+ printf("%d: %s\n", offset * 2, opname);
+ }
+ fflush(stdout);
+}
+static void
+lltrace_resume_frame(_PyInterpreterFrame *frame)
+{
+ PyFunctionObject *f = frame->f_func;
+ if (f == NULL) {
+ printf("\nResuming frame.");
+ return;
+ }
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
+ PyObject *name = f->func_qualname;
+ if (name == NULL) {
+ name = f->func_name;
+ }
+ printf("\nResuming frame");
+ if (name) {
+ printf(" for ");
+ if (PyObject_Print(name, stdout, 0) < 0) {
+ PyErr_Clear();
+ }
}
+ if (f->func_module) {
+ printf(" in module ");
+ if (PyObject_Print(f->func_module, stdout, 0) < 0) {
+ PyErr_Clear();
+ }
+ }
+ printf("\n");
+ fflush(stdout);
+ PyErr_Restore(type, value, traceback);
}
#endif
static int call_trace(Py_tracefunc, PyObject *,
@@ -1266,7 +1328,8 @@ eval_frame_handle_pending(PyThreadState *tstate)
/* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */
#ifdef LLTRACE
-#define PRE_DISPATCH_GOTO() if (lltrace) { lltrace_instruction(frame, opcode, oparg); }
+#define PRE_DISPATCH_GOTO() if (lltrace) { \
+ lltrace_instruction(frame, stack_pointer, next_instr); }
#else
#define PRE_DISPATCH_GOTO() ((void)0)
#endif
@@ -1375,6 +1438,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
/* The stack can grow at most MAXINT deep, as co_nlocals and
co_stacksize are ints. */
#define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame)))
+#define STACK_SIZE() (frame->f_code->co_stacksize)
#define EMPTY() (STACK_LEVEL() == 0)
#define TOP() (stack_pointer[-1])
#define SECOND() (stack_pointer[-2])
@@ -1387,23 +1451,21 @@ eval_frame_handle_pending(PyThreadState *tstate)
#define BASIC_PUSH(v) (*stack_pointer++ = (v))
#define BASIC_POP() (*--stack_pointer)
-#ifdef LLTRACE
-#define PUSH(v) { (void)(BASIC_PUSH(v), \
- lltrace && prtrace(tstate, TOP(), "push")); \
- assert(STACK_LEVEL() <= frame->f_code->co_stacksize); }
-#define POP() ((void)(lltrace && prtrace(tstate, TOP(), "pop")), \
- BASIC_POP())
+#ifdef Py_DEBUG
+#define PUSH(v) do { \
+ BASIC_PUSH(v); \
+ assert(STACK_LEVEL() <= STACK_SIZE()); \
+ } while (0)
+#define POP() (assert(STACK_LEVEL() > 0), BASIC_POP())
#define STACK_GROW(n) do { \
- assert(n >= 0); \
- (void)(BASIC_STACKADJ(n), \
- lltrace && prtrace(tstate, TOP(), "stackadj")); \
- assert(STACK_LEVEL() <= frame->f_code->co_stacksize); \
+ assert(n >= 0); \
+ BASIC_STACKADJ(n); \
+ assert(STACK_LEVEL() <= STACK_SIZE()); \
} while (0)
#define STACK_SHRINK(n) do { \
assert(n >= 0); \
- (void)(lltrace && prtrace(tstate, TOP(), "stackadj")); \
- (void)(BASIC_STACKADJ(-(n))); \
- assert(STACK_LEVEL() <= frame->f_code->co_stacksize); \
+ assert(STACK_LEVEL() >= n); \
+ BASIC_STACKADJ(-(n)); \
} while (0)
#else
#define PUSH(v) BASIC_PUSH(v)
@@ -1673,6 +1735,9 @@ resume_frame:
}
lltrace = r;
}
+ if (lltrace) {
+ lltrace_resume_frame(frame);
+ }
#endif
#ifdef Py_DEBUG
@@ -6663,23 +6728,6 @@ Error:
return 0;
}
-#ifdef LLTRACE
-static int
-prtrace(PyThreadState *tstate, PyObject *v, const char *str)
-{
- printf("%s ", str);
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
- if (PyObject_Print(v, stdout, 0) != 0) {
- /* Don't know what else to do */
- _PyErr_Clear(tstate);
- }
- printf("\n");
- PyErr_Restore(type, value, traceback);
- return 1;
-}
-#endif
-
static void
call_exc_trace(Py_tracefunc func, PyObject *self,
PyThreadState *tstate,