- added myself to copyright on files i remember adding large contributions for over...
[openocd.git] / src / server / gdb_server.c
index 8ebe94395f456468cb39855badfd22d50da4a7d6..7a50fbaaf91cb9eaa1324be91bfb007bc6ef275d 100644 (file)
@@ -5,6 +5,9 @@
  *   Copyright (C) 2007,2008 Ã˜yvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
  *   the Free Software Foundation; either version 2 of the License, or     *
@@ -395,13 +398,119 @@ int gdb_put_packet(connection_t *connection, char *buffer, int len)
        return retval;
 }
 
-int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
+static __inline__ int fetch_packet(connection_t *connection, int *checksum_ok, int noack, int *len, char *buffer)
 {
+       unsigned char my_checksum = 0;
+       char checksum[3];
        int character;
+       int retval;
+       
+       gdb_connection_t *gdb_con = connection->priv;
+       my_checksum = 0;
        int count = 0;
+       count = 0;
+       for (;;)
+       {
+               /* The common case is that we have an entire packet with no escape chars.
+                * We need to leave at least 2 bytes in the buffer to have
+                * gdb_get_char() update various bits and bobs correctly.
+                */
+               if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len))
+               {
+                       /* The compiler will struggle a bit with constant propagation and
+                        * aliasing, so we help it by showing that these values do not
+                        * change inside the loop
+                        */
+                       int i;
+                       char *buf = gdb_con->buf_p;
+                       int run = gdb_con->buf_cnt - 2;
+                       i = 0;
+                       int done = 0;
+                       while (i < run)
+                       {
+                               character = *buf++;
+                               i++;
+                               if (character == '#')
+                               {
+                                       /* Danger! character can be '#' when esc is
+                                        * used so we need an explicit boolean for done here.
+                                        */
+                                       done = 1;
+                                       break;
+                               }
+
+                               if (character == '}')
+                               {
+                                       /* data transmitted in binary mode (X packet)
+                                        * uses 0x7d as escape character */
+                                       my_checksum += character & 0xff;
+                                       character = *buf++;
+                                       i++;
+                                       my_checksum += character & 0xff;
+                                       buffer[count++] = (character ^ 0x20) & 0xff;
+                               }
+                               else
+                               {
+                                       my_checksum += character & 0xff;
+                                       buffer[count++] = character & 0xff;
+                               }
+                       }
+                       gdb_con->buf_p += i;
+                       gdb_con->buf_cnt -= i;
+                       if (done)
+                               break;
+               }
+               if (count > *len)
+               {
+                       LOG_ERROR("packet buffer too small");
+                       return ERROR_GDB_BUFFER_TOO_SMALL;
+               }
+
+               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+                       return retval;
+
+               if (character == '#')
+                       break;
+
+               if (character == '}')
+               {
+                       /* data transmitted in binary mode (X packet)
+                        * uses 0x7d as escape character */
+                       my_checksum += character & 0xff;
+                       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+                               return retval;
+                       my_checksum += character & 0xff;
+                       buffer[count++] = (character ^ 0x20) & 0xff;
+               }
+               else
+               {
+                       my_checksum += character & 0xff;
+                       buffer[count++] = character & 0xff;
+               }
+       }
+
+       *len = count;
+
+       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+               return retval;
+       checksum[0] = character;
+       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+               return retval;
+       checksum[1] = character;
+       checksum[2] = 0;
+       
+       if (!noack)
+       {
+               *checksum_ok=(my_checksum == strtoul(checksum, NULL, 16));
+       }
+       
+       return ERROR_OK;
+}
+
+int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
+{
+       int character;
        int retval;
-       char checksum[3];
-       unsigned char my_checksum = 0;
        gdb_connection_t *gdb_con = connection->priv;
 
        while (1)
@@ -437,116 +546,30 @@ int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
                        }
                } while (character != '$');
 
-               my_checksum = 0;
 
