Procházet zdrojové kódy

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>
lightovernight před 7 měsíci
rodič
revize
d516b51063
2 změnil soubory, kde provedl 33 přidání a 18 odebrání
  1. 2 2
      src/debugger/core.c
  2. 31 16
      src/debugger/dap.c

+ 2 - 2
src/debugger/core.c

@@ -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;
 }
 

+ 31 - 16
src/debugger/dap.c

@@ -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);
 }