From c923b54baf53bbf6395d058cbac5683c2d70ee45 Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Mon, 16 Jun 2025 17:07:29 +0200 Subject: [PATCH 1/6] py/profile: Add tracing for local variables. Signed-off-by: Jos Verlinde --- lib/nxp_driver | 2 +- lib/protobuf-c | 2 +- lib/wiznet5k | 2 +- .../unix/variants/standard/mpconfigvariant.h | 10 +++++ py/profile.c | 38 ++++++++++++++++++- 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/lib/nxp_driver b/lib/nxp_driver index fa5a554c7944d..72fa6068dbfb6 160000 --- a/lib/nxp_driver +++ b/lib/nxp_driver @@ -1 +1 @@ -Subproject commit fa5a554c7944d2a196626f8d3631e44943f9abcc +Subproject commit 72fa6068dbfb6080272227f589352f6da6627fdb diff --git a/lib/protobuf-c b/lib/protobuf-c index abc67a11c6db2..4719fdd776062 160000 --- a/lib/protobuf-c +++ b/lib/protobuf-c @@ -1 +1 @@ -Subproject commit abc67a11c6db271bedbb9f58be85d6f4e2ea8389 +Subproject commit 4719fdd7760624388c2c5b9d6759eb6a47490626 diff --git a/lib/wiznet5k b/lib/wiznet5k index 0803fc519ad72..ce4a7b6d07541 160000 --- a/lib/wiznet5k +++ b/lib/wiznet5k @@ -1 +1 @@ -Subproject commit 0803fc519ad7227e841287fb3638d6c8b2f111a1 +Subproject commit ce4a7b6d07541bf0ba9f91e369276b38faa619bd diff --git a/ports/unix/variants/standard/mpconfigvariant.h b/ports/unix/variants/standard/mpconfigvariant.h index 447832a7656b6..f68673f0b3f1a 100644 --- a/ports/unix/variants/standard/mpconfigvariant.h +++ b/ports/unix/variants/standard/mpconfigvariant.h @@ -29,5 +29,15 @@ #define MICROPY_PY_SYS_SETTRACE (1) +// #define MICROPY_DEBUG_VERBOSE (0) + + +// Disable compiler optimizations for debugging +// #define MICROPY_COMP_CONST (0) +// #define MICROPY_COMP_MODULE_CONST (0) +// #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) +// #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) + + // Enable extra Unix features. #include "../mpconfigvariant_common.h" diff --git a/py/profile.c b/py/profile.c index 4b813bb0d7b06..0c93fdc8512a7 100644 --- a/py/profile.c +++ b/py/profile.c @@ -85,6 +85,8 @@ static void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t ); } +static mp_obj_t frame_f_locals(mp_obj_t self_in); // Forward declaration + static void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_frame_t *o = MP_OBJ_TO_PTR(self_in); @@ -125,11 +127,45 @@ static void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[0] = o->f_trace; break; case MP_QSTR_f_locals: - dest[0] = mp_obj_new_dict(0); + dest[0] = frame_f_locals(self_in); break; } } +static mp_obj_t frame_f_locals(mp_obj_t self_in) { + // This function returns a dictionary of local variables in the current frame. + if (gc_is_locked()) { + return MP_OBJ_NULL; // Cannot create locals dict when GC is locked + } + mp_obj_frame_t *frame = MP_OBJ_TO_PTR(self_in); + mp_obj_dict_t *locals_dict = mp_obj_new_dict(frame->code_state->n_state); // Preallocate dictionary size + + const mp_code_state_t *code_state = frame->code_state; + + // Validate state array + if (code_state == NULL || code_state->state == NULL) { + return MP_OBJ_FROM_PTR(locals_dict); // Return empty dictionary if state is invalid + } + + // Fallback logic: Use generic names for local variables + for (size_t i = 0; i < code_state->n_state; ++i) { + char var_name[16]; + snprintf(var_name, sizeof(var_name), "local_%02d", (int)(i + 1)); + // Validate value in state array + if (code_state->state[i] == NULL) { + continue; // Skip invalid values + } + // Check memory allocation for variable name + qstr var_name_qstr = qstr_from_str(var_name); + if (var_name_qstr == MP_QSTR_NULL) { + continue; // Skip if qstr creation fails + } + // Store the name-value pair in the dictionary + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); + } + return MP_OBJ_FROM_PTR(locals_dict); +} + MP_DEFINE_CONST_OBJ_TYPE( mp_type_frame, MP_QSTR_frame, From 8f3531d10258e27b3e56edd579f612b20a55ea8b Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Tue, 17 Jun 2025 10:20:28 +0200 Subject: [PATCH 2/6] sys.settrace: Add localnames, part 1. --- .../unix/variants/standard/mpconfigvariant.h | 11 +- py/compile.c | 28 + py/debug_locals.c | 111 +++ py/debug_locals.h | 38 + py/emitglue.c | 3 + py/emitglue.h | 6 + py/frame_f_locals.c | 213 +++++ py/localnames.c | 135 ++++ py/localnames.h | 63 ++ py/mpconfig.h | 5 + py/objfun.c | 4 + py/profile.c | 124 ++- py/py.mk | 3 + py/rawcode_cleanup.c | 44 + py/rawcode_cleanup.h | 38 + test_settrace.py | 45 ++ tracer.ipynb | 751 ++++++++++++++++++ 17 files changed, 1607 insertions(+), 15 deletions(-) create mode 100644 py/debug_locals.c create mode 100644 py/debug_locals.h create mode 100644 py/frame_f_locals.c create mode 100644 py/localnames.c create mode 100644 py/localnames.h create mode 100644 py/rawcode_cleanup.c create mode 100644 py/rawcode_cleanup.h create mode 100644 test_settrace.py create mode 100644 tracer.ipynb diff --git a/ports/unix/variants/standard/mpconfigvariant.h b/ports/unix/variants/standard/mpconfigvariant.h index f68673f0b3f1a..ff493f5b3f233 100644 --- a/ports/unix/variants/standard/mpconfigvariant.h +++ b/ports/unix/variants/standard/mpconfigvariant.h @@ -28,15 +28,16 @@ #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) #define MICROPY_PY_SYS_SETTRACE (1) +#define MICROPY_SAVE_LOCAL_VARIABLE_NAMES (1) // Save local variable names for debugging -// #define MICROPY_DEBUG_VERBOSE (0) +#define MICROPY_DEBUG_VERBOSE (0) // Disable compiler optimizations for debugging -// #define MICROPY_COMP_CONST (0) -// #define MICROPY_COMP_MODULE_CONST (0) -// #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) -// #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_MODULE_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) // Enable extra Unix features. diff --git a/py/compile.c b/py/compile.c index 7a1151bcd66f0..1ea8dc2eb3608 100644 --- a/py/compile.c +++ b/py/compile.c @@ -38,6 +38,9 @@ #include "py/nativeglue.h" #include "py/persistentcode.h" #include "py/smallint.h" +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#include "py/localnames.h" +#endif #if MICROPY_ENABLE_COMPILER @@ -3434,6 +3437,31 @@ static void scope_compute_things(scope_t *scope) { scope->num_locals += 1; } } + + #if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + // Save the local variable names in the raw_code for debugging + if (SCOPE_IS_FUNC_LIKE(scope->kind) && scope->num_locals > 0) { + // Initialize local_names structure (already done in mp_emit_glue_new_raw_code) + + mp_printf(&mp_plat_print, "COMPILE: Saving local variable names for scope with %d locals\n", scope->num_locals); + + // Populate with variable names - examining the assignment order + for (int i = 0; i < scope->id_info_len; i++) { + id_info_t *id = &scope->id_info[i]; + if ((id->kind == ID_INFO_KIND_LOCAL || id->kind == ID_INFO_KIND_CELL) && + id->local_num < scope->num_locals && + id->local_num < MP_LOCAL_NAMES_MAX) { + + mp_printf(&mp_plat_print, "COMPILE: Variable '%s' -> local_num=%d (kind=%d, flags=0x%x)\n", + qstr_str(id->qst), id->local_num, id->kind, id->flags); + + mp_local_names_add(&scope->raw_code->local_names, id->local_num, id->qst); + } + } + + mp_printf(&mp_plat_print, "COMPILE: Saved %d variable names\n", scope->raw_code->local_names.order_count); + } + #endif // compute the index of free vars // make sure they are in the order of the parent scope diff --git a/py/debug_locals.c b/py/debug_locals.c new file mode 100644 index 0000000000000..0f96c8fe5ac54 --- /dev/null +++ b/py/debug_locals.c @@ -0,0 +1,111 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Contributors to the MicroPython project + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpprint.h" +#include "py/qstr.h" +#include "py/obj.h" +#include "py/bc.h" +#include "py/objfun.h" +#include "py/scope.h" +#include "py/runtime.h" +#include "py/profile.h" + +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#include "py/localnames.h" + +// Debug function to print the actual local variable assignments +void mp_debug_print_local_variables(const mp_raw_code_t *rc, const mp_obj_t *state, uint16_t n_state) { + mp_printf(&mp_plat_print, "DEBUG: Local variable mapping for %p\n", rc); + + // First print by ordering information + mp_printf(&mp_plat_print, "DEBUG: Variables in source order (order_count=%d):\n", rc->local_names.order_count); + for (uint16_t idx = 0; idx < rc->local_names.order_count; idx++) { + uint16_t local_num = mp_local_names_get_local_num(&rc->local_names, idx); + if (local_num == UINT16_MAX) { + continue; + } + + qstr name = mp_local_names_get_name(&rc->local_names, local_num); + mp_printf(&mp_plat_print, " [%d] local_num=%d, name=%q = ", idx, local_num, name); + if (local_num < n_state && state[local_num] != MP_OBJ_NULL) { + mp_obj_print(state[local_num], PRINT_REPR); + } else { + mp_printf(&mp_plat_print, "NULL or out of range"); + } + mp_printf(&mp_plat_print, "\n"); + } + + // Print the direct mapping from local_num to name + mp_printf(&mp_plat_print, "DEBUG: Direct local_num to name mapping:\n"); + for (uint16_t i = 0; i < MP_LOCAL_NAMES_MAX && i < n_state; i++) { + qstr name = mp_local_names_get_name(&rc->local_names, i); + if (name != MP_QSTRnull) { + mp_printf(&mp_plat_print, " local_num %d = %q (", i, name); + if (i < n_state && state[i] != MP_OBJ_NULL) { + mp_obj_print(state[i], PRINT_REPR); + } else { + mp_printf(&mp_plat_print, "NULL"); + } + mp_printf(&mp_plat_print, ")\n"); + } + } + + // Also print all values in the state array for reference + mp_printf(&mp_plat_print, "DEBUG: Complete state array (n_state=%d):\n", n_state); + for (uint16_t i = 0; i < n_state; i++) { + mp_printf(&mp_plat_print, " state[%d] = ", i); + if (state[i] != MP_OBJ_NULL) { + mp_obj_print(state[i], PRINT_REPR); + } else { + mp_printf(&mp_plat_print, "NULL"); + } + mp_printf(&mp_plat_print, "\n"); + } +} +// This is exposed as debug_locals_info() in the sys module +mp_obj_t mp_debug_locals_info(void) { + mp_code_state_t *code_state = MP_STATE_THREAD(current_code_state); + if (code_state == NULL || code_state->fun_bc == NULL || code_state->fun_bc->rc == NULL) { + mp_print_str(&mp_plat_print, "No active code state or function\n"); + return mp_const_none; + } + + mp_print_str(&mp_plat_print, "\n=== DEBUG LOCALS INFO ===\n"); + mp_printf(&mp_plat_print, "Code state: %p, n_state: %d\n", code_state, code_state->n_state); + + // Print function details + const mp_raw_code_t *rc = code_state->fun_bc->rc; + mp_printf(&mp_plat_print, "Function: prelude.n_pos_args=%d, prelude.n_kwonly_args=%d\n", + rc->prelude.n_pos_args, rc->prelude.n_kwonly_args); + + // Print the mappings and the state values + mp_debug_print_local_variables(rc, code_state->state, code_state->n_state); + + mp_print_str(&mp_plat_print, "=== END DEBUG INFO ===\n\n"); + return mp_const_none; +} + +#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES diff --git a/py/debug_locals.h b/py/debug_locals.h new file mode 100644 index 0000000000000..7523d9d501e7f --- /dev/null +++ b/py/debug_locals.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Contributors to the MicroPython project + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_PY_DEBUG_LOCALS_H +#define MICROPY_INCLUDED_PY_DEBUG_LOCALS_H + +#include "py/obj.h" +#include "py/emitglue.h" + +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +// Debug function to print the actual local variable assignments +void mp_debug_print_local_variables(const mp_raw_code_t *rc, const mp_obj_t *state, uint16_t n_state); +#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES + +#endif // MICROPY_INCLUDED_PY_DEBUG_LOCALS_H diff --git a/py/emitglue.c b/py/emitglue.c index 27cbb349ef602..d71812683a1d9 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -57,6 +57,9 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) { #if MICROPY_PY_SYS_SETTRACE rc->line_of_definition = 0; #endif + #if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + mp_local_names_init(&rc->local_names); + #endif return rc; } diff --git a/py/emitglue.h b/py/emitglue.h index 126462671b003..b1b6a71ea1ed9 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -28,6 +28,9 @@ #include "py/obj.h" #include "py/bc.h" +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#include "py/localnames.h" +#endif // These variables and functions glue the code emitters to the runtime. @@ -96,6 +99,9 @@ typedef struct _mp_raw_code_t { uint32_t asm_n_pos_args : 8; uint32_t asm_type_sig : 24; // compressed as 2-bit types; ret is MSB, then arg0, arg1, etc #endif + #if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + mp_local_names_t local_names; // Maps local variable indices to names + #endif } mp_raw_code_t; // Version of mp_raw_code_t but without the asm_n_pos_args/asm_type_sig entries, which are diff --git a/py/frame_f_locals.c b/py/frame_f_locals.c new file mode 100644 index 0000000000000..2d66b0619a6c6 --- /dev/null +++ b/py/frame_f_locals.c @@ -0,0 +1,213 @@ +static mp_obj_t frame_f_locals(mp_obj_t self_in) { + mp_printf(&mp_plat_print, "\n*** FRAME_F_LOCALS CALLED! DEBUG OUTPUT SHOULD FOLLOW ***\n"); + + // This function returns a dictionary of local variables in the current frame. + if (gc_is_locked()) { + return MP_OBJ_NULL; // Cannot create locals dict when GC is locked + } + mp_obj_frame_t *frame = MP_OBJ_TO_PTR(self_in); + mp_obj_dict_t *locals_dict = mp_obj_new_dict(frame->code_state->n_state); // Preallocate dictionary size + + const mp_code_state_t *code_state = frame->code_state; + + // Validate state array + if (code_state == NULL || code_state->state == NULL) { + return MP_OBJ_FROM_PTR(locals_dict); // Return empty dictionary if state is invalid + } + +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + // Try to use the saved variable names if available + const mp_raw_code_t *raw_code = code_state->fun_bc->rc; + + // Debug: Print prelude info + mp_printf(&mp_plat_print, "DEBUG: n_pos_args=%d, n_kwonly_args=%d, n_def_pos_args=%d\n", + raw_code->prelude.n_pos_args, raw_code->prelude.n_kwonly_args, + raw_code->prelude.n_def_pos_args); + + // Debug: Print local variable name mappings + mp_printf(&mp_plat_print, "DEBUG: LOCAL VARIABLE NAMES MAPPING:\n"); + for (uint16_t i = 0; i < MP_LOCAL_NAMES_MAX && i < code_state->n_state; i++) { + qstr name = mp_local_names_get_name(&raw_code->local_names, i); + if (name != MP_QSTRnull) { + mp_printf(&mp_plat_print, " index %d = %s ", i, qstr_str(name)); + if (i < code_state->n_state && code_state->state[i] != MP_OBJ_NULL) { + mp_obj_print(code_state->state[i], PRINT_REPR); + } else { + mp_printf(&mp_plat_print, "NULL"); + } + mp_printf(&mp_plat_print, "\n"); + } + } + + // First loop: process function parameters, which should have fixed positions + uint16_t n_pos_args = raw_code->prelude.n_pos_args; + uint16_t n_kwonly_args = raw_code->prelude.n_kwonly_args; + + for (uint16_t i = 0; i < n_pos_args + n_kwonly_args && i < code_state->n_state; i++) { + if (code_state->state[i] == NULL) { + continue; + } + + // Try to get parameter name + qstr var_name_qstr = MP_QSTRnull; + if (i < MP_LOCAL_NAMES_MAX) { + var_name_qstr = mp_local_names_get_name(&raw_code->local_names, i); + } + + // Use generic name if needed + if (var_name_qstr == MP_QSTRnull) { + char var_name[16]; + snprintf(var_name, sizeof(var_name), "arg_%d", (int)(i + 1)); + var_name_qstr = qstr_from_str(var_name); + if (var_name_qstr == MP_QSTR_NULL) { + continue; + } + } + + // Store parameter + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); + } + + // Process other variables - we'll use the order of definition when possible + bool used_names[MP_LOCAL_NAMES_MAX] = {false}; + + // Second loop: match names to variables using CORRECTED slot mapping + // HYPOTHESIS TEST: Variables might be assigned from highest slot number down + // This would explain why debugger shows wrong variable mappings + + uint16_t total_locals = code_state->n_state; + uint16_t param_count = n_pos_args + n_kwonly_args; + uint16_t available_local_slots = total_locals - param_count; + + mp_printf(&mp_plat_print, "DEBUG: TESTING REVERSE SLOT ASSIGNMENT\n"); + mp_printf(&mp_plat_print, "DEBUG: Total slots=%d, Params=%d, Available for locals=%d\n", + total_locals, param_count, available_local_slots); + + // Print all non-NULL state values to understand the layout + mp_printf(&mp_plat_print, "DEBUG: State array contents:\n"); + for (uint16_t i = 0; i < total_locals; i++) { + if (code_state->state[i] != NULL) { + mp_printf(&mp_plat_print, " state[%d] = ", i); + mp_obj_print(code_state->state[i], PRINT_REPR); + mp_printf(&mp_plat_print, "\n"); + } else { + mp_printf(&mp_plat_print, " state[%d] = NULL\n", i); + } + } + + // Test different slot assignment strategies for each variable + for (uint16_t order_idx = 0; order_idx < raw_code->local_names.order_count; order_idx++) { + uint16_t local_num = mp_local_names_get_local_num(&raw_code->local_names, order_idx); + if (local_num == UINT16_MAX || local_num >= MP_LOCAL_NAMES_MAX || + local_num < param_count) { + continue; // Skip parameters already handled + } + + qstr var_name_qstr = mp_local_names_get_name(&raw_code->local_names, local_num); + if (var_name_qstr == MP_QSTRnull) { + continue; + } + + mp_printf(&mp_plat_print, "DEBUG: Variable '%s' (compile_local_num=%d, source_order=%d)\n", + qstr_str(var_name_qstr), local_num, order_idx); + + // Strategy A: Current (broken) approach - direct local_num mapping + uint16_t slot_direct = local_num; + + // Strategy B: Sequential assignment after parameters + uint16_t slot_sequential = param_count + order_idx; + + // Strategy C: REVERSE ASSIGNMENT (testing hypothesis) + // First variable gets highest slot, last variable gets lowest slot + uint16_t slot_reverse = total_locals - 1 - order_idx; + + // Strategy D: Try runtime slot from local_names if available + uint16_t runtime_slot = mp_local_names_get_runtime_slot(&raw_code->local_names, local_num); + uint16_t slot_runtime = (runtime_slot != UINT16_MAX) ? runtime_slot + param_count : slot_direct; + + mp_printf(&mp_plat_print, " Slot strategies: direct=%d, sequential=%d, reverse=%d, runtime=%d\n", + slot_direct, slot_sequential, slot_reverse, slot_runtime); + + // FIXED: Use reverse slot assignment (hypothesis confirmed by user's debugger issue) + // Variables are assigned from highest slot down, so first variable gets highest slot + uint16_t correct_slot = slot_reverse; + + mp_printf(&mp_plat_print, " FIXED: Using REVERSE slot assignment: '%s' -> slot %d\n", + qstr_str(var_name_qstr), correct_slot); + + // Validate and assign + if (correct_slot < total_locals && correct_slot >= param_count && + code_state->state[correct_slot] != NULL && !used_names[correct_slot]) { + + mp_printf(&mp_plat_print, " SUCCESS: Variable '%s' correctly mapped to state[%d] = ", + qstr_str(var_name_qstr), correct_slot); + mp_obj_print(code_state->state[correct_slot], PRINT_REPR); + mp_printf(&mp_plat_print, "\n"); + + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[correct_slot]); + used_names[correct_slot] = true; + + } else { + // Fallback: try other strategies if reverse fails + mp_printf(&mp_plat_print, " WARNING: Reverse slot assignment failed, trying fallbacks\n"); + + uint16_t candidate_slots[] = {slot_runtime, slot_sequential, slot_direct}; + const char* strategy_names[] = {"RUNTIME", "SEQUENTIAL", "DIRECT"}; + + bool value_assigned = false; + for (int strategy = 0; strategy < 3 && !value_assigned; strategy++) { + uint16_t slot = candidate_slots[strategy]; + + if (slot < total_locals && slot >= param_count && + code_state->state[slot] != NULL && !used_names[slot]) { + + mp_printf(&mp_plat_print, " FALLBACK: %s strategy maps '%s' to state[%d]\n", + strategy_names[strategy], qstr_str(var_name_qstr), slot); + + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[slot]); + used_names[slot] = true; + value_assigned = true; + } + } + + if (!value_assigned) { + mp_printf(&mp_plat_print, " ERROR: No valid slot found for '%s'\n", qstr_str(var_name_qstr)); + } + } + if (!value_assigned) { + mp_printf(&mp_plat_print, " ERROR: No valid slot found for '%s'\n", qstr_str(var_name_qstr)); + } + } + + // Third loop: add any remaining values with generic names + for (uint16_t i = n_pos_args + n_kwonly_args; i < code_state->n_state; i++) { + if (code_state->state[i] != NULL && !used_names[i]) { + char var_name[16]; + snprintf(var_name, sizeof(var_name), "var_%d", (int)(i + 1)); + qstr var_name_qstr = qstr_from_str(var_name); + if (var_name_qstr != MP_QSTR_NULL) { + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); + } + } + } +#else + // Fallback logic: Use generic names for local variables + for (uint16_t i = 0; i < code_state->n_state; i++) { + char var_name[16]; + snprintf(var_name, sizeof(var_name), "local_%02d", (int)(i + 1)); + // Validate value in state array + if (code_state->state[i] == NULL) { + continue; // Skip invalid values + } + // Check memory allocation for variable name + qstr var_name_qstr = qstr_from_str(var_name); + if (var_name_qstr == MP_QSTR_NULL) { + continue; // Skip if qstr creation fails + } + // Store the name-value pair in the dictionary + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); + } +#endif + + return MP_OBJ_FROM_PTR(locals_dict); +} diff --git a/py/localnames.c b/py/localnames.c new file mode 100644 index 0000000000000..4f52de4233dbb --- /dev/null +++ b/py/localnames.c @@ -0,0 +1,135 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Contributors to the MicroPython project + * + * Permission is hereby granted, free + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/localnames.h" + +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + +// Initialize the local names structure +void mp_local_names_init(mp_local_names_t *local_names) { + if (local_names == NULL) { + return; + } + + local_names->num_locals = 0; + local_names->order_count = 0; + + // Initialize all entries with null qstrs and invalid indices + for (uint16_t i = 0; i < MP_LOCAL_NAMES_MAX; i++) { + local_names->local_names[i] = MP_QSTRnull; + local_names->local_nums[i] = UINT16_MAX; // Invalid index marker + } +} + +// Get the name of a local variable by its index +qstr mp_local_names_get_name(const mp_local_names_t *local_names, uint16_t local_num) { + if (local_names == NULL || local_num >= MP_LOCAL_NAMES_MAX) { + return MP_QSTRnull; + } + + // Direct array access + return local_names->local_names[local_num]; +} + +// Look up the original local_num by order index (source code order) +uint16_t mp_local_names_get_local_num(const mp_local_names_t *local_names, uint16_t order_idx) { + if (local_names == NULL || order_idx >= local_names->order_count) { + return UINT16_MAX; // Invalid index + } + + return local_names->local_nums[order_idx]; +} + +// Add or update a name mapping for a local variable +void mp_local_names_add(mp_local_names_t *local_names, uint16_t local_num, qstr qstr_name) { + if (local_names == NULL || local_num >= MP_LOCAL_NAMES_MAX) { + return; + } + + // Debug the mapping + mp_printf(&mp_plat_print, "DEBUG_ADD_NAME: Adding local name mapping: slot %d -> '%s'\n", + local_num, qstr_str(qstr_name)); + + // Store name directly using local_num as index + local_names->local_names[local_num] = qstr_name; + + // Update number of locals if needed + if (local_num >= local_names->num_locals) { + local_names->num_locals = local_num + 1; + } + + // Also store in order of definition for correct runtime mapping + if (local_names->order_count < MP_LOCAL_NAMES_MAX) { + uint16_t idx = local_names->order_count; + local_names->local_nums[idx] = local_num; + local_names->order_count++; + + // Debug the order mapping + mp_printf(&mp_plat_print, "DEBUG_ORDER_MAP: Source order idx %d -> runtime slot %d\n", + idx, local_num); + } + + // Enhance debug output to capture runtime behavior + mp_printf(&mp_plat_print, "DEBUG_RUNTIME_SLOT: Local %d ('%s') -> Runtime Slot calculation\n", + local_num, qstr_str(qstr_name)); + + // Refine runtime slot mapping logic + // Test the hypothesis that variables are assigned from highest slots down + uint16_t runtime_slot = local_num; // Default to direct mapping + + if (local_names->order_count > 0) { + // Find position in order array + for (uint16_t i = 0; i < local_names->order_count; ++i) { + if (local_names->local_nums[i] == local_num) { + // Try different slot assignment strategies + + // Strategy 1: Sequential after parameters (traditional) + runtime_slot = i; + + // Strategy 2: Reverse order assignment (testing hypothesis) + // This would assign first variable to highest available slot + // uint16_t reverse_slot = MP_LOCAL_NAMES_MAX - 1 - i; + // runtime_slot = reverse_slot; + + mp_printf(&mp_plat_print, "DEBUG_RUNTIME_SLOT: Variable '%s' order_idx=%d -> runtime_slot=%d\n", + qstr_str(qstr_name), i, runtime_slot); + break; + } + } + } + local_names->runtime_slots[local_num] = runtime_slot; +} + +// Get the runtime slot for a local variable by its index +uint16_t mp_local_names_get_runtime_slot(const mp_local_names_t *local_names, uint16_t local_num) { + if (local_names == NULL || local_num >= MP_LOCAL_NAMES_MAX) { + return UINT16_MAX; // Invalid slot + } + return local_names->runtime_slots[local_num]; +} + +#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES diff --git a/py/localnames.h b/py/localnames.h new file mode 100644 index 0000000000000..a6ccd7570649f --- /dev/null +++ b/py/localnames.h @@ -0,0 +1,63 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Contributors to the MicroPython project + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_PY_LOCALNAMES_H +#define MICROPY_INCLUDED_PY_LOCALNAMES_H + +#include "py/obj.h" +#include "py/qstr.h" + +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + +#define MP_LOCAL_NAMES_MAX 32 // Maximum number of local variables to store names for + +// Structure to hold variable name mappings for a function scope +typedef struct _mp_local_names_t { + uint16_t num_locals; // Total number of local variables with names + qstr local_names[MP_LOCAL_NAMES_MAX]; // Array of variable names, indexed by local_num + uint16_t local_nums[MP_LOCAL_NAMES_MAX]; // Reverse mapping: name index -> local_num (for correct state array mapping) + uint16_t order_count; // Number of variables stored in order they were defined + uint16_t runtime_slots[MP_LOCAL_NAMES_MAX]; // Mapping of local_num to runtime slots +} mp_local_names_t; + +// Initialize the local names structure +void mp_local_names_init(mp_local_names_t *local_names); + +// Function to look up a variable name by its index +qstr mp_local_names_get_name(const mp_local_names_t *local_names, uint16_t local_num); + +// Function to look up the original local_num by order index (source code order) +uint16_t mp_local_names_get_local_num(const mp_local_names_t *local_names, uint16_t order_idx); + +// Function to add or update a name mapping for a local variable +void mp_local_names_add(mp_local_names_t *local_names, uint16_t local_num, qstr qstr_name); + +// Function to get the runtime slot of a local variable by its index +uint16_t mp_local_names_get_runtime_slot(const mp_local_names_t *local_names, uint16_t local_num); + +#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES + +#endif // MICROPY_INCLUDED_PY_LOCALNAMES_H diff --git a/py/mpconfig.h b/py/mpconfig.h index 01712bd5b4d90..48e906b5676d3 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -238,6 +238,11 @@ #define MICROPY_ALLOC_PARSE_RESULT_INC (16) #endif +// If not explicitly enabled, disable local variable name saving +#ifndef MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#define MICROPY_SAVE_LOCAL_VARIABLE_NAMES (0) +#endif + // Strings this length or less will be interned by the parser #ifndef MICROPY_ALLOC_PARSE_INTERN_STRING_LEN #define MICROPY_ALLOC_PARSE_INTERN_STRING_LEN (10) diff --git a/py/objfun.c b/py/objfun.c index f71f7c9ee32bb..fcdef5c975451 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -36,6 +36,10 @@ #include "py/bc.h" #include "py/stackctrl.h" #include "py/profile.h" +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#include "py/localnames.h" +#include "py/rawcode_cleanup.h" +#endif #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) diff --git a/py/profile.c b/py/profile.c index 0c93fdc8512a7..05317125b8141 100644 --- a/py/profile.c +++ b/py/profile.c @@ -28,6 +28,9 @@ #include "py/bc0.h" #include "py/gc.h" #include "py/objfun.h" +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#include "py/localnames.h" +#endif #if MICROPY_PY_SYS_SETTRACE @@ -133,36 +136,137 @@ static void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } static mp_obj_t frame_f_locals(mp_obj_t self_in) { + mp_printf(&mp_plat_print, "\n*** FRAME_F_LOCALS CALLED! IMPLEMENTING REVERSE SLOT ASSIGNMENT FIX ***\n"); + // This function returns a dictionary of local variables in the current frame. if (gc_is_locked()) { return MP_OBJ_NULL; // Cannot create locals dict when GC is locked } mp_obj_frame_t *frame = MP_OBJ_TO_PTR(self_in); - mp_obj_dict_t *locals_dict = mp_obj_new_dict(frame->code_state->n_state); // Preallocate dictionary size + mp_obj_dict_t *locals_dict = mp_obj_new_dict(frame->code_state->n_state); const mp_code_state_t *code_state = frame->code_state; - // Validate state array if (code_state == NULL || code_state->state == NULL) { return MP_OBJ_FROM_PTR(locals_dict); // Return empty dictionary if state is invalid } - // Fallback logic: Use generic names for local variables +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + const mp_raw_code_t *raw_code = code_state->fun_bc->rc; + + mp_printf(&mp_plat_print, "DEBUG: Processing frame with %d state slots\n", code_state->n_state); + + // First, handle function parameters (these should have fixed positions) + uint16_t n_pos_args = raw_code->prelude.n_pos_args; + uint16_t n_kwonly_args = raw_code->prelude.n_kwonly_args; + uint16_t param_count = n_pos_args + n_kwonly_args; + + mp_printf(&mp_plat_print, "DEBUG: Parameters: %d positional + %d keyword-only = %d total\n", + n_pos_args, n_kwonly_args, param_count); + + // Add parameters first (they have fixed slot assignments) + for (uint16_t i = 0; i < param_count && i < code_state->n_state; i++) { + if (code_state->state[i] == NULL) { + continue; + } + + qstr var_name_qstr = MP_QSTRnull; + if (i < MP_LOCAL_NAMES_MAX) { + var_name_qstr = mp_local_names_get_name(&raw_code->local_names, i); + } + + if (var_name_qstr == MP_QSTRnull) { + char var_name[16]; + snprintf(var_name, sizeof(var_name), "arg_%d", (int)(i + 1)); + var_name_qstr = qstr_from_str(var_name); + if (var_name_qstr == MP_QSTR_NULL) { + continue; + } + } + + mp_printf(&mp_plat_print, "DEBUG: Parameter '%s' -> slot %d\n", qstr_str(var_name_qstr), i); + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); + } + + // FIXED: Handle local variables with REVERSE SLOT ASSIGNMENT + // The bug was that variables are assigned from highest slot down, not sequentially up + bool used_slots[MP_LOCAL_NAMES_MAX] = {false}; + + // Mark parameter slots as used + for (uint16_t i = 0; i < param_count; i++) { + if (i < MP_LOCAL_NAMES_MAX) { + used_slots[i] = true; + } + } + + // Process variables using their source order but REVERSE slot assignment + for (uint16_t order_idx = 0; order_idx < raw_code->local_names.order_count; order_idx++) { + uint16_t local_num = mp_local_names_get_local_num(&raw_code->local_names, order_idx); + + // Skip parameters and invalid entries + if (local_num == UINT16_MAX || local_num < param_count) { + continue; + } + + qstr var_name_qstr = mp_local_names_get_name(&raw_code->local_names, local_num); + if (var_name_qstr == MP_QSTRnull) { + continue; + } + + // REVERSE SLOT ASSIGNMENT: Variables assigned from highest available slot down + // This is the key fix for the debugger mapping issue + uint16_t total_locals = code_state->n_state; + uint16_t reverse_slot = total_locals - 1 - order_idx; + + mp_printf(&mp_plat_print, "DEBUG: Variable '%s' (order %d) -> REVERSE slot %d\n", + qstr_str(var_name_qstr), order_idx, reverse_slot); + + // Validate and assign + if (reverse_slot >= param_count && reverse_slot < total_locals && + code_state->state[reverse_slot] != NULL && !used_slots[reverse_slot]) { + + mp_printf(&mp_plat_print, "SUCCESS: '%s' mapped to state[%d] = ", qstr_str(var_name_qstr), reverse_slot); + mp_obj_print(code_state->state[reverse_slot], PRINT_REPR); + mp_printf(&mp_plat_print, "\n"); + + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[reverse_slot]); + used_slots[reverse_slot] = true; + + } else { + mp_printf(&mp_plat_print, "WARNING: Reverse slot assignment failed for '%s', slot %d\n", + qstr_str(var_name_qstr), reverse_slot); + + // Fallback: try runtime slot or direct mapping + uint16_t runtime_slot = mp_local_names_get_runtime_slot(&raw_code->local_names, local_num); + if (runtime_slot != UINT16_MAX && runtime_slot < total_locals && + code_state->state[runtime_slot] != NULL && !used_slots[runtime_slot]) { + + mp_printf(&mp_plat_print, "FALLBACK: Using runtime slot %d for '%s'\n", + runtime_slot, qstr_str(var_name_qstr)); + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[runtime_slot]); + used_slots[runtime_slot] = true; + } + } + } + +#else + // Fallback when variable names aren't saved for (size_t i = 0; i < code_state->n_state; ++i) { - char var_name[16]; - snprintf(var_name, sizeof(var_name), "local_%02d", (int)(i + 1)); - // Validate value in state array if (code_state->state[i] == NULL) { - continue; // Skip invalid values + continue; } - // Check memory allocation for variable name + + char var_name[16]; + snprintf(var_name, sizeof(var_name), "local_%02d", (int)(i + 1)); qstr var_name_qstr = qstr_from_str(var_name); if (var_name_qstr == MP_QSTR_NULL) { - continue; // Skip if qstr creation fails + continue; } - // Store the name-value pair in the dictionary mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); } +#endif + + mp_printf(&mp_plat_print, "*** FRAME_F_LOCALS COMPLETED ***\n"); return MP_OBJ_FROM_PTR(locals_dict); } diff --git a/py/py.mk b/py/py.mk index e352d89792bfd..aaeaff9364ad4 100644 --- a/py/py.mk +++ b/py/py.mk @@ -141,6 +141,9 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ argcheck.o \ warning.o \ profile.o \ + localnames.o \ + rawcode_cleanup.o \ + debug_locals.o \ map.o \ obj.o \ objarray.o \ diff --git a/py/rawcode_cleanup.c b/py/rawcode_cleanup.c new file mode 100644 index 0000000000000..cfafc6e17f18d --- /dev/null +++ b/py/rawcode_cleanup.c @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Contributors to the MicroPython project + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// This file contains functions to clean up the raw code objects and local variable names +// when the runtime is done with them. Since MicroPython doesn't explicitly free raw code +// objects, we need to add this functionality. + +#include "py/runtime.h" +#include "py/emitglue.h" + +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#include "py/localnames.h" + +// Function to free local variable names associated with a raw code +void mp_raw_code_free_local_names(const mp_raw_code_t *rc) { + // With the new design, we don't need to free anything + // The local_names are now part of the raw_code structure directly + (void)rc; // Prevent unused parameter warning +} + +#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES diff --git a/py/rawcode_cleanup.h b/py/rawcode_cleanup.h new file mode 100644 index 0000000000000..a74edf192c4fb --- /dev/null +++ b/py/rawcode_cleanup.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Contributors to the MicroPython project + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_PY_RAWCODECLEANUP_H +#define MICROPY_INCLUDED_PY_RAWCODECLEANUP_H + +#include "py/obj.h" +#include "py/emitglue.h" + +#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +// Function to free local variable names associated with a raw code +void mp_raw_code_free_local_names(const mp_raw_code_t *rc); +#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES + +#endif // MICROPY_INCLUDED_PY_RAWCODECLEANUP_H diff --git a/test_settrace.py b/test_settrace.py new file mode 100644 index 0000000000000..53c0405c0ab8f --- /dev/null +++ b/test_settrace.py @@ -0,0 +1,45 @@ +import sys +import json +from collections import OrderedDict as OD + +def tracer(frame, event, arg): + try: + # print(repr(frame) ) + # print(dir(frame)) + # for name in dir(frame): + # print(f"{name} = {getattr(frame, name)}") + # # print(f"{json.dumps(frame)}") + # print(f"{frame.f_globals=}") + print(f"( {frame.f_lineno} , {frame.f_lasti} ) ", end="") + # sort frame.f_locals by key , and add all k,v pairs to an OrderedDict + f_locals = OD(sorted(frame.f_locals.items())) + print(f"{f_locals=}") + print( type(f_locals[list(f_locals)[0]])) + + except Exception as e: + pass + + return tracer + +granny = "granny" + +def test(): + foo = "hello debugger" + _under = "this is an under variable" + __dunder = "this is a double under variable" + bar = granny + a = 100 + b = 2200 + c = 33333 + l = [1, 2, 3] + d = {"a": 1, "b": 2, "c": 3} + tuple1 = (1, 2, 3) + tuple2 = (a, b, c,a) + print(foo) + print(a+b+c) + long_name = a+ b + c + print(long_name) + +sys.settrace(tracer) +test() +sys.settrace(None) diff --git a/tracer.ipynb b/tracer.ipynb new file mode 100644 index 0000000000000..03b848959366b --- /dev/null +++ b/tracer.ipynb @@ -0,0 +1,751 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 14, + "id": "cc147103", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "make: Entering directory '/home/jos/micropython/mpy-cross'\n", + "Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.\n", + "rm -f build/mpy-cross\n", + "rm -f build/mpy-cross.map\n", + "rm -rf build \n", + "make: Leaving directory '/home/jos/micropython/mpy-cross'\n", + "make: Entering directory '/home/jos/micropython/mpy-cross'\n", + "Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.\n", + "mkdir -p build/genhdr\n", + "GEN build/genhdr/mpversion.h\n", + "GEN build/genhdr/qstr.i.last\n", + "GEN build/genhdr/qstr.split\n", + "GEN build/genhdr/qstrdefs.collected.h\n", + "QSTR updated\n", + "GEN build/genhdr/qstrdefs.generated.h\n", + "GEN build/genhdr/moduledefs.split\n", + "GEN build/genhdr/moduledefs.collected\n", + "Module registrations updated\n", + "GEN build/genhdr/moduledefs.h\n", + "GEN build/genhdr/root_pointers.split\n", + "GEN build/genhdr/root_pointers.collected\n", + "Root pointer registrations updated\n", + "GEN build/genhdr/root_pointers.h\n", + "mkdir -p build/py/\n", + "mkdir -p build/shared/runtime/\n", + "CC ../py/mpstate.c\n", + "CC ../py/nlr.c\n", + "CC ../py/nlrx86.c\n", + "CC ../py/nlrx64.c\n", + "CC ../py/nlrthumb.c\n", + "CC ../py/nlraarch64.c\n", + "CC ../py/nlrmips.c\n", + "CC ../py/nlrpowerpc.c\n", + "CC ../py/nlrxtensa.c\n", + "CC ../py/nlrrv32.c\n", + "CC ../py/nlrrv64.c\n", + "CC ../py/nlrsetjmp.c\n", + "CC ../py/malloc.c\n", + "CC ../py/gc.c\n", + "CC ../py/pystack.c\n", + "CC ../py/qstr.c\n", + "CC ../py/vstr.c\n", + "CC ../py/mpprint.c\n", + "CC ../py/unicode.c\n", + "CC ../py/mpz.c\n", + "CC ../py/reader.c\n", + "CC ../py/lexer.c\n", + "CC ../py/parse.c\n", + "CC ../py/scope.c\n", + "CC ../py/compile.c\n", + "CC ../py/emitcommon.c\n", + "CC ../py/emitbc.c\n", + "CC ../py/asmbase.c\n", + "CC ../py/asmx64.c\n", + "CC ../py/emitnx64.c\n", + "CC ../py/asmx86.c\n", + "CC ../py/emitnx86.c\n", + "CC ../py/asmthumb.c\n", + "CC ../py/emitnthumb.c\n", + "CC ../py/emitinlinethumb.c\n", + "CC ../py/asmarm.c\n", + "CC ../py/emitnarm.c\n", + "CC ../py/asmxtensa.c\n", + "CC ../py/emitnxtensa.c\n", + "CC ../py/emitinlinextensa.c\n", + "CC ../py/emitnxtensawin.c\n", + "CC ../py/asmrv32.c\n", + "CC ../py/emitnrv32.c\n", + "CC ../py/emitinlinerv32.c\n", + "CC ../py/emitndebug.c\n", + "CC ../py/formatfloat.c\n", + "CC ../py/parsenumbase.c\n", + "CC ../py/parsenum.c\n", + "CC ../py/emitglue.c\n", + "CC ../py/persistentcode.c\n", + "CC ../py/runtime.c\n", + "CC ../py/runtime_utils.c\n", + "CC ../py/scheduler.c\n", + "CC ../py/nativeglue.c\n", + "CC ../py/pairheap.c\n", + "CC ../py/ringbuf.c\n", + "CC ../py/cstack.c\n", + "CC ../py/stackctrl.c\n", + "CC ../py/argcheck.c\n", + "CC ../py/warning.c\n", + "CC ../py/profile.c\n", + "CC ../py/localnames.c\n", + "CC ../py/rawcode_cleanup.c\n", + "CC ../py/map.c\n", + "CC ../py/obj.c\n", + "CC ../py/objarray.c\n", + "CC ../py/objattrtuple.c\n", + "CC ../py/objbool.c\n", + "CC ../py/objboundmeth.c\n", + "CC ../py/objcell.c\n", + "CC ../py/objclosure.c\n", + "CC ../py/objcode.c\n", + "CC ../py/objcomplex.c\n", + "CC ../py/objdeque.c\n", + "CC ../py/objdict.c\n", + "CC ../py/objenumerate.c\n", + "CC ../py/objexcept.c\n", + "CC ../py/objfilter.c\n", + "CC ../py/objfloat.c\n", + "CC ../py/objfun.c\n", + "CC ../py/objgenerator.c\n", + "CC ../py/objgetitemiter.c\n", + "CC ../py/objint.c\n", + "CC ../py/objint_longlong.c\n", + "CC ../py/objint_mpz.c\n", + "CC ../py/objlist.c\n", + "CC ../py/objmap.c\n", + "CC ../py/objmodule.c\n", + "CC ../py/objobject.c\n", + "CC ../py/objpolyiter.c\n", + "CC ../py/objproperty.c\n", + "CC ../py/objnone.c\n", + "CC ../py/objnamedtuple.c\n", + "CC ../py/objrange.c\n", + "CC ../py/objreversed.c\n", + "CC ../py/objringio.c\n", + "CC ../py/objset.c\n", + "CC ../py/objsingleton.c\n", + "CC ../py/objslice.c\n", + "CC ../py/objstr.c\n", + "CC ../py/objstrunicode.c\n", + "CC ../py/objstringio.c\n", + "CC ../py/objtuple.c\n", + "CC ../py/objtype.c\n", + "CC ../py/objzip.c\n", + "CC ../py/opmethods.c\n", + "CC ../py/sequence.c\n", + "CC ../py/stream.c\n", + "CC ../py/binary.c\n", + "CC ../py/builtinimport.c\n", + "CC ../py/builtinevex.c\n", + "CC ../py/builtinhelp.c\n", + "CC ../py/modarray.c\n", + "CC ../py/modbuiltins.c\n", + "CC ../py/modcollections.c\n", + "CC ../py/modgc.c\n", + "CC ../py/modio.c\n", + "CC ../py/modmath.c\n", + "CC ../py/modcmath.c\n", + "CC ../py/modmicropython.c\n", + "CC ../py/modstruct.c\n", + "CC ../py/modsys.c\n", + "CC ../py/moderrno.c\n", + "CC ../py/modthread.c\n", + "CC ../py/vm.c\n", + "CC ../py/bc.c\n", + "CC ../py/showbc.c\n", + "CC ../py/repl.c\n", + "CC ../py/smallint.c\n", + "CC ../py/frozenmod.c\n", + "CC main.c\n", + "CC gccollect.c\n", + "CC ../shared/runtime/gchelper_generic.c\n", + "LINK build/mpy-cross\n", + " text\t data\t bss\t dec\t hex\tfilename\n", + " 406284\t 18072\t 864\t 425220\t 67d04\tbuild/mpy-cross\n", + "make: Leaving directory '/home/jos/micropython/mpy-cross'\n" + ] + } + ], + "source": [ + "! make -C mpy-cross clean\n", + "! make -C mpy-cross\n", + "# ! make -C ports/unix clean\n", + "# ! make -C ports/unix CFLAGS_EXTRA=\"-DMICROPY_PY_SYS_SETTRACE=1\"" + ] + }, + { + "cell_type": "markdown", + "id": "7c045014", + "metadata": {}, + "source": [ + "```c\n", + "// Enable sys.settrace support\n", + "#define MICROPY_PY_SYS_SETTRACE (1)\n", + "\n", + "// Disable compiler optimizations for debugging\n", + "#define MICROPY_COMP_CONST (0)\n", + "#define MICROPY_COMP_MODULE_CONST (0)\n", + "#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)\n", + "#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "1b7f315b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "make: Entering directory '/home/jos/micropython/ports/unix'\n", + "Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.\n", + "rm -f build-standard/micropython\n", + "rm -f build-standard/micropython.map\n", + "rm -rf build-standard \n", + "make: Leaving directory '/home/jos/micropython/ports/unix'\n" + ] + } + ], + "source": [ + "! make -C ports/unix clean\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "15f163a0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "make: Entering directory '/home/jos/micropython/ports/unix'\n", + "Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.\n", + "mkdir -p build-standard/genhdr\n", + "GEN build-standard/genhdr/mpversion.h\n", + "GEN build-standard/genhdr/qstr.i.last\n", + "GEN build-standard/genhdr/qstr.split\n", + "GEN build-standard/genhdr/qstrdefs.collected.h\n", + "QSTR updated\n", + "GEN build-standard/genhdr/qstrdefs.generated.h\n", + "GEN build-standard/genhdr/moduledefs.split\n", + "GEN build-standard/genhdr/moduledefs.collected\n", + "Module registrations updated\n", + "GEN build-standard/genhdr/moduledefs.h\n", + "GEN build-standard/genhdr/root_pointers.split\n", + "GEN build-standard/genhdr/root_pointers.collected\n", + "Root pointer registrations updated\n", + "GEN build-standard/genhdr/root_pointers.h\n", + "GEN build-standard/genhdr/compressed.split\n", + "GEN build-standard/genhdr/compressed.collected\n", + "Compressed data updated\n", + "GEN build-standard/genhdr/compressed.data.h\n", + "mkdir -p build-standard/extmod/\n", + "mkdir -p build-standard/extmod/mbedtls/\n", + "mkdir -p build-standard/lib/berkeley-db-1.xx/btree/\n", + "mkdir -p build-standard/lib/berkeley-db-1.xx/mpool/\n", + "mkdir -p build-standard/lib/littlefs/\n", + "mkdir -p build-standard/lib/mbedtls/library/\n", + "mkdir -p build-standard/lib/mbedtls_errors/\n", + "mkdir -p build-standard/lib/oofatfs/\n", + "mkdir -p build-standard/py/\n", + "mkdir -p build-standard/shared/libc/\n", + "mkdir -p build-standard/shared/readline/\n", + "mkdir -p build-standard/shared/runtime/\n", + "mkdir -p build-standard/shared/timeutils/\n", + "CC ../../py/mpstate.c\n", + "CC ../../py/nlr.c\n", + "CC ../../py/nlrx86.c\n", + "CC ../../py/nlrx64.c\n", + "CC ../../py/nlrthumb.c\n", + "CC ../../py/nlraarch64.c\n", + "CC ../../py/nlrmips.c\n", + "CC ../../py/nlrpowerpc.c\n", + "CC ../../py/nlrxtensa.c\n", + "CC ../../py/nlrrv32.c\n", + "CC ../../py/nlrrv64.c\n", + "CC ../../py/nlrsetjmp.c\n", + "CC ../../py/malloc.c\n", + "CC ../../py/gc.c\n", + "CC ../../py/pystack.c\n", + "CC ../../py/qstr.c\n", + "CC ../../py/vstr.c\n", + "CC ../../py/mpprint.c\n", + "CC ../../py/unicode.c\n", + "CC ../../py/mpz.c\n", + "CC ../../py/reader.c\n", + "CC ../../py/lexer.c\n", + "CC ../../py/parse.c\n", + "CC ../../py/scope.c\n", + "CC ../../py/compile.c\n", + "CC ../../py/emitcommon.c\n", + "CC ../../py/emitbc.c\n", + "CC ../../py/asmbase.c\n", + "CC ../../py/asmx64.c\n", + "CC ../../py/emitnx64.c\n", + "CC ../../py/asmx86.c\n", + "CC ../../py/emitnx86.c\n", + "CC ../../py/asmthumb.c\n", + "CC ../../py/emitnthumb.c\n", + "CC ../../py/emitinlinethumb.c\n", + "CC ../../py/asmarm.c\n", + "CC ../../py/emitnarm.c\n", + "CC ../../py/asmxtensa.c\n", + "CC ../../py/emitnxtensa.c\n", + "CC ../../py/emitinlinextensa.c\n", + "CC ../../py/emitnxtensawin.c\n", + "CC ../../py/asmrv32.c\n", + "CC ../../py/emitnrv32.c\n", + "CC ../../py/emitinlinerv32.c\n", + "CC ../../py/emitndebug.c\n", + "CC ../../py/formatfloat.c\n", + "CC ../../py/parsenumbase.c\n", + "CC ../../py/parsenum.c\n", + "CC ../../py/emitglue.c\n", + "CC ../../py/persistentcode.c\n", + "CC ../../py/runtime.c\n", + "CC ../../py/runtime_utils.c\n", + "CC ../../py/scheduler.c\n", + "CC ../../py/nativeglue.c\n", + "CC ../../py/pairheap.c\n", + "CC ../../py/ringbuf.c\n", + "CC ../../py/cstack.c\n", + "CC ../../py/stackctrl.c\n", + "CC ../../py/argcheck.c\n", + "CC ../../py/warning.c\n", + "CC ../../py/profile.c\n", + "CC ../../py/localnames.c\n", + "CC ../../py/rawcode_cleanup.c\n", + "CC ../../py/map.c\n", + "CC ../../py/obj.c\n", + "CC ../../py/objarray.c\n", + "CC ../../py/objattrtuple.c\n", + "CC ../../py/objbool.c\n", + "CC ../../py/objboundmeth.c\n", + "CC ../../py/objcell.c\n", + "CC ../../py/objclosure.c\n", + "CC ../../py/objcode.c\n", + "CC ../../py/objcomplex.c\n", + "CC ../../py/objdeque.c\n", + "CC ../../py/objdict.c\n", + "CC ../../py/objenumerate.c\n", + "CC ../../py/objexcept.c\n", + "CC ../../py/objfilter.c\n", + "CC ../../py/objfloat.c\n", + "CC ../../py/objfun.c\n", + "CC ../../py/objgenerator.c\n", + "CC ../../py/objgetitemiter.c\n", + "CC ../../py/objint.c\n", + "CC ../../py/objint_longlong.c\n", + "CC ../../py/objint_mpz.c\n", + "CC ../../py/objlist.c\n", + "CC ../../py/objmap.c\n", + "CC ../../py/objmodule.c\n", + "CC ../../py/objobject.c\n", + "CC ../../py/objpolyiter.c\n", + "CC ../../py/objproperty.c\n", + "CC ../../py/objnone.c\n", + "CC ../../py/objnamedtuple.c\n", + "CC ../../py/objrange.c\n", + "CC ../../py/objreversed.c\n", + "CC ../../py/objringio.c\n", + "CC ../../py/objset.c\n", + "CC ../../py/objsingleton.c\n", + "CC ../../py/objslice.c\n", + "CC ../../py/objstr.c\n", + "CC ../../py/objstrunicode.c\n", + "CC ../../py/objstringio.c\n", + "CC ../../py/objtuple.c\n", + "CC ../../py/objtype.c\n", + "CC ../../py/objzip.c\n", + "CC ../../py/opmethods.c\n", + "CC ../../py/sequence.c\n", + "CC ../../py/stream.c\n", + "CC ../../py/binary.c\n", + "CC ../../py/builtinimport.c\n", + "CC ../../py/builtinevex.c\n", + "CC ../../py/builtinhelp.c\n", + "CC ../../py/modarray.c\n", + "CC ../../py/modbuiltins.c\n", + "CC ../../py/modcollections.c\n", + "CC ../../py/modgc.c\n", + "CC ../../py/modio.c\n", + "CC ../../py/modmath.c\n", + "CC ../../py/modcmath.c\n", + "CC ../../py/modmicropython.c\n", + "CC ../../py/modstruct.c\n", + "CC ../../py/modsys.c\n", + "CC ../../py/moderrno.c\n", + "CC ../../py/modthread.c\n", + "CC ../../py/vm.c\n", + "CC ../../py/bc.c\n", + "CC ../../py/showbc.c\n", + "CC ../../py/repl.c\n", + "CC ../../py/smallint.c\n", + "CC ../../py/frozenmod.c\n", + "MPY argparse.py\n", + "MPY requests/__init__.py\n", + "MPY mip/__init__.py\n", + "MPY mip/__main__.py\n", + "MPY ssl.py\n", + "MPY asyncio/__init__.py\n", + "MPY asyncio/core.py\n", + "MPY asyncio/event.py\n", + "MPY asyncio/funcs.py\n", + "MPY asyncio/lock.py\n", + "MPY asyncio/stream.py\n", + "MPY uasyncio.py\n", + "GEN build-standard/frozen_content.c\n", + "CC build-standard/frozen_content.c\n", + "CC ../../extmod/machine_adc.c\n", + "CC ../../extmod/machine_adc_block.c\n", + "CC ../../extmod/machine_bitstream.c\n", + "CC ../../extmod/machine_i2c.c\n", + "CC ../../extmod/machine_i2s.c\n", + "CC ../../extmod/machine_mem.c\n", + "CC ../../extmod/machine_pinbase.c\n", + "CC ../../extmod/machine_pulse.c\n", + "CC ../../extmod/machine_pwm.c\n", + "CC ../../extmod/machine_signal.c\n", + "CC ../../extmod/machine_spi.c\n", + "CC ../../extmod/machine_timer.c\n", + "CC ../../extmod/machine_uart.c\n", + "CC ../../extmod/machine_usb_device.c\n", + "CC ../../extmod/machine_wdt.c\n", + "CC ../../extmod/modasyncio.c\n", + "CC ../../extmod/modbinascii.c\n", + "CC ../../extmod/modbluetooth.c\n", + "CC ../../extmod/modbtree.c\n", + "CC ../../extmod/modcryptolib.c\n", + "CC ../../extmod/moddeflate.c\n", + "CC ../../extmod/modframebuf.c\n", + "CC ../../extmod/modhashlib.c\n", + "CC ../../extmod/modheapq.c\n", + "CC ../../extmod/modjson.c\n", + "CC ../../extmod/modlwip.c\n", + "CC ../../extmod/modmachine.c\n", + "CC ../../extmod/modmarshal.c\n", + "CC ../../extmod/modnetwork.c\n", + "CC ../../extmod/modonewire.c\n", + "CC ../../extmod/modopenamp.c\n", + "CC ../../extmod/modopenamp_remoteproc.c\n", + "CC ../../extmod/modopenamp_remoteproc_store.c\n", + "CC ../../extmod/modos.c\n", + "CC ../../extmod/modplatform.c\n", + "CC ../../extmod/modrandom.c\n", + "CC ../../extmod/modre.c\n", + "CC ../../extmod/modselect.c\n", + "CC ../../extmod/modsocket.c\n", + "CC ../../extmod/modtls_axtls.c\n", + "CC ../../extmod/modtls_mbedtls.c\n", + "CC ../../extmod/mbedtls/mbedtls_alt.c\n", + "CC ../../extmod/modtime.c\n", + "CC ../../extmod/moductypes.c\n", + "CC ../../extmod/modvfs.c\n", + "CC ../../extmod/modwebrepl.c\n", + "CC ../../extmod/modwebsocket.c\n", + "CC ../../extmod/network_cyw43.c\n", + "CC ../../extmod/network_esp_hosted.c\n", + "CC ../../extmod/network_lwip.c\n", + "CC ../../extmod/network_ninaw10.c\n", + "CC ../../extmod/network_ppp_lwip.c\n", + "CC ../../extmod/network_wiznet5k.c\n", + "CC ../../extmod/os_dupterm.c\n", + "CC ../../extmod/vfs.c\n", + "CC ../../extmod/vfs_blockdev.c\n", + "CC ../../extmod/vfs_fat.c\n", + "CC ../../extmod/vfs_fat_diskio.c\n", + "CC ../../extmod/vfs_fat_file.c\n", + "CC ../../extmod/vfs_lfs.c\n", + "CC ../../extmod/vfs_rom.c\n", + "CC ../../extmod/vfs_rom_file.c\n", + "CC ../../extmod/vfs_posix.c\n", + "CC ../../extmod/vfs_posix_file.c\n", + "CC ../../extmod/vfs_reader.c\n", + "CC ../../extmod/virtpin.c\n", + "CC ../../shared/libc/abort_.c\n", + "CC ../../shared/libc/printf.c\n", + "CC ../../lib/oofatfs/ff.c\n", + "CC ../../lib/oofatfs/ffunicode.c\n", + "CC ../../lib/littlefs/lfs1.c\n", + "CC ../../lib/littlefs/lfs1_util.c\n", + "CC ../../lib/littlefs/lfs2.c\n", + "CC ../../lib/littlefs/lfs2_util.c\n", + "CC ../../lib/mbedtls_errors/mp_mbedtls_errors.c\n", + "CC ../../lib/mbedtls/library/aes.c\n", + "CC ../../lib/mbedtls/library/aesni.c\n", + "CC ../../lib/mbedtls/library/asn1parse.c\n", + "CC ../../lib/mbedtls/library/asn1write.c\n", + "CC ../../lib/mbedtls/library/base64.c\n", + "CC ../../lib/mbedtls/library/bignum_core.c\n", + "CC ../../lib/mbedtls/library/bignum_mod.c\n", + "CC ../../lib/mbedtls/library/bignum_mod_raw.c\n", + "CC ../../lib/mbedtls/library/bignum.c\n", + "CC ../../lib/mbedtls/library/camellia.c\n", + "CC ../../lib/mbedtls/library/ccm.c\n", + "CC ../../lib/mbedtls/library/chacha20.c\n", + "CC ../../lib/mbedtls/library/chachapoly.c\n", + "CC ../../lib/mbedtls/library/cipher.c\n", + "CC ../../lib/mbedtls/library/cipher_wrap.c\n", + "CC ../../lib/mbedtls/library/nist_kw.c\n", + "CC ../../lib/mbedtls/library/aria.c\n", + "CC ../../lib/mbedtls/library/cmac.c\n", + "CC ../../lib/mbedtls/library/constant_time.c\n", + "CC ../../lib/mbedtls/library/mps_reader.c\n", + "CC ../../lib/mbedtls/library/mps_trace.c\n", + "CC ../../lib/mbedtls/library/ctr_drbg.c\n", + "CC ../../lib/mbedtls/library/debug.c\n", + "CC ../../lib/mbedtls/library/des.c\n", + "CC ../../lib/mbedtls/library/dhm.c\n", + "CC ../../lib/mbedtls/library/ecdh.c\n", + "CC ../../lib/mbedtls/library/ecdsa.c\n", + "CC ../../lib/mbedtls/library/ecjpake.c\n", + "CC ../../lib/mbedtls/library/ecp.c\n", + "CC ../../lib/mbedtls/library/ecp_curves.c\n", + "CC ../../lib/mbedtls/library/entropy.c\n", + "CC ../../lib/mbedtls/library/entropy_poll.c\n", + "CC ../../lib/mbedtls/library/gcm.c\n", + "CC ../../lib/mbedtls/library/hmac_drbg.c\n", + "CC ../../lib/mbedtls/library/md5.c\n", + "CC ../../lib/mbedtls/library/md.c\n", + "CC ../../lib/mbedtls/library/oid.c\n", + "CC ../../lib/mbedtls/library/padlock.c\n", + "CC ../../lib/mbedtls/library/pem.c\n", + "CC ../../lib/mbedtls/library/pk.c\n", + "CC ../../lib/mbedtls/library/pkcs12.c\n", + "CC ../../lib/mbedtls/library/pkcs5.c\n", + "CC ../../lib/mbedtls/library/pkparse.c\n", + "CC ../../lib/mbedtls/library/pk_ecc.c\n", + "CC ../../lib/mbedtls/library/pk_wrap.c\n", + "CC ../../lib/mbedtls/library/pkwrite.c\n", + "CC ../../lib/mbedtls/library/platform.c\n", + "CC ../../lib/mbedtls/library/platform_util.c\n", + "CC ../../lib/mbedtls/library/poly1305.c\n", + "CC ../../lib/mbedtls/library/ripemd160.c\n", + "CC ../../lib/mbedtls/library/rsa.c\n", + "CC ../../lib/mbedtls/library/rsa_alt_helpers.c\n", + "CC ../../lib/mbedtls/library/sha1.c\n", + "CC ../../lib/mbedtls/library/sha256.c\n", + "CC ../../lib/mbedtls/library/sha512.c\n", + "CC ../../lib/mbedtls/library/ssl_cache.c\n", + "CC ../../lib/mbedtls/library/ssl_ciphersuites.c\n", + "CC ../../lib/mbedtls/library/ssl_client.c\n", + "CC ../../lib/mbedtls/library/ssl_cookie.c\n", + "CC ../../lib/mbedtls/library/ssl_debug_helpers_generated.c\n", + "CC ../../lib/mbedtls/library/ssl_msg.c\n", + "CC ../../lib/mbedtls/library/ssl_ticket.c\n", + "CC ../../lib/mbedtls/library/ssl_tls.c\n", + "CC ../../lib/mbedtls/library/ssl_tls12_client.c\n", + "CC ../../lib/mbedtls/library/ssl_tls12_server.c\n", + "CC ../../lib/mbedtls/library/timing.c\n", + "CC ../../lib/mbedtls/library/x509.c\n", + "CC ../../lib/mbedtls/library/x509_create.c\n", + "CC ../../lib/mbedtls/library/x509_crl.c\n", + "CC ../../lib/mbedtls/library/x509_crt.c\n", + "CC ../../lib/mbedtls/library/x509_csr.c\n", + "CC ../../lib/mbedtls/library/x509write_crt.c\n", + "CC ../../lib/mbedtls/library/x509write_csr.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_close.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_conv.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_debug.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_delete.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_get.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_open.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_overflow.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_page.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_put.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_search.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_seq.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_split.c\n", + "CC ../../lib/berkeley-db-1.xx/btree/bt_utils.c\n", + "CC ../../lib/berkeley-db-1.xx/mpool/mpool.c\n", + "CC main.c\n", + "CC gccollect.c\n", + "CC unix_mphal.c\n", + "CC mpthreadport.c\n", + "CC input.c\n", + "CC alloc.c\n", + "CC fatfs_port.c\n", + "CC mpbthciport.c\n", + "CC mpbtstackport_common.c\n", + "CC mpbtstackport_h4.c\n", + "CC mpbtstackport_usb.c\n", + "CC mpnimbleport.c\n", + "CC modtermios.c\n", + "CC modsocket.c\n", + "CC modffi.c\n", + "CC modjni.c\n", + "CC ../../shared/runtime/gchelper_generic.c\n", + "CC ../../shared/timeutils/timeutils.c\n", + "CC ../../shared/readline/readline.c\n", + "LINK build-standard/micropython\n", + " text\t data\t bss\t dec\t hex\tfilename\n", + " 804612\t 84056\t 2992\t 891660\t d9b0c\tbuild-standard/micropython\n", + "make: Leaving directory '/home/jos/micropython/ports/unix'\n" + ] + } + ], + "source": [ + "# with modified mpportconfig\n", + "! make -C ports/unix " + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "902fbf50", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting test_settrace.py\n" + ] + } + ], + "source": [ + "%%writefile test_settrace.py\n", + "import sys\n", + "import json\n", + "from collections import OrderedDict as OD\n", + "\n", + "def tracer(frame, event, arg):\n", + " try:\n", + " # print(repr(frame) )\n", + " # print(dir(frame))\n", + " # for name in dir(frame):\n", + " # print(f\"{name} = {getattr(frame, name)}\")\n", + " # # print(f\"{json.dumps(frame)}\")\n", + " # print(f\"{frame.f_globals=}\")\n", + " print(f\"( {frame.f_lineno} , {frame.f_lasti} ) \", end=\"\")\n", + " # sort frame.f_locals by key , and add all k,v pairs to an OrderedDict\n", + " f_locals = OD(sorted(frame.f_locals.items()))\n", + " print(f\"{f_locals=}\")\n", + " print( type(f_locals[list(f_locals)[0]]))\n", + "\n", + " except Exception as e:\n", + " pass\n", + "\n", + " return tracer\n", + "\n", + "granny = \"granny\"\n", + "\n", + "def test():\n", + " foo = \"hello debugger\"\n", + " _under = \"this is an under variable\"\n", + " __dunder = \"this is a double under variable\"\n", + " bar = granny\n", + " a = 100\n", + " b = 2200\n", + " c = 33333\n", + " l = [1, 2, 3]\n", + " d = {\"a\": 1, \"b\": 2, \"c\": 3}\n", + " tuple1 = (1, 2, 3)\n", + " tuple2 = (a, b, c,a)\n", + " print(foo)\n", + " print(a+b+c)\n", + " long_name = a+ b + c\n", + " print(long_name)\n", + "\n", + "sys.settrace(tracer)\n", + "test()\n", + "sys.settrace(None)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "268565fd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "( 26 , 0 ) f_locals=OrderedDict({})\n", + "( 27 , 0 ) f_locals=OrderedDict({})\n", + "( 28 , 0 ) f_locals=OrderedDict({'foo': 'hello debugger', 'local_16': 'hello debugger'})\n", + "\n", + "( 29 , 0 ) f_locals=OrderedDict({'foo': 'this is an under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger'})\n", + "\n", + "( 30 , 0 ) f_locals=OrderedDict({'foo': 'this is a double under variable', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger'})\n", + "\n", + "( 31 , 0 ) f_locals=OrderedDict({'foo': 'granny', 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger'})\n", + "\n", + "( 32 , 0 ) f_locals=OrderedDict({'foo': 100, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100})\n", + "\n", + "( 33 , 0 ) f_locals=OrderedDict({'foo': 2200, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple2': 2200})\n", + "\n", + "( 34 , 0 ) f_locals=OrderedDict({'foo': 33333, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", + "\n", + "( 35 , 0 ) f_locals=OrderedDict({'__dunder': 3, '_under': 2, 'd': [1, 2, 3], 'foo': [1, 2, 3], 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", + "\n", + "( 36 , 0 ) f_locals=OrderedDict({'__dunder': 'c', '_under': 3, 'd': [1, 2, 3], 'foo': {'b': 2, 'c': 3, 'a': 1}, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", + "\n", + "( 37 , 0 ) f_locals=OrderedDict({'__dunder': 'c', '_under': 3, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': (1, 2, 3), 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", + "\n", + "( 38 , 0 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 2200, 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': (100, 2200, 33333, 100), 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", + "\n", + "hello debugger\n", + "( 39 , 59 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 'hello debugger', 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': None, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", + "\n", + "35633\n", + "( 40 , 69 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 35633, 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': None, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", + "\n", + "( 41 , 69 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 33333, 'a': 35633, 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': 35633, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", + "\n", + "35633\n", + "( 41 , 81 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 35633, 'a': 35633, 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': None, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", + "\n" + ] + } + ], + "source": [ + "! ./ports/unix/build-standard/micropython test_settrace.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc707a4e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 2f9968f58496969f0d8ac4ca49b77bb0727e589b Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Tue, 17 Jun 2025 14:32:27 +0200 Subject: [PATCH 3/6] Fixup : Rename Macros to standard. Signed-off-by: Jos Verlinde --- lib/micropython-lib | 2 +- .../unix/variants/standard/mpconfigvariant.h | 11 +- py/compile.c | 26 +-- py/debug_locals.c | 26 +-- py/debug_locals.h | 4 +- py/emitglue.c | 2 +- py/emitglue.h | 4 +- py/frame_f_locals.c | 213 ------------------ py/localnames.c | 46 ++-- py/localnames.h | 12 +- py/mpconfig.h | 4 +- py/objfun.c | 3 +- py/profile.c | 76 ++----- py/py.mk | 1 - py/rawcode_cleanup.c | 44 ---- py/rawcode_cleanup.h | 38 ---- 16 files changed, 89 insertions(+), 423 deletions(-) delete mode 100644 py/frame_f_locals.c delete mode 100644 py/rawcode_cleanup.c delete mode 100644 py/rawcode_cleanup.h diff --git a/lib/micropython-lib b/lib/micropython-lib index f345a0db99b9d..5b496e944ec04 160000 --- a/lib/micropython-lib +++ b/lib/micropython-lib @@ -1 +1 @@ -Subproject commit f345a0db99b9dc454ffcbfb13bfb68978467018d +Subproject commit 5b496e944ec045177afa1620920a168410b7f60b diff --git a/ports/unix/variants/standard/mpconfigvariant.h b/ports/unix/variants/standard/mpconfigvariant.h index ff493f5b3f233..644de1749a5d7 100644 --- a/ports/unix/variants/standard/mpconfigvariant.h +++ b/ports/unix/variants/standard/mpconfigvariant.h @@ -28,16 +28,7 @@ #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) #define MICROPY_PY_SYS_SETTRACE (1) -#define MICROPY_SAVE_LOCAL_VARIABLE_NAMES (1) // Save local variable names for debugging - -#define MICROPY_DEBUG_VERBOSE (0) - - -// Disable compiler optimizations for debugging -#define MICROPY_COMP_CONST (0) -#define MICROPY_COMP_MODULE_CONST (0) -#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) -#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#define MICROPY_PY_SYS_SETTRACE_SAVE_NAMES (1) // Save local variable names for debugging // Enable extra Unix features. diff --git a/py/compile.c b/py/compile.c index 1ea8dc2eb3608..2939f31b65e6a 100644 --- a/py/compile.c +++ b/py/compile.c @@ -38,7 +38,7 @@ #include "py/nativeglue.h" #include "py/persistentcode.h" #include "py/smallint.h" -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES #include "py/localnames.h" #endif @@ -3437,28 +3437,28 @@ static void scope_compute_things(scope_t *scope) { scope->num_locals += 1; } } - - #if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + + #if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES // Save the local variable names in the raw_code for debugging if (SCOPE_IS_FUNC_LIKE(scope->kind) && scope->num_locals > 0) { // Initialize local_names structure (already done in mp_emit_glue_new_raw_code) - + mp_printf(&mp_plat_print, "COMPILE: Saving local variable names for scope with %d locals\n", scope->num_locals); - + // Populate with variable names - examining the assignment order for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; - if ((id->kind == ID_INFO_KIND_LOCAL || id->kind == ID_INFO_KIND_CELL) && - id->local_num < scope->num_locals && - id->local_num < MP_LOCAL_NAMES_MAX) { - - mp_printf(&mp_plat_print, "COMPILE: Variable '%s' -> local_num=%d (kind=%d, flags=0x%x)\n", - qstr_str(id->qst), id->local_num, id->kind, id->flags); - + if ((id->kind == ID_INFO_KIND_LOCAL || id->kind == ID_INFO_KIND_CELL) && + id->local_num < scope->num_locals && + id->local_num < MICROPY_PY_SYS_SETTRACE_NAMES_MAX) { + + mp_printf(&mp_plat_print, "COMPILE: Variable '%s' -> local_num=%d (kind=%d, flags=0x%x)\n", + qstr_str(id->qst), id->local_num, id->kind, id->flags); + mp_local_names_add(&scope->raw_code->local_names, id->local_num, id->qst); } } - + mp_printf(&mp_plat_print, "COMPILE: Saved %d variable names\n", scope->raw_code->local_names.order_count); } #endif diff --git a/py/debug_locals.c b/py/debug_locals.c index 0f96c8fe5ac54..030e61070cf66 100644 --- a/py/debug_locals.c +++ b/py/debug_locals.c @@ -33,13 +33,13 @@ #include "py/runtime.h" #include "py/profile.h" -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES #include "py/localnames.h" // Debug function to print the actual local variable assignments void mp_debug_print_local_variables(const mp_raw_code_t *rc, const mp_obj_t *state, uint16_t n_state) { mp_printf(&mp_plat_print, "DEBUG: Local variable mapping for %p\n", rc); - + // First print by ordering information mp_printf(&mp_plat_print, "DEBUG: Variables in source order (order_count=%d):\n", rc->local_names.order_count); for (uint16_t idx = 0; idx < rc->local_names.order_count; idx++) { @@ -47,7 +47,7 @@ void mp_debug_print_local_variables(const mp_raw_code_t *rc, const mp_obj_t *sta if (local_num == UINT16_MAX) { continue; } - + qstr name = mp_local_names_get_name(&rc->local_names, local_num); mp_printf(&mp_plat_print, " [%d] local_num=%d, name=%q = ", idx, local_num, name); if (local_num < n_state && state[local_num] != MP_OBJ_NULL) { @@ -57,10 +57,10 @@ void mp_debug_print_local_variables(const mp_raw_code_t *rc, const mp_obj_t *sta } mp_printf(&mp_plat_print, "\n"); } - + // Print the direct mapping from local_num to name mp_printf(&mp_plat_print, "DEBUG: Direct local_num to name mapping:\n"); - for (uint16_t i = 0; i < MP_LOCAL_NAMES_MAX && i < n_state; i++) { + for (uint16_t i = 0; i < MICROPY_PY_SYS_SETTRACE_NAMES_MAX && i < n_state; i++) { qstr name = mp_local_names_get_name(&rc->local_names, i); if (name != MP_QSTRnull) { mp_printf(&mp_plat_print, " local_num %d = %q (", i, name); @@ -72,7 +72,7 @@ void mp_debug_print_local_variables(const mp_raw_code_t *rc, const mp_obj_t *sta mp_printf(&mp_plat_print, ")\n"); } } - + // Also print all values in the state array for reference mp_printf(&mp_plat_print, "DEBUG: Complete state array (n_state=%d):\n", n_state); for (uint16_t i = 0; i < n_state; i++) { @@ -92,20 +92,20 @@ mp_obj_t mp_debug_locals_info(void) { mp_print_str(&mp_plat_print, "No active code state or function\n"); return mp_const_none; } - + mp_print_str(&mp_plat_print, "\n=== DEBUG LOCALS INFO ===\n"); mp_printf(&mp_plat_print, "Code state: %p, n_state: %d\n", code_state, code_state->n_state); - + // Print function details const mp_raw_code_t *rc = code_state->fun_bc->rc; - mp_printf(&mp_plat_print, "Function: prelude.n_pos_args=%d, prelude.n_kwonly_args=%d\n", - rc->prelude.n_pos_args, rc->prelude.n_kwonly_args); - + mp_printf(&mp_plat_print, "Function: prelude.n_pos_args=%d, prelude.n_kwonly_args=%d\n", + rc->prelude.n_pos_args, rc->prelude.n_kwonly_args); + // Print the mappings and the state values mp_debug_print_local_variables(rc, code_state->state, code_state->n_state); - + mp_print_str(&mp_plat_print, "=== END DEBUG INFO ===\n\n"); return mp_const_none; } -#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#endif // MICROPY_PY_SYS_SETTRACE_SAVE_NAMES diff --git a/py/debug_locals.h b/py/debug_locals.h index 7523d9d501e7f..06f468844463f 100644 --- a/py/debug_locals.h +++ b/py/debug_locals.h @@ -30,9 +30,9 @@ #include "py/obj.h" #include "py/emitglue.h" -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES // Debug function to print the actual local variable assignments void mp_debug_print_local_variables(const mp_raw_code_t *rc, const mp_obj_t *state, uint16_t n_state); -#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#endif // MICROPY_PY_SYS_SETTRACE_SAVE_NAMES #endif // MICROPY_INCLUDED_PY_DEBUG_LOCALS_H diff --git a/py/emitglue.c b/py/emitglue.c index d71812683a1d9..a1ec52f11a74f 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -57,7 +57,7 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) { #if MICROPY_PY_SYS_SETTRACE rc->line_of_definition = 0; #endif - #if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + #if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES mp_local_names_init(&rc->local_names); #endif return rc; diff --git a/py/emitglue.h b/py/emitglue.h index b1b6a71ea1ed9..1c2fffd23f7eb 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -28,7 +28,7 @@ #include "py/obj.h" #include "py/bc.h" -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES #include "py/localnames.h" #endif @@ -99,7 +99,7 @@ typedef struct _mp_raw_code_t { uint32_t asm_n_pos_args : 8; uint32_t asm_type_sig : 24; // compressed as 2-bit types; ret is MSB, then arg0, arg1, etc #endif - #if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + #if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES mp_local_names_t local_names; // Maps local variable indices to names #endif } mp_raw_code_t; diff --git a/py/frame_f_locals.c b/py/frame_f_locals.c deleted file mode 100644 index 2d66b0619a6c6..0000000000000 --- a/py/frame_f_locals.c +++ /dev/null @@ -1,213 +0,0 @@ -static mp_obj_t frame_f_locals(mp_obj_t self_in) { - mp_printf(&mp_plat_print, "\n*** FRAME_F_LOCALS CALLED! DEBUG OUTPUT SHOULD FOLLOW ***\n"); - - // This function returns a dictionary of local variables in the current frame. - if (gc_is_locked()) { - return MP_OBJ_NULL; // Cannot create locals dict when GC is locked - } - mp_obj_frame_t *frame = MP_OBJ_TO_PTR(self_in); - mp_obj_dict_t *locals_dict = mp_obj_new_dict(frame->code_state->n_state); // Preallocate dictionary size - - const mp_code_state_t *code_state = frame->code_state; - - // Validate state array - if (code_state == NULL || code_state->state == NULL) { - return MP_OBJ_FROM_PTR(locals_dict); // Return empty dictionary if state is invalid - } - -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES - // Try to use the saved variable names if available - const mp_raw_code_t *raw_code = code_state->fun_bc->rc; - - // Debug: Print prelude info - mp_printf(&mp_plat_print, "DEBUG: n_pos_args=%d, n_kwonly_args=%d, n_def_pos_args=%d\n", - raw_code->prelude.n_pos_args, raw_code->prelude.n_kwonly_args, - raw_code->prelude.n_def_pos_args); - - // Debug: Print local variable name mappings - mp_printf(&mp_plat_print, "DEBUG: LOCAL VARIABLE NAMES MAPPING:\n"); - for (uint16_t i = 0; i < MP_LOCAL_NAMES_MAX && i < code_state->n_state; i++) { - qstr name = mp_local_names_get_name(&raw_code->local_names, i); - if (name != MP_QSTRnull) { - mp_printf(&mp_plat_print, " index %d = %s ", i, qstr_str(name)); - if (i < code_state->n_state && code_state->state[i] != MP_OBJ_NULL) { - mp_obj_print(code_state->state[i], PRINT_REPR); - } else { - mp_printf(&mp_plat_print, "NULL"); - } - mp_printf(&mp_plat_print, "\n"); - } - } - - // First loop: process function parameters, which should have fixed positions - uint16_t n_pos_args = raw_code->prelude.n_pos_args; - uint16_t n_kwonly_args = raw_code->prelude.n_kwonly_args; - - for (uint16_t i = 0; i < n_pos_args + n_kwonly_args && i < code_state->n_state; i++) { - if (code_state->state[i] == NULL) { - continue; - } - - // Try to get parameter name - qstr var_name_qstr = MP_QSTRnull; - if (i < MP_LOCAL_NAMES_MAX) { - var_name_qstr = mp_local_names_get_name(&raw_code->local_names, i); - } - - // Use generic name if needed - if (var_name_qstr == MP_QSTRnull) { - char var_name[16]; - snprintf(var_name, sizeof(var_name), "arg_%d", (int)(i + 1)); - var_name_qstr = qstr_from_str(var_name); - if (var_name_qstr == MP_QSTR_NULL) { - continue; - } - } - - // Store parameter - mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); - } - - // Process other variables - we'll use the order of definition when possible - bool used_names[MP_LOCAL_NAMES_MAX] = {false}; - - // Second loop: match names to variables using CORRECTED slot mapping - // HYPOTHESIS TEST: Variables might be assigned from highest slot number down - // This would explain why debugger shows wrong variable mappings - - uint16_t total_locals = code_state->n_state; - uint16_t param_count = n_pos_args + n_kwonly_args; - uint16_t available_local_slots = total_locals - param_count; - - mp_printf(&mp_plat_print, "DEBUG: TESTING REVERSE SLOT ASSIGNMENT\n"); - mp_printf(&mp_plat_print, "DEBUG: Total slots=%d, Params=%d, Available for locals=%d\n", - total_locals, param_count, available_local_slots); - - // Print all non-NULL state values to understand the layout - mp_printf(&mp_plat_print, "DEBUG: State array contents:\n"); - for (uint16_t i = 0; i < total_locals; i++) { - if (code_state->state[i] != NULL) { - mp_printf(&mp_plat_print, " state[%d] = ", i); - mp_obj_print(code_state->state[i], PRINT_REPR); - mp_printf(&mp_plat_print, "\n"); - } else { - mp_printf(&mp_plat_print, " state[%d] = NULL\n", i); - } - } - - // Test different slot assignment strategies for each variable - for (uint16_t order_idx = 0; order_idx < raw_code->local_names.order_count; order_idx++) { - uint16_t local_num = mp_local_names_get_local_num(&raw_code->local_names, order_idx); - if (local_num == UINT16_MAX || local_num >= MP_LOCAL_NAMES_MAX || - local_num < param_count) { - continue; // Skip parameters already handled - } - - qstr var_name_qstr = mp_local_names_get_name(&raw_code->local_names, local_num); - if (var_name_qstr == MP_QSTRnull) { - continue; - } - - mp_printf(&mp_plat_print, "DEBUG: Variable '%s' (compile_local_num=%d, source_order=%d)\n", - qstr_str(var_name_qstr), local_num, order_idx); - - // Strategy A: Current (broken) approach - direct local_num mapping - uint16_t slot_direct = local_num; - - // Strategy B: Sequential assignment after parameters - uint16_t slot_sequential = param_count + order_idx; - - // Strategy C: REVERSE ASSIGNMENT (testing hypothesis) - // First variable gets highest slot, last variable gets lowest slot - uint16_t slot_reverse = total_locals - 1 - order_idx; - - // Strategy D: Try runtime slot from local_names if available - uint16_t runtime_slot = mp_local_names_get_runtime_slot(&raw_code->local_names, local_num); - uint16_t slot_runtime = (runtime_slot != UINT16_MAX) ? runtime_slot + param_count : slot_direct; - - mp_printf(&mp_plat_print, " Slot strategies: direct=%d, sequential=%d, reverse=%d, runtime=%d\n", - slot_direct, slot_sequential, slot_reverse, slot_runtime); - - // FIXED: Use reverse slot assignment (hypothesis confirmed by user's debugger issue) - // Variables are assigned from highest slot down, so first variable gets highest slot - uint16_t correct_slot = slot_reverse; - - mp_printf(&mp_plat_print, " FIXED: Using REVERSE slot assignment: '%s' -> slot %d\n", - qstr_str(var_name_qstr), correct_slot); - - // Validate and assign - if (correct_slot < total_locals && correct_slot >= param_count && - code_state->state[correct_slot] != NULL && !used_names[correct_slot]) { - - mp_printf(&mp_plat_print, " SUCCESS: Variable '%s' correctly mapped to state[%d] = ", - qstr_str(var_name_qstr), correct_slot); - mp_obj_print(code_state->state[correct_slot], PRINT_REPR); - mp_printf(&mp_plat_print, "\n"); - - mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[correct_slot]); - used_names[correct_slot] = true; - - } else { - // Fallback: try other strategies if reverse fails - mp_printf(&mp_plat_print, " WARNING: Reverse slot assignment failed, trying fallbacks\n"); - - uint16_t candidate_slots[] = {slot_runtime, slot_sequential, slot_direct}; - const char* strategy_names[] = {"RUNTIME", "SEQUENTIAL", "DIRECT"}; - - bool value_assigned = false; - for (int strategy = 0; strategy < 3 && !value_assigned; strategy++) { - uint16_t slot = candidate_slots[strategy]; - - if (slot < total_locals && slot >= param_count && - code_state->state[slot] != NULL && !used_names[slot]) { - - mp_printf(&mp_plat_print, " FALLBACK: %s strategy maps '%s' to state[%d]\n", - strategy_names[strategy], qstr_str(var_name_qstr), slot); - - mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[slot]); - used_names[slot] = true; - value_assigned = true; - } - } - - if (!value_assigned) { - mp_printf(&mp_plat_print, " ERROR: No valid slot found for '%s'\n", qstr_str(var_name_qstr)); - } - } - if (!value_assigned) { - mp_printf(&mp_plat_print, " ERROR: No valid slot found for '%s'\n", qstr_str(var_name_qstr)); - } - } - - // Third loop: add any remaining values with generic names - for (uint16_t i = n_pos_args + n_kwonly_args; i < code_state->n_state; i++) { - if (code_state->state[i] != NULL && !used_names[i]) { - char var_name[16]; - snprintf(var_name, sizeof(var_name), "var_%d", (int)(i + 1)); - qstr var_name_qstr = qstr_from_str(var_name); - if (var_name_qstr != MP_QSTR_NULL) { - mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); - } - } - } -#else - // Fallback logic: Use generic names for local variables - for (uint16_t i = 0; i < code_state->n_state; i++) { - char var_name[16]; - snprintf(var_name, sizeof(var_name), "local_%02d", (int)(i + 1)); - // Validate value in state array - if (code_state->state[i] == NULL) { - continue; // Skip invalid values - } - // Check memory allocation for variable name - qstr var_name_qstr = qstr_from_str(var_name); - if (var_name_qstr == MP_QSTR_NULL) { - continue; // Skip if qstr creation fails - } - // Store the name-value pair in the dictionary - mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); - } -#endif - - return MP_OBJ_FROM_PTR(locals_dict); -} diff --git a/py/localnames.c b/py/localnames.c index 4f52de4233dbb..ddc4d36412b38 100644 --- a/py/localnames.c +++ b/py/localnames.c @@ -27,19 +27,19 @@ #include "py/runtime.h" #include "py/localnames.h" -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES // Initialize the local names structure void mp_local_names_init(mp_local_names_t *local_names) { if (local_names == NULL) { return; } - + local_names->num_locals = 0; local_names->order_count = 0; - + // Initialize all entries with null qstrs and invalid indices - for (uint16_t i = 0; i < MP_LOCAL_NAMES_MAX; i++) { + for (uint16_t i = 0; i < MICROPY_PY_SYS_SETTRACE_NAMES_MAX; i++) { local_names->local_names[i] = MP_QSTRnull; local_names->local_nums[i] = UINT16_MAX; // Invalid index marker } @@ -47,10 +47,10 @@ void mp_local_names_init(mp_local_names_t *local_names) { // Get the name of a local variable by its index qstr mp_local_names_get_name(const mp_local_names_t *local_names, uint16_t local_num) { - if (local_names == NULL || local_num >= MP_LOCAL_NAMES_MAX) { + if (local_names == NULL || local_num >= MICROPY_PY_SYS_SETTRACE_NAMES_MAX) { return MP_QSTRnull; } - + // Direct array access return local_names->local_names[local_num]; } @@ -60,19 +60,19 @@ uint16_t mp_local_names_get_local_num(const mp_local_names_t *local_names, uint1 if (local_names == NULL || order_idx >= local_names->order_count) { return UINT16_MAX; // Invalid index } - + return local_names->local_nums[order_idx]; } // Add or update a name mapping for a local variable void mp_local_names_add(mp_local_names_t *local_names, uint16_t local_num, qstr qstr_name) { - if (local_names == NULL || local_num >= MP_LOCAL_NAMES_MAX) { + if (local_names == NULL || local_num >= MICROPY_PY_SYS_SETTRACE_NAMES_MAX) { return; } // Debug the mapping - mp_printf(&mp_plat_print, "DEBUG_ADD_NAME: Adding local name mapping: slot %d -> '%s'\n", - local_num, qstr_str(qstr_name)); + mp_printf(&mp_plat_print, "DEBUG_ADD_NAME: Adding local name mapping: slot %d -> '%s'\n", + local_num, qstr_str(qstr_name)); // Store name directly using local_num as index local_names->local_names[local_num] = qstr_name; @@ -83,40 +83,40 @@ void mp_local_names_add(mp_local_names_t *local_names, uint16_t local_num, qstr } // Also store in order of definition for correct runtime mapping - if (local_names->order_count < MP_LOCAL_NAMES_MAX) { + if (local_names->order_count < MICROPY_PY_SYS_SETTRACE_NAMES_MAX) { uint16_t idx = local_names->order_count; local_names->local_nums[idx] = local_num; local_names->order_count++; // Debug the order mapping - mp_printf(&mp_plat_print, "DEBUG_ORDER_MAP: Source order idx %d -> runtime slot %d\n", - idx, local_num); + mp_printf(&mp_plat_print, "DEBUG_ORDER_MAP: Source order idx %d -> runtime slot %d\n", + idx, local_num); } // Enhance debug output to capture runtime behavior - mp_printf(&mp_plat_print, "DEBUG_RUNTIME_SLOT: Local %d ('%s') -> Runtime Slot calculation\n", - local_num, qstr_str(qstr_name)); + mp_printf(&mp_plat_print, "DEBUG_RUNTIME_SLOT: Local %d ('%s') -> Runtime Slot calculation\n", + local_num, qstr_str(qstr_name)); // Refine runtime slot mapping logic // Test the hypothesis that variables are assigned from highest slots down uint16_t runtime_slot = local_num; // Default to direct mapping - + if (local_names->order_count > 0) { // Find position in order array for (uint16_t i = 0; i < local_names->order_count; ++i) { if (local_names->local_nums[i] == local_num) { // Try different slot assignment strategies - + // Strategy 1: Sequential after parameters (traditional) runtime_slot = i; - + // Strategy 2: Reverse order assignment (testing hypothesis) // This would assign first variable to highest available slot - // uint16_t reverse_slot = MP_LOCAL_NAMES_MAX - 1 - i; + // uint16_t reverse_slot = MICROPY_PY_SYS_SETTRACE_NAMES_MAX - 1 - i; // runtime_slot = reverse_slot; - + mp_printf(&mp_plat_print, "DEBUG_RUNTIME_SLOT: Variable '%s' order_idx=%d -> runtime_slot=%d\n", - qstr_str(qstr_name), i, runtime_slot); + qstr_str(qstr_name), i, runtime_slot); break; } } @@ -126,10 +126,10 @@ void mp_local_names_add(mp_local_names_t *local_names, uint16_t local_num, qstr // Get the runtime slot for a local variable by its index uint16_t mp_local_names_get_runtime_slot(const mp_local_names_t *local_names, uint16_t local_num) { - if (local_names == NULL || local_num >= MP_LOCAL_NAMES_MAX) { + if (local_names == NULL || local_num >= MICROPY_PY_SYS_SETTRACE_NAMES_MAX) { return UINT16_MAX; // Invalid slot } return local_names->runtime_slots[local_num]; } -#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#endif // MICROPY_PY_SYS_SETTRACE_SAVE_NAMES diff --git a/py/localnames.h b/py/localnames.h index a6ccd7570649f..fc968c56b6ab0 100644 --- a/py/localnames.h +++ b/py/localnames.h @@ -30,17 +30,17 @@ #include "py/obj.h" #include "py/qstr.h" -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES -#define MP_LOCAL_NAMES_MAX 32 // Maximum number of local variables to store names for +#define MICROPY_PY_SYS_SETTRACE_NAMES_MAX 32 // Maximum number of local variables to store names for // Structure to hold variable name mappings for a function scope typedef struct _mp_local_names_t { uint16_t num_locals; // Total number of local variables with names - qstr local_names[MP_LOCAL_NAMES_MAX]; // Array of variable names, indexed by local_num - uint16_t local_nums[MP_LOCAL_NAMES_MAX]; // Reverse mapping: name index -> local_num (for correct state array mapping) + qstr local_names[MICROPY_PY_SYS_SETTRACE_NAMES_MAX]; // Array of variable names, indexed by local_num + uint16_t local_nums[MICROPY_PY_SYS_SETTRACE_NAMES_MAX]; // Reverse mapping: name index -> local_num (for correct state array mapping) uint16_t order_count; // Number of variables stored in order they were defined - uint16_t runtime_slots[MP_LOCAL_NAMES_MAX]; // Mapping of local_num to runtime slots + uint16_t runtime_slots[MICROPY_PY_SYS_SETTRACE_NAMES_MAX]; // Mapping of local_num to runtime slots } mp_local_names_t; // Initialize the local names structure @@ -58,6 +58,6 @@ void mp_local_names_add(mp_local_names_t *local_names, uint16_t local_num, qstr // Function to get the runtime slot of a local variable by its index uint16_t mp_local_names_get_runtime_slot(const mp_local_names_t *local_names, uint16_t local_num); -#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#endif // MICROPY_PY_SYS_SETTRACE_SAVE_NAMES #endif // MICROPY_INCLUDED_PY_LOCALNAMES_H diff --git a/py/mpconfig.h b/py/mpconfig.h index 48e906b5676d3..d0e7db64410d5 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -239,8 +239,8 @@ #endif // If not explicitly enabled, disable local variable name saving -#ifndef MICROPY_SAVE_LOCAL_VARIABLE_NAMES -#define MICROPY_SAVE_LOCAL_VARIABLE_NAMES (0) +#ifndef MICROPY_PY_SYS_SETTRACE_SAVE_NAMES +#define MICROPY_PY_SYS_SETTRACE_SAVE_NAMES (0) #endif // Strings this length or less will be interned by the parser diff --git a/py/objfun.c b/py/objfun.c index fcdef5c975451..088c013c57ae6 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -36,9 +36,8 @@ #include "py/bc.h" #include "py/stackctrl.h" #include "py/profile.h" -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES #include "py/localnames.h" -#include "py/rawcode_cleanup.h" #endif #if MICROPY_DEBUG_VERBOSE // print debugging info diff --git a/py/profile.c b/py/profile.c index 05317125b8141..1b7464b6386b7 100644 --- a/py/profile.c +++ b/py/profile.c @@ -28,7 +28,7 @@ #include "py/bc0.h" #include "py/gc.h" #include "py/objfun.h" -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES +#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES #include "py/localnames.h" #endif @@ -136,8 +136,6 @@ static void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } static mp_obj_t frame_f_locals(mp_obj_t self_in) { - mp_printf(&mp_plat_print, "\n*** FRAME_F_LOCALS CALLED! IMPLEMENTING REVERSE SLOT ASSIGNMENT FIX ***\n"); - // This function returns a dictionary of local variables in the current frame. if (gc_is_locked()) { return MP_OBJ_NULL; // Cannot create locals dict when GC is locked @@ -151,30 +149,25 @@ static mp_obj_t frame_f_locals(mp_obj_t self_in) { return MP_OBJ_FROM_PTR(locals_dict); // Return empty dictionary if state is invalid } -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES + #if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES const mp_raw_code_t *raw_code = code_state->fun_bc->rc; - - mp_printf(&mp_plat_print, "DEBUG: Processing frame with %d state slots\n", code_state->n_state); - + // First, handle function parameters (these should have fixed positions) uint16_t n_pos_args = raw_code->prelude.n_pos_args; uint16_t n_kwonly_args = raw_code->prelude.n_kwonly_args; uint16_t param_count = n_pos_args + n_kwonly_args; - - mp_printf(&mp_plat_print, "DEBUG: Parameters: %d positional + %d keyword-only = %d total\n", - n_pos_args, n_kwonly_args, param_count); - + // Add parameters first (they have fixed slot assignments) for (uint16_t i = 0; i < param_count && i < code_state->n_state; i++) { if (code_state->state[i] == NULL) { continue; } - + qstr var_name_qstr = MP_QSTRnull; - if (i < MP_LOCAL_NAMES_MAX) { + if (i < MICROPY_PY_SYS_SETTRACE_NAMES_MAX) { var_name_qstr = mp_local_names_get_name(&raw_code->local_names, i); } - + if (var_name_qstr == MP_QSTRnull) { char var_name[16]; snprintf(var_name, sizeof(var_name), "arg_%d", (int)(i + 1)); @@ -183,79 +176,59 @@ static mp_obj_t frame_f_locals(mp_obj_t self_in) { continue; } } - - mp_printf(&mp_plat_print, "DEBUG: Parameter '%s' -> slot %d\n", qstr_str(var_name_qstr), i); - mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); } - - // FIXED: Handle local variables with REVERSE SLOT ASSIGNMENT - // The bug was that variables are assigned from highest slot down, not sequentially up - bool used_slots[MP_LOCAL_NAMES_MAX] = {false}; - + + // Handle local variables with REVERSE SLOT ASSIGNMENT + bool used_slots[MICROPY_PY_SYS_SETTRACE_NAMES_MAX] = {false}; + // Mark parameter slots as used for (uint16_t i = 0; i < param_count; i++) { - if (i < MP_LOCAL_NAMES_MAX) { + if (i < MICROPY_PY_SYS_SETTRACE_NAMES_MAX) { used_slots[i] = true; } } - + // Process variables using their source order but REVERSE slot assignment for (uint16_t order_idx = 0; order_idx < raw_code->local_names.order_count; order_idx++) { uint16_t local_num = mp_local_names_get_local_num(&raw_code->local_names, order_idx); - - // Skip parameters and invalid entries + + // Skip parameters and invalid entries if (local_num == UINT16_MAX || local_num < param_count) { continue; } - + qstr var_name_qstr = mp_local_names_get_name(&raw_code->local_names, local_num); if (var_name_qstr == MP_QSTRnull) { continue; } - + // REVERSE SLOT ASSIGNMENT: Variables assigned from highest available slot down - // This is the key fix for the debugger mapping issue uint16_t total_locals = code_state->n_state; uint16_t reverse_slot = total_locals - 1 - order_idx; - - mp_printf(&mp_plat_print, "DEBUG: Variable '%s' (order %d) -> REVERSE slot %d\n", - qstr_str(var_name_qstr), order_idx, reverse_slot); - // Validate and assign - if (reverse_slot >= param_count && reverse_slot < total_locals && + if (reverse_slot >= param_count && reverse_slot < total_locals && code_state->state[reverse_slot] != NULL && !used_slots[reverse_slot]) { - - mp_printf(&mp_plat_print, "SUCCESS: '%s' mapped to state[%d] = ", qstr_str(var_name_qstr), reverse_slot); - mp_obj_print(code_state->state[reverse_slot], PRINT_REPR); - mp_printf(&mp_plat_print, "\n"); - mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[reverse_slot]); used_slots[reverse_slot] = true; - } else { - mp_printf(&mp_plat_print, "WARNING: Reverse slot assignment failed for '%s', slot %d\n", - qstr_str(var_name_qstr), reverse_slot); - // Fallback: try runtime slot or direct mapping uint16_t runtime_slot = mp_local_names_get_runtime_slot(&raw_code->local_names, local_num); - if (runtime_slot != UINT16_MAX && runtime_slot < total_locals && + if (runtime_slot != UINT16_MAX && runtime_slot < total_locals && code_state->state[runtime_slot] != NULL && !used_slots[runtime_slot]) { - - mp_printf(&mp_plat_print, "FALLBACK: Using runtime slot %d for '%s'\n", - runtime_slot, qstr_str(var_name_qstr)); mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[runtime_slot]); used_slots[runtime_slot] = true; } } } - -#else + + #else // Fallback when variable names aren't saved + // TODO: Use reversed slot order here as well for (size_t i = 0; i < code_state->n_state; ++i) { if (code_state->state[i] == NULL) { continue; } - + char var_name[16]; snprintf(var_name, sizeof(var_name), "local_%02d", (int)(i + 1)); qstr var_name_qstr = qstr_from_str(var_name); @@ -264,9 +237,8 @@ static mp_obj_t frame_f_locals(mp_obj_t self_in) { } mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); } -#endif + #endif - mp_printf(&mp_plat_print, "*** FRAME_F_LOCALS COMPLETED ***\n"); return MP_OBJ_FROM_PTR(locals_dict); } diff --git a/py/py.mk b/py/py.mk index aaeaff9364ad4..c13023814fce0 100644 --- a/py/py.mk +++ b/py/py.mk @@ -142,7 +142,6 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ warning.o \ profile.o \ localnames.o \ - rawcode_cleanup.o \ debug_locals.o \ map.o \ obj.o \ diff --git a/py/rawcode_cleanup.c b/py/rawcode_cleanup.c deleted file mode 100644 index cfafc6e17f18d..0000000000000 --- a/py/rawcode_cleanup.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2025 Contributors to the MicroPython project - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// This file contains functions to clean up the raw code objects and local variable names -// when the runtime is done with them. Since MicroPython doesn't explicitly free raw code -// objects, we need to add this functionality. - -#include "py/runtime.h" -#include "py/emitglue.h" - -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES -#include "py/localnames.h" - -// Function to free local variable names associated with a raw code -void mp_raw_code_free_local_names(const mp_raw_code_t *rc) { - // With the new design, we don't need to free anything - // The local_names are now part of the raw_code structure directly - (void)rc; // Prevent unused parameter warning -} - -#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES diff --git a/py/rawcode_cleanup.h b/py/rawcode_cleanup.h deleted file mode 100644 index a74edf192c4fb..0000000000000 --- a/py/rawcode_cleanup.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2025 Contributors to the MicroPython project - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef MICROPY_INCLUDED_PY_RAWCODECLEANUP_H -#define MICROPY_INCLUDED_PY_RAWCODECLEANUP_H - -#include "py/obj.h" -#include "py/emitglue.h" - -#if MICROPY_SAVE_LOCAL_VARIABLE_NAMES -// Function to free local variable names associated with a raw code -void mp_raw_code_free_local_names(const mp_raw_code_t *rc); -#endif // MICROPY_SAVE_LOCAL_VARIABLE_NAMES - -#endif // MICROPY_INCLUDED_PY_RAWCODECLEANUP_H From 9afe2a917ef31a88888cd0e123c8b147ccb23f3b Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Tue, 17 Jun 2025 14:50:02 +0200 Subject: [PATCH 4/6] py/profile: Fix naming for placeholder local variable names. Signed-off-by: Jos Verlinde --- .../unix/variants/standard/mpconfigvariant.h | 4 +- py/compile.c | 12 +- py/debug_locals.c | 111 --- py/debug_locals.h | 38 - py/localnames.c | 25 +- py/profile.c | 19 +- py/py.mk | 1 - test_settrace.py | 45 -- tracer.ipynb | 751 ------------------ 9 files changed, 14 insertions(+), 992 deletions(-) delete mode 100644 py/debug_locals.c delete mode 100644 py/debug_locals.h delete mode 100644 test_settrace.py delete mode 100644 tracer.ipynb diff --git a/ports/unix/variants/standard/mpconfigvariant.h b/ports/unix/variants/standard/mpconfigvariant.h index 644de1749a5d7..024b08fec7245 100644 --- a/ports/unix/variants/standard/mpconfigvariant.h +++ b/ports/unix/variants/standard/mpconfigvariant.h @@ -27,8 +27,8 @@ // Set base feature level. #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) -#define MICROPY_PY_SYS_SETTRACE (1) -#define MICROPY_PY_SYS_SETTRACE_SAVE_NAMES (1) // Save local variable names for debugging +// #define MICROPY_PY_SYS_SETTRACE (1) +// #define MICROPY_PY_SYS_SETTRACE_SAVE_NAMES (1) // Save local variable names for debugging // Enable extra Unix features. diff --git a/py/compile.c b/py/compile.c index 2939f31b65e6a..219fcf57eecab 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3441,25 +3441,15 @@ static void scope_compute_things(scope_t *scope) { #if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES // Save the local variable names in the raw_code for debugging if (SCOPE_IS_FUNC_LIKE(scope->kind) && scope->num_locals > 0) { - // Initialize local_names structure (already done in mp_emit_glue_new_raw_code) - - mp_printf(&mp_plat_print, "COMPILE: Saving local variable names for scope with %d locals\n", scope->num_locals); - - // Populate with variable names - examining the assignment order + // Initialize local_names structure with variable names for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; if ((id->kind == ID_INFO_KIND_LOCAL || id->kind == ID_INFO_KIND_CELL) && id->local_num < scope->num_locals && id->local_num < MICROPY_PY_SYS_SETTRACE_NAMES_MAX) { - - mp_printf(&mp_plat_print, "COMPILE: Variable '%s' -> local_num=%d (kind=%d, flags=0x%x)\n", - qstr_str(id->qst), id->local_num, id->kind, id->flags); - mp_local_names_add(&scope->raw_code->local_names, id->local_num, id->qst); } } - - mp_printf(&mp_plat_print, "COMPILE: Saved %d variable names\n", scope->raw_code->local_names.order_count); } #endif diff --git a/py/debug_locals.c b/py/debug_locals.c deleted file mode 100644 index 030e61070cf66..0000000000000 --- a/py/debug_locals.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2025 Contributors to the MicroPython project - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/mpprint.h" -#include "py/qstr.h" -#include "py/obj.h" -#include "py/bc.h" -#include "py/objfun.h" -#include "py/scope.h" -#include "py/runtime.h" -#include "py/profile.h" - -#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES -#include "py/localnames.h" - -// Debug function to print the actual local variable assignments -void mp_debug_print_local_variables(const mp_raw_code_t *rc, const mp_obj_t *state, uint16_t n_state) { - mp_printf(&mp_plat_print, "DEBUG: Local variable mapping for %p\n", rc); - - // First print by ordering information - mp_printf(&mp_plat_print, "DEBUG: Variables in source order (order_count=%d):\n", rc->local_names.order_count); - for (uint16_t idx = 0; idx < rc->local_names.order_count; idx++) { - uint16_t local_num = mp_local_names_get_local_num(&rc->local_names, idx); - if (local_num == UINT16_MAX) { - continue; - } - - qstr name = mp_local_names_get_name(&rc->local_names, local_num); - mp_printf(&mp_plat_print, " [%d] local_num=%d, name=%q = ", idx, local_num, name); - if (local_num < n_state && state[local_num] != MP_OBJ_NULL) { - mp_obj_print(state[local_num], PRINT_REPR); - } else { - mp_printf(&mp_plat_print, "NULL or out of range"); - } - mp_printf(&mp_plat_print, "\n"); - } - - // Print the direct mapping from local_num to name - mp_printf(&mp_plat_print, "DEBUG: Direct local_num to name mapping:\n"); - for (uint16_t i = 0; i < MICROPY_PY_SYS_SETTRACE_NAMES_MAX && i < n_state; i++) { - qstr name = mp_local_names_get_name(&rc->local_names, i); - if (name != MP_QSTRnull) { - mp_printf(&mp_plat_print, " local_num %d = %q (", i, name); - if (i < n_state && state[i] != MP_OBJ_NULL) { - mp_obj_print(state[i], PRINT_REPR); - } else { - mp_printf(&mp_plat_print, "NULL"); - } - mp_printf(&mp_plat_print, ")\n"); - } - } - - // Also print all values in the state array for reference - mp_printf(&mp_plat_print, "DEBUG: Complete state array (n_state=%d):\n", n_state); - for (uint16_t i = 0; i < n_state; i++) { - mp_printf(&mp_plat_print, " state[%d] = ", i); - if (state[i] != MP_OBJ_NULL) { - mp_obj_print(state[i], PRINT_REPR); - } else { - mp_printf(&mp_plat_print, "NULL"); - } - mp_printf(&mp_plat_print, "\n"); - } -} -// This is exposed as debug_locals_info() in the sys module -mp_obj_t mp_debug_locals_info(void) { - mp_code_state_t *code_state = MP_STATE_THREAD(current_code_state); - if (code_state == NULL || code_state->fun_bc == NULL || code_state->fun_bc->rc == NULL) { - mp_print_str(&mp_plat_print, "No active code state or function\n"); - return mp_const_none; - } - - mp_print_str(&mp_plat_print, "\n=== DEBUG LOCALS INFO ===\n"); - mp_printf(&mp_plat_print, "Code state: %p, n_state: %d\n", code_state, code_state->n_state); - - // Print function details - const mp_raw_code_t *rc = code_state->fun_bc->rc; - mp_printf(&mp_plat_print, "Function: prelude.n_pos_args=%d, prelude.n_kwonly_args=%d\n", - rc->prelude.n_pos_args, rc->prelude.n_kwonly_args); - - // Print the mappings and the state values - mp_debug_print_local_variables(rc, code_state->state, code_state->n_state); - - mp_print_str(&mp_plat_print, "=== END DEBUG INFO ===\n\n"); - return mp_const_none; -} - -#endif // MICROPY_PY_SYS_SETTRACE_SAVE_NAMES diff --git a/py/debug_locals.h b/py/debug_locals.h deleted file mode 100644 index 06f468844463f..0000000000000 --- a/py/debug_locals.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2025 Contributors to the MicroPython project - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef MICROPY_INCLUDED_PY_DEBUG_LOCALS_H -#define MICROPY_INCLUDED_PY_DEBUG_LOCALS_H - -#include "py/obj.h" -#include "py/emitglue.h" - -#if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES -// Debug function to print the actual local variable assignments -void mp_debug_print_local_variables(const mp_raw_code_t *rc, const mp_obj_t *state, uint16_t n_state); -#endif // MICROPY_PY_SYS_SETTRACE_SAVE_NAMES - -#endif // MICROPY_INCLUDED_PY_DEBUG_LOCALS_H diff --git a/py/localnames.c b/py/localnames.c index ddc4d36412b38..90bbe01adf4e8 100644 --- a/py/localnames.c +++ b/py/localnames.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2025 Contributors to the MicroPython project + * Copyright (c) 2025 Jos Verlinde * * Permission is hereby granted, free * of this software and associated documentation files (the "Software"), to deal @@ -70,10 +70,6 @@ void mp_local_names_add(mp_local_names_t *local_names, uint16_t local_num, qstr return; } - // Debug the mapping - mp_printf(&mp_plat_print, "DEBUG_ADD_NAME: Adding local name mapping: slot %d -> '%s'\n", - local_num, qstr_str(qstr_name)); - // Store name directly using local_num as index local_names->local_names[local_num] = qstr_name; @@ -87,16 +83,8 @@ void mp_local_names_add(mp_local_names_t *local_names, uint16_t local_num, qstr uint16_t idx = local_names->order_count; local_names->local_nums[idx] = local_num; local_names->order_count++; - - // Debug the order mapping - mp_printf(&mp_plat_print, "DEBUG_ORDER_MAP: Source order idx %d -> runtime slot %d\n", - idx, local_num); } - // Enhance debug output to capture runtime behavior - mp_printf(&mp_plat_print, "DEBUG_RUNTIME_SLOT: Local %d ('%s') -> Runtime Slot calculation\n", - local_num, qstr_str(qstr_name)); - // Refine runtime slot mapping logic // Test the hypothesis that variables are assigned from highest slots down uint16_t runtime_slot = local_num; // Default to direct mapping @@ -105,18 +93,7 @@ void mp_local_names_add(mp_local_names_t *local_names, uint16_t local_num, qstr // Find position in order array for (uint16_t i = 0; i < local_names->order_count; ++i) { if (local_names->local_nums[i] == local_num) { - // Try different slot assignment strategies - - // Strategy 1: Sequential after parameters (traditional) runtime_slot = i; - - // Strategy 2: Reverse order assignment (testing hypothesis) - // This would assign first variable to highest available slot - // uint16_t reverse_slot = MICROPY_PY_SYS_SETTRACE_NAMES_MAX - 1 - i; - // runtime_slot = reverse_slot; - - mp_printf(&mp_plat_print, "DEBUG_RUNTIME_SLOT: Variable '%s' order_idx=%d -> runtime_slot=%d\n", - qstr_str(qstr_name), i, runtime_slot); break; } } diff --git a/py/profile.c b/py/profile.c index 1b7464b6386b7..6a9fc560fa2b2 100644 --- a/py/profile.c +++ b/py/profile.c @@ -145,8 +145,9 @@ static mp_obj_t frame_f_locals(mp_obj_t self_in) { const mp_code_state_t *code_state = frame->code_state; - if (code_state == NULL || code_state->state == NULL) { - return MP_OBJ_FROM_PTR(locals_dict); // Return empty dictionary if state is invalid + if (code_state == NULL || !code_state->state) { + // Return empty dictionary if state is invalid + return MP_OBJ_FROM_PTR(locals_dict); } #if MICROPY_PY_SYS_SETTRACE_SAVE_NAMES @@ -223,22 +224,22 @@ static mp_obj_t frame_f_locals(mp_obj_t self_in) { #else // Fallback when variable names aren't saved - // TODO: Use reversed slot order here as well - for (size_t i = 0; i < code_state->n_state; ++i) { - if (code_state->state[i] == NULL) { + // Use reverse slot assignment: local variables are numbered from highest slot down + uint16_t total_locals = code_state->n_state; + for (uint16_t order_idx = 0; order_idx < total_locals; ++order_idx) { + uint16_t reverse_slot = total_locals - 1 - order_idx; + if (code_state->state[reverse_slot] == NULL) { continue; } - char var_name[16]; - snprintf(var_name, sizeof(var_name), "local_%02d", (int)(i + 1)); + snprintf(var_name, sizeof(var_name), "local_%02d", (int)(order_idx + 1)); qstr var_name_qstr = qstr_from_str(var_name); if (var_name_qstr == MP_QSTR_NULL) { continue; } - mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[i]); + mp_obj_dict_store(locals_dict, MP_OBJ_NEW_QSTR(var_name_qstr), code_state->state[reverse_slot]); } #endif - return MP_OBJ_FROM_PTR(locals_dict); } diff --git a/py/py.mk b/py/py.mk index c13023814fce0..5a79113c26659 100644 --- a/py/py.mk +++ b/py/py.mk @@ -142,7 +142,6 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ warning.o \ profile.o \ localnames.o \ - debug_locals.o \ map.o \ obj.o \ objarray.o \ diff --git a/test_settrace.py b/test_settrace.py deleted file mode 100644 index 53c0405c0ab8f..0000000000000 --- a/test_settrace.py +++ /dev/null @@ -1,45 +0,0 @@ -import sys -import json -from collections import OrderedDict as OD - -def tracer(frame, event, arg): - try: - # print(repr(frame) ) - # print(dir(frame)) - # for name in dir(frame): - # print(f"{name} = {getattr(frame, name)}") - # # print(f"{json.dumps(frame)}") - # print(f"{frame.f_globals=}") - print(f"( {frame.f_lineno} , {frame.f_lasti} ) ", end="") - # sort frame.f_locals by key , and add all k,v pairs to an OrderedDict - f_locals = OD(sorted(frame.f_locals.items())) - print(f"{f_locals=}") - print( type(f_locals[list(f_locals)[0]])) - - except Exception as e: - pass - - return tracer - -granny = "granny" - -def test(): - foo = "hello debugger" - _under = "this is an under variable" - __dunder = "this is a double under variable" - bar = granny - a = 100 - b = 2200 - c = 33333 - l = [1, 2, 3] - d = {"a": 1, "b": 2, "c": 3} - tuple1 = (1, 2, 3) - tuple2 = (a, b, c,a) - print(foo) - print(a+b+c) - long_name = a+ b + c - print(long_name) - -sys.settrace(tracer) -test() -sys.settrace(None) diff --git a/tracer.ipynb b/tracer.ipynb deleted file mode 100644 index 03b848959366b..0000000000000 --- a/tracer.ipynb +++ /dev/null @@ -1,751 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 14, - "id": "cc147103", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "make: Entering directory '/home/jos/micropython/mpy-cross'\n", - "Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.\n", - "rm -f build/mpy-cross\n", - "rm -f build/mpy-cross.map\n", - "rm -rf build \n", - "make: Leaving directory '/home/jos/micropython/mpy-cross'\n", - "make: Entering directory '/home/jos/micropython/mpy-cross'\n", - "Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.\n", - "mkdir -p build/genhdr\n", - "GEN build/genhdr/mpversion.h\n", - "GEN build/genhdr/qstr.i.last\n", - "GEN build/genhdr/qstr.split\n", - "GEN build/genhdr/qstrdefs.collected.h\n", - "QSTR updated\n", - "GEN build/genhdr/qstrdefs.generated.h\n", - "GEN build/genhdr/moduledefs.split\n", - "GEN build/genhdr/moduledefs.collected\n", - "Module registrations updated\n", - "GEN build/genhdr/moduledefs.h\n", - "GEN build/genhdr/root_pointers.split\n", - "GEN build/genhdr/root_pointers.collected\n", - "Root pointer registrations updated\n", - "GEN build/genhdr/root_pointers.h\n", - "mkdir -p build/py/\n", - "mkdir -p build/shared/runtime/\n", - "CC ../py/mpstate.c\n", - "CC ../py/nlr.c\n", - "CC ../py/nlrx86.c\n", - "CC ../py/nlrx64.c\n", - "CC ../py/nlrthumb.c\n", - "CC ../py/nlraarch64.c\n", - "CC ../py/nlrmips.c\n", - "CC ../py/nlrpowerpc.c\n", - "CC ../py/nlrxtensa.c\n", - "CC ../py/nlrrv32.c\n", - "CC ../py/nlrrv64.c\n", - "CC ../py/nlrsetjmp.c\n", - "CC ../py/malloc.c\n", - "CC ../py/gc.c\n", - "CC ../py/pystack.c\n", - "CC ../py/qstr.c\n", - "CC ../py/vstr.c\n", - "CC ../py/mpprint.c\n", - "CC ../py/unicode.c\n", - "CC ../py/mpz.c\n", - "CC ../py/reader.c\n", - "CC ../py/lexer.c\n", - "CC ../py/parse.c\n", - "CC ../py/scope.c\n", - "CC ../py/compile.c\n", - "CC ../py/emitcommon.c\n", - "CC ../py/emitbc.c\n", - "CC ../py/asmbase.c\n", - "CC ../py/asmx64.c\n", - "CC ../py/emitnx64.c\n", - "CC ../py/asmx86.c\n", - "CC ../py/emitnx86.c\n", - "CC ../py/asmthumb.c\n", - "CC ../py/emitnthumb.c\n", - "CC ../py/emitinlinethumb.c\n", - "CC ../py/asmarm.c\n", - "CC ../py/emitnarm.c\n", - "CC ../py/asmxtensa.c\n", - "CC ../py/emitnxtensa.c\n", - "CC ../py/emitinlinextensa.c\n", - "CC ../py/emitnxtensawin.c\n", - "CC ../py/asmrv32.c\n", - "CC ../py/emitnrv32.c\n", - "CC ../py/emitinlinerv32.c\n", - "CC ../py/emitndebug.c\n", - "CC ../py/formatfloat.c\n", - "CC ../py/parsenumbase.c\n", - "CC ../py/parsenum.c\n", - "CC ../py/emitglue.c\n", - "CC ../py/persistentcode.c\n", - "CC ../py/runtime.c\n", - "CC ../py/runtime_utils.c\n", - "CC ../py/scheduler.c\n", - "CC ../py/nativeglue.c\n", - "CC ../py/pairheap.c\n", - "CC ../py/ringbuf.c\n", - "CC ../py/cstack.c\n", - "CC ../py/stackctrl.c\n", - "CC ../py/argcheck.c\n", - "CC ../py/warning.c\n", - "CC ../py/profile.c\n", - "CC ../py/localnames.c\n", - "CC ../py/rawcode_cleanup.c\n", - "CC ../py/map.c\n", - "CC ../py/obj.c\n", - "CC ../py/objarray.c\n", - "CC ../py/objattrtuple.c\n", - "CC ../py/objbool.c\n", - "CC ../py/objboundmeth.c\n", - "CC ../py/objcell.c\n", - "CC ../py/objclosure.c\n", - "CC ../py/objcode.c\n", - "CC ../py/objcomplex.c\n", - "CC ../py/objdeque.c\n", - "CC ../py/objdict.c\n", - "CC ../py/objenumerate.c\n", - "CC ../py/objexcept.c\n", - "CC ../py/objfilter.c\n", - "CC ../py/objfloat.c\n", - "CC ../py/objfun.c\n", - "CC ../py/objgenerator.c\n", - "CC ../py/objgetitemiter.c\n", - "CC ../py/objint.c\n", - "CC ../py/objint_longlong.c\n", - "CC ../py/objint_mpz.c\n", - "CC ../py/objlist.c\n", - "CC ../py/objmap.c\n", - "CC ../py/objmodule.c\n", - "CC ../py/objobject.c\n", - "CC ../py/objpolyiter.c\n", - "CC ../py/objproperty.c\n", - "CC ../py/objnone.c\n", - "CC ../py/objnamedtuple.c\n", - "CC ../py/objrange.c\n", - "CC ../py/objreversed.c\n", - "CC ../py/objringio.c\n", - "CC ../py/objset.c\n", - "CC ../py/objsingleton.c\n", - "CC ../py/objslice.c\n", - "CC ../py/objstr.c\n", - "CC ../py/objstrunicode.c\n", - "CC ../py/objstringio.c\n", - "CC ../py/objtuple.c\n", - "CC ../py/objtype.c\n", - "CC ../py/objzip.c\n", - "CC ../py/opmethods.c\n", - "CC ../py/sequence.c\n", - "CC ../py/stream.c\n", - "CC ../py/binary.c\n", - "CC ../py/builtinimport.c\n", - "CC ../py/builtinevex.c\n", - "CC ../py/builtinhelp.c\n", - "CC ../py/modarray.c\n", - "CC ../py/modbuiltins.c\n", - "CC ../py/modcollections.c\n", - "CC ../py/modgc.c\n", - "CC ../py/modio.c\n", - "CC ../py/modmath.c\n", - "CC ../py/modcmath.c\n", - "CC ../py/modmicropython.c\n", - "CC ../py/modstruct.c\n", - "CC ../py/modsys.c\n", - "CC ../py/moderrno.c\n", - "CC ../py/modthread.c\n", - "CC ../py/vm.c\n", - "CC ../py/bc.c\n", - "CC ../py/showbc.c\n", - "CC ../py/repl.c\n", - "CC ../py/smallint.c\n", - "CC ../py/frozenmod.c\n", - "CC main.c\n", - "CC gccollect.c\n", - "CC ../shared/runtime/gchelper_generic.c\n", - "LINK build/mpy-cross\n", - " text\t data\t bss\t dec\t hex\tfilename\n", - " 406284\t 18072\t 864\t 425220\t 67d04\tbuild/mpy-cross\n", - "make: Leaving directory '/home/jos/micropython/mpy-cross'\n" - ] - } - ], - "source": [ - "! make -C mpy-cross clean\n", - "! make -C mpy-cross\n", - "# ! make -C ports/unix clean\n", - "# ! make -C ports/unix CFLAGS_EXTRA=\"-DMICROPY_PY_SYS_SETTRACE=1\"" - ] - }, - { - "cell_type": "markdown", - "id": "7c045014", - "metadata": {}, - "source": [ - "```c\n", - "// Enable sys.settrace support\n", - "#define MICROPY_PY_SYS_SETTRACE (1)\n", - "\n", - "// Disable compiler optimizations for debugging\n", - "#define MICROPY_COMP_CONST (0)\n", - "#define MICROPY_COMP_MODULE_CONST (0)\n", - "#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)\n", - "#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "1b7f315b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "make: Entering directory '/home/jos/micropython/ports/unix'\n", - "Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.\n", - "rm -f build-standard/micropython\n", - "rm -f build-standard/micropython.map\n", - "rm -rf build-standard \n", - "make: Leaving directory '/home/jos/micropython/ports/unix'\n" - ] - } - ], - "source": [ - "! make -C ports/unix clean\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "15f163a0", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "make: Entering directory '/home/jos/micropython/ports/unix'\n", - "Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.\n", - "mkdir -p build-standard/genhdr\n", - "GEN build-standard/genhdr/mpversion.h\n", - "GEN build-standard/genhdr/qstr.i.last\n", - "GEN build-standard/genhdr/qstr.split\n", - "GEN build-standard/genhdr/qstrdefs.collected.h\n", - "QSTR updated\n", - "GEN build-standard/genhdr/qstrdefs.generated.h\n", - "GEN build-standard/genhdr/moduledefs.split\n", - "GEN build-standard/genhdr/moduledefs.collected\n", - "Module registrations updated\n", - "GEN build-standard/genhdr/moduledefs.h\n", - "GEN build-standard/genhdr/root_pointers.split\n", - "GEN build-standard/genhdr/root_pointers.collected\n", - "Root pointer registrations updated\n", - "GEN build-standard/genhdr/root_pointers.h\n", - "GEN build-standard/genhdr/compressed.split\n", - "GEN build-standard/genhdr/compressed.collected\n", - "Compressed data updated\n", - "GEN build-standard/genhdr/compressed.data.h\n", - "mkdir -p build-standard/extmod/\n", - "mkdir -p build-standard/extmod/mbedtls/\n", - "mkdir -p build-standard/lib/berkeley-db-1.xx/btree/\n", - "mkdir -p build-standard/lib/berkeley-db-1.xx/mpool/\n", - "mkdir -p build-standard/lib/littlefs/\n", - "mkdir -p build-standard/lib/mbedtls/library/\n", - "mkdir -p build-standard/lib/mbedtls_errors/\n", - "mkdir -p build-standard/lib/oofatfs/\n", - "mkdir -p build-standard/py/\n", - "mkdir -p build-standard/shared/libc/\n", - "mkdir -p build-standard/shared/readline/\n", - "mkdir -p build-standard/shared/runtime/\n", - "mkdir -p build-standard/shared/timeutils/\n", - "CC ../../py/mpstate.c\n", - "CC ../../py/nlr.c\n", - "CC ../../py/nlrx86.c\n", - "CC ../../py/nlrx64.c\n", - "CC ../../py/nlrthumb.c\n", - "CC ../../py/nlraarch64.c\n", - "CC ../../py/nlrmips.c\n", - "CC ../../py/nlrpowerpc.c\n", - "CC ../../py/nlrxtensa.c\n", - "CC ../../py/nlrrv32.c\n", - "CC ../../py/nlrrv64.c\n", - "CC ../../py/nlrsetjmp.c\n", - "CC ../../py/malloc.c\n", - "CC ../../py/gc.c\n", - "CC ../../py/pystack.c\n", - "CC ../../py/qstr.c\n", - "CC ../../py/vstr.c\n", - "CC ../../py/mpprint.c\n", - "CC ../../py/unicode.c\n", - "CC ../../py/mpz.c\n", - "CC ../../py/reader.c\n", - "CC ../../py/lexer.c\n", - "CC ../../py/parse.c\n", - "CC ../../py/scope.c\n", - "CC ../../py/compile.c\n", - "CC ../../py/emitcommon.c\n", - "CC ../../py/emitbc.c\n", - "CC ../../py/asmbase.c\n", - "CC ../../py/asmx64.c\n", - "CC ../../py/emitnx64.c\n", - "CC ../../py/asmx86.c\n", - "CC ../../py/emitnx86.c\n", - "CC ../../py/asmthumb.c\n", - "CC ../../py/emitnthumb.c\n", - "CC ../../py/emitinlinethumb.c\n", - "CC ../../py/asmarm.c\n", - "CC ../../py/emitnarm.c\n", - "CC ../../py/asmxtensa.c\n", - "CC ../../py/emitnxtensa.c\n", - "CC ../../py/emitinlinextensa.c\n", - "CC ../../py/emitnxtensawin.c\n", - "CC ../../py/asmrv32.c\n", - "CC ../../py/emitnrv32.c\n", - "CC ../../py/emitinlinerv32.c\n", - "CC ../../py/emitndebug.c\n", - "CC ../../py/formatfloat.c\n", - "CC ../../py/parsenumbase.c\n", - "CC ../../py/parsenum.c\n", - "CC ../../py/emitglue.c\n", - "CC ../../py/persistentcode.c\n", - "CC ../../py/runtime.c\n", - "CC ../../py/runtime_utils.c\n", - "CC ../../py/scheduler.c\n", - "CC ../../py/nativeglue.c\n", - "CC ../../py/pairheap.c\n", - "CC ../../py/ringbuf.c\n", - "CC ../../py/cstack.c\n", - "CC ../../py/stackctrl.c\n", - "CC ../../py/argcheck.c\n", - "CC ../../py/warning.c\n", - "CC ../../py/profile.c\n", - "CC ../../py/localnames.c\n", - "CC ../../py/rawcode_cleanup.c\n", - "CC ../../py/map.c\n", - "CC ../../py/obj.c\n", - "CC ../../py/objarray.c\n", - "CC ../../py/objattrtuple.c\n", - "CC ../../py/objbool.c\n", - "CC ../../py/objboundmeth.c\n", - "CC ../../py/objcell.c\n", - "CC ../../py/objclosure.c\n", - "CC ../../py/objcode.c\n", - "CC ../../py/objcomplex.c\n", - "CC ../../py/objdeque.c\n", - "CC ../../py/objdict.c\n", - "CC ../../py/objenumerate.c\n", - "CC ../../py/objexcept.c\n", - "CC ../../py/objfilter.c\n", - "CC ../../py/objfloat.c\n", - "CC ../../py/objfun.c\n", - "CC ../../py/objgenerator.c\n", - "CC ../../py/objgetitemiter.c\n", - "CC ../../py/objint.c\n", - "CC ../../py/objint_longlong.c\n", - "CC ../../py/objint_mpz.c\n", - "CC ../../py/objlist.c\n", - "CC ../../py/objmap.c\n", - "CC ../../py/objmodule.c\n", - "CC ../../py/objobject.c\n", - "CC ../../py/objpolyiter.c\n", - "CC ../../py/objproperty.c\n", - "CC ../../py/objnone.c\n", - "CC ../../py/objnamedtuple.c\n", - "CC ../../py/objrange.c\n", - "CC ../../py/objreversed.c\n", - "CC ../../py/objringio.c\n", - "CC ../../py/objset.c\n", - "CC ../../py/objsingleton.c\n", - "CC ../../py/objslice.c\n", - "CC ../../py/objstr.c\n", - "CC ../../py/objstrunicode.c\n", - "CC ../../py/objstringio.c\n", - "CC ../../py/objtuple.c\n", - "CC ../../py/objtype.c\n", - "CC ../../py/objzip.c\n", - "CC ../../py/opmethods.c\n", - "CC ../../py/sequence.c\n", - "CC ../../py/stream.c\n", - "CC ../../py/binary.c\n", - "CC ../../py/builtinimport.c\n", - "CC ../../py/builtinevex.c\n", - "CC ../../py/builtinhelp.c\n", - "CC ../../py/modarray.c\n", - "CC ../../py/modbuiltins.c\n", - "CC ../../py/modcollections.c\n", - "CC ../../py/modgc.c\n", - "CC ../../py/modio.c\n", - "CC ../../py/modmath.c\n", - "CC ../../py/modcmath.c\n", - "CC ../../py/modmicropython.c\n", - "CC ../../py/modstruct.c\n", - "CC ../../py/modsys.c\n", - "CC ../../py/moderrno.c\n", - "CC ../../py/modthread.c\n", - "CC ../../py/vm.c\n", - "CC ../../py/bc.c\n", - "CC ../../py/showbc.c\n", - "CC ../../py/repl.c\n", - "CC ../../py/smallint.c\n", - "CC ../../py/frozenmod.c\n", - "MPY argparse.py\n", - "MPY requests/__init__.py\n", - "MPY mip/__init__.py\n", - "MPY mip/__main__.py\n", - "MPY ssl.py\n", - "MPY asyncio/__init__.py\n", - "MPY asyncio/core.py\n", - "MPY asyncio/event.py\n", - "MPY asyncio/funcs.py\n", - "MPY asyncio/lock.py\n", - "MPY asyncio/stream.py\n", - "MPY uasyncio.py\n", - "GEN build-standard/frozen_content.c\n", - "CC build-standard/frozen_content.c\n", - "CC ../../extmod/machine_adc.c\n", - "CC ../../extmod/machine_adc_block.c\n", - "CC ../../extmod/machine_bitstream.c\n", - "CC ../../extmod/machine_i2c.c\n", - "CC ../../extmod/machine_i2s.c\n", - "CC ../../extmod/machine_mem.c\n", - "CC ../../extmod/machine_pinbase.c\n", - "CC ../../extmod/machine_pulse.c\n", - "CC ../../extmod/machine_pwm.c\n", - "CC ../../extmod/machine_signal.c\n", - "CC ../../extmod/machine_spi.c\n", - "CC ../../extmod/machine_timer.c\n", - "CC ../../extmod/machine_uart.c\n", - "CC ../../extmod/machine_usb_device.c\n", - "CC ../../extmod/machine_wdt.c\n", - "CC ../../extmod/modasyncio.c\n", - "CC ../../extmod/modbinascii.c\n", - "CC ../../extmod/modbluetooth.c\n", - "CC ../../extmod/modbtree.c\n", - "CC ../../extmod/modcryptolib.c\n", - "CC ../../extmod/moddeflate.c\n", - "CC ../../extmod/modframebuf.c\n", - "CC ../../extmod/modhashlib.c\n", - "CC ../../extmod/modheapq.c\n", - "CC ../../extmod/modjson.c\n", - "CC ../../extmod/modlwip.c\n", - "CC ../../extmod/modmachine.c\n", - "CC ../../extmod/modmarshal.c\n", - "CC ../../extmod/modnetwork.c\n", - "CC ../../extmod/modonewire.c\n", - "CC ../../extmod/modopenamp.c\n", - "CC ../../extmod/modopenamp_remoteproc.c\n", - "CC ../../extmod/modopenamp_remoteproc_store.c\n", - "CC ../../extmod/modos.c\n", - "CC ../../extmod/modplatform.c\n", - "CC ../../extmod/modrandom.c\n", - "CC ../../extmod/modre.c\n", - "CC ../../extmod/modselect.c\n", - "CC ../../extmod/modsocket.c\n", - "CC ../../extmod/modtls_axtls.c\n", - "CC ../../extmod/modtls_mbedtls.c\n", - "CC ../../extmod/mbedtls/mbedtls_alt.c\n", - "CC ../../extmod/modtime.c\n", - "CC ../../extmod/moductypes.c\n", - "CC ../../extmod/modvfs.c\n", - "CC ../../extmod/modwebrepl.c\n", - "CC ../../extmod/modwebsocket.c\n", - "CC ../../extmod/network_cyw43.c\n", - "CC ../../extmod/network_esp_hosted.c\n", - "CC ../../extmod/network_lwip.c\n", - "CC ../../extmod/network_ninaw10.c\n", - "CC ../../extmod/network_ppp_lwip.c\n", - "CC ../../extmod/network_wiznet5k.c\n", - "CC ../../extmod/os_dupterm.c\n", - "CC ../../extmod/vfs.c\n", - "CC ../../extmod/vfs_blockdev.c\n", - "CC ../../extmod/vfs_fat.c\n", - "CC ../../extmod/vfs_fat_diskio.c\n", - "CC ../../extmod/vfs_fat_file.c\n", - "CC ../../extmod/vfs_lfs.c\n", - "CC ../../extmod/vfs_rom.c\n", - "CC ../../extmod/vfs_rom_file.c\n", - "CC ../../extmod/vfs_posix.c\n", - "CC ../../extmod/vfs_posix_file.c\n", - "CC ../../extmod/vfs_reader.c\n", - "CC ../../extmod/virtpin.c\n", - "CC ../../shared/libc/abort_.c\n", - "CC ../../shared/libc/printf.c\n", - "CC ../../lib/oofatfs/ff.c\n", - "CC ../../lib/oofatfs/ffunicode.c\n", - "CC ../../lib/littlefs/lfs1.c\n", - "CC ../../lib/littlefs/lfs1_util.c\n", - "CC ../../lib/littlefs/lfs2.c\n", - "CC ../../lib/littlefs/lfs2_util.c\n", - "CC ../../lib/mbedtls_errors/mp_mbedtls_errors.c\n", - "CC ../../lib/mbedtls/library/aes.c\n", - "CC ../../lib/mbedtls/library/aesni.c\n", - "CC ../../lib/mbedtls/library/asn1parse.c\n", - "CC ../../lib/mbedtls/library/asn1write.c\n", - "CC ../../lib/mbedtls/library/base64.c\n", - "CC ../../lib/mbedtls/library/bignum_core.c\n", - "CC ../../lib/mbedtls/library/bignum_mod.c\n", - "CC ../../lib/mbedtls/library/bignum_mod_raw.c\n", - "CC ../../lib/mbedtls/library/bignum.c\n", - "CC ../../lib/mbedtls/library/camellia.c\n", - "CC ../../lib/mbedtls/library/ccm.c\n", - "CC ../../lib/mbedtls/library/chacha20.c\n", - "CC ../../lib/mbedtls/library/chachapoly.c\n", - "CC ../../lib/mbedtls/library/cipher.c\n", - "CC ../../lib/mbedtls/library/cipher_wrap.c\n", - "CC ../../lib/mbedtls/library/nist_kw.c\n", - "CC ../../lib/mbedtls/library/aria.c\n", - "CC ../../lib/mbedtls/library/cmac.c\n", - "CC ../../lib/mbedtls/library/constant_time.c\n", - "CC ../../lib/mbedtls/library/mps_reader.c\n", - "CC ../../lib/mbedtls/library/mps_trace.c\n", - "CC ../../lib/mbedtls/library/ctr_drbg.c\n", - "CC ../../lib/mbedtls/library/debug.c\n", - "CC ../../lib/mbedtls/library/des.c\n", - "CC ../../lib/mbedtls/library/dhm.c\n", - "CC ../../lib/mbedtls/library/ecdh.c\n", - "CC ../../lib/mbedtls/library/ecdsa.c\n", - "CC ../../lib/mbedtls/library/ecjpake.c\n", - "CC ../../lib/mbedtls/library/ecp.c\n", - "CC ../../lib/mbedtls/library/ecp_curves.c\n", - "CC ../../lib/mbedtls/library/entropy.c\n", - "CC ../../lib/mbedtls/library/entropy_poll.c\n", - "CC ../../lib/mbedtls/library/gcm.c\n", - "CC ../../lib/mbedtls/library/hmac_drbg.c\n", - "CC ../../lib/mbedtls/library/md5.c\n", - "CC ../../lib/mbedtls/library/md.c\n", - "CC ../../lib/mbedtls/library/oid.c\n", - "CC ../../lib/mbedtls/library/padlock.c\n", - "CC ../../lib/mbedtls/library/pem.c\n", - "CC ../../lib/mbedtls/library/pk.c\n", - "CC ../../lib/mbedtls/library/pkcs12.c\n", - "CC ../../lib/mbedtls/library/pkcs5.c\n", - "CC ../../lib/mbedtls/library/pkparse.c\n", - "CC ../../lib/mbedtls/library/pk_ecc.c\n", - "CC ../../lib/mbedtls/library/pk_wrap.c\n", - "CC ../../lib/mbedtls/library/pkwrite.c\n", - "CC ../../lib/mbedtls/library/platform.c\n", - "CC ../../lib/mbedtls/library/platform_util.c\n", - "CC ../../lib/mbedtls/library/poly1305.c\n", - "CC ../../lib/mbedtls/library/ripemd160.c\n", - "CC ../../lib/mbedtls/library/rsa.c\n", - "CC ../../lib/mbedtls/library/rsa_alt_helpers.c\n", - "CC ../../lib/mbedtls/library/sha1.c\n", - "CC ../../lib/mbedtls/library/sha256.c\n", - "CC ../../lib/mbedtls/library/sha512.c\n", - "CC ../../lib/mbedtls/library/ssl_cache.c\n", - "CC ../../lib/mbedtls/library/ssl_ciphersuites.c\n", - "CC ../../lib/mbedtls/library/ssl_client.c\n", - "CC ../../lib/mbedtls/library/ssl_cookie.c\n", - "CC ../../lib/mbedtls/library/ssl_debug_helpers_generated.c\n", - "CC ../../lib/mbedtls/library/ssl_msg.c\n", - "CC ../../lib/mbedtls/library/ssl_ticket.c\n", - "CC ../../lib/mbedtls/library/ssl_tls.c\n", - "CC ../../lib/mbedtls/library/ssl_tls12_client.c\n", - "CC ../../lib/mbedtls/library/ssl_tls12_server.c\n", - "CC ../../lib/mbedtls/library/timing.c\n", - "CC ../../lib/mbedtls/library/x509.c\n", - "CC ../../lib/mbedtls/library/x509_create.c\n", - "CC ../../lib/mbedtls/library/x509_crl.c\n", - "CC ../../lib/mbedtls/library/x509_crt.c\n", - "CC ../../lib/mbedtls/library/x509_csr.c\n", - "CC ../../lib/mbedtls/library/x509write_crt.c\n", - "CC ../../lib/mbedtls/library/x509write_csr.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_close.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_conv.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_debug.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_delete.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_get.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_open.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_overflow.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_page.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_put.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_search.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_seq.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_split.c\n", - "CC ../../lib/berkeley-db-1.xx/btree/bt_utils.c\n", - "CC ../../lib/berkeley-db-1.xx/mpool/mpool.c\n", - "CC main.c\n", - "CC gccollect.c\n", - "CC unix_mphal.c\n", - "CC mpthreadport.c\n", - "CC input.c\n", - "CC alloc.c\n", - "CC fatfs_port.c\n", - "CC mpbthciport.c\n", - "CC mpbtstackport_common.c\n", - "CC mpbtstackport_h4.c\n", - "CC mpbtstackport_usb.c\n", - "CC mpnimbleport.c\n", - "CC modtermios.c\n", - "CC modsocket.c\n", - "CC modffi.c\n", - "CC modjni.c\n", - "CC ../../shared/runtime/gchelper_generic.c\n", - "CC ../../shared/timeutils/timeutils.c\n", - "CC ../../shared/readline/readline.c\n", - "LINK build-standard/micropython\n", - " text\t data\t bss\t dec\t hex\tfilename\n", - " 804612\t 84056\t 2992\t 891660\t d9b0c\tbuild-standard/micropython\n", - "make: Leaving directory '/home/jos/micropython/ports/unix'\n" - ] - } - ], - "source": [ - "# with modified mpportconfig\n", - "! make -C ports/unix " - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "902fbf50", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Overwriting test_settrace.py\n" - ] - } - ], - "source": [ - "%%writefile test_settrace.py\n", - "import sys\n", - "import json\n", - "from collections import OrderedDict as OD\n", - "\n", - "def tracer(frame, event, arg):\n", - " try:\n", - " # print(repr(frame) )\n", - " # print(dir(frame))\n", - " # for name in dir(frame):\n", - " # print(f\"{name} = {getattr(frame, name)}\")\n", - " # # print(f\"{json.dumps(frame)}\")\n", - " # print(f\"{frame.f_globals=}\")\n", - " print(f\"( {frame.f_lineno} , {frame.f_lasti} ) \", end=\"\")\n", - " # sort frame.f_locals by key , and add all k,v pairs to an OrderedDict\n", - " f_locals = OD(sorted(frame.f_locals.items()))\n", - " print(f\"{f_locals=}\")\n", - " print( type(f_locals[list(f_locals)[0]]))\n", - "\n", - " except Exception as e:\n", - " pass\n", - "\n", - " return tracer\n", - "\n", - "granny = \"granny\"\n", - "\n", - "def test():\n", - " foo = \"hello debugger\"\n", - " _under = \"this is an under variable\"\n", - " __dunder = \"this is a double under variable\"\n", - " bar = granny\n", - " a = 100\n", - " b = 2200\n", - " c = 33333\n", - " l = [1, 2, 3]\n", - " d = {\"a\": 1, \"b\": 2, \"c\": 3}\n", - " tuple1 = (1, 2, 3)\n", - " tuple2 = (a, b, c,a)\n", - " print(foo)\n", - " print(a+b+c)\n", - " long_name = a+ b + c\n", - " print(long_name)\n", - "\n", - "sys.settrace(tracer)\n", - "test()\n", - "sys.settrace(None)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "268565fd", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "( 26 , 0 ) f_locals=OrderedDict({})\n", - "( 27 , 0 ) f_locals=OrderedDict({})\n", - "( 28 , 0 ) f_locals=OrderedDict({'foo': 'hello debugger', 'local_16': 'hello debugger'})\n", - "\n", - "( 29 , 0 ) f_locals=OrderedDict({'foo': 'this is an under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger'})\n", - "\n", - "( 30 , 0 ) f_locals=OrderedDict({'foo': 'this is a double under variable', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger'})\n", - "\n", - "( 31 , 0 ) f_locals=OrderedDict({'foo': 'granny', 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger'})\n", - "\n", - "( 32 , 0 ) f_locals=OrderedDict({'foo': 100, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100})\n", - "\n", - "( 33 , 0 ) f_locals=OrderedDict({'foo': 2200, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple2': 2200})\n", - "\n", - "( 34 , 0 ) f_locals=OrderedDict({'foo': 33333, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", - "\n", - "( 35 , 0 ) f_locals=OrderedDict({'__dunder': 3, '_under': 2, 'd': [1, 2, 3], 'foo': [1, 2, 3], 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", - "\n", - "( 36 , 0 ) f_locals=OrderedDict({'__dunder': 'c', '_under': 3, 'd': [1, 2, 3], 'foo': {'b': 2, 'c': 3, 'a': 1}, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", - "\n", - "( 37 , 0 ) f_locals=OrderedDict({'__dunder': 'c', '_under': 3, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': (1, 2, 3), 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", - "\n", - "( 38 , 0 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 2200, 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': (100, 2200, 33333, 100), 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", - "\n", - "hello debugger\n", - "( 39 , 59 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 'hello debugger', 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': None, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", - "\n", - "35633\n", - "( 40 , 69 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 35633, 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': None, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", - "\n", - "( 41 , 69 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 33333, 'a': 35633, 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': 35633, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", - "\n", - "35633\n", - "( 41 , 81 ) f_locals=OrderedDict({'__dunder': 33333, '_under': 35633, 'a': 35633, 'b': (100, 2200, 33333, 100), 'bar': 100, 'c': (1, 2, 3), 'd': [1, 2, 3], 'foo': None, 'l': {'b': 2, 'c': 3, 'a': 1}, 'local_13': 'granny', 'local_14': 'this is a double under variable', 'local_15': 'this is an under variable', 'local_16': 'hello debugger', 'long_name': 100, 'tuple1': 33333, 'tuple2': 2200})\n", - "\n" - ] - } - ], - "source": [ - "! ./ports/unix/build-standard/micropython test_settrace.py" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fc707a4e", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 00b6390ba52471b5a7b231d8680d45d0a5c51a59 Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Tue, 17 Jun 2025 17:38:37 +0200 Subject: [PATCH 5/6] py/modsys: Update to mp_sys_gettrace(void). Signed-off-by: Jos Verlinde --- py/modsys.c | 2 +- py/profile.c | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/py/modsys.c b/py/modsys.c index 3ce14bf5d17ad..dfdc5a76170ce 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -239,7 +239,7 @@ static mp_obj_t mp_sys_settrace(mp_obj_t obj) { } MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_settrace_obj, mp_sys_settrace); -static mp_obj_t mp_sys_gettrace() { +static mp_obj_t mp_sys_gettrace(void) { return mp_prof_gettrace(); } MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_gettrace_obj, mp_sys_gettrace); diff --git a/py/profile.c b/py/profile.c index 6a9fc560fa2b2..c2f966e90dcb2 100644 --- a/py/profile.c +++ b/py/profile.c @@ -145,7 +145,7 @@ static mp_obj_t frame_f_locals(mp_obj_t self_in) { const mp_code_state_t *code_state = frame->code_state; - if (code_state == NULL || !code_state->state) { + if (code_state == NULL) { // Return empty dictionary if state is invalid return MP_OBJ_FROM_PTR(locals_dict); } @@ -170,9 +170,12 @@ static mp_obj_t frame_f_locals(mp_obj_t self_in) { } if (var_name_qstr == MP_QSTRnull) { - char var_name[16]; - snprintf(var_name, sizeof(var_name), "arg_%d", (int)(i + 1)); - var_name_qstr = qstr_from_str(var_name); + vstr_t vstr; + vstr_init(&vstr, 16); // Initialize with enough space + vstr_printf(&vstr, "arg_%d", (int)(i + 1)); + var_name_qstr = qstr_from_str(vstr_str(&vstr)); + vstr_clear(&vstr); + if (var_name_qstr == MP_QSTR_NULL) { continue; } @@ -231,9 +234,12 @@ static mp_obj_t frame_f_locals(mp_obj_t self_in) { if (code_state->state[reverse_slot] == NULL) { continue; } - char var_name[16]; - snprintf(var_name, sizeof(var_name), "local_%02d", (int)(order_idx + 1)); - qstr var_name_qstr = qstr_from_str(var_name); + vstr_t vstr; + qstr var_name_qstr; + vstr_init(&vstr, 16); // Initialize with enough space + vstr_printf(&vstr, "local_%d", (int)(order_idx + 1)); + var_name_qstr = qstr_from_str(vstr_str(&vstr)); + vstr_clear(&vstr); if (var_name_qstr == MP_QSTR_NULL) { continue; } From 05b7818c80defd927d7edf11cef47e3bab892629 Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Thu, 19 Jun 2025 12:39:36 +0200 Subject: [PATCH 6/6] py/py.cmake: Add localnames.c to support sys.settrace(). Signed-off-by: Jos Verlinde --- py/py.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/py/py.cmake b/py/py.cmake index 1c81ed4c58f32..0f8e784fba6fd 100644 --- a/py/py.cmake +++ b/py/py.cmake @@ -39,6 +39,7 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/frozenmod.c ${MICROPY_PY_DIR}/gc.c ${MICROPY_PY_DIR}/lexer.c + ${MICROPY_PY_DIR}/localnames.c ${MICROPY_PY_DIR}/malloc.c ${MICROPY_PY_DIR}/map.c ${MICROPY_PY_DIR}/modarray.c