-               count = 0;
-               gdb_connection_t *gdb_con = connection->priv;
-               for (;;)
-               {
-                       /* The common case is that we have an entire packet with no escape chars.
-                        * We need to leave at least 2 bytes in the buffer to have
-                        * gdb_get_char() update various bits and bobs correctly.
-                        */
-                       if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len))
-                       {
-                               /* The compiler will struggle a bit with constant propagation and
-                                * aliasing, so we help it by showing that these values do not
-                                * change inside the loop
-                                */
-                               int i;
-                               char *buf = gdb_con->buf_p;
-                               int run = gdb_con->buf_cnt - 2;
-                               i = 0;
-                               int done = 0;
-                               while (i < run)
-                               {
-                                       character = *buf++;
-                                       i++;
-                                       if (character == '#')
-                                       {
-                                               /* Danger! character can be '#' when esc is
-                                                * used so we need an explicit boolean for done here.
-                                                */
-                                               done = 1;
-                                               break;
-                                       }
 
-                                       if (character == '}')
-                                       {
-                                               /* data transmitted in binary mode (X packet)
-                                                * uses 0x7d as escape character */
-                                               my_checksum += character & 0xff;
-                                               character = *buf++;
-                                               i++;
-                                               my_checksum += character & 0xff;
-                                               buffer[count++] = (character ^ 0x20) & 0xff;
-                                       }
-                                       else
-                                       {
-                                               my_checksum += character & 0xff;
-                                               buffer[count++] = character & 0xff;
-                                       }
-                               }
-                               gdb_con->buf_p += i;
-                               gdb_con->buf_cnt -= i;
-                               if (done)
-                                       break;
-                       }
-                       if (count > *len)
-                       {
-                               LOG_ERROR("packet buffer too small");
-                               return ERROR_GDB_BUFFER_TOO_SMALL;
-                       }
-
-                       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+               int checksum_ok;
+               /* explicit code expansion here to get faster inlined code in -O3 by not
+                * calculating checksum
+                */
+               if (gdb_con->noack_mode)
+               {
+                       if ((retval=fetch_packet(connection, &checksum_ok, 1, len, buffer))!=ERROR_OK)
                                return retval;
-
-                       if (character == '#')
-                               break;
-
-                       if (character == '}')
-                       {
-                               /* data transmitted in binary mode (X packet)
-                                * uses 0x7d as escape character */
-                               my_checksum += character & 0xff;
-                               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                                       return retval;
-                               my_checksum += character & 0xff;
-                               buffer[count++] = (character ^ 0x20) & 0xff;
-                       }
-                       else
-                       {
-                               my_checksum += character & 0xff;
-                               buffer[count++] = character & 0xff;
-                       }
-               }
-
-               *len = count;
-
-               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                       return retval;
-               checksum[0] = character;
-               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                       return retval;
-               checksum[1] = character;
-               checksum[2] = 0;
-
-               if (my_checksum == strtoul(checksum, NULL, 16))
+               } else
                {
-                       if (gdb_con->noack_mode)
-                               break;
-                       gdb_write(connection, "+", 1);
-                       break;
+                       if ((retval=fetch_packet(connection, &checksum_ok, 0, len, buffer))!=ERROR_OK)
+                               return retval;
                }
 
-               if (!gdb_con->noack_mode)
+               if (gdb_con->noack_mode)
                {
-                       LOG_WARNING("checksum error, requesting retransmission");
-                       gdb_write(connection, "-", 1);
+                       /* checksum is not checked in noack mode */
+                       break;
                }
-               else
+               if (checksum_ok)
                {
-                       LOG_WARNING("checksum error, no-ack-mode");
+                       gdb_write(connection, "+", 1);
                        break;
                }
        }
@@ -594,15 +617,6 @@ int gdb_output(struct command_context_s *context, const char* line)
        return ERROR_OK;
 }
 
