mirror of
https://github.com/python/cpython.git
synced 2025-08-30 13:38:43 +00:00
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
This commit is contained in:
parent
25af5ea40f
commit
8560f4a0f2
3 changed files with 173 additions and 43 deletions
118
Python/ceval.c
118
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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue