diff options
author | Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com> | 2022-04-16 21:36:29 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-16 21:36:29 (GMT) |
commit | 8560f4a0f288fec33ba49f85bb872353d631a4dc (patch) | |
tree | bde96f3f8e2e1efefd8810d7ec48714567696fc3 /Python/ceval.c | |
parent | 25af5ea40f286df0a578c738c67ab54faceda90a (diff) | |
download | cpython-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.c | 118 |
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, |