-int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)
-{
-       struct command_context_s *cmd_ctx = priv;
-
-       target_invoke_script(cmd_ctx, target, "gdb_program");
-       jtag_execute_queue();
-
-       return ERROR_OK;
-}
 
 static void gdb_frontend_halted(struct target_s *target, connection_t *connection)
 {
@@ -644,13 +658,15 @@ int gdb_target_callback_event_handler(struct target_s *target, enum target_event
 {
        connection_t *connection = priv;
 
+       target_handle_event( target, event );
        switch (event)
        {
                case TARGET_EVENT_HALTED:
                        gdb_frontend_halted(target, connection);
                        break;
-               case TARGET_EVENT_GDB_PROGRAM:
-                       gdb_program_handler(target, event, connection->cmd_ctx);
+               case TARGET_EVENT_GDB_FLASH_ERASE_START:
+                       target_handle_event( target, TARGET_EVENT_OLD_gdb_program_config );
+                       jtag_execute_queue();
                        break;
                default:
                        break;
@@ -728,7 +744,7 @@ int gdb_new_connection(connection_t *connection)
         */
        if (initial_ack != '+')
                gdb_putback_char(connection, initial_ack);
-
+       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH );
        return ERROR_OK;
 }
 
@@ -761,6 +777,7 @@ int gdb_connection_closed(connection_t *connection)
        target_unregister_event_callback(gdb_target_callback_event_handler, connection);
        log_remove_callback(gdb_log_callback, connection);
 
+       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH );
        return ERROR_OK;
 }
 
@@ -1259,7 +1276,7 @@ int gdb_step_continue_packet(connection_t *connection, target_t *target, char *p
        if (packet[0] == 'c')
        {
                LOG_DEBUG("continue");
-               target_invoke_script(connection->cmd_ctx, target, "pre_resume");
+               target_handle_event( target, TARGET_EVENT_OLD_pre_resume );
                retval=target_resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */
        }
        else if (packet[0] == 's')
@@ -1769,10 +1786,12 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
                flash_set_dirty();
 
                /* perform any target specific operations before the erase */
-               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);
+               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_START);
+               result = flash_erase_address_range(gdb_service->target, addr, length );
+               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_END);
 
                /* perform erase */
-               if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)
+               if (result != ERROR_OK)
                {
                        /* GDB doesn't evaluate the actual error number returned,
                         * treat a failed erase as an I/O error
@@ -1826,7 +1845,10 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
 
                /* process the flashing buffer. No need to erase as GDB
                 * always issues a vFlashErase first. */
-               if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0)) != ERROR_OK)
+               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_START);
+               result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0);
+               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END);
+               if ( result != ERROR_OK)
                {
                        if (result == ERROR_FLASH_DST_OUT_OF_BANK)
                                gdb_put_packet(connection, "E.memtype", 9);
@@ -1852,10 +1874,11 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
 
 int gdb_detach(connection_t *connection, target_t *target)
 {
+
        switch( detach_mode )
        {
                case GDB_DETACH_RESUME:
-                       target_invoke_script(connection->cmd_ctx, target, "pre_resume");
+                       target_handle_event( target, TARGET_EVENT_OLD_pre_resume );
                        target_resume(target, 1, 0, 1, 0);
                        break;
 
@@ -1873,7 +1896,6 @@ int gdb_detach(connection_t *connection, target_t *target)
        }
 
        gdb_put_packet(connection, "OK", 2);
-
        return ERROR_OK;
 }
 
@@ -2063,8 +2085,7 @@ int gdb_input(connection_t *connection)
 int gdb_init(void)
 {
        gdb_service_t *gdb_service;
-       target_t *target = targets;
-       int i = 0;
+       target_t *target = all_targets;
 
        if (!target)
        {
@@ -2082,16 +2103,21 @@ int gdb_init(void)
        {
                char service_name[8];
 
-               snprintf(service_name, 8, "gdb-%2.2i", i);
+               snprintf(service_name, 8, "gdb-%2.2i", target->target_number);
 
                gdb_service = malloc(sizeof(gdb_service_t));
                gdb_service->target = target;
 
-               add_service("gdb", CONNECTION_GDB, gdb_port + i, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
+               add_service("gdb", CONNECTION_GDB, 
+                           gdb_port + target->target_number, 
+                           1, gdb_new_connection, gdb_input, 
+                           gdb_connection_closed, 
+                           gdb_service);
 
-               LOG_DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i);
+               LOG_DEBUG("gdb service for target %s at port %i", 
+                         target->type->name, 
+                         gdb_port + target->target_number);
 
-               i++;
                target = target->next;
        }
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)