mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
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:
parent
839bf0ed1c
commit
d516b51063
@ -47,7 +47,7 @@ inline static void init_structures() {
|
|||||||
c11_vector__ctor(&debugger.py_frames, sizeof(py_Frame*));
|
c11_vector__ctor(&debugger.py_frames, sizeof(py_Frame*));
|
||||||
c11_smallmap_d2index__ctor(&debugger.scopes_query_cache);
|
c11_smallmap_d2index__ctor(&debugger.scopes_query_cache);
|
||||||
py_newlist(python_vars);
|
py_newlist(python_vars);
|
||||||
py_newnil(py_list_emplace(python_vars));
|
py_newnone(py_list_emplace(python_vars));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void clear_structures() {
|
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;
|
case TRACE_EVENT_POP: debugger.curr_stack_depth--; break;
|
||||||
default: 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;
|
return C11_DEBUGGER_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
X(initialize) \
|
X(initialize) \
|
||||||
X(setBreakpoints) \
|
X(setBreakpoints) \
|
||||||
X(attach) \
|
X(attach) \
|
||||||
|
X(launch) \
|
||||||
X(next) \
|
X(next) \
|
||||||
X(stepIn) \
|
X(stepIn) \
|
||||||
X(stepOut) \
|
X(stepOut) \
|
||||||
@ -16,7 +17,8 @@
|
|||||||
X(scopes) \
|
X(scopes) \
|
||||||
X(variables) \
|
X(variables) \
|
||||||
X(threads) \
|
X(threads) \
|
||||||
X(configurationDone)
|
X(configurationDone) \
|
||||||
|
X(ready)
|
||||||
|
|
||||||
#define DECLARE_HANDLE_FN(name) void c11_dap_handle_##name(py_Ref arguments, c11_sbuf*);
|
#define DECLARE_HANDLE_FN(name) void c11_dap_handle_##name(py_Ref arguments, c11_sbuf*);
|
||||||
DAP_COMMAND_LIST(DECLARE_HANDLE_FN)
|
DAP_COMMAND_LIST(DECLARE_HANDLE_FN)
|
||||||
@ -36,9 +38,6 @@ static dap_command_entry dap_command_table[] = {
|
|||||||
|
|
||||||
#undef DAP_ENTRY
|
#undef DAP_ENTRY
|
||||||
|
|
||||||
// #undef DAP_COMMAND_LIST
|
|
||||||
|
|
||||||
// static int dap_next_seq = 1;
|
|
||||||
static struct c11_dap_server {
|
static struct c11_dap_server {
|
||||||
int dap_next_seq;
|
int dap_next_seq;
|
||||||
char buffer_data[1024];
|
char buffer_data[1024];
|
||||||
@ -48,6 +47,7 @@ static struct c11_dap_server {
|
|||||||
c11_socket_handler toclient;
|
c11_socket_handler toclient;
|
||||||
bool isconfiguredone;
|
bool isconfiguredone;
|
||||||
bool isatttach;
|
bool isatttach;
|
||||||
|
bool isclientready;
|
||||||
} server;
|
} server;
|
||||||
|
|
||||||
void c11_dap_handle_initialize(py_Ref arguments, c11_sbuf* buffer) {
|
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_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) {
|
void c11_dap_handle_next(py_Ref arguments, c11_sbuf* buffer) {
|
||||||
c11_debugger_set_step_mode(C11_STEP_OVER);
|
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) {
|
const char* c11_dap_handle_request(const char* message) {
|
||||||
if(!py_json_loads(message)) {
|
if(!py_json_loads(message)) {
|
||||||
py_printexc();
|
py_printexc();
|
||||||
return NULL;
|
c11__abort("[DEBUGGER ERROR] invalid JSON request");
|
||||||
}
|
}
|
||||||
py_Ref py_request = py_pushtmp();
|
py_Ref py_request = py_pushtmp();
|
||||||
py_Ref py_arguments = 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];
|
char header[64];
|
||||||
int header_len = snprintf(header, sizeof(header), "Content-Length: %d\r\n\r\n", json_len);
|
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, header, header_len);
|
||||||
c11_socket_send(server.toclient, json, json_len);
|
c11_socket_send(server.toclient, json, json_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void c11_dap_send_stop_event() {
|
void c11_dap_send_stop_event() {
|
||||||
c11_dap_send_event("stopped",
|
c11_dap_send_event("stopped", "{\"threadId\":1,\"allThreadsStopped\":true}");
|
||||||
"{\"threadId\":1,\"allThreadsStopped\":true}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void c11_dap_send_exited_event(int exitCode) {
|
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;
|
char* endptr = NULL;
|
||||||
long value = strtol(length_begin, &endptr, 10);
|
long value = strtol(length_begin, &endptr, 10);
|
||||||
if(endptr == length_begin) {
|
if(endptr == length_begin) {
|
||||||
printf("[DEBUGGER EORRO] : the number is empty\n");
|
printf("[DEBUGGER EORRO] : the length field is empty\n");
|
||||||
*header_length = 0;
|
*header_length = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -321,16 +324,20 @@ void c11_dap_init_server(const char* hostname, unsigned short port) {
|
|||||||
server.isconfiguredone = false;
|
server.isconfiguredone = false;
|
||||||
server.buffer_begin = server.buffer_data;
|
server.buffer_begin = server.buffer_data;
|
||||||
server.server = c11_socket_create(C11_AF_INET, C11_SOCK_STREAM, 0);
|
server.server = c11_socket_create(C11_AF_INET, C11_SOCK_STREAM, 0);
|
||||||
|
server.isclientready = false;
|
||||||
c11_socket_bind(server.server, hostname, port);
|
c11_socket_bind(server.server, hostname, port);
|
||||||
c11_socket_listen(server.server, 0);
|
c11_socket_listen(server.server, 0);
|
||||||
printf("[DEBUGGER INFO] : listen on %s:%hu\n", hostname, port);
|
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);
|
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() {
|
inline static void c11_dap_handle_message() {
|
||||||
const char* message = c11_dap_read_message();
|
const char* message = c11_dap_read_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); }
|
||||||
@ -350,6 +357,9 @@ void c11_dap_configure_debugger() {
|
|||||||
if(server.isatttach) {
|
if(server.isatttach) {
|
||||||
c11_dap_send_initialized_event();
|
c11_dap_send_initialized_event();
|
||||||
server.isatttach = false;
|
server.isatttach = false;
|
||||||
|
} else if(server.isclientready) {
|
||||||
|
server.isclientready = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("[DEBUGGER INFO] : configure done\n");
|
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) {
|
void py_debugger_waitforattach(const char* hostname, unsigned short port) {
|
||||||
c11_dap_init_server(hostname, port);
|
|
||||||
c11_debugger_init();
|
c11_debugger_init();
|
||||||
|
c11_dap_init_server(hostname, port);
|
||||||
|
while(!server.isconfiguredone) {
|
||||||
|
c11_dap_waitforclient(hostname, port);
|
||||||
c11_dap_configure_debugger();
|
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);
|
c11_socket_set_block(server.toclient, 0);
|
||||||
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) {
|
||||||
char body[64];
|
c11_dap_send_exited_event(exitCode);
|
||||||
snprintf(body, sizeof(body), "{\"exitCode\":%d}", exitCode);
|
|
||||||
c11_dap_send_event("exited", body);
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user