]> git.gag.com Git - fw/openocd/commitdiff
server/gdb: fix return of gdb remote monitor command
authorAntonio Borneo <borneo.antonio@gmail.com>
Wed, 30 Mar 2022 21:55:04 +0000 (23:55 +0200)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sat, 23 Apr 2022 09:25:43 +0000 (09:25 +0000)
Current implementation for gdb remote monitor command uses the
command_run_line() to execute the command.
While command_run_line() has several advantages, it unfortunately
hides the error codes and outputs the result of the command
through LOG_USER(), which is not what gdb requires. See 'qRcmd' in
https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html

Replace command_run_line() with Jim_EvalObj() and parse the output
to provide the proper result to gdb.

Can be tested by defining in OpenOCD:
proc a {} {return hello}
proc b {} {return -code 4}
proc c {} {return -code 4 "This is an error!"}
then by executing in gdb console:
monitor a
monitor b
monitor c
monitor foo

Change-Id: I1b85554d59221560e97861a499e16764e70c1172
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reported-by: Torbjorn Svensson <torbjorn.svensson@st.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6886
Tested-by: jenkins
src/server/gdb_server.c

index 82c8ce92b31faf395ee6f933ba147ee8ad1582ac..fcc87fba1c45a542e5d8f6855107dcee551d3bfe 100644 (file)
@@ -2761,11 +2761,52 @@ static int gdb_query_packet(struct connection *connection,
                        /* some commands need to know the GDB connection, make note of current
                         * GDB connection. */
                        current_gdb_connection = gdb_connection;
-                       command_run_line(cmd_ctx, cmd);
+                       struct target *saved_target_override = cmd_ctx->current_target_override;
+                       cmd_ctx->current_target_override = target;
+
+                       int retval = Jim_EvalObj(cmd_ctx->interp, Jim_NewStringObj(cmd_ctx->interp, cmd, -1));
+
+                       cmd_ctx->current_target_override = saved_target_override;
                        current_gdb_connection = NULL;
                        target_call_timer_callbacks_now();
                        gdb_connection->output_flag = GDB_OUTPUT_NO;
                        free(cmd);
+                       if (retval == JIM_RETURN)
+                               retval = cmd_ctx->interp->returnCode;
+                       int lenmsg;
+                       const char *cretmsg = Jim_GetString(Jim_GetResult(cmd_ctx->interp), &lenmsg);
+                       char *retmsg;
+                       if (lenmsg && cretmsg[lenmsg - 1] != '\n') {
+                               retmsg = alloc_printf("%s\n", cretmsg);
+                               lenmsg++;
+                       } else {
+                               retmsg = strdup(cretmsg);
+                       }
+                       if (!retmsg)
+                               return ERROR_GDB_BUFFER_TOO_SMALL;
+
+                       if (retval == JIM_OK) {
+                               if (lenmsg) {
+                                       char *hex_buffer = malloc(lenmsg * 2 + 1);
+                                       if (!hex_buffer) {
+                                               free(retmsg);
+                                               return ERROR_GDB_BUFFER_TOO_SMALL;
+                                       }
+
+                                       size_t pkt_len = hexify(hex_buffer, (const uint8_t *)retmsg, lenmsg,
+                                                                                       lenmsg * 2 + 1);
+                                       gdb_put_packet(connection, hex_buffer, pkt_len);
+                                       free(hex_buffer);
+                               } else {
+                                       gdb_put_packet(connection, "OK", 2);
+                               }
+                       } else {
+                               if (lenmsg)
+                                       gdb_output_con(connection, retmsg);
+                               gdb_send_error(connection, retval);
+                       }
+                       free(retmsg);
+                       return ERROR_OK;
                }
                gdb_put_packet(connection, "OK", 2);
                return ERROR_OK;