Skip to content

Commit be2342f

Browse files
authored
Merge pull request #5072 from microDev1/traceback
Add traceback module
2 parents 93aa4e9 + 870f26b commit be2342f

File tree

22 files changed

+434
-77
lines changed

22 files changed

+434
-77
lines changed

lib/utils/pyexec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ STATIC mp_uint_t mp_reader_stdin_readbyte(void *data) {
247247
mp_hal_stdout_tx_strn("\x04", 1); // indicate end to host
248248
if (c == CHAR_CTRL_C) {
249249
#if MICROPY_KBD_EXCEPTION
250-
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
250+
MP_STATE_VM(mp_kbd_exception).traceback->data = NULL;
251251
nlr_raise(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
252252
#else
253253
mp_raise_type(&mp_type_KeyboardInterrupt);

locale/circuitpython.pot

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ msgid ""
3535
"https://github.com/adafruit/circuitpython/issues\n"
3636
msgstr ""
3737

38-
#: py/obj.c
38+
#: py/obj.c shared-bindings/traceback/__init__.c
3939
msgid " File \"%q\""
4040
msgstr ""
4141

42-
#: py/obj.c
42+
#: py/obj.c shared-bindings/traceback/__init__.c
4343
msgid " File \"%q\", line %d"
4444
msgstr ""
4545

@@ -322,7 +322,7 @@ msgstr ""
322322
msgid "*x must be assignment target"
323323
msgstr ""
324324

325-
#: py/obj.c
325+
#: py/obj.c shared-bindings/traceback/__init__.c
326326
msgid ", in %q\n"
327327
msgstr ""
328328

@@ -1185,11 +1185,6 @@ msgstr ""
11851185
msgid "Input/output error"
11861186
msgstr ""
11871187

1188-
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
1189-
#, c-format
1190-
msgid "Missing jmp_pin. Instruction %d jumps on pin"
1191-
msgstr ""
1192-
11931188
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
11941189
#, c-format
11951190
msgid "Instruction %d shifts in more bits than pin count"
@@ -1506,6 +1501,11 @@ msgstr ""
15061501
msgid "Missing first_set_pin. Instruction %d sets pin(s)"
15071502
msgstr ""
15081503

1504+
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
1505+
#, c-format
1506+
msgid "Missing jmp_pin. Instruction %d jumps on pin"
1507+
msgstr ""
1508+
15091509
#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c
15101510
msgid "Must be a %q subclass."
15111511
msgstr ""
@@ -2212,7 +2212,7 @@ msgstr ""
22122212
msgid "Touch alarms not available"
22132213
msgstr ""
22142214

2215-
#: py/obj.c
2215+
#: py/obj.c shared-bindings/traceback/__init__.c
22162216
msgid "Traceback (most recent call last):\n"
22172217
msgstr ""
22182218

@@ -2510,7 +2510,7 @@ msgid "argument name reused"
25102510
msgstr ""
25112511

25122512
#: py/argcheck.c shared-bindings/_stage/__init__.c
2513-
#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/gamepad/GamePad.c
2513+
#: shared-bindings/digitalio/DigitalInOut.c
25142514
msgid "argument num/types mismatch"
25152515
msgstr ""
25162516

@@ -3074,6 +3074,10 @@ msgstr ""
30743074
msgid "file must be a file opened in byte mode"
30753075
msgstr ""
30763076

3077+
#: shared-bindings/traceback/__init__.c
3078+
msgid "file write is not available"
3079+
msgstr ""
3080+
30773081
#: shared-bindings/storage/__init__.c
30783082
msgid "filesystem must provide mount method"
30793083
msgstr ""
@@ -3361,6 +3365,10 @@ msgstr ""
33613365
msgid "invalid element_size %d, must be, 1, 2, or 4"
33623366
msgstr ""
33633367

3368+
#: shared-bindings/traceback/__init__.c
3369+
msgid "invalid exception"
3370+
msgstr ""
3371+
33643372
#: extmod/modframebuf.c
33653373
msgid "invalid format"
33663374
msgstr ""
@@ -3398,6 +3406,10 @@ msgstr ""
33983406
msgid "invalid syntax for number"
33993407
msgstr ""
34003408

3409+
#: py/objexcept.c shared-bindings/traceback/__init__.c
3410+
msgid "invalid traceback"
3411+
msgstr ""
3412+
34013413
#: py/objtype.c
34023414
msgid "issubclass() arg 1 must be a class"
34033415
msgstr ""
@@ -3442,6 +3454,10 @@ msgstr ""
34423454
msgid "lhs and rhs should be compatible"
34433455
msgstr ""
34443456

3457+
#: shared-bindings/traceback/__init__.c
3458+
msgid "limit should be an int"
3459+
msgstr ""
3460+
34453461
#: py/emitnative.c
34463462
msgid "local '%q' has type '%q' but source is '%q'"
34473463
msgstr ""
@@ -3594,10 +3610,6 @@ msgstr ""
35943610
msgid "no active exception to reraise"
35953611
msgstr ""
35963612

3597-
#: shared-bindings/socket/__init__.c shared-module/network/__init__.c
3598-
msgid "no available NIC"
3599-
msgstr ""
3600-
36013613
#: py/compile.c
36023614
msgid "no binding for nonlocal found"
36033615
msgstr ""

ports/atmel-samd/boards/adafruit_proxlight_trinkey_m0/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ CIRCUITPY_PWMIO = 0
1919
CIRCUITPY_ROTARYIO = 0
2020
CIRCUITPY_RTC = 0
2121
CIRCUITPY_USB_MIDI = 0
22+
CIRCUITPY_TRACEBACK = 0
2223

2324
CIRCUITPY_PIXELBUF = 1
2425
CIRCUITPY_BUSDEVICE = 1

py/circuitpy_defns.mk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ endif
293293
ifeq ($(CIRCUITPY_TOUCHIO),1)
294294
SRC_PATTERNS += touchio/%
295295
endif
296+
ifeq ($(CIRCUITPY_TRACEBACK),1)
297+
SRC_PATTERNS += traceback/%
298+
endif
296299
ifeq ($(CIRCUITPY_UHEAP),1)
297300
SRC_PATTERNS += uheap/%
298301
endif
@@ -544,6 +547,7 @@ SRC_SHARED_MODULE_ALL = \
544547
terminalio/Terminal.c \
545548
terminalio/__init__.c \
546549
time/__init__.c \
550+
traceback/__init__.c \
547551
uheap/__init__.c \
548552
ustack/__init__.c \
549553
vectorio/Circle.c \

py/circuitpy_mpconfig.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,13 @@ extern const struct _mp_obj_module_t touchio_module;
763763
#define TOUCHIO_MODULE
764764
#endif
765765

766+
#if CIRCUITPY_TRACEBACK
767+
extern const struct _mp_obj_module_t traceback_module;
768+
#define TRACEBACK_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_traceback), (mp_obj_t)&traceback_module },
769+
#else
770+
#define TRACEBACK_MODULE
771+
#endif
772+
766773
#if CIRCUITPY_UHEAP
767774
extern const struct _mp_obj_module_t uheap_module;
768775
#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;
917924
SUPERVISOR_MODULE \
918925
SYNTHIO_MODULE \
919926
TOUCHIO_MODULE \
927+
TRACEBACK_MODULE \
920928
UHEAP_MODULE \
921929
USB_CDC_MODULE \
922930
USB_HID_MODULE \

py/circuitpy_mpconfig.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ CFLAGS += -DCIRCUITPY_TOUCHIO_USE_NATIVE=$(CIRCUITPY_TOUCHIO_USE_NATIVE)
324324
CIRCUITPY_TOUCHIO ?= 1
325325
CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO)
326326

327+
CIRCUITPY_TRACEBACK ?= 1
328+
CFLAGS += -DCIRCUITPY_TRACEBACK=$(CIRCUITPY_TRACEBACK)
329+
327330
# For debugging.
328331
CIRCUITPY_UHEAP ?= 0
329332
CFLAGS += -DCIRCUITPY_UHEAP=$(CIRCUITPY_UHEAP)

py/modsys.c

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -120,25 +120,6 @@ STATIC mp_obj_t mp_sys_exit(size_t n_args, const mp_obj_t *args) {
120120
}
121121
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit);
122122

123-
STATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) {
124-
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
125-
void *stream_obj = &mp_sys_stdout_obj;
126-
if (n_args > 1) {
127-
mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE);
128-
stream_obj = MP_OBJ_TO_PTR(args[1]);
129-
}
130-
131-
mp_print_t print = {stream_obj, mp_stream_write_adaptor};
132-
mp_obj_print_exception(&print, args[0]);
133-
#else
134-
(void)n_args;
135-
mp_obj_print_exception(&mp_plat_print, args[0]);
136-
#endif
137-
138-
return mp_const_none;
139-
}
140-
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_print_exception_obj, 1, 2, mp_sys_print_exception);
141-
142123
#if MICROPY_PY_SYS_EXC_INFO
143124
STATIC mp_obj_t mp_sys_exc_info(void) {
144125
mp_obj_t cur_exc = MP_OBJ_FROM_PTR(MP_STATE_VM(cur_exception));

py/mpstate.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ typedef struct _mp_state_vm_t {
120120

121121
qstr_pool_t *last_pool;
122122

123+
// non-heap memory for creating a traceback if we can't allocate RAM
124+
mp_obj_traceback_t mp_emergency_traceback_obj;
125+
123126
// non-heap memory for creating an exception if we can't allocate RAM
124127
mp_obj_exception_t mp_emergency_exception_obj;
125128

@@ -137,6 +140,8 @@ typedef struct _mp_state_vm_t {
137140
#if MICROPY_KBD_EXCEPTION
138141
// exception object of type KeyboardInterrupt
139142
mp_obj_exception_t mp_kbd_exception;
143+
// traceback object to store traceback
144+
mp_obj_traceback_t mp_kbd_traceback;
140145
#endif
141146

142147
// exception object of type ReloadException

py/obj.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ extern const mp_obj_type_t mp_type_bytearray;
692692
extern const mp_obj_type_t mp_type_memoryview;
693693
extern const mp_obj_type_t mp_type_float;
694694
extern const mp_obj_type_t mp_type_complex;
695+
extern const mp_obj_type_t mp_type_traceback;
695696
extern const mp_obj_type_t mp_type_tuple;
696697
extern const mp_obj_type_t mp_type_list;
697698
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;
791792
extern const struct _mp_obj_str_t mp_const_empty_bytes_obj;
792793
extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj;
793794
extern const struct _mp_obj_dict_t mp_const_empty_dict_obj;
795+
extern const struct _mp_obj_traceback_t mp_const_empty_traceback_obj;
794796
extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;
795797
extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj;
796798
extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj;

py/objexcept.c

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,15 @@ mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, con
156156

157157
// Populate the exception object
158158
o_exc->base.type = type;
159-
o_exc->traceback_data = NULL;
159+
160+
// Try to allocate memory for the traceback, with fallback to emergency traceback object
161+
o_exc->traceback = m_new_obj_maybe(mp_obj_traceback_t);
162+
if (o_exc->traceback == NULL) {
163+
o_exc->traceback = &MP_STATE_VM(mp_emergency_traceback_obj);
164+
}
165+
166+
// Populate the traceback object
167+
*o_exc->traceback = mp_const_empty_traceback_obj;
160168

161169
mp_obj_tuple_t *o_tuple;
162170
if (n_args == 0) {
@@ -208,22 +216,25 @@ void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
208216
mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
209217
if (dest[0] != MP_OBJ_NULL) {
210218
// store/delete attribute
211-
if (attr == MP_QSTR___traceback__ && dest[1] == mp_const_none) {
212-
// We allow 'exc.__traceback__ = None' assignment as low-level
213-
// optimization of pre-allocating exception instance and raising
214-
// it repeatedly - this avoids memory allocation during raise.
215-
// However, uPy will keep adding traceback entries to such
216-
// exception instance, so before throwing it, traceback should
217-
// be cleared like above.
218-
self->traceback_len = 0;
219+
if (attr == MP_QSTR___traceback__) {
220+
if (dest[1] == mp_const_none) {
221+
self->traceback->data = NULL;
222+
} else {
223+
if (!mp_obj_is_type(dest[1], &mp_type_traceback)) {
224+
mp_raise_TypeError(MP_ERROR_TEXT("invalid traceback"));
225+
}
226+
self->traceback = MP_OBJ_TO_PTR(dest[1]);
227+
}
219228
dest[0] = MP_OBJ_NULL; // indicate success
220229
}
221230
return;
222231
}
223232
if (attr == MP_QSTR_args) {
224233
dest[0] = MP_OBJ_FROM_PTR(self->args);
225-
} else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) {
234+
} else if (attr == MP_QSTR_value && self->base.type == &mp_type_StopIteration) {
226235
dest[0] = mp_obj_exception_get_value(self_in);
236+
} else if (attr == MP_QSTR___traceback__) {
237+
dest[0] = (self->traceback->data) ? MP_OBJ_FROM_PTR(self->traceback) : mp_const_none;
227238
#if MICROPY_CPYTHON_COMPAT
228239
} else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
229240
if (attr == MP_QSTR_errno) {
@@ -552,7 +563,7 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
552563
GET_NATIVE_EXCEPTION(self, self_in);
553564
// just set the traceback to the null object
554565
// we don't want to call any memory management functions here
555-
self->traceback_data = NULL;
566+
self->traceback->data = NULL;
556567
}
557568

558569
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
561572
// append this traceback info to traceback data
562573
// if memory allocation fails (eg because gc is locked), just return
563574

564-
if (self->traceback_data == NULL) {
565-
self->traceback_data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN);
566-
if (self->traceback_data == NULL) {
575+
if (self->traceback->data == NULL) {
576+
self->traceback->data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN);
577+
if (self->traceback->data == NULL) {
567578
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
568579
if (mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)) {
569580
// There is room in the emergency buffer for traceback data
570581
size_t *tb = (size_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)
571582
+ EMG_BUF_TRACEBACK_OFFSET);
572-
self->traceback_data = tb;
573-
self->traceback_alloc = EMG_BUF_TRACEBACK_SIZE / sizeof(size_t);
583+
self->traceback->data = tb;
584+
self->traceback->alloc = EMG_BUF_TRACEBACK_SIZE / sizeof(size_t);
574585
} else {
575586
// Can't allocate and no room in emergency buffer
576587
return;
@@ -581,28 +592,28 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
581592
#endif
582593
} else {
583594
// Allocated the traceback data on the heap
584-
self->traceback_alloc = TRACEBACK_ENTRY_LEN;
595+
self->traceback->alloc = TRACEBACK_ENTRY_LEN;
585596
}
586-
self->traceback_len = 0;
587-
} else if (self->traceback_len + TRACEBACK_ENTRY_LEN > self->traceback_alloc) {
597+
self->traceback->len = 0;
598+
} else if (self->traceback->len + TRACEBACK_ENTRY_LEN > self->traceback->alloc) {
588599
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
589-
if (self->traceback_data == (size_t *)MP_STATE_VM(mp_emergency_exception_buf)) {
600+
if (self->traceback->data == (size_t *)MP_STATE_VM(mp_emergency_exception_buf)) {
590601
// Can't resize the emergency buffer
591602
return;
592603
}
593604
#endif
594605
// be conservative with growing traceback data
595-
size_t *tb_data = m_renew_maybe(size_t, self->traceback_data, self->traceback_alloc,
596-
self->traceback_alloc + TRACEBACK_ENTRY_LEN, true);
606+
size_t *tb_data = m_renew_maybe(size_t, self->traceback->data, self->traceback->alloc,
607+
self->traceback->alloc + TRACEBACK_ENTRY_LEN, true);
597608
if (tb_data == NULL) {
598609
return;
599610
}
600-
self->traceback_data = tb_data;
601-
self->traceback_alloc += TRACEBACK_ENTRY_LEN;
611+
self->traceback->data = tb_data;
612+
self->traceback->alloc += TRACEBACK_ENTRY_LEN;
602613
}
603614

604-
size_t *tb_data = &self->traceback_data[self->traceback_len];
605-
self->traceback_len += TRACEBACK_ENTRY_LEN;
615+
size_t *tb_data = &self->traceback->data[self->traceback->len];
616+
self->traceback->len += TRACEBACK_ENTRY_LEN;
606617
tb_data[0] = file;
607618
tb_data[1] = line;
608619
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
611622
void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values) {
612623
GET_NATIVE_EXCEPTION(self, self_in);
613624

614-
if (self->traceback_data == NULL) {
625+
if (self->traceback->data == NULL) {
615626
*n = 0;
616627
*values = NULL;
617628
} else {
618-
*n = self->traceback_len;
619-
*values = self->traceback_data;
629+
*n = self->traceback->len;
630+
*values = self->traceback->data;
620631
}
621632
}
622633

0 commit comments

Comments
 (0)