I just realized that we can print out some messages when
handling the stepi/continue packets to inform the GDB
user what's happening.



-- 
Øyvind Harboe
http://www.zylin.com/zy1000.html
ARM7 ARM9 ARM11 XScale Cortex
JTAG debugger and flash programmer
### Eclipse Workspace Patch 1.0
#P openocd
Index: src/server/gdb_server.h
===================================================================
--- src/server/gdb_server.h     (revision 2748)
+++ src/server/gdb_server.h     (working copy)
@@ -43,6 +43,10 @@
        int closed;
        int busy;
        int noack_mode;
+       bool sync;      /* set flag to true if you want the next stepi to 
return immediately.
+                      allowing GDB to pick up a fresh set of register values 
from the target
+                      without modifying the target state. */
+
 } gdb_connection_t;
 
 typedef struct gdb_service_s
Index: src/server/gdb_server.c
===================================================================
--- src/server/gdb_server.c     (revision 2748)
+++ src/server/gdb_server.c     (working copy)
@@ -40,6 +40,8 @@
 #define _DEBUG_GDB_IO_
 #endif
 
+static gdb_connection_t *current_gdb_connection;
+
 static int gdb_breakpoint_override;
 static enum breakpoint_type gdb_breakpoint_override_type;
 
@@ -750,6 +752,7 @@
        gdb_connection->closed = 0;
        gdb_connection->busy = 0;
        gdb_connection->noack_mode = 0;
+       gdb_connection->sync = true;
 
        /* send ACK to GDB for debug request */
        gdb_write(connection, "+", 1);
@@ -767,30 +770,6 @@
        /* register callback to be informed about target events */
        target_register_event_callback(gdb_target_callback_event_handler, 
connection);
 
-       /* a gdb session just attached, try to put the target in halt mode.
-        *
-        * DANGER!!!!
-        *
-        * If the halt fails(e.g. target needs a reset, JTAG communication not
-        * working, etc.), then the GDB connect will succeed as
-        * the get_gdb_reg_list() will lie and return a register list with
-        * dummy values.
-        *
-        * This allows GDB monitor commands to be run from a GDB init script to
-        * initialize the target
-        *
-        * Also, since the halt() is asynchronous target connect will be
-        * instantaneous and thus avoiding annoying timeout problems during
-        * connect.
-        */
-       target_halt(gdb_service->target);
-       /* FIX!!!! could extended-remote work better here?
-        *
-        *  wait a tiny bit for halted state or we just continue. The
-        * GDB register packet will then contain garbage
-        */
-       target_wait_state(gdb_service->target, TARGET_HALTED, 500);
-
        /* remove the initial ACK from the incoming buffer */
        if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)
                return retval;
@@ -1609,7 +1588,11 @@
                        /* We want to print all debug output to GDB connection 
*/
                        log_add_callback(gdb_log_callback, connection);
                        target_call_timer_callbacks_now();
+                       /* 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);
+                       current_gdb_connection = NULL;
                        target_call_timer_callbacks_now();
                        log_remove_callback(gdb_log_callback, connection);
                        free(cmd);
@@ -2107,20 +2090,47 @@
                                case 'c':
                                case 's':
                                        {
-                                               if (target->state != 
TARGET_HALTED)
+                                               int retval = ERROR_OK;
+                                               gdb_connection_t *gdb_con = 
connection->priv;
+                                               
log_add_callback(gdb_log_callback, connection);
+
+                                               bool nostep = false;
+                                               if (target->state == 
TARGET_RUNNING)
+                                               {
+                                                       LOG_WARNING("The target 
is already running. Halt target before stepi/continue.");
+                                                       retval = 
target_halt(target);
+                                                       if (retval == ERROR_OK)
+                                                               retval = 
target_wait_state(target, TARGET_HALTED, 100);
+                                               } else if (target->state != 
TARGET_HALTED)
+                                               {
+                                                       LOG_WARNING("The target 
is not in the halted nor running stated, stepi/continue ignored.");
+                                                       nostep = true;
+                                               } else if (gdb_con->sync)
+                                               {
+                                                       nostep = true;
+                                                       
LOG_WARNING("stepi/continue ignored. GDB will now fetch the register state from 
the target.");
+                                               }
+                                               gdb_con->sync = false;
+
+                                               if ((retval!=ERROR_OK) || 
nostep)
                                                {
-                                                       /* If the target isn't 
in the halted state, then we can't
+                                                       /* Either the target 
isn't in the halted state, then we can't
                                                         * step/continue. This 
might be early setup, etc.
+                                                        *
+                                                        * Or we want to allow 
GDB to pick up a fresh set of
+                                                        * register values 
without modifying the target state.
+                                                        *
                                                         */
                                                        
gdb_sig_halted(connection);
+
+                                                       /* stop forwarding log 
packets! */
+                                                       
log_remove_callback(gdb_log_callback, connection);
                                                } else
                                                {
                                                        /* We're 
running/stepping, in which case we can
                                                         * forward log output 
until the target is halted
                                                         */
-                                                       gdb_connection_t 
*gdb_con = connection->priv;
                                                        gdb_con->frontend_state 
= TARGET_RUNNING;
-                                                       
log_add_callback(gdb_log_callback, connection);
                                                        
target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
                                                        int retval = 
gdb_step_continue_packet(connection, target, packet, packet_size);
                                                        if (retval != ERROR_OK)
@@ -2255,6 +2265,25 @@
        return ERROR_OK;
 }
 
+int handle_gdb_sync_command(struct command_context_s *cmd_ctx, char *cmd, char 
**args, int argc)
+{
+       if (argc != 0)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (current_gdb_connection == NULL)
+       {
+               command_print(cmd_ctx,
+                               "gdb_sync command can only be run from within 
gdb using \"monitor gdb_sync\"");
+               return ERROR_FAIL;
+       }
+
+       current_gdb_connection->sync = true;
+
+       return ERROR_OK;
+}
+
 /* daemon configuration command gdb_port */
 int handle_gdb_port_command(struct command_context_s *cmd_ctx, char *cmd, char 
**args, int argc)
 {
@@ -2399,6 +2428,8 @@
 
 int gdb_register_commands(command_context_t *command_context)
 {
+       register_command(command_context, NULL, "gdb_sync", 
handle_gdb_sync_command,
+                       COMMAND_ANY, "next stepi will return immediately 
allowing GDB fetch register state without affecting target state");
        register_command(command_context, NULL, "gdb_port", 
handle_gdb_port_command,
                        COMMAND_ANY, "daemon configuration command gdb_port");
        register_command(command_context, NULL, "gdb_detach", 
handle_gdb_detach_command,
_______________________________________________
Openocd-development mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/openocd-development

Reply via email to