Patch attached.

1. The first "stepi/continue" after a connect will return immediately
without affecting the state of the target. This allows GDB to sync
up to the target state. Nice when wanting to attach GDB to
a running target and deciding using GDB monitor commands how
to start examining/halting the target.

2. You can explicitly use the "monitor gdb_sync" command to tell
OpenOCD to return immediately from the next stepi/continue to
sync up GDB to the target state.

3. As before GDB will return garbage register values to allow
GDB to be in the "halted" state even if the target is running,
powered down or unresponsive, etc.

A possible change would be to automatically set the
sync flag if *any* monitor command was issued from GDB,
but I held back on that one since it seemed a bit too helpful...


(gdb) monitor reg pc 0x20000000
pc (/32): 0x20000000
(gdb) print $pc
$2 = (void (*)()) 0x18

# Now sync up GDB to target register values!

(gdb) monitor gdb_sync

# Notice that target state is not affected!
(gdb) stepi

Program received signal SIGINT, Interrupt.
0x20000000 in ?? ()

# if we didn't have the gdb_sync command, we would
# have crashed when donig a stepi to sync up!
(gdb) c
Continuing.
Sensed nSRST asserted.

Program received signal SIGTRAP, Trace/breakpoint trap.
0xe880ffe6 in ?? ()



On Mon, Sep 21, 2009 at 9:02 PM, Øyvind Harboe <oyvind.har...@zylin.com> wrote:
> I'm wondering if it would be a good idea to modify the handling
> of GDB halted/running state as follows:
>
> - do nothing upon attaching GDB to OpenOCD. This gives
> the GDB init script more freedom w.r.t. what should happen
> when connecting to the target.
> - if the target is running and GDB is halted, then OpenOCD
> returns "white lies" in the register and memory queries. This
> allows users to issue a "monitor halt" or "stepi/continue" command
> after attaching to either halt the target or sync up with it.
> - When connecting to a halted target, the next stepi/continue
> returns immediately, thus allowing the register state to sync
> up to the current state of the target without modifying the
> state of the target
> - if, while GDB is halted, the target state changes behind
> GDBs back, then the  next stepi/continue returns immediately
> to sync up GDB to the current state
>
>
> --
> Øyvind Harboe
> Embedded software and hardware consulting services
> http://www.zylin.com
>



-- 
Ø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,10 +2090,17 @@
                                case 'c':
                                case 's':
                                        {
-                                               if (target->state != 
TARGET_HALTED)
+                                               gdb_connection_t *gdb_con = 
connection->priv;
+                                               bool nostep = (target->state != 
TARGET_HALTED) || gdb_con->sync;
+                                               gdb_con->sync = false;
+                                               if (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);
                                                } else
@@ -2118,7 +2108,6 @@
                                                        /* 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);
@@ -2255,6 +2244,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 +2407,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
Openocd-development@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/openocd-development

Reply via email to