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];
} 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.
enum py_TraceEvent {
TRACE_EVENT_LINE,
TRACE_EVENT_EXCEPTION,
TRACE_EVENT_PUSH,
TRACE_EVENT_POP,
};
@ -710,6 +709,8 @@ PK_API char* py_profiler_report();
/************* DAP *************/
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);
/************* Unchecked Functions *************/
@ -820,9 +821,9 @@ enum py_PredefinedType {
tp_module,
tp_function,
tp_nativefunc,
tp_boundmethod, // 2 slots (self, func)
tp_super, // 1 slot + py_Type
tp_BaseException, // 2 slots (arg + inner_exc)
tp_boundmethod, // 2 slots (self, func)
tp_super, // 1 slot + py_Type
tp_BaseException,
tp_Exception,
tp_bytes,
tp_namedict,

View File

@ -3,6 +3,8 @@
#include "pocketpy/common/socket.h"
#include "pocketpy/debugger/core.h"
#include "pocketpy/objects/base.h"
#include "pocketpy/objects/exception.h"
#include "pocketpy/pocketpy.h"
#define DAP_COMMAND_LIST(X) \
X(initialize) \
@ -59,7 +61,7 @@ void c11_dap_handle_attach(py_Ref arguments, c11_sbuf* buffer) { server.isatttac
void c11_dap_handle_launch(py_Ref arguments, c11_sbuf* buffer) { server.isatttach = true; }
void c11_dap_handle_ready(py_Ref arguments, c11_sbuf* buffer) {server.isclientready = true;}
void c11_dap_handle_ready(py_Ref arguments, c11_sbuf* buffer) { server.isclientready = true; }
void c11_dap_handle_next(py_Ref arguments, c11_sbuf* buffer) {
c11_debugger_set_step_mode(C11_STEP_OVER);
@ -340,7 +342,8 @@ inline static void c11_dap_handle_message() {
if(message == NULL) { return; }
// printf("[DEBUGGER INFO] read request %s\n", 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__ctor(&buffer);
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);
}
void py_debugger_exit(int exitCode) {
c11_dap_send_exited_event(exitCode);
void py_debugger_exit(int 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();
__ERROR:
py_BaseException__stpush(&self->curr_exception,
py_BaseException__stpush(frame, &self->curr_exception,
frame->co->src,
Frame__lineno(frame),
!frame->is_locals_special ? frame->co->name->data : NULL);

View File

@ -7,6 +7,7 @@
#include "pocketpy/objects/base.h"
#include "pocketpy/interpreter/types.h"
#include "pocketpy/common/_generated.h"
#include "pocketpy/objects/exception.h"
#include "pocketpy/pocketpy.h"
#include <stdbool.h>
#include <assert.h>
@ -719,6 +720,16 @@ void ManagedHeap__mark(ManagedHeap* self) {
function__gc_mark(ud, p_stack);
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: {
CodeObject* self = ud;
CodeObject__gc_mark(self, p_stack);

View File

@ -22,7 +22,7 @@ bool _py_compile(CodeObject* out,
Error* err = pk_compile(src, out);
if(err) {
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(err->src);

View File

@ -1,30 +1,29 @@
#include "pocketpy/objects/codeobject.h"
#include "pocketpy/objects/error.h"
#include "pocketpy/pocketpy.h"
#include "pocketpy/common/utils.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/sstream.h"
#include "pocketpy/objects/exception.h"
typedef struct BaseExceptionFrame {
SourceData_ src;
int lineno;
c11_string* name;
} BaseExceptionFrame;
typedef struct BaseException {
c11_vector /*T=BaseExceptionFrame*/ stacktrace;
} BaseException;
void py_BaseException__stpush(py_Ref self, SourceData_ src, int lineno, const char* func_name) {
void py_BaseException__stpush(py_Frame* frame,
py_Ref self,
SourceData_ src,
int lineno,
const char* func_name) {
BaseException* ud = py_touserdata(self);
if(ud->stacktrace.length >= 7) return;
BaseExceptionFrame* frame = c11_vector__emplace(&ud->stacktrace);
int max_frame_dumps = py_debugger_isattached() ? 31 : 7;
if(ud->stacktrace.length >= max_frame_dumps) return;
BaseExceptionFrame* frame_dump = c11_vector__emplace(&ud->stacktrace);
PK_INCREF(src);
frame->src = src;
frame->lineno = lineno;
frame->name = func_name ? c11_string__new(func_name) : NULL;
frame_dump->src = src;
frame_dump->lineno = lineno;
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) {
@ -38,28 +37,33 @@ static void BaseException__dtor(void* ud) {
static bool _py_BaseException__new__(int argc, py_Ref 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));
return true;
}
static bool _py_BaseException__init__(int argc, py_Ref argv) {
BaseException* ud = py_touserdata(argv);
py_newnone(py_retval());
if(argc == 1 + 0) return true;
if(argc == 1 + 1) {
py_setslot(py_arg(0), 0, py_arg(1));
py_assign(&ud->args, &argv[1]);
return true;
}
return TypeError("__init__() takes at most 1 arguments but %d were given", argc - 1);
}
static bool _py_BaseException__repr__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
BaseException* ud = py_touserdata(argv);
c11_sbuf ss;
c11_sbuf__ctor(&ss);
pk_sprintf(&ss, "%t(", argv->type);
py_Ref arg = py_getslot(argv, 0);
if(!py_isnil(arg)) {
if(!py_repr(arg)) return false;
py_Ref args = &ud->args;
if(!py_isnil(args)) {
if(!py_repr(args)) return false;
c11_sbuf__write_sv(&ss, py_tosv(py_retval()));
}
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) {
PY_CHECK_ARGC(1);
BaseException* ud = py_touserdata(argv);
c11_sbuf ss;
c11_sbuf__ctor(&ss);
py_Ref arg = py_getslot(argv, 0);
if(!py_isnil(arg)) {
py_Ref args = &ud->args;
if(!py_isnil(args)) {
if(argv->type == tp_KeyError) {
if(!py_repr(arg)) return false;
if(!py_repr(args)) return false;
} else {
if(!py_str(arg)) return false;
if(!py_str(args)) return false;
}
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) {
BaseException* ud = py_touserdata(argv);
PY_CHECK_ARGC(1);
py_Ref arg = py_getslot(argv, 0);
if(!py_isnil(arg)) {
py_Ref args = &ud->args;
if(!py_isnil(args)) {
py_Ref p = py_newtuple(py_retval(), 1);
p[0] = *arg;
p[0] = *args;
} else {
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) {
BaseException* ud = py_touserdata(argv);
PY_CHECK_ARGC(1);
py_Ref arg = py_getslot(argv, 0);
if(py_isnil(arg)) {
py_Ref args = &ud->args;
if(py_isnil(args)) {
py_newnone(py_retval());
} else {
py_assign(py_retval(), arg);
py_assign(py_retval(), args);
}
return true;
}
@ -158,14 +166,6 @@ void py_clearexc(py_StackRef 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) {
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);
}
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() {
VM* vm = pk_current_vm;
if(py_isnil(&vm->curr_exception)) return NULL;
@ -205,7 +213,8 @@ char* py_formatexc() {
c11_sbuf 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)) {
c11_sbuf__write_exc(&ss, &vm->curr_exception);
} else {
@ -221,6 +230,8 @@ char* py_formatexc() {
memcpy(dup, res->data, res->size);
dup[res->size] = '\0';
c11_string__delete(res);
if(py_debugger_isattached()) py_debugger_exceptionbreakpoint(&vm->curr_exception);
return dup;
}
@ -253,16 +264,11 @@ bool py_raise(py_Ref exc) {
assert(py_isinstance(exc, tp_BaseException));
VM* vm = pk_current_vm;
if(!py_isnil(&vm->curr_exception)) {
// inner exception
py_setslot(exc, 1, &vm->curr_exception);
BaseException* ud = py_touserdata(&vm->curr_exception);
ud->inner_exc = vm->curr_exception;
}
vm->curr_exception = *exc;
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;
}