Search code examples
pythoninterpretercpython

Accessing Python intepreter's data stack through sys.set_trace



I am using sys.set_trace(..) to perform a bytecodes analysis on python code.
More specifically, I set a tracer function to be triggered every time a bytecode gets executed.

For my analysis I need to get the object on which the bytecode with opcode "STORE_ATTR" is going to store a value.
E.g. I have this bytecode:

Instruction(opname='STORE_ATTR', opcode=95, arg=9, argval='pos', argrepr='pos', offset=188, starts_line=None, is_jump_target=False)

Upon seeing this, the interpreter will try to pop the top element from the data-stack in order to store a value in it. Is there a way for me to access that object as well? Is there an API like a TOP() function that I can call from within the tracer and get the top value of the stack of the frame that is being currently executed?


Solution

  • Unfortunately, such information is not accessible through Python, but you can do that with the C API. Another issue here is that this is highly dependent on the Python version you have. The following holds for Python 3.8.5, but with small modifications can work for other versions too.

    The equivalent PyEval_SetTrace has access to the f_stacktop field of PyFrameObject class. This field is used by TOP() at ceval.c.

    You can also verify that f_stacktop is not exposed to the Python frame class here.

    Here you can see a code sample that gets access to the TOS of the current frame:

    int tracefunc(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) {
        [...]
        PyObject **stack_pointer = frame->f_stacktop;
        PyObject *tos = stack_pointer[-1];
        [...]
    }