add exception breakpoint

This commit is contained in:
blueloveTH 2025-08-18 11:40:13 +08:00
parent d516b51063
commit b786fda39d
8 changed files with 109 additions and 60 deletions

View File

@ -9,4 +9,4 @@ typedef struct{
char msg[512]; char msg[512];
} Error; } Error;
void py_BaseException__stpush(py_Ref, SourceData_ src, int lineno, const char* func_name); void py_BaseException__stpush(py_Frame* frame, py_Ref, SourceData_ src, int lineno, const char* func_name);

View File

@ -0,0 +1,19 @@
#pragma once
#include "pocketpy/objects/sourcedata.h"
#include "pocketpy/objects/base.h"
typedef struct BaseExceptionFrame {
SourceData_ src;
int lineno;
c11_string* name;
py_TValue locals; // for debugger only
py_TValue globals; // for debugger only
} BaseExceptionFrame;
typedef struct BaseException {
py_TValue args;
py_TValue inner_exc;
c11_vector /*T=BaseExceptionFrame*/ stacktrace;
} BaseException;

View File

@ -68,7 +68,6 @@ typedef struct py_Frame py_Frame;
// An enum for tracing events. // An enum for tracing events.
enum py_TraceEvent { enum py_TraceEvent {
TRACE_EVENT_LINE, TRACE_EVENT_LINE,
TRACE_EVENT_EXCEPTION,
TRACE_EVENT_PUSH, TRACE_EVENT_PUSH,
TRACE_EVENT_POP, TRACE_EVENT_POP,
}; };
@ -710,6 +709,8 @@ PK_API char* py_profiler_report();
/************* DAP *************/ /************* DAP *************/
PK_API void py_debugger_waitforattach(const char* hostname, unsigned short port); PK_API void py_debugger_waitforattach(const char* hostname, unsigned short port);
PK_API bool py_debugger_isattached();
PK_API void py_debugger_exceptionbreakpoint(py_Ref exc);
PK_API void py_debugger_exit(int exitCode); PK_API void py_debugger_exit(int exitCode);
/************* Unchecked Functions *************/ /************* Unchecked Functions *************/
@ -822,7 +823,7 @@ enum py_PredefinedType {
tp_nativefunc, tp_nativefunc,
tp_boundmethod, // 2 slots (self, func) tp_boundmethod, // 2 slots (self, func)
tp_super, // 1 slot + py_Type tp_super, // 1 slot + py_Type
tp_BaseException, // 2 slots (arg + inner_exc) tp_BaseException,
tp_Exception, tp_Exception,
tp_bytes, tp_bytes,
tp_namedict, tp_namedict,

View File

@ -3,6 +3,8 @@
#include "pocketpy/common/socket.h" #include "pocketpy/common/socket.h"
#include "pocketpy/debugger/core.h" #include "pocketpy/debugger/core.h"
#include "pocketpy/objects/base.h" #include "pocketpy/objects/base.h"
#include "pocketpy/objects/exception.h"
#include "pocketpy/pocketpy.h"
#define DAP_COMMAND_LIST(X) \ #define DAP_COMMAND_LIST(X) \
X(initialize) \ X(initialize) \
@ -340,7 +342,8 @@ inline static void c11_dap_handle_message() {
if(message == NULL) { return; } if(message == NULL) { return; }
// printf("[DEBUGGER INFO] read request %s\n", message); // printf("[DEBUGGER INFO] read request %s\n", message);
const char* response_content = c11_dap_handle_request(message); const char* response_content = c11_dap_handle_request(message);
// if(response_content != NULL) { printf("[DEBUGGER INFO] send response %s\n", response_content); } // if(response_content != NULL) { printf("[DEBUGGER INFO] send response %s\n",
// response_content); }
c11_sbuf buffer; c11_sbuf buffer;
c11_sbuf__ctor(&buffer); c11_sbuf__ctor(&buffer);
pk_sprintf(&buffer, "Content-Length: %d\r\n\r\n%s", strlen(response_content), response_content); pk_sprintf(&buffer, "Content-Length: %d\r\n\r\n%s", strlen(response_content), response_content);
@ -413,6 +416,15 @@ void py_debugger_waitforattach(const char* hostname, unsigned short port) {
py_sys_settrace(c11_dap_tracefunc, true); py_sys_settrace(c11_dap_tracefunc, true);
} }
void py_debugger_exit(int exitCode) { void py_debugger_exit(int exitCode) { c11_dap_send_exited_event(exitCode); }
c11_dap_send_exited_event(exitCode);
bool py_debugger_isattached() {
return false; // TODO: implement this function
}
void py_debugger_exceptionbreakpoint(py_Ref exc) {
assert(py_isinstance(exc, tp_BaseException));
// BaseException* ud = py_touserdata(exc);
// c11_vector* stacktrace = &ud->stacktrace;
// TODO: implement this function
} }

View File

@ -1219,7 +1219,7 @@ __NEXT_STEP:
c11__unreachable(); c11__unreachable();
__ERROR: __ERROR:
py_BaseException__stpush(&self->curr_exception, py_BaseException__stpush(frame, &self->curr_exception,
frame->co->src, frame->co->src,
Frame__lineno(frame), Frame__lineno(frame),
!frame->is_locals_special ? frame->co->name->data : NULL); !frame->is_locals_special ? frame->co->name->data : NULL);

View File

@ -7,6 +7,7 @@
#include "pocketpy/objects/base.h" #include "pocketpy/objects/base.h"
#include "pocketpy/interpreter/types.h" #include "pocketpy/interpreter/types.h"
#include "pocketpy/common/_generated.h" #include "pocketpy/common/_generated.h"
#include "pocketpy/objects/exception.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include <stdbool.h> #include <stdbool.h>
#include <assert.h> #include <assert.h>
@ -719,6 +720,16 @@ void ManagedHeap__mark(ManagedHeap* self) {
function__gc_mark(ud, p_stack); function__gc_mark(ud, p_stack);
break; break;
} }
case tp_BaseException: {
BaseException* self = ud;
pk__mark_value(&self->args);
pk__mark_value(&self->inner_exc);
c11__foreach(BaseExceptionFrame, &self->stacktrace, frame) {
pk__mark_value(&frame->locals);
pk__mark_value(&frame->globals);
}
break;
}
case tp_code: { case tp_code: {
CodeObject* self = ud; CodeObject* self = ud;
CodeObject__gc_mark(self, p_stack); CodeObject__gc_mark(self, p_stack);

View File

@ -22,7 +22,7 @@ bool _py_compile(CodeObject* out,
Error* err = pk_compile(src, out); Error* err = pk_compile(src, out);
if(err) { if(err) {
py_exception(tp_SyntaxError, err->msg); py_exception(tp_SyntaxError, err->msg);
py_BaseException__stpush(&vm->curr_exception, err->src, err->lineno, NULL); py_BaseException__stpush(NULL, &vm->curr_exception, err->src, err->lineno, NULL);
PK_DECREF(src); PK_DECREF(src);
PK_DECREF(err->src); PK_DECREF(err->src);

View File

@ -1,30 +1,29 @@
#include "pocketpy/objects/codeobject.h"
#include "pocketpy/objects/error.h" #include "pocketpy/objects/error.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/objects/exception.h"
typedef struct BaseExceptionFrame { void py_BaseException__stpush(py_Frame* frame,
SourceData_ src; py_Ref self,
int lineno; SourceData_ src,
c11_string* name; int lineno,
} BaseExceptionFrame; const char* func_name) {
typedef struct BaseException {
c11_vector /*T=BaseExceptionFrame*/ stacktrace;
} BaseException;
void py_BaseException__stpush(py_Ref self, SourceData_ src, int lineno, const char* func_name) {
BaseException* ud = py_touserdata(self); BaseException* ud = py_touserdata(self);
if(ud->stacktrace.length >= 7) return; int max_frame_dumps = py_debugger_isattached() ? 31 : 7;
BaseExceptionFrame* frame = c11_vector__emplace(&ud->stacktrace); if(ud->stacktrace.length >= max_frame_dumps) return;
BaseExceptionFrame* frame_dump = c11_vector__emplace(&ud->stacktrace);
PK_INCREF(src); PK_INCREF(src);
frame->src = src; frame_dump->src = src;
frame->lineno = lineno; frame_dump->lineno = lineno;
frame->name = func_name ? c11_string__new(func_name) : NULL; frame_dump->name = func_name ? c11_string__new(func_name) : NULL;
if(py_debugger_isattached() && frame != NULL) {
py_Frame_newlocals(frame, &frame_dump->locals);
py_Frame_newglobals(frame, &frame_dump->globals);
}
} }
static void BaseException__dtor(void* ud) { static void BaseException__dtor(void* ud) {
@ -38,28 +37,33 @@ static void BaseException__dtor(void* ud) {
static bool _py_BaseException__new__(int argc, py_Ref argv) { static bool _py_BaseException__new__(int argc, py_Ref argv) {
py_Type cls = py_totype(argv); py_Type cls = py_totype(argv);
BaseException* ud = py_newobject(py_retval(), cls, 2, sizeof(BaseException)); BaseException* ud = py_newobject(py_retval(), cls, 0, sizeof(BaseException));
py_newnil(&ud->args);
py_newnil(&ud->inner_exc);
c11_vector__ctor(&ud->stacktrace, sizeof(BaseExceptionFrame)); c11_vector__ctor(&ud->stacktrace, sizeof(BaseExceptionFrame));
return true; return true;
} }
static bool _py_BaseException__init__(int argc, py_Ref argv) { static bool _py_BaseException__init__(int argc, py_Ref argv) {
BaseException* ud = py_touserdata(argv);
py_newnone(py_retval()); py_newnone(py_retval());
if(argc == 1 + 0) return true; if(argc == 1 + 0) return true;
if(argc == 1 + 1) { if(argc == 1 + 1) {
py_setslot(py_arg(0), 0, py_arg(1)); py_assign(&ud->args, &argv[1]);
return true; return true;
} }
return TypeError("__init__() takes at most 1 arguments but %d were given", argc - 1); return TypeError("__init__() takes at most 1 arguments but %d were given", argc - 1);
} }
static bool _py_BaseException__repr__(int argc, py_Ref argv) { static bool _py_BaseException__repr__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
BaseException* ud = py_touserdata(argv);
c11_sbuf ss; c11_sbuf ss;
c11_sbuf__ctor(&ss); c11_sbuf__ctor(&ss);
pk_sprintf(&ss, "%t(", argv->type); pk_sprintf(&ss, "%t(", argv->type);
py_Ref arg = py_getslot(argv, 0); py_Ref args = &ud->args;
if(!py_isnil(arg)) { if(!py_isnil(args)) {
if(!py_repr(arg)) return false; if(!py_repr(args)) return false;
c11_sbuf__write_sv(&ss, py_tosv(py_retval())); c11_sbuf__write_sv(&ss, py_tosv(py_retval()));
} }
c11_sbuf__write_char(&ss, ')'); c11_sbuf__write_char(&ss, ')');
@ -68,14 +72,16 @@ static bool _py_BaseException__repr__(int argc, py_Ref argv) {
} }
static bool _py_BaseException__str__(int argc, py_Ref argv) { static bool _py_BaseException__str__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
BaseException* ud = py_touserdata(argv);
c11_sbuf ss; c11_sbuf ss;
c11_sbuf__ctor(&ss); c11_sbuf__ctor(&ss);
py_Ref arg = py_getslot(argv, 0); py_Ref args = &ud->args;
if(!py_isnil(arg)) { if(!py_isnil(args)) {
if(argv->type == tp_KeyError) { if(argv->type == tp_KeyError) {
if(!py_repr(arg)) return false; if(!py_repr(args)) return false;
} else { } else {
if(!py_str(arg)) return false; if(!py_str(args)) return false;
} }
c11_sbuf__write_sv(&ss, py_tosv(py_retval())); c11_sbuf__write_sv(&ss, py_tosv(py_retval()));
} }
@ -84,11 +90,12 @@ static bool _py_BaseException__str__(int argc, py_Ref argv) {
} }
static bool BaseException_args(int argc, py_Ref argv) { static bool BaseException_args(int argc, py_Ref argv) {
BaseException* ud = py_touserdata(argv);
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
py_Ref arg = py_getslot(argv, 0); py_Ref args = &ud->args;
if(!py_isnil(arg)) { if(!py_isnil(args)) {
py_Ref p = py_newtuple(py_retval(), 1); py_Ref p = py_newtuple(py_retval(), 1);
p[0] = *arg; p[0] = *args;
} else { } else {
py_newtuple(py_retval(), 0); py_newtuple(py_retval(), 0);
} }
@ -96,12 +103,13 @@ static bool BaseException_args(int argc, py_Ref argv) {
} }
static bool StopIteration_value(int argc, py_Ref argv) { static bool StopIteration_value(int argc, py_Ref argv) {
BaseException* ud = py_touserdata(argv);
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
py_Ref arg = py_getslot(argv, 0); py_Ref args = &ud->args;
if(py_isnil(arg)) { if(py_isnil(args)) {
py_newnone(py_retval()); py_newnone(py_retval());
} else { } else {
py_assign(py_retval(), arg); py_assign(py_retval(), args);
} }
return true; return true;
} }
@ -158,14 +166,6 @@ void py_clearexc(py_StackRef p0) {
if(p0) vm->stack.sp = p0; if(p0) vm->stack.sp = p0;
} }
void py_printexc() {
char* msg = py_formatexc();
if(!msg) return;
pk_current_vm->callbacks.print(msg);
pk_current_vm->callbacks.print("\n");
PK_FREE(msg);
}
static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc) { static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc) {
if(true) { c11_sbuf__write_cstr(self, "Traceback (most recent call last):\n"); } if(true) { c11_sbuf__write_cstr(self, "Traceback (most recent call last):\n"); }
@ -195,6 +195,14 @@ static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc) {
c11_sbuf__write_cstr(self, message); c11_sbuf__write_cstr(self, message);
} }
void py_printexc() {
char* msg = py_formatexc();
if(!msg) return;
pk_current_vm->callbacks.print(msg);
pk_current_vm->callbacks.print("\n");
PK_FREE(msg);
}
char* py_formatexc() { char* py_formatexc() {
VM* vm = pk_current_vm; VM* vm = pk_current_vm;
if(py_isnil(&vm->curr_exception)) return NULL; if(py_isnil(&vm->curr_exception)) return NULL;
@ -205,7 +213,8 @@ char* py_formatexc() {
c11_sbuf ss; c11_sbuf ss;
c11_sbuf__ctor(&ss); c11_sbuf__ctor(&ss);
py_Ref inner = py_getslot(&vm->curr_exception, 1); BaseException* ud = py_touserdata(&vm->curr_exception);
py_Ref inner = &ud->inner_exc;
if(py_isnil(inner)) { if(py_isnil(inner)) {
c11_sbuf__write_exc(&ss, &vm->curr_exception); c11_sbuf__write_exc(&ss, &vm->curr_exception);
} else { } else {
@ -221,6 +230,8 @@ char* py_formatexc() {
memcpy(dup, res->data, res->size); memcpy(dup, res->data, res->size);
dup[res->size] = '\0'; dup[res->size] = '\0';
c11_string__delete(res); c11_string__delete(res);
if(py_debugger_isattached()) py_debugger_exceptionbreakpoint(&vm->curr_exception);
return dup; return dup;
} }
@ -253,16 +264,11 @@ bool py_raise(py_Ref exc) {
assert(py_isinstance(exc, tp_BaseException)); assert(py_isinstance(exc, tp_BaseException));
VM* vm = pk_current_vm; VM* vm = pk_current_vm;
if(!py_isnil(&vm->curr_exception)) { if(!py_isnil(&vm->curr_exception)) {
// inner exception BaseException* ud = py_touserdata(&vm->curr_exception);
py_setslot(exc, 1, &vm->curr_exception); ud->inner_exc = vm->curr_exception;
} }
vm->curr_exception = *exc; vm->curr_exception = *exc;
vm->is_curr_exc_handled = false; vm->is_curr_exc_handled = false;
if(vm->trace_info.func && !py_istype(exc, tp_StopIteration)) {
py_Frame* frame = vm->top_frame;
vm->trace_info.func(frame, TRACE_EVENT_EXCEPTION);
}
return false; return false;
} }