Skip to content

Improve sys.settrace to help support debugpy / pdb debugging #8767

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/micropython-lib
Submodule micropython-lib updated 81 files
+2 −1 .github/workflows/ruff.yml
+2 −1 .pre-commit-config.yaml
+19 −14 micropython/aiorepl/aiorepl.py
+1 −1 micropython/aiorepl/manifest.py
+1 −1 micropython/bluetooth/aioble/examples/l2cap_file_client.py
+1 −1 micropython/bluetooth/aioble/examples/l2cap_file_server.py
+4 −8 micropython/drivers/codec/wm8960/wm8960.py
+2 −4 micropython/drivers/display/lcd160cr/lcd160cr.py
+1 −0 micropython/drivers/imu/lsm9ds1/lsm9ds1.py
+1 −2 micropython/drivers/radio/nrf24l01/nrf24l01.py
+1 −1 micropython/drivers/sensor/hts221/hts221.py
+1 −0 micropython/drivers/sensor/lps22h/lps22h.py
+8 −8 micropython/espflash/espflash.py
+1 −1 micropython/lora/examples/reliable_delivery/sender.py
+1 −1 micropython/lora/examples/reliable_delivery/sender_async.py
+3 −2 micropython/lora/lora-sx126x/lora/sx126x.py
+1 −1 micropython/lora/lora-sx126x/manifest.py
+0 −1 micropython/senml/examples/actuator.py
+0 −1 micropython/senml/examples/base.py
+0 −1 micropython/senml/examples/basic.py
+0 −1 micropython/senml/examples/basic2.py
+0 −1 micropython/senml/examples/basic_cbor.py
+0 −1 micropython/senml/examples/custom_record.py
+0 −1 micropython/senml/examples/gateway.py
+0 −1 micropython/senml/examples/gateway_actuators.py
+0 −1 micropython/senml/examples/supported_data_types.py
+0 −1 micropython/senml/senml/__init__.py
+0 −1 micropython/senml/senml/senml_pack.py
+0 −1 micropython/senml/senml/senml_record.py
+1 −1 micropython/urllib.urequest/manifest.py
+7 −1 micropython/urllib.urequest/urllib/urequest.py
+12 −0 micropython/utop/README.md
+6 −0 micropython/utop/manifest.py
+109 −0 micropython/utop/utop.py
+2 −1 pyproject.toml
+0 −1 python-ecosys/cbor2/cbor2/__init__.py
+0 −1 python-ecosys/cbor2/cbor2/_decoder.py
+0 −1 python-ecosys/cbor2/cbor2/_encoder.py
+0 −1 python-ecosys/cbor2/examples/cbor_test.py
+171 −0 python-ecosys/debugpy/README.md
+112 −0 python-ecosys/debugpy/VSCODE_TESTING_GUIDE.md
+20 −0 python-ecosys/debugpy/debugpy/__init__.py
+1 −0 python-ecosys/debugpy/debugpy/common/__init__.py
+57 −0 python-ecosys/debugpy/debugpy/common/constants.py
+127 −0 python-ecosys/debugpy/debugpy/common/messaging.py
+103 −0 python-ecosys/debugpy/debugpy/public_api.py
+1 −0 python-ecosys/debugpy/debugpy/server/__init__.py
+282 −0 python-ecosys/debugpy/debugpy/server/debug_session.py
+250 −0 python-ecosys/debugpy/debugpy/server/pdb_adapter.py
+68 −0 python-ecosys/debugpy/demo.py
+6 −0 python-ecosys/debugpy/manifest.py
+59 −0 python-ecosys/debugpy/test_debugpy.py
+170 −0 python-ecosys/debugpy/test_integration.py
+121 −0 python-ecosys/debugpy/test_simple.py
+56 −0 python-ecosys/debugpy/test_vscode.py
+21 −0 python-ecosys/debugpy/vscode_launch_example.json
+900 −0 python-stdlib/bdb/bdb.py
+3 −0 python-stdlib/bdb/metadata.txt
+24 −0 python-stdlib/bdb/setup.py
+4 −1 python-stdlib/cmd/cmd.py
+315 −0 python-stdlib/code/code.py
+3 −0 python-stdlib/code/metadata.txt
+24 −0 python-stdlib/code/setup.py
+155 −0 python-stdlib/codeop/codeop.py
+3 −0 python-stdlib/codeop/metadata.txt
+24 −0 python-stdlib/codeop/setup.py
+1 −0 python-stdlib/errno/errno.py
+1 −1 python-stdlib/errno/manifest.py
+182 −0 python-stdlib/linecache/linecache.py
+3 −0 python-stdlib/linecache/metadata.txt
+24 −0 python-stdlib/linecache/setup.py
+2 −2 python-stdlib/logging/logging.py
+1 −1 python-stdlib/logging/manifest.py
+4 −0 python-stdlib/os-path/os/path.py
+34 −2 python-stdlib/os/os/__init__.py
+3 −0 python-stdlib/pdb/metadata.txt
+1,811 −0 python-stdlib/pdb/pdb.py
+24 −0 python-stdlib/pdb/setup.py
+5 −0 python-stdlib/tokenize/metadata.txt
+8 −0 python-stdlib/tokenize/tokenize.py
+30 −3 tools/verifygitlog.py
2 changes: 2 additions & 0 deletions ports/unix/variants/standard/mpconfigvariant.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@
// Set base feature level.
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)

