commit
be2342f32f
|
@ -247,7 +247,7 @@ STATIC mp_uint_t mp_reader_stdin_readbyte(void *data) {
|
|||
mp_hal_stdout_tx_strn("\x04", 1); // indicate end to host
|
||||
if (c == CHAR_CTRL_C) {
|
||||
#if MICROPY_KBD_EXCEPTION
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
|
||||
MP_STATE_VM(mp_kbd_exception).traceback->data = NULL;
|
||||
nlr_raise(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
|
||||
#else
|
||||
mp_raise_type(&mp_type_KeyboardInterrupt);
|
||||
|
|
|
@ -35,11 +35,11 @@ msgid ""
|
|||
"https://github.com/adafruit/circuitpython/issues\n"
|
||||
msgstr ""
|
||||
|
||||
#: py/obj.c
|
||||
#: py/obj.c shared-bindings/traceback/__init__.c
|
||||
msgid " File \"%q\""
|
||||
msgstr ""
|
||||
|
||||
#: py/obj.c
|
||||
#: py/obj.c shared-bindings/traceback/__init__.c
|
||||
msgid " File \"%q\", line %d"
|
||||
msgstr ""
|
||||
|
||||
|
@ -322,7 +322,7 @@ msgstr ""
|
|||
msgid "*x must be assignment target"
|
||||
msgstr ""
|
||||
|
||||
#: py/obj.c
|
||||
#: py/obj.c shared-bindings/traceback/__init__.c
|
||||
msgid ", in %q\n"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1185,11 +1185,6 @@ msgstr ""
|
|||
msgid "Input/output error"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Missing jmp_pin. Instruction %d jumps on pin"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Instruction %d shifts in more bits than pin count"
|
||||
|
@ -1506,6 +1501,11 @@ msgstr ""
|
|||
msgid "Missing first_set_pin. Instruction %d sets pin(s)"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Missing jmp_pin. Instruction %d jumps on pin"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c
|
||||
msgid "Must be a %q subclass."
|
||||
msgstr ""
|
||||
|
@ -2212,7 +2212,7 @@ msgstr ""
|
|||
msgid "Touch alarms not available"
|
||||
msgstr ""
|
||||
|
||||
#: py/obj.c
|
||||
#: py/obj.c shared-bindings/traceback/__init__.c
|
||||
msgid "Traceback (most recent call last):\n"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2510,7 +2510,7 @@ msgid "argument name reused"
|
|||
msgstr ""
|
||||
|
||||
#: py/argcheck.c shared-bindings/_stage/__init__.c
|
||||
#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/gamepad/GamePad.c
|
||||
#: shared-bindings/digitalio/DigitalInOut.c
|
||||
msgid "argument num/types mismatch"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3074,6 +3074,10 @@ msgstr ""
|
|||
msgid "file must be a file opened in byte mode"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/traceback/__init__.c
|
||||
msgid "file write is not available"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/storage/__init__.c
|
||||
msgid "filesystem must provide mount method"
|
||||
msgstr ""
|
||||
|
@ -3361,6 +3365,10 @@ msgstr ""
|
|||
msgid "invalid element_size %d, must be, 1, 2, or 4"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/traceback/__init__.c
|
||||
msgid "invalid exception"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/modframebuf.c
|
||||
msgid "invalid format"
|
||||
msgstr ""
|
||||
|
@ -3398,6 +3406,10 @@ msgstr ""
|
|||
msgid "invalid syntax for number"
|
||||
msgstr ""
|
||||
|
||||
#: py/objexcept.c shared-bindings/traceback/__init__.c
|
||||
msgid "invalid traceback"
|
||||
msgstr ""
|
||||
|
||||
#: py/objtype.c
|
||||
msgid "issubclass() arg 1 must be a class"
|
||||
msgstr ""
|
||||
|
@ -3442,6 +3454,10 @@ msgstr ""
|
|||
msgid "lhs and rhs should be compatible"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/traceback/__init__.c
|
||||
msgid "limit should be an int"
|
||||
msgstr ""
|
||||
|
||||
#: py/emitnative.c
|
||||
msgid "local '%q' has type '%q' but source is '%q'"
|
||||
msgstr ""
|
||||
|
@ -3594,10 +3610,6 @@ msgstr ""
|
|||
msgid "no active exception to reraise"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/socket/__init__.c shared-module/network/__init__.c
|
||||
msgid "no available NIC"
|
||||
msgstr ""
|
||||
|
||||
#: py/compile.c
|
||||
msgid "no binding for nonlocal found"
|
||||
msgstr ""
|
||||
|
|
|
@ -19,6 +19,7 @@ CIRCUITPY_PWMIO = 0
|
|||
CIRCUITPY_ROTARYIO = 0
|
||||
CIRCUITPY_RTC = 0
|
||||
CIRCUITPY_USB_MIDI = 0
|
||||
CIRCUITPY_TRACEBACK = 0
|
||||
|
||||
CIRCUITPY_PIXELBUF = 1
|
||||
CIRCUITPY_BUSDEVICE = 1
|
||||
|
|
|
@ -293,6 +293,9 @@ endif
|
|||
ifeq ($(CIRCUITPY_TOUCHIO),1)
|
||||
SRC_PATTERNS += touchio/%
|
||||
endif
|
||||
ifeq ($(CIRCUITPY_TRACEBACK),1)
|
||||
SRC_PATTERNS += traceback/%
|
||||
endif
|
||||
ifeq ($(CIRCUITPY_UHEAP),1)
|
||||
SRC_PATTERNS += uheap/%
|
||||
endif
|
||||
|
@ -544,6 +547,7 @@ SRC_SHARED_MODULE_ALL = \
|
|||
terminalio/Terminal.c \
|
||||
terminalio/__init__.c \
|
||||
time/__init__.c \
|
||||
traceback/__init__.c \
|
||||
uheap/__init__.c \
|
||||
ustack/__init__.c \
|
||||
vectorio/Circle.c \
|
||||
|
|
|
@ -763,6 +763,13 @@ extern const struct _mp_obj_module_t touchio_module;
|
|||
#define TOUCHIO_MODULE
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_TRACEBACK
|
||||
extern const struct _mp_obj_module_t traceback_module;
|
||||
#define TRACEBACK_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_traceback), (mp_obj_t)&traceback_module },
|
||||
#else
|
||||
#define TRACEBACK_MODULE
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_UHEAP
|
||||
extern const struct _mp_obj_module_t uheap_module;
|
||||
#define UHEAP_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_uheap),(mp_obj_t)&uheap_module },
|
||||
|
@ -917,6 +924,7 @@ extern const struct _mp_obj_module_t msgpack_module;
|
|||
SUPERVISOR_MODULE \
|
||||
SYNTHIO_MODULE \
|
||||
TOUCHIO_MODULE \
|
||||
TRACEBACK_MODULE \
|
||||
UHEAP_MODULE \
|
||||
USB_CDC_MODULE \
|
||||
USB_HID_MODULE \
|
||||
|
|
|
@ -324,6 +324,9 @@ CFLAGS += -DCIRCUITPY_TOUCHIO_USE_NATIVE=$(CIRCUITPY_TOUCHIO_USE_NATIVE)
|
|||
CIRCUITPY_TOUCHIO ?= 1
|
||||
CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO)
|
||||
|
||||
CIRCUITPY_TRACEBACK ?= 1
|
||||
CFLAGS += -DCIRCUITPY_TRACEBACK=$(CIRCUITPY_TRACEBACK)
|
||||
|
||||
# For debugging.
|
||||
CIRCUITPY_UHEAP ?= 0
|
||||
CFLAGS += -DCIRCUITPY_UHEAP=$(CIRCUITPY_UHEAP)
|
||||
|
|
19
py/modsys.c
19
py/modsys.c
|
@ -120,25 +120,6 @@ STATIC mp_obj_t mp_sys_exit(size_t n_args, const mp_obj_t *args) {
|
|||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit);
|
||||
|
||||
STATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) {
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
void *stream_obj = &mp_sys_stdout_obj;
|
||||
if (n_args > 1) {
|
||||
mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE);
|
||||
stream_obj = MP_OBJ_TO_PTR(args[1]);
|
||||
}
|
||||
|
||||
mp_print_t print = {stream_obj, mp_stream_write_adaptor};
|
||||
mp_obj_print_exception(&print, args[0]);
|
||||
#else
|
||||
(void)n_args;
|
||||
mp_obj_print_exception(&mp_plat_print, args[0]);
|
||||
#endif
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_print_exception_obj, 1, 2, mp_sys_print_exception);
|
||||
|
||||
#if MICROPY_PY_SYS_EXC_INFO
|
||||
STATIC mp_obj_t mp_sys_exc_info(void) {
|
||||
mp_obj_t cur_exc = MP_OBJ_FROM_PTR(MP_STATE_VM(cur_exception));
|
||||
|
|
|
@ -120,6 +120,9 @@ typedef struct _mp_state_vm_t {
|
|||
|
||||
qstr_pool_t *last_pool;
|
||||
|
||||
// non-heap memory for creating a traceback if we can't allocate RAM
|
||||
mp_obj_traceback_t mp_emergency_traceback_obj;
|
||||
|
||||
// non-heap memory for creating an exception if we can't allocate RAM
|
||||
mp_obj_exception_t mp_emergency_exception_obj;
|
||||
|
||||
|
@ -137,6 +140,8 @@ typedef struct _mp_state_vm_t {
|
|||
#if MICROPY_KBD_EXCEPTION
|
||||
// exception object of type KeyboardInterrupt
|
||||
mp_obj_exception_t mp_kbd_exception;
|
||||
// traceback object to store traceback
|
||||
mp_obj_traceback_t mp_kbd_traceback;
|
||||
#endif
|
||||
|
||||
// exception object of type ReloadException
|
||||
|
|
2
py/obj.h
2
py/obj.h
|
@ -692,6 +692,7 @@ extern const mp_obj_type_t mp_type_bytearray;
|
|||
extern const mp_obj_type_t mp_type_memoryview;
|
||||
extern const mp_obj_type_t mp_type_float;
|
||||
extern const mp_obj_type_t mp_type_complex;
|
||||
extern const mp_obj_type_t mp_type_traceback;
|
||||
extern const mp_obj_type_t mp_type_tuple;
|
||||
extern const mp_obj_type_t mp_type_list;
|
||||
extern const mp_obj_type_t mp_type_map; // map (the python builtin, not the dict implementation detail)
|
||||
|
@ -791,6 +792,7 @@ extern const struct _mp_obj_bool_t mp_const_true_obj;
|
|||
extern const struct _mp_obj_str_t mp_const_empty_bytes_obj;
|
||||
extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj;
|
||||
extern const struct _mp_obj_dict_t mp_const_empty_dict_obj;
|
||||
extern const struct _mp_obj_traceback_t mp_const_empty_traceback_obj;
|
||||
extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;
|
||||
extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj;
|
||||
extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj;
|
||||
|
|
|
@ -156,7 +156,15 @@ mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, con
|
|||
|
||||
// Populate the exception object
|
||||
o_exc->base.type = type;
|
||||
o_exc->traceback_data = NULL;
|
||||
|
||||
// Try to allocate memory for the traceback, with fallback to emergency traceback object
|
||||
o_exc->traceback = m_new_obj_maybe(mp_obj_traceback_t);
|
||||
if (o_exc->traceback == NULL) {
|
||||
o_exc->traceback = &MP_STATE_VM(mp_emergency_traceback_obj);
|
||||
}
|
||||
|
||||
// Populate the traceback object
|
||||
*o_exc->traceback = mp_const_empty_traceback_obj;
|
||||
|
||||
mp_obj_tuple_t *o_tuple;
|
||||
if (n_args == 0) {
|
||||
|
@ -208,22 +216,25 @@ void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
|||
mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (dest[0] != MP_OBJ_NULL) {
|
||||
// store/delete attribute
|
||||
if (attr == MP_QSTR___traceback__ && dest[1] == mp_const_none) {
|
||||
// We allow 'exc.__traceback__ = None' assignment as low-level
|
||||
// optimization of pre-allocating exception instance and raising
|
||||
// it repeatedly - this avoids memory allocation during raise.
|
||||
// However, uPy will keep adding traceback entries to such
|
||||
// exception instance, so before throwing it, traceback should
|
||||
// be cleared like above.
|
||||
self->traceback_len = 0;
|
||||
if (attr == MP_QSTR___traceback__) {
|
||||
if (dest[1] == mp_const_none) {
|
||||
self->traceback->data = NULL;
|
||||
} else {
|
||||
if (!mp_obj_is_type(dest[1], &mp_type_traceback)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("invalid traceback"));
|
||||
}
|
||||
self->traceback = MP_OBJ_TO_PTR(dest[1]);
|
||||
}
|
||||
dest[0] = MP_OBJ_NULL; // indicate success
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (attr == MP_QSTR_args) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(self->args);
|
||||
} else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) {
|
||||
} else if (attr == MP_QSTR_value && self->base.type == &mp_type_StopIteration) {
|
||||
dest[0] = mp_obj_exception_get_value(self_in);
|
||||
} else if (attr == MP_QSTR___traceback__) {
|
||||
dest[0] = (self->traceback->data) ? MP_OBJ_FROM_PTR(self->traceback) : mp_const_none;
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
} else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
|
||||
if (attr == MP_QSTR_errno) {
|
||||
|
@ -552,7 +563,7 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
|
|||
GET_NATIVE_EXCEPTION(self, self_in);
|
||||
// just set the traceback to the null object
|
||||
// we don't want to call any memory management functions here
|
||||
self->traceback_data = NULL;
|
||||
self->traceback->data = NULL;
|
||||
}
|
||||
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block) {
|
||||
|
@ -561,16 +572,16 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
|
|||
// append this traceback info to traceback data
|
||||
// if memory allocation fails (eg because gc is locked), just return
|
||||
|
||||
if (self->traceback_data == NULL) {
|
||||
self->traceback_data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN);
|
||||
if (self->traceback_data == NULL) {
|
||||
if (self->traceback->data == NULL) {
|
||||
self->traceback->data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN);
|
||||
if (self->traceback->data == NULL) {
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
if (mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)) {
|
||||
// There is room in the emergency buffer for traceback data
|
||||
size_t *tb = (size_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)
|
||||
+ EMG_BUF_TRACEBACK_OFFSET);
|
||||
self->traceback_data = tb;
|
||||
self->traceback_alloc = EMG_BUF_TRACEBACK_SIZE / sizeof(size_t);
|
||||
self->traceback->data = tb;
|
||||
self->traceback->alloc = EMG_BUF_TRACEBACK_SIZE / sizeof(size_t);
|
||||
} else {
|
||||
// Can't allocate and no room in emergency buffer
|
||||
return;
|
||||
|
@ -581,28 +592,28 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
|
|||
#endif
|
||||
} else {
|
||||
// Allocated the traceback data on the heap
|
||||
self->traceback_alloc = TRACEBACK_ENTRY_LEN;
|
||||
self->traceback->alloc = TRACEBACK_ENTRY_LEN;
|
||||
}
|
||||
self->traceback_len = 0;
|
||||
} else if (self->traceback_len + TRACEBACK_ENTRY_LEN > self->traceback_alloc) {
|
||||
self->traceback->len = 0;
|
||||
} else if (self->traceback->len + TRACEBACK_ENTRY_LEN > self->traceback->alloc) {
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
if (self->traceback_data == (size_t *)MP_STATE_VM(mp_emergency_exception_buf)) {
|
||||
if (self->traceback->data == (size_t *)MP_STATE_VM(mp_emergency_exception_buf)) {
|
||||
// Can't resize the emergency buffer
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// be conservative with growing traceback data
|
||||
size_t *tb_data = m_renew_maybe(size_t, self->traceback_data, self->traceback_alloc,
|
||||
self->traceback_alloc + TRACEBACK_ENTRY_LEN, true);
|
||||
size_t *tb_data = m_renew_maybe(size_t, self->traceback->data, self->traceback->alloc,
|
||||
self->traceback->alloc + TRACEBACK_ENTRY_LEN, true);
|
||||
if (tb_data == NULL) {
|
||||
return;
|
||||
}
|
||||
self->traceback_data = tb_data;
|
||||
self->traceback_alloc += TRACEBACK_ENTRY_LEN;
|
||||
self->traceback->data = tb_data;
|
||||
self->traceback->alloc += TRACEBACK_ENTRY_LEN;
|
||||
}
|
||||
|
||||
size_t *tb_data = &self->traceback_data[self->traceback_len];
|
||||
self->traceback_len += TRACEBACK_ENTRY_LEN;
|
||||
size_t *tb_data = &self->traceback->data[self->traceback->len];
|
||||
self->traceback->len += TRACEBACK_ENTRY_LEN;
|
||||
tb_data[0] = file;
|
||||
tb_data[1] = line;
|
||||
tb_data[2] = block;
|
||||
|
@ -611,12 +622,12 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
|
|||
void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values) {
|
||||
GET_NATIVE_EXCEPTION(self, self_in);
|
||||
|
||||
if (self->traceback_data == NULL) {
|
||||
if (self->traceback->data == NULL) {
|
||||
*n = 0;
|
||||
*values = NULL;
|
||||
} else {
|
||||
*n = self->traceback_len;
|
||||
*values = self->traceback_data;
|
||||
*n = self->traceback->len;
|
||||
*values = self->traceback->data;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,13 +28,12 @@
|
|||
|
||||
#include "py/obj.h"
|
||||
#include "py/objtuple.h"
|
||||
#include "py/objtraceback.h"
|
||||
|
||||
typedef struct _mp_obj_exception_t {
|
||||
mp_obj_base_t base;
|
||||
size_t traceback_alloc : (8 * sizeof(size_t) / 2);
|
||||
size_t traceback_len : (8 * sizeof(size_t) / 2);
|
||||
size_t *traceback_data;
|
||||
mp_obj_tuple_t *args;
|
||||
mp_obj_traceback_t *traceback;
|
||||
} mp_obj_exception_t;
|
||||
|
||||
void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include "supervisor/shared/translate.h"
|
||||
|
||||
// Instance of GeneratorExit exception - needed by generator.close()
|
||||
const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t *)&mp_const_empty_tuple_obj};
|
||||
const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, (mp_obj_tuple_t *)&mp_const_empty_tuple_obj, (mp_obj_traceback_t *)&mp_const_empty_traceback_obj};
|
||||
|
||||
/******************************************************************************/
|
||||
/* generator wrapper */
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 microDev
|
||||
*
|
||||
* 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/runtime.h"
|
||||
#include "py/objtraceback.h"
|
||||
|
||||
const mp_obj_traceback_t mp_const_empty_traceback_obj = {{&mp_type_traceback}, 0, 0, NULL};
|
||||
|
||||
STATIC void mp_obj_traceback_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
mp_obj_traceback_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
mp_printf(print, "<traceback object at 0x%p>", o);
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_traceback = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_traceback,
|
||||
.print = mp_obj_traceback_print,
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 microDev
|
||||
*
|
||||
* 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_OBJTRACEBACK_H
|
||||
#define MICROPY_INCLUDED_PY_OBJTRACEBACK_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
typedef struct _mp_obj_traceback_t {
|
||||
mp_obj_base_t base;
|
||||
size_t alloc : (8 * sizeof(size_t) / 2);
|
||||
size_t len : (8 * sizeof(size_t) / 2);
|
||||
size_t *data;
|
||||
} mp_obj_traceback_t;
|
||||
|
||||
#endif // MICROPY_INCLUDED_PY_OBJTRACEBACK_H
|
|
@ -95,6 +95,7 @@ set(MICROPY_SOURCE_PY
|
|||
${MICROPY_PY_DIR}/objstr.c
|
||||
${MICROPY_PY_DIR}/objstringio.c
|
||||
${MICROPY_PY_DIR}/objstrunicode.c
|
||||
${MICROPY_PY_DIR}/objtraceback.c
|
||||
${MICROPY_PY_DIR}/objtuple.c
|
||||
${MICROPY_PY_DIR}/objtype.c
|
||||
${MICROPY_PY_DIR}/objzip.c
|
||||
|
|
1
py/py.mk
1
py/py.mk
|
@ -153,6 +153,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\
|
|||
objstr.o \
|
||||
objstrunicode.o \
|
||||
objstringio.o \
|
||||
objtraceback.o \
|
||||
objtuple.o \
|
||||
objtype.o \
|
||||
objzip.o \
|
||||
|
|
|
@ -79,17 +79,14 @@ void mp_init(void) {
|
|||
#if MICROPY_KBD_EXCEPTION
|
||||
// initialise the exception object for raising KeyboardInterrupt
|
||||
MP_STATE_VM(mp_kbd_exception).base.type = &mp_type_KeyboardInterrupt;
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_alloc = 0;
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_len = 0;
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
|
||||
MP_STATE_VM(mp_kbd_exception).args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;
|
||||
MP_STATE_VM(mp_kbd_exception).traceback = &MP_STATE_VM(mp_kbd_traceback);
|
||||
*MP_STATE_VM(mp_kbd_exception).traceback = mp_const_empty_traceback_obj;
|
||||
#endif
|
||||
|
||||
MP_STATE_VM(mp_reload_exception).base.type = &mp_type_ReloadException;
|
||||
MP_STATE_VM(mp_reload_exception).traceback_alloc = 0;
|
||||
MP_STATE_VM(mp_reload_exception).traceback_len = 0;
|
||||
MP_STATE_VM(mp_reload_exception).traceback_data = NULL;
|
||||
MP_STATE_VM(mp_reload_exception).args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;
|
||||
MP_STATE_VM(mp_reload_exception).traceback = (mp_obj_traceback_t *)&mp_const_empty_traceback_obj;
|
||||
|
||||
// call port specific initialization if any
|
||||
#ifdef MICROPY_PORT_INIT_FUNC
|
||||
|
|
|
@ -40,7 +40,7 @@ void MICROPY_WRAP_MP_SCHED_EXCEPTION(mp_sched_exception)(mp_obj_t exc) {
|
|||
#if MICROPY_KBD_EXCEPTION
|
||||
// This function may be called asynchronously at any time so only do the bare minimum.
|
||||
void MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(mp_sched_keyboard_interrupt)(void) {
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
|
||||
MP_STATE_VM(mp_kbd_exception).traceback->data = NULL;
|
||||
mp_sched_exception(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 microDev
|
||||
*
|
||||
* 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/stream.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-module/traceback/__init__.h"
|
||||
|
||||
//| """Traceback Module
|
||||
//|
|
||||
//| This module provides a standard interface to print stack traces of programs.
|
||||
//| This is useful when you want to print stack traces under program control.
|
||||
//|
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
|
||||
//| def print_exception(etype: Type[BaseException], value: BaseException, tb: TracebackType,
|
||||
//| limit: Optional[int] = None, file: Optional[io.FileIO] = None, chain: Optional[bool] = True) -> None:
|
||||
//|
|
||||
//| """Prints exception information and stack trace entries.
|
||||
//|
|
||||
//| .. note: Setting `chain` will have no effect as chained exceptions are not yet implemented.
|
||||
//|
|
||||
//| :param Type[BaseException] etype: This is ignored and inferred from the type of ``value``.
|
||||
//| :param BaseException value: The exception. Must be an instance of `BaseException`.
|
||||
//| :param TracebackType tb: The traceback object. If `None`, the traceback will not be printed.
|
||||
//| :param int limit: Print up to limit stack trace entries (starting from the caller’s frame) if limit is positive.
|
||||
//| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed.
|
||||
//| :param io.FileIO file: If file is omitted or `None`, the output goes to `sys.stderr`; otherwise it should be an open
|
||||
//| file or file-like object to receive the output.
|
||||
//| :param bool chain: If `True` then chained exceptions will be printed (note: not yet implemented).
|
||||
//|
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t traceback_print_exception(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_etype, ARG_value, ARG_tb, ARG_limit, ARG_file, ARG_chain };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_etype, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_value, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_tb, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_limit, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_file, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_chain, MP_ARG_BOOL, {.u_bool = true} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
if (!mp_obj_is_exception_instance(args[ARG_value].u_obj)) {
|
||||
mp_raise_TypeError(translate("invalid exception"));
|
||||
}
|
||||
mp_obj_exception_t exc = *(mp_obj_exception_t *)MP_OBJ_TO_PTR(args[ARG_value].u_obj);
|
||||
|
||||
mp_print_t print = mp_plat_print;
|
||||
if (args[ARG_file].u_obj != mp_const_none) {
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
mp_get_stream_raise(args[ARG_file].u_obj, MP_STREAM_OP_WRITE);
|
||||
print.data = MP_OBJ_TO_PTR(args[ARG_file].u_obj);
|
||||
print.print_strn = mp_stream_write_adaptor;
|
||||
#else
|
||||
mp_raise_NotImplementedError(translate("file write is not available"));
|
||||
#endif
|
||||
}
|
||||
|
||||
mp_int_t limit = 0;
|
||||
bool print_tb = true;
|
||||
if (args[ARG_limit].u_obj != mp_const_none) {
|
||||
if (!mp_obj_get_int_maybe(args[ARG_limit].u_obj, &limit)) {
|
||||
mp_raise_TypeError(translate("limit should be an int"));
|
||||
}
|
||||
print_tb = (limit != 0);
|
||||
}
|
||||
|
||||
if (args[ARG_tb].u_obj != mp_const_none && print_tb) {
|
||||
if (!mp_obj_is_type(args[ARG_tb].u_obj, &mp_type_traceback)) {
|
||||
mp_raise_TypeError(translate("invalid traceback"));
|
||||
}
|
||||
exc.traceback = MP_OBJ_TO_PTR(args[ARG_tb].u_obj);
|
||||
} else {
|
||||
exc.traceback = NULL;
|
||||
}
|
||||
|
||||
shared_module_traceback_print_exception(&exc, &print, limit);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(traceback_print_exception_obj, 3, traceback_print_exception);
|
||||
|
||||
STATIC const mp_rom_map_elem_t traceback_module_globals_table[] = {
|
||||
// module name
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_traceback) },
|
||||
// module functions
|
||||
{ MP_ROM_QSTR(MP_QSTR_print_exception), MP_ROM_PTR(&traceback_print_exception_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(traceback_module_globals, traceback_module_globals_table);
|
||||
|
||||
const mp_obj_module_t traceback_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&traceback_module_globals,
|
||||
};
|
|
@ -61,10 +61,8 @@ const mp_obj_type_t mp_type_WatchDogTimeout = {
|
|||
|
||||
mp_obj_exception_t mp_watchdog_timeout_exception = {
|
||||
.base.type = &mp_type_WatchDogTimeout,
|
||||
.traceback_alloc = 0,
|
||||
.traceback_len = 0,
|
||||
.traceback_data = NULL,
|
||||
.args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj,
|
||||
.traceback = (mp_obj_traceback_t *)&mp_const_empty_traceback_obj,
|
||||
};
|
||||
|
||||
STATIC const mp_rom_map_elem_t watchdog_module_globals_table[] = {
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 microDev
|
||||
*
|
||||
* 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 "shared-module/traceback/__init__.h"
|
||||
|
||||
void shared_module_traceback_print_exception(mp_obj_exception_t *exc, mp_print_t *print, mp_int_t limit) {
|
||||
// Print traceback
|
||||
if (exc->traceback != NULL) {
|
||||
size_t n = exc->traceback->len;
|
||||
size_t *values = exc->traceback->data;
|
||||
if (n > 0) {
|
||||
assert(n % 3 == 0);
|
||||
// Decompress the format strings
|
||||
const compressed_string_t *traceback = MP_ERROR_TEXT("Traceback (most recent call last):\n");
|
||||
char decompressed[decompress_length(traceback)];
|
||||
decompress(traceback, decompressed);
|
||||
#if MICROPY_ENABLE_SOURCE_LINE
|
||||
const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\", line %d");
|
||||
#else
|
||||
const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\"");
|
||||
#endif
|
||||
char decompressed_frame[decompress_length(frame)];
|
||||
decompress(frame, decompressed_frame);
|
||||
const compressed_string_t *block_fmt = MP_ERROR_TEXT(", in %q\n");
|
||||
char decompressed_block[decompress_length(block_fmt)];
|
||||
decompress(block_fmt, decompressed_block);
|
||||
|
||||
// Set traceback formatting
|
||||
// Default: Print full traceback
|
||||
limit = limit * 3;
|
||||
mp_int_t i = n - 3, j;
|
||||
if (limit > 0) {
|
||||
// Print upto limit traceback
|
||||
// entries from caller's frame
|
||||
if ((unsigned)limit > n) {
|
||||
limit = n;
|
||||
}
|
||||
limit = n - limit;
|
||||
} else if (limit < 0) {
|
||||
// Print upto limit traceback
|
||||
// entries from last
|
||||
if ((unsigned)-limit > n) {
|
||||
limit = -n;
|
||||
}
|
||||
i = 0, limit = limit + 3;
|
||||
}
|
||||
|
||||
// Print the traceback
|
||||
mp_print_str(print, decompressed);
|
||||
for (; i >= limit; i -= 3) {
|
||||
j = (i < 0) ? -i : i;
|
||||
#if MICROPY_ENABLE_SOURCE_LINE
|
||||
mp_printf(print, decompressed_frame, values[j], (int)values[j + 1]);
|
||||
#else
|
||||
mp_printf(print, decompressed_frame, values[j]);
|
||||
#endif
|
||||
// The block name can be NULL if it's unknown
|
||||
qstr block = values[j + 2];
|
||||
if (block == MP_QSTRnull) {
|
||||
mp_print_str(print, "\n");
|
||||
} else {
|
||||
mp_printf(print, decompressed_block, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Print exception
|
||||
mp_obj_print_helper(print, exc, PRINT_EXC);
|
||||
mp_print_str(print, "\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 microDev
|
||||
*
|
||||
* 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_SHARED_MODULE_TRACEBACK___INIT___H
|
||||
#define MICROPY_INCLUDED_SHARED_MODULE_TRACEBACK___INIT___H
|
||||
|
||||
#include "py/objexcept.h"
|
||||
#include "py/objtraceback.h"
|
||||
|
||||
extern void shared_module_traceback_print_exception(mp_obj_exception_t *exc,
|
||||
mp_print_t *print, mp_int_t limit);
|
||||
|
||||
#endif // MICROPY_INCLUDED_SHARED_MODULE_TRACEBACK___INIT___H
|
Loading…
Reference in New Issue