Gsoc 2025 debugger (#387)

* add debugger module

* simplify the workdir process

* Update main.c

* Update main.c

* update debugger

* change port to 6110

* Update main.c

* simplify the workdir process and minor optimizations

* implement exit event

* Fix memory management in setBreakpoints

* replace free to PK_FREE

* Add custom command ready

---------

Co-authored-by: blueloveTH <blueloveth@foxmail.com>
This commit is contained in:
lightovernight 2025-08-16 20:04:59 +08:00 committed by GitHub
parent 839bf0ed1c
commit d516b51063
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 18 deletions

View File

@ -47,7 +47,7 @@ inline static void init_structures() {
c11_vector__ctor(&debugger.py_frames, sizeof(py_Frame*));
c11_smallmap_d2index__ctor(&debugger.scopes_query_cache);
py_newlist(python_vars);
py_newnil(py_list_emplace(python_vars));
py_newnone(py_list_emplace(python_vars));
}
inline static void clear_structures() {
@ -91,7 +91,7 @@ C11_DEBUGGER_STATUS c11_debugger_on_trace(py_Frame* frame, enum py_TraceEvent ev
case TRACE_EVENT_POP: debugger.curr_stack_depth--; break;
default: break;
}
if(debugger.curr_stack_depth == 0) return C11_DEBUGGER_EXIT;
// if(debugger.curr_stack_depth == 0) return C11_DEBUGGER_EXIT;
return C11_DEBUGGER_SUCCESS;
}

View File

@ -8,6 +8,7 @@
X(initialize) \
X(setBreakpoints) \
X(attach) \
X(launch) \
X(next) \
X(stepIn) \
X(stepOut) \
@ -16,7 +17,8 @@
X(scopes) \
X(variables) \
X(threads) \
X(configurationDone)
X(configurationDone) \
X(ready)
#define DECLARE_HANDLE_FN(name) void c11_dap_handle_##name(py_Ref arguments, c11_sbuf*);
DAP_COMMAND_LIST(DECLARE_HANDLE_FN)
@ -36,9 +38,6 @@ static dap_command_entry dap_command_table[] = {
#undef DAP_ENTRY
// #undef DAP_COMMAND_LIST
// static int dap_next_seq = 1;
static struct c11_dap_server {
int dap_next_seq;
char buffer_data[1024];
@ -48,6 +47,7 @@ static struct c11_dap_server {
c11_socket_handler toclient;
bool isconfiguredone;
bool isatttach;
bool isclientready;
} server;
void c11_dap_handle_initialize(py_Ref arguments, c11_sbuf* buffer) {
@ -57,6 +57,10 @@ void c11_dap_handle_initialize(py_Ref arguments, c11_sbuf* buffer) {
void c11_dap_handle_attach(py_Ref arguments, c11_sbuf* buffer) { server.isatttach = true; }
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_next(py_Ref arguments, c11_sbuf* buffer) {
c11_debugger_set_step_mode(C11_STEP_OVER);
}
@ -154,7 +158,7 @@ void c11_dap_handle_variables(py_Ref arguments, c11_sbuf* buffer) {
const char* c11_dap_handle_request(const char* message) {
if(!py_json_loads(message)) {
py_printexc();
return NULL;
c11__abort("[DEBUGGER ERROR] invalid JSON request");
}
py_Ref py_request = py_pushtmp();
py_Ref py_arguments = py_pushtmp();
@ -222,14 +226,13 @@ void c11_dap_send_event(const char* event_name, const char* body_json) {
char header[64];
int header_len = snprintf(header, sizeof(header), "Content-Length: %d\r\n\r\n", json_len);
// printf("[DEBUGGER INFO] send event %s\n", json);
c11_socket_send(server.toclient, header, header_len);
c11_socket_send(server.toclient, json, json_len);
}
void c11_dap_send_stop_event() {
c11_dap_send_event("stopped",
"{\"threadId\":1,\"allThreadsStopped\":true}");
c11_dap_send_event("stopped", "{\"threadId\":1,\"allThreadsStopped\":true}");
}
void c11_dap_send_exited_event(int exitCode) {
@ -263,7 +266,7 @@ int c11_dap_read_content_length(const char* buffer, int* header_length) {
char* endptr = NULL;
long value = strtol(length_begin, &endptr, 10);
if(endptr == length_begin) {
printf("[DEBUGGER EORRO] : the number is empty\n");
printf("[DEBUGGER EORRO] : the length field is empty\n");
*header_length = 0;
return -1;
}
@ -321,16 +324,20 @@ void c11_dap_init_server(const char* hostname, unsigned short port) {
server.isconfiguredone = false;
server.buffer_begin = server.buffer_data;
server.server = c11_socket_create(C11_AF_INET, C11_SOCK_STREAM, 0);
server.isclientready = false;
c11_socket_bind(server.server, hostname, port);
c11_socket_listen(server.server, 0);
printf("[DEBUGGER INFO] : listen on %s:%hu\n", hostname, port);
}
void c11_dap_waitforclient(const char* hostname, unsigned short port) {
server.toclient = c11_socket_accept(server.server, NULL, NULL);
printf("[DEBUGGER INFO] : connected client\n");
printf("[DEBUGGER INFO] : connected a client\n");
}
inline static void c11_dap_handle_message() {
const char* message = c11_dap_read_message();
if(message == NULL) return;
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); }
@ -350,6 +357,9 @@ void c11_dap_configure_debugger() {
if(server.isatttach) {
c11_dap_send_initialized_event();
server.isatttach = false;
} else if(server.isclientready) {
server.isclientready = false;
return;
}
}
printf("[DEBUGGER INFO] : configure done\n");
@ -389,15 +399,20 @@ void c11_dap_tracefunc(py_Frame* frame, enum py_TraceEvent event) {
}
void py_debugger_waitforattach(const char* hostname, unsigned short port) {
c11_dap_init_server(hostname, port);
c11_debugger_init();
c11_dap_configure_debugger();
c11_dap_init_server(hostname, port);
while(!server.isconfiguredone) {
c11_dap_waitforclient(hostname, port);
c11_dap_configure_debugger();
if(!server.isconfiguredone) {
c11_socket_close(server.toclient);
printf("[DEBUGGER INFO] : An clinet is ready\n");
}
}
c11_socket_set_block(server.toclient, 0);
py_sys_settrace(c11_dap_tracefunc, true);
}
void py_debugger_exit(int exitCode) {
char body[64];
snprintf(body, sizeof(body), "{\"exitCode\":%d}", exitCode);
c11_dap_send_event("exited", body);
c11_dap_send_exited_event(exitCode);
}