#define MICROPY_PY_SYS_SETTRACE (1)

// Enable extra Unix features.
#include "../mpconfigvariant_common.h"
17 changes: 17 additions & 0 deletions py/modsys.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,21 @@ static mp_obj_t mp_sys_settrace(mp_obj_t obj) {
return mp_prof_settrace(obj);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_settrace_obj, mp_sys_settrace);

static mp_obj_t mp_sys_gettrace() {
return mp_prof_gettrace();
}
MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_gettrace_obj, mp_sys_gettrace);

// _getframe(): Return current frame object.
static mp_obj_t mp_sys__getframe(size_t n_args, const mp_obj_t *args) {
size_t depth = 0;
if (n_args == 1) {
depth = mp_obj_get_int(args[0]);
}
return mp_prof_get_frame(depth);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_getframe_obj, 0, 1, mp_sys__getframe);
#endif // MICROPY_PY_SYS_SETTRACE

#if MICROPY_PY_SYS_PATH && !MICROPY_PY_SYS_ATTR_DELEGATION
Expand Down Expand Up @@ -322,6 +337,8 @@ static const mp_rom_map_elem_t mp_module_sys_globals_table[] = {

#if MICROPY_PY_SYS_SETTRACE
{ MP_ROM_QSTR(MP_QSTR_settrace), MP_ROM_PTR(&mp_sys_settrace_obj) },
{ MP_ROM_QSTR(MP_QSTR_gettrace), MP_ROM_PTR(&mp_sys_gettrace_obj) },
{ MP_ROM_QSTR(MP_QSTR__getframe), MP_ROM_PTR(&mp_sys_getframe_obj) },
#endif

#if MICROPY_PY_SYS_STDFILES
Expand Down
19 changes: 8 additions & 11 deletions py/objfun.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
#include "py/objfun.h"
#include "py/runtime.h"
#include "py/bc.h"
#include "py/cstack.h"
#include "py/stackctrl.h"
#include "py/profile.h"

#if MICROPY_DEBUG_VERBOSE // print debugging info
#define DEBUG_PRINT (1)
Expand Down Expand Up @@ -366,17 +367,13 @@ void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
dest[0] = MP_OBJ_FROM_PTR(self->context->module.globals);
}
#if MICROPY_PY_FUNCTION_ATTRS_CODE

#if MICROPY_PY_SYS_SETTRACE
if (attr == MP_QSTR___code__) {
const mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
if ((self->base.type == &mp_type_fun_bc
|| self->base.type == &mp_type_gen_wrap)
&& self->child_table == NULL) {
#if MICROPY_PY_BUILTINS_CODE <= MICROPY_PY_BUILTINS_CODE_BASIC
dest[0] = mp_obj_new_code(self->context->constants, self->bytecode);
#else
dest[0] = mp_obj_new_code(self->context, self->rc, true);
#endif
mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
mp_obj_t code_obj = mp_obj_new_code(self->context, self->rc, false);
if (code_obj != MP_OBJ_NULL) {
dest[0] = code_obj;
}
}
#endif
Expand Down
51 changes: 47 additions & 4 deletions py/profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,26 @@ static void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t
}

static void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (dest[0] != MP_OBJ_NULL) {
mp_obj_frame_t *o = MP_OBJ_TO_PTR(self_in);

if (dest[0] == MP_OBJ_SENTINEL) {
// store attr
switch (attr) {
case MP_QSTR_f_trace:
o->f_trace = dest[1];
dest[0] = MP_OBJ_NULL;
break;
}
return;
} else if (dest[0] != MP_OBJ_NULL) {
// not load attribute
return;
}

mp_obj_frame_t *o = MP_OBJ_TO_PTR(self_in);

switch (attr) {
case MP_QSTR_f_back:
dest[0] = mp_const_none;
if (o->code_state->prev_state) {
if (o->code_state->prev_state && o->code_state->prev_state->frame) {
dest[0] = MP_OBJ_FROM_PTR(o->code_state->prev_state->frame);
}
break;
Expand All @@ -112,6 +121,12 @@ static void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
case MP_QSTR_f_lineno:
dest[0] = MP_OBJ_NEW_SMALL_INT(o->lineno);
break;
case MP_QSTR_f_trace:
dest[0] = o->f_trace;
break;
case MP_QSTR_f_locals:
dest[0] = mp_obj_new_dict(0);
break;
}
}

Expand Down Expand Up @@ -148,6 +163,7 @@ mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state) {
o->lineno = mp_prof_bytecode_lineno(rc, o->lasti);
o->trace_opcodes = false;
o->callback = MP_OBJ_NULL;
o->f_trace = MP_OBJ_NULL;

return MP_OBJ_FROM_PTR(o);
}
Expand Down Expand Up @@ -187,6 +203,33 @@ mp_obj_t mp_prof_settrace(mp_obj_t callback) {
return mp_const_none;
}

mp_obj_t mp_prof_gettrace(void) {
if (prof_trace_cb == MP_OBJ_NULL) {
return mp_const_none;
}
return prof_trace_cb;
}

mp_obj_t mp_prof_get_frame(size_t depth) {

mp_code_state_t *code_state = MP_STATE_THREAD(current_code_state);

for (size_t i = 0; i < depth; i++) {
code_state = code_state->prev_state;
if (code_state == NULL) {
mp_raise_ValueError(MP_ERROR_TEXT("call stack is not deep enough"));
}
}

mp_obj_frame_t *frame = MP_OBJ_TO_PTR(mp_obj_new_frame(code_state));
if (frame == NULL) {
// Couldn't allocate a frame object
return MP_OBJ_NULL;
}

return MP_OBJ_FROM_PTR(frame);
}

mp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state) {
assert(!mp_prof_is_executing);

Expand Down
3 changes: 3 additions & 0 deletions py/profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ typedef struct _mp_obj_frame_t {
mp_uint_t lasti;
mp_uint_t lineno;
bool trace_opcodes;
mp_obj_t f_trace;
} mp_obj_frame_t;

uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc);
Expand All @@ -52,7 +53,9 @@ mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state);

// This is the implementation for the sys.settrace
mp_obj_t mp_prof_settrace(mp_obj_t callback);
mp_obj_t mp_prof_gettrace(void);

mp_obj_t mp_prof_get_frame(size_t depth);
mp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state);
mp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state);

Expand Down
27 changes: 27 additions & 0 deletions tests/misc/sys__getframe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import sys

try:
sys._getframe
except AttributeError:
print("SKIP")
raise SystemExit

top_frame = sys._getframe()

print(top_frame.f_code.co_name == "<module>")


def new_frame():
curr_frame = sys._getframe()
prev_frame = sys._getframe(1)

print(curr_frame.f_code.co_name == "new_frame")

print(prev_frame.f_code.co_name == "<module>")
print(curr_frame.f_back.f_code.co_name == "<module>")

print(prev_frame.f_lineno == curr_frame.f_back.f_lineno)
print(prev_frame.f_code.co_filename == curr_frame.f_back.f_code.co_filename)


new_frame()
Loading