gdb_server: support File-I/O Remote Protocol Extension 02/1102/19
authorHsiangkai Wang <hsiangkai@gmail.com>
Wed, 2 Jan 2013 04:02:00 +0000 (12:02 +0800)
committerSpencer Oliver <spen@spen-soft.co.uk>
Wed, 7 Aug 2013 21:01:25 +0000 (21:01 +0000)
The File I/O remote protocol extension allows the target to use the
host's file system and console I/O to perform various system calls.

To use the function, targets need to prepare two callback functions:
* get_gdb_finish_info: to get file I/O parameters from target
* gdb_fileio_end: pass file I/O response to target

As target is halted, gdb_server will try to get file-I/O information
from target through target_get_gdb_fileio_info(). If the callback function
returns ERROR_OK, gdb_server will initiate a file-I/O request to gdb.
After gdb finishes system call, gdb will pass response of the system call
to target through target_gdb_fileio_end() and continue to run(continue or step).

To implement the function, I add a new data structure in struct target,
called struct gdb_fileio_info, to record file I/O name and parameters.

Details refer to GDB manual "File-I/O Remote Protocol Extension"

Change-Id: I7f4d45e7c9e967b6d898dc79ba01d86bc46315d3
Signed-off-by: Hsiangkai Wang <hsiangkai@gmail.com>
Reviewed-on: http://openocd.zylin.com/1102
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
src/server/gdb_server.c
src/target/nds32.c
src/target/nds32.h
src/target/nds32_v3.c
src/target/nds32_v3_common.c
src/target/nds32_v3m.c
src/target/target.c
src/target/target.h
src/target/target_type.h

index 8eacf8c388c4b549af590eada61db30aa7abc7db..14925a2bf48329daa6557a7894166d837c52cd4b 100644 (file)
@@ -125,6 +125,9 @@ static int gdb_report_data_abort;
 /* disabled by default */
 static int gdb_use_target_description;
 
 /* disabled by default */
 static int gdb_use_target_description;
 
+/* current processing free-run type, used by file-I/O */
+static char gdb_running_type;
+
 static int gdb_last_signal(struct target *target)
 {
        switch (target->debug_reason) {
 static int gdb_last_signal(struct target *target)
 {
        switch (target->debug_reason) {
@@ -691,6 +694,142 @@ static int gdb_output(struct command_context *context, const char *line)
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
 
+static void gdb_signal_reply(struct target *target, struct connection *connection)
+{
+       struct gdb_connection *gdb_connection = connection->priv;
+       char sig_reply[20];
+       char stop_reason[20];
+       int sig_reply_len;
+       int signal_var;
+
+       if (gdb_connection->ctrl_c) {
+               signal_var = 0x2;
+               gdb_connection->ctrl_c = 0;
+       } else
+               signal_var = gdb_last_signal(target);
+
+       stop_reason[0] = '\0';
+       if (target->debug_reason == DBG_REASON_WATCHPOINT) {
+               enum watchpoint_rw hit_wp_type;
+               uint32_t hit_wp_address;
+
+               if (watchpoint_hit(target, &hit_wp_type, &hit_wp_address) == ERROR_OK) {
+
+                       switch (hit_wp_type) {
+                               case WPT_WRITE:
+                                       snprintf(stop_reason, sizeof(stop_reason),
+                                                       "watch:%08x;", hit_wp_address);
+                                       break;
+                               case WPT_READ:
+                                       snprintf(stop_reason, sizeof(stop_reason),
+                                                       "rwatch:%08x;", hit_wp_address);
+                                       break;
+                               case WPT_ACCESS:
+                                       snprintf(stop_reason, sizeof(stop_reason),
+                                                       "awatch:%08x;", hit_wp_address);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
+       sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s",
+                       signal_var, stop_reason);
+
+       gdb_put_packet(connection, sig_reply, sig_reply_len);
+       gdb_connection->frontend_state = TARGET_HALTED;
+       rtos_update_threads(target);
+}
+
+static void gdb_fileio_reply(struct target *target, struct connection *connection)
+{
+       struct gdb_connection *gdb_connection = connection->priv;
+       char fileio_command[256];
+       int command_len;
+       bool program_exited = false;
+
+       if (strcmp(target->fileio_info->identifier, "open") == 0)
+               sprintf(fileio_command, "F%s,%x/%x,%x,%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3,
+                               target->fileio_info->param_4);
+       else if (strcmp(target->fileio_info->identifier, "close") == 0)
+               sprintf(fileio_command, "F%s,%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1);
+       else if (strcmp(target->fileio_info->identifier, "read") == 0)
+               sprintf(fileio_command, "F%s,%x,%x,%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3);
+       else if (strcmp(target->fileio_info->identifier, "write") == 0)
+               sprintf(fileio_command, "F%s,%x,%x,%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3);
+       else if (strcmp(target->fileio_info->identifier, "lseek") == 0)
+               sprintf(fileio_command, "F%s,%x,%x,%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3);
+       else if (strcmp(target->fileio_info->identifier, "rename") == 0)
+               sprintf(fileio_command, "F%s,%x/%x,%x/%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3,
+                               target->fileio_info->param_4);
+       else if (strcmp(target->fileio_info->identifier, "unlink") == 0)
+               sprintf(fileio_command, "F%s,%x/%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2);
+       else if (strcmp(target->fileio_info->identifier, "stat") == 0)
+               sprintf(fileio_command, "F%s,%x/%x,%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3);
+       else if (strcmp(target->fileio_info->identifier, "fstat") == 0)
+               sprintf(fileio_command, "F%s,%x,%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2);
+       else if (strcmp(target->fileio_info->identifier, "gettimeofday") == 0)
+               sprintf(fileio_command, "F%s,%x,%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2);
+       else if (strcmp(target->fileio_info->identifier, "isatty") == 0)
+               sprintf(fileio_command, "F%s,%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1);
+       else if (strcmp(target->fileio_info->identifier, "system") == 0)
+               sprintf(fileio_command, "F%s,%x/%x", target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2);
+       else if (strcmp(target->fileio_info->identifier, "exit") == 0) {
+               /* If target hits exit syscall, report to GDB the program is terminated.
+                * In addition, let target run its own exit syscall handler. */
+               program_exited = true;
+               sprintf(fileio_command, "W%02x", target->fileio_info->param_1);
+       } else {
+               LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier);
+
+               /* encounter unknown syscall, continue */
+               gdb_connection->frontend_state = TARGET_RUNNING;
+               target_resume(target, 1, 0x0, 0, 0);
+               return;
+       }
+
+       command_len = strlen(fileio_command);
+       gdb_put_packet(connection, fileio_command, command_len);
+
+       if (program_exited) {
+               /* Use target_resume() to let target run its own exit syscall handler. */
+               gdb_connection->frontend_state = TARGET_RUNNING;
+               target_resume(target, 1, 0x0, 0, 0);
+       } else {
+               gdb_connection->frontend_state = TARGET_HALTED;
+               rtos_update_threads(target);
+       }
+}
+
 static void gdb_frontend_halted(struct target *target, struct connection *connection)
 {
        struct gdb_connection *gdb_connection = connection->priv;
 static void gdb_frontend_halted(struct target *target, struct connection *connection)
 {
        struct gdb_connection *gdb_connection = connection->priv;
@@ -705,52 +844,14 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec
         * that are to be ignored.
         */
        if (gdb_connection->frontend_state == TARGET_RUNNING) {
         * that are to be ignored.
         */
        if (gdb_connection->frontend_state == TARGET_RUNNING) {
-               char sig_reply[20];
-               char stop_reason[20];
-               int sig_reply_len;
-               int signal_var;
-
                /* stop forwarding log packets! */
                log_remove_callback(gdb_log_callback, connection);
 
                /* stop forwarding log packets! */
                log_remove_callback(gdb_log_callback, connection);
 
-               if (gdb_connection->ctrl_c) {
-                       signal_var = 0x2;
-                       gdb_connection->ctrl_c = 0;
-               } else
-                       signal_var = gdb_last_signal(target);
-
-               stop_reason[0] = '\0';
-               if (target->debug_reason == DBG_REASON_WATCHPOINT) {
-                       enum watchpoint_rw hit_wp_type;
-                       uint32_t hit_wp_address;
-
-                       if (watchpoint_hit(target, &hit_wp_type, &hit_wp_address) == ERROR_OK) {
-
-                               switch (hit_wp_type) {
-                                       case WPT_WRITE:
-                                               snprintf(stop_reason, sizeof(stop_reason),
-                                                               "watch:%08x;", hit_wp_address);
-                                               break;
-                                       case WPT_READ:
-                                               snprintf(stop_reason, sizeof(stop_reason),
-                                                               "rwatch:%08x;", hit_wp_address);
-                                               break;
-                                       case WPT_ACCESS:
-                                               snprintf(stop_reason, sizeof(stop_reason),
-                                                               "awatch:%08x;", hit_wp_address);
-                                               break;
-                                       default:
-                                               break;
-                               }
-                       }
-               }
-
-               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s",
-                               signal_var, stop_reason);
-
-               gdb_put_packet(connection, sig_reply, sig_reply_len);
-               gdb_connection->frontend_state = TARGET_HALTED;
-               rtos_update_threads(target);
+               /* check fileio first */
+               if (target_get_gdb_fileio_info(target, target->fileio_info) == ERROR_OK)
+                       gdb_fileio_reply(target, connection);
+               else
+                       gdb_signal_reply(target, connection);
        }
 }
 
        }
 }
 
@@ -1391,6 +1492,7 @@ static int gdb_step_continue_packet(struct connection *connection,
        } else
                current = 1;
 
        } else
                current = 1;
 
+       gdb_running_type = packet[0];
        if (packet[0] == 'c') {
                LOG_DEBUG("continue");
                /* resume at current address, don't handle breakpoints, not debugging */
        if (packet[0] == 'c') {
                LOG_DEBUG("continue");
                /* resume at current address, don't handle breakpoints, not debugging */
@@ -2315,6 +2417,54 @@ static int gdb_detach(struct connection *connection)
        return gdb_put_packet(connection, "OK", 2);
 }
 
        return gdb_put_packet(connection, "OK", 2);
 }
 
+/* The format of 'F' response packet is
+ * Fretcode,errno,Ctrl-C flag;call-specific attachment
+ */
+static int gdb_fileio_response_packet(struct connection *connection,
+               char *packet, int packet_size)
+{
+       struct target *target = get_target_from_connection(connection);
+       char *separator;
+       char *parsing_point;
+       int fileio_retcode = strtoul(packet + 1, &separator, 16);
+       int fileio_errno = 0;
+       bool fileio_ctrl_c = false;
+       int retval;
+
+       LOG_DEBUG("-");
+
+       if (*separator == ',') {
+               parsing_point = separator + 1;
+               fileio_errno = strtoul(parsing_point, &separator, 16);
+               if (*separator == ',') {
+                       if (*(separator + 1) == 'C') {
+                               /* TODO: process ctrl-c */
+                               fileio_ctrl_c = true;
+                       }
+               }
+       }
+
+       LOG_DEBUG("File-I/O response, retcode: 0x%x, errno: 0x%x, ctrl-c: %s",
+                       fileio_retcode, fileio_errno, fileio_ctrl_c ? "true" : "false");
+
+       retval = target_gdb_fileio_end(target, fileio_retcode, fileio_errno, fileio_ctrl_c);
+       if (retval != ERROR_OK)
+               return ERROR_FAIL;
+
+       /* After File-I/O ends, keep continue or step */
+       if (gdb_running_type == 'c')
+               retval = target_resume(target, 1, 0x0, 0, 0);
+       else if (gdb_running_type == 's')
+               retval = target_step(target, 1, 0x0, 0);
+       else
+               retval = ERROR_FAIL;
+
+       if (retval != ERROR_OK)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
 static void gdb_log_callback(void *priv, const char *file, unsigned line,
                const char *function, const char *string)
 {
 static void gdb_log_callback(void *priv, const char *file, unsigned line,
                const char *function, const char *string)
 {
@@ -2541,6 +2691,19 @@ static int gdb_input_inner(struct connection *connection)
                                        gdb_write_smp_packet(connection, packet, packet_size);
                                        break;
 
                                        gdb_write_smp_packet(connection, packet, packet_size);
                                        break;
 
+                               case 'F':
+                                       /* File-I/O extension */
+                                       /* After gdb uses host-side syscall to complete target file
+                                        * I/O, gdb sends host-side syscall return value to target
+                                        * by 'F' packet.
+                                        * The format of 'F' response packet is
+                                        * Fretcode,errno,Ctrl-C flag;call-specific attachment
+                                        */
+                                       gdb_con->frontend_state = TARGET_RUNNING;
+                                       log_add_callback(gdb_log_callback, connection);
+                                       gdb_fileio_response_packet(connection, packet, packet_size);
+                                       break;
+
                                default:
                                        /* ignore unknown packets */
                                        LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]);
                                default:
                                        /* ignore unknown packets */
                                        LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]);
index 95a249d0535bf553cf4176260cf461c2cf052c48..c4bd63aadf197f53b777b7928e9df3b637fcaf11 100644 (file)
@@ -1645,6 +1645,10 @@ int nds32_init_arch_info(struct target *target, struct nds32 *nds32)
        nds32->keep_target_edm_ctl = false;
        nds32->word_access_mem = false;
        nds32->virtual_hosting = false;
        nds32->keep_target_edm_ctl = false;
        nds32->word_access_mem = false;
        nds32->virtual_hosting = false;
+       nds32->hit_syscall = false;
+       nds32->active_syscall_id = NDS32_SYSCALL_UNDEFINED;
+       nds32->virtual_hosting_errno = 0;
+       nds32->virtual_hosting_ctrl_c = false;
 
        nds32_reg_init();
 
 
        nds32_reg_init();
 
@@ -1772,13 +1776,24 @@ int nds32_step(struct target *target, int current,
                ir14_value &= ~(0x1 << 31);
        nds32_set_mapped_reg(nds32, IR14, ir14_value);
 
                ir14_value &= ~(0x1 << 31);
        nds32_set_mapped_reg(nds32, IR14, ir14_value);
 
+       /* check hit_syscall before leave_debug_state() because
+        * leave_debug_state() may clear hit_syscall flag */
+       bool no_step = false;
+       if (nds32->hit_syscall)
+               /* step after hit_syscall should be ignored because
+                * leave_debug_state will step implicitly to skip the
+                * syscall */
+               no_step = true;
+
        /********* TODO: maybe create another function to handle this part */
        CHECK_RETVAL(nds32->leave_debug_state(nds32, true));
        CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED));
 
        /********* TODO: maybe create another function to handle this part */
        CHECK_RETVAL(nds32->leave_debug_state(nds32, true));
        CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED));
 
-       struct aice_port_s *aice = target_to_aice(target);
-       if (ERROR_OK != aice_step(aice))
-               return ERROR_FAIL;
+       if (no_step == false) {
+               struct aice_port_s *aice = target_to_aice(target);
+               if (ERROR_OK != aice_step(aice))
+                       return ERROR_FAIL;
+       }
 
        /* save state */
        CHECK_RETVAL(nds32->enter_debug_state(nds32, true));
 
        /* save state */
        CHECK_RETVAL(nds32->enter_debug_state(nds32, true));
@@ -1878,6 +1893,12 @@ int nds32_examine_debug_reason(struct nds32 *nds32)
        uint32_t reason;
        struct target *target = nds32->target;
 
        uint32_t reason;
        struct target *target = nds32->target;
 
+       if (nds32->hit_syscall == true) {
+               LOG_DEBUG("Hit syscall breakpoint");
+               target->debug_reason = DBG_REASON_BREAKPOINT;
+               return ERROR_OK;
+       }
+
        nds32->get_debug_reason(nds32, &reason);
 
        LOG_DEBUG("nds32 examines debug reason: %s", nds32_debug_type_name[reason]);
        nds32->get_debug_reason(nds32, &reason);
 
        LOG_DEBUG("nds32 examines debug reason: %s", nds32_debug_type_name[reason]);
@@ -2110,8 +2131,11 @@ int nds32_resume(struct target *target, int current,
        CHECK_RETVAL(nds32->leave_debug_state(nds32, true));
        CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED));
 
        CHECK_RETVAL(nds32->leave_debug_state(nds32, true));
        CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED));
 
-       struct aice_port_s *aice = target_to_aice(target);
-       aice_run(aice);
+       if (nds32->virtual_hosting_ctrl_c == false) {
+               struct aice_port_s *aice = target_to_aice(target);
+               aice_run(aice);
+       } else
+               nds32->virtual_hosting_ctrl_c = false;
 
        target->debug_reason = DBG_REASON_NOTHALTED;
        if (!debug_execution)
 
        target->debug_reason = DBG_REASON_NOTHALTED;
        if (!debug_execution)
@@ -2239,6 +2263,292 @@ int nds32_init(struct nds32 *nds32)
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
 
+int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
+{
+       /* fill syscall parameters to file-I/O info */
+       if (NULL == fileio_info) {
+               LOG_ERROR("Target has not initial file-I/O data structure");
+               return ERROR_FAIL;
+       }
+
+       struct nds32 *nds32 = target_to_nds32(target);
+       uint32_t value_ir6;
+       uint32_t syscall_id;
+
+       if (nds32->hit_syscall == false)
+               return ERROR_FAIL;
+
+       nds32_get_mapped_reg(nds32, IR6, &value_ir6);
+       syscall_id = (value_ir6 >> 16) & 0x7FFF;
+       nds32->active_syscall_id = syscall_id;
+
+       LOG_DEBUG("hit syscall ID: 0x%x", syscall_id);
+
+       /* free previous identifier storage */
+       if (NULL != fileio_info->identifier) {
+               free(fileio_info->identifier);
+               fileio_info->identifier = NULL;
+       }
+
+       switch (syscall_id) {
+               case NDS32_SYSCALL_EXIT:
+                       fileio_info->identifier = (char *)malloc(5);
+                       sprintf(fileio_info->identifier, "exit");
+                       nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                       break;
+               case NDS32_SYSCALL_OPEN:
+                       {
+                               uint8_t filename[256];
+                               fileio_info->identifier = (char *)malloc(5);
+                               sprintf(fileio_info->identifier, "open");
+                               nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                               /* reserve fileio_info->param_2 for length of path */
+                               nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3));
+                               nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_4));
+
+                               target->type->read_buffer(target, fileio_info->param_1,
+                                               256, filename);
+                               fileio_info->param_2 = strlen((char *)filename) + 1;
+                       }
+                       break;
+               case NDS32_SYSCALL_CLOSE:
+                       fileio_info->identifier = (char *)malloc(6);
+                       sprintf(fileio_info->identifier, "close");
+                       nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                       break;
+               case NDS32_SYSCALL_READ:
+                       fileio_info->identifier = (char *)malloc(5);
+                       sprintf(fileio_info->identifier, "read");
+                       nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                       nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
+                       nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3));
+                       break;
+               case NDS32_SYSCALL_WRITE:
+                       fileio_info->identifier = (char *)malloc(6);
+                       sprintf(fileio_info->identifier, "write");
+                       nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                       nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
+                       nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3));
+                       break;
+               case NDS32_SYSCALL_LSEEK:
+                       fileio_info->identifier = (char *)malloc(6);
+                       sprintf(fileio_info->identifier, "lseek");
+                       nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                       nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
+                       nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3));
+                       break;
+               case NDS32_SYSCALL_UNLINK:
+                       {
+                               uint8_t filename[256];
+                               fileio_info->identifier = (char *)malloc(7);
+                               sprintf(fileio_info->identifier, "unlink");
+                               nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                               /* reserve fileio_info->param_2 for length of path */
+
+                               target->type->read_buffer(target, fileio_info->param_1,
+                                               256, filename);
+                               fileio_info->param_2 = strlen((char *)filename) + 1;
+                       }
+                       break;
+               case NDS32_SYSCALL_RENAME:
+                       {
+                               uint8_t filename[256];
+                               fileio_info->identifier = (char *)malloc(7);
+                               sprintf(fileio_info->identifier, "rename");
+                               nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                               /* reserve fileio_info->param_2 for length of old path */
+                               nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3));
+                               /* reserve fileio_info->param_4 for length of new path */
+
+                               target->type->read_buffer(target, fileio_info->param_1,
+                                               256, filename);
+                               fileio_info->param_2 = strlen((char *)filename) + 1;
+
+                               target->type->read_buffer(target, fileio_info->param_3,
+                                               256, filename);
+                               fileio_info->param_4 = strlen((char *)filename) + 1;
+                       }
+                       break;
+               case NDS32_SYSCALL_FSTAT:
+                       fileio_info->identifier = (char *)malloc(6);
+                       sprintf(fileio_info->identifier, "fstat");
+                       nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                       nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
+                       break;
+               case NDS32_SYSCALL_STAT:
+                       {
+                               uint8_t filename[256];
+                               fileio_info->identifier = (char *)malloc(5);
+                               sprintf(fileio_info->identifier, "stat");
+                               nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                               /* reserve fileio_info->param_2 for length of old path */
+                               nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3));
+
+                               target->type->read_buffer(target, fileio_info->param_1,
+                                               256, filename);
+                               fileio_info->param_2 = strlen((char *)filename) + 1;
+                       }
+                       break;
+               case NDS32_SYSCALL_GETTIMEOFDAY:
+                       fileio_info->identifier = (char *)malloc(13);
+                       sprintf(fileio_info->identifier, "gettimeofday");
+                       nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                       nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
+                       break;
+               case NDS32_SYSCALL_ISATTY:
+                       fileio_info->identifier = (char *)malloc(7);
+                       sprintf(fileio_info->identifier, "isatty");
+                       nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                       break;
+               case NDS32_SYSCALL_SYSTEM:
+                       {
+                               uint8_t command[256];
+                               fileio_info->identifier = (char *)malloc(7);
+                               sprintf(fileio_info->identifier, "system");
+                               nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
+                               /* reserve fileio_info->param_2 for length of old path */
+
+                               target->type->read_buffer(target, fileio_info->param_1,
+                                               256, command);
+                               fileio_info->param_2 = strlen((char *)command) + 1;
+                       }
+                       break;
+               case NDS32_SYSCALL_ERRNO:
+                       fileio_info->identifier = (char *)malloc(6);
+                       sprintf(fileio_info->identifier, "errno");
+                       nds32_set_mapped_reg(nds32, R0, nds32->virtual_hosting_errno);
+                       break;
+               default:
+                       fileio_info->identifier = (char *)malloc(8);
+                       sprintf(fileio_info->identifier, "unknown");
+                       break;
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c)
+{
+       LOG_DEBUG("syscall return code: 0x%x, errno: 0x%x, ctrl_c: %s",
+                       retcode, fileio_errno, ctrl_c ? "true" : "false");
+
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       nds32_set_mapped_reg(nds32, R0, (uint32_t)retcode);
+
+       nds32->virtual_hosting_errno = fileio_errno;
+       nds32->virtual_hosting_ctrl_c = ctrl_c;
+       nds32->active_syscall_id = NDS32_SYSCALL_UNDEFINED;
+
+       return ERROR_OK;
+}
+
+int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address,
+               uint32_t size, const uint8_t *buffer)
+{
+       if ((NDS32_SYSCALL_FSTAT == nds32->active_syscall_id) ||
+                       (NDS32_SYSCALL_STAT == nds32->active_syscall_id)) {
+               /* If doing GDB file-I/O, target should convert 'struct stat'
+                * from gdb-format to target-format */
+               uint8_t stat_buffer[NDS32_STRUCT_STAT_SIZE];
+               /* st_dev 2 */
+               stat_buffer[0] = buffer[3];
+               stat_buffer[1] = buffer[2];
+               /* st_ino 2 */
+               stat_buffer[2] = buffer[7];
+               stat_buffer[3] = buffer[6];
+               /* st_mode 4 */
+               stat_buffer[4] = buffer[11];
+               stat_buffer[5] = buffer[10];
+               stat_buffer[6] = buffer[9];
+               stat_buffer[7] = buffer[8];
+               /* st_nlink 2 */
+               stat_buffer[8] = buffer[15];
+               stat_buffer[9] = buffer[16];
+               /* st_uid 2 */
+               stat_buffer[10] = buffer[19];
+               stat_buffer[11] = buffer[18];
+               /* st_gid 2 */
+               stat_buffer[12] = buffer[23];
+               stat_buffer[13] = buffer[22];
+               /* st_rdev 2 */
+               stat_buffer[14] = buffer[27];
+               stat_buffer[15] = buffer[26];
+               /* st_size 4 */
+               stat_buffer[16] = buffer[35];
+               stat_buffer[17] = buffer[34];
+               stat_buffer[18] = buffer[33];
+               stat_buffer[19] = buffer[32];
+               /* st_atime 4 */
+               stat_buffer[20] = buffer[55];
+               stat_buffer[21] = buffer[54];
+               stat_buffer[22] = buffer[53];
+               stat_buffer[23] = buffer[52];
+               /* st_spare1 4 */
+               stat_buffer[24] = 0;
+               stat_buffer[25] = 0;
+               stat_buffer[26] = 0;
+               stat_buffer[27] = 0;
+               /* st_mtime 4 */
+               stat_buffer[28] = buffer[59];
+               stat_buffer[29] = buffer[58];
+               stat_buffer[30] = buffer[57];
+               stat_buffer[31] = buffer[56];
+               /* st_spare2 4 */
+               stat_buffer[32] = 0;
+               stat_buffer[33] = 0;
+               stat_buffer[34] = 0;
+               stat_buffer[35] = 0;
+               /* st_ctime 4 */
+               stat_buffer[36] = buffer[63];
+               stat_buffer[37] = buffer[62];
+               stat_buffer[38] = buffer[61];
+               stat_buffer[39] = buffer[60];
+               /* st_spare3 4 */
+               stat_buffer[40] = 0;
+               stat_buffer[41] = 0;
+               stat_buffer[42] = 0;
+               stat_buffer[43] = 0;
+               /* st_blksize 4 */
+               stat_buffer[44] = buffer[43];
+               stat_buffer[45] = buffer[42];
+               stat_buffer[46] = buffer[41];
+               stat_buffer[47] = buffer[40];
+               /* st_blocks 4 */
+               stat_buffer[48] = buffer[51];
+               stat_buffer[49] = buffer[50];
+               stat_buffer[50] = buffer[49];
+               stat_buffer[51] = buffer[48];
+               /* st_spare4 8 */
+               stat_buffer[52] = 0;
+               stat_buffer[53] = 0;
+               stat_buffer[54] = 0;
+               stat_buffer[55] = 0;
+               stat_buffer[56] = 0;
+               stat_buffer[57] = 0;
+               stat_buffer[58] = 0;
+               stat_buffer[59] = 0;
+
+               return nds32_write_buffer(nds32->target, address, NDS32_STRUCT_STAT_SIZE, stat_buffer);
+       } else if (NDS32_SYSCALL_GETTIMEOFDAY == nds32->active_syscall_id) {
+               /* If doing GDB file-I/O, target should convert 'struct timeval'
+                * from gdb-format to target-format */
+               uint8_t timeval_buffer[NDS32_STRUCT_TIMEVAL_SIZE];
+               timeval_buffer[0] = buffer[3];
+               timeval_buffer[1] = buffer[2];
+               timeval_buffer[2] = buffer[1];
+               timeval_buffer[3] = buffer[0];
+               timeval_buffer[4] = buffer[11];
+               timeval_buffer[5] = buffer[10];
+               timeval_buffer[6] = buffer[9];
+               timeval_buffer[7] = buffer[8];
+
+               return nds32_write_buffer(nds32->target, address, NDS32_STRUCT_TIMEVAL_SIZE, timeval_buffer);
+       }
+
+       return nds32_write_buffer(nds32->target, address, size, buffer);
+}
+
 int nds32_reset_halt(struct nds32 *nds32)
 {
        LOG_INFO("reset halt as init");
 int nds32_reset_halt(struct nds32 *nds32)
 {
        LOG_INFO("reset halt as init");
index b7e787cf00defc571ab3cac96e7489b98ef12ec7..8acd915f0c1899b5d0d5d7c04305859f84187d5f 100644 (file)
@@ -284,6 +284,18 @@ struct nds32 {
        /** Flag reporting whether virtual hosting is active. */
        bool virtual_hosting;
 
        /** Flag reporting whether virtual hosting is active. */
        bool virtual_hosting;
 
+       /** Flag reporting whether continue/step hits syscall or not */
+       bool hit_syscall;
+
+       /** Value to be returned by virtual hosting SYS_ERRNO request. */
+       int virtual_hosting_errno;
+
+       /** Flag reporting whether syscall is aborted */
+       bool virtual_hosting_ctrl_c;
+
+       /** Record syscall ID for other operations to do special processing for target */
+       int active_syscall_id;
+
        /** Flag reporting whether global stop is active. */
        bool global_stop;
 
        /** Flag reporting whether global stop is active. */
        bool global_stop;
 
@@ -404,6 +416,10 @@ extern int nds32_resume(struct target *target, int current,
                uint32_t address, int handle_breakpoints, int debug_execution);
 extern int nds32_assert_reset(struct target *target);
 extern int nds32_init(struct nds32 *nds32);
                uint32_t address, int handle_breakpoints, int debug_execution);
 extern int nds32_assert_reset(struct target *target);
 extern int nds32_init(struct nds32 *nds32);
+extern int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
+extern int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address,
+               uint32_t size, const uint8_t *buffer);
+extern int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
 extern int nds32_reset_halt(struct nds32 *nds32);
 extern int nds32_login(struct nds32 *nds32);
 
 extern int nds32_reset_halt(struct nds32 *nds32);
 extern int nds32_login(struct nds32 *nds32);
 
index 868260dc9e59f52900e42b4b3049ca1d4bf02546..766e5ccbb8873002f08710c48f019fe20081b572 100644 (file)
@@ -520,4 +520,7 @@ struct target_type nds32_v3_target = {
        .target_create = nds32_v3_target_create,
        .init_target = nds32_v3_init_target,
        .examine = nds32_v3_examine,
        .target_create = nds32_v3_target_create,
        .init_target = nds32_v3_init_target,
        .examine = nds32_v3_examine,
+
+       .get_gdb_fileio_info = nds32_get_gdb_fileio_info,
+       .gdb_fileio_end = nds32_gdb_fileio_end,
 };
 };
index 2fbd1a3780ad61928f76febcd38e6a3d3dfd841a..f0cd77d234079ab1e37a768adbf2be16f5311f87 100644 (file)
 #include "nds32_aice.h"
 #include "nds32_v3_common.h"
 
 #include "nds32_aice.h"
 #include "nds32_v3_common.h"
 
+static struct breakpoint syscall_breakpoint = {
+       0x80,
+       0,
+       4,
+       BKPT_SOFT,
+       0,
+       NULL,
+       NULL,
+       0x515CA11,
+       0,
+};
+
 static struct nds32_v3_common_callback *v3_common_callback;
 
 static int nds32_v3_register_mapping(struct nds32 *nds32, int reg_no)
 static struct nds32_v3_common_callback *v3_common_callback;
 
 static int nds32_v3_register_mapping(struct nds32 *nds32, int reg_no)
@@ -80,6 +92,22 @@ static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint)
        if (enable_watchpoint)
                CHECK_RETVAL(v3_common_callback->deactivate_hardware_watchpoint(nds32->target));
 
        if (enable_watchpoint)
                CHECK_RETVAL(v3_common_callback->deactivate_hardware_watchpoint(nds32->target));
 
+       if (nds32->virtual_hosting) {
+               if (syscall_breakpoint.set) {
+                       /** disable virtual hosting */
+
+                       /* remove breakpoint at syscall entry */
+                       target_remove_breakpoint(nds32->target, &syscall_breakpoint);
+                       syscall_breakpoint.set = 0;
+
+                       uint32_t value_pc;
+                       nds32_get_mapped_reg(nds32, PC, &value_pc);
+                       if (value_pc == syscall_breakpoint.address)
+                               /** process syscall for virtual hosting */
+                               nds32->hit_syscall = true;
+               }
+       }
+
        if (ERROR_OK != nds32_examine_debug_reason(nds32)) {
                nds32->target->state = backup_state;
 
        if (ERROR_OK != nds32_examine_debug_reason(nds32)) {
                nds32->target->state = backup_state;
 
@@ -132,6 +160,74 @@ static int nds32_v3_leave_debug_state(struct nds32 *nds32, bool enable_watchpoin
         */
        CHECK_RETVAL(nds32_restore_context(target));
 
         */
        CHECK_RETVAL(nds32_restore_context(target));
 
+       if (nds32->virtual_hosting) {
+               /** enable virtual hosting */
+               uint32_t value_ir3;
+               uint32_t entry_size;
+               uint32_t syscall_address;
+
+               /* get syscall entry address */
+               nds32_get_mapped_reg(nds32, IR3, &value_ir3);
+               entry_size = 0x4 << (((value_ir3 >> 14) & 0x3) << 1);
+               syscall_address = (value_ir3 & 0xFFFF0000) + entry_size * 8; /* The index of SYSCALL is 8 */
+
+               if (nds32->hit_syscall) {
+                       /* single step to skip syscall entry */
+                       /* use IRET to skip syscall */
+                       struct aice_port_s *aice = target_to_aice(target);
+                       uint32_t value_ir9;
+                       uint32_t value_ir6;
+                       uint32_t syscall_id;
+
+                       nds32_get_mapped_reg(nds32, IR6, &value_ir6);
+                       syscall_id = (value_ir6 >> 16) & 0x7FFF;
+
+                       if (syscall_id == NDS32_SYSCALL_EXIT) {
+                               /* If target hits exit syscall, do not use IRET to skip handler. */
+                               aice_step(aice);
+                       } else {
+                               /* use api->read/write_reg to skip nds32 register cache */
+                               uint32_t value_dimbr;
+                               aice_read_debug_reg(aice, NDS_EDM_SR_DIMBR, &value_dimbr);
+                               aice_write_register(aice, IR11, value_dimbr + 0xC);
+
+                               aice_read_register(aice, IR9, &value_ir9);
+                               value_ir9 += 4; /* syscall is always 4 bytes */
+                               aice_write_register(aice, IR9, value_ir9);
+
+                               /* backup hardware breakpoint 0 */
+                               uint32_t backup_bpa, backup_bpam, backup_bpc;
+                               aice_read_debug_reg(aice, NDS_EDM_SR_BPA0, &backup_bpa);
+                               aice_read_debug_reg(aice, NDS_EDM_SR_BPAM0, &backup_bpam);
+                               aice_read_debug_reg(aice, NDS_EDM_SR_BPC0, &backup_bpc);
+
+                               /* use hardware breakpoint 0 to stop cpu after skipping syscall */
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, value_ir9);
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, 0);
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, 0xA);
+
+                               /* Execute two IRET.
+                                * First IRET is used to quit debug mode.
+                                * Second IRET is used to quit current syscall. */
+                               uint32_t dim_inst[4] = {NOP, NOP, IRET, IRET};
+                               aice_execute(aice, dim_inst, 4);
+
+                               /* restore origin hardware breakpoint 0 */
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, backup_bpa);
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, backup_bpam);
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, backup_bpc);
+                       }
+
+                       nds32->hit_syscall = false;
+               }
+
+               /* insert breakpoint at syscall entry */
+               syscall_breakpoint.address = syscall_address;
+               syscall_breakpoint.type = BKPT_SOFT;
+               syscall_breakpoint.set = 1;
+               target_add_breakpoint(target, &syscall_breakpoint);
+       }
+
        /* enable polling */
        jtag_poll_set_enabled(true);
 
        /* enable polling */
        jtag_poll_set_enabled(true);
 
@@ -398,7 +494,27 @@ int nds32_v3_read_buffer(struct target *target, uint32_t address,
        else
                return ERROR_FAIL;
 
        else
                return ERROR_FAIL;
 
-       return nds32_read_buffer(target, address, size, buffer);
+       int result;
+       struct aice_port_s *aice = target_to_aice(target);
+       /* give arbitrary initial value to avoid warning messages */
+       enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU;
+
+       if (nds32->hit_syscall) {
+               /* Use bus mode to access memory during virtual hosting */
+               origin_access_channel = memory->access_channel;
+               memory->access_channel = NDS_MEMORY_ACC_BUS;
+               aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
+       }
+
+       result = nds32_read_buffer(target, address, size, buffer);
+
+       if (nds32->hit_syscall) {
+               /* Restore access_channel after virtual hosting */
+               memory->access_channel = origin_access_channel;
+               aice_memory_access(aice, origin_access_channel);
+       }
+
+       return result;
 }
 
 int nds32_v3_write_buffer(struct target *target, uint32_t address,
 }
 
 int nds32_v3_write_buffer(struct target *target, uint32_t address,
@@ -436,6 +552,24 @@ int nds32_v3_write_buffer(struct target *target, uint32_t address,
        else
                return ERROR_FAIL;
 
        else
                return ERROR_FAIL;
 
+       if (nds32->hit_syscall) {
+               /* Use bus mode to access memory during virtual hosting */
+               struct aice_port_s *aice = target_to_aice(target);
+               enum nds_memory_access origin_access_channel;
+               int result;
+
+               origin_access_channel = memory->access_channel;
+               memory->access_channel = NDS_MEMORY_ACC_BUS;
+               aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
+
+               result = nds32_gdb_fileio_write_memory(nds32, address, size, buffer);
+
+               memory->access_channel = origin_access_channel;
+               aice_memory_access(aice, origin_access_channel);
+
+               return result;
+       }
+
        return nds32_write_buffer(target, address, size, buffer);
 }
 
        return nds32_write_buffer(target, address, size, buffer);
 }
 
@@ -474,10 +608,26 @@ int nds32_v3_read_memory(struct target *target, uint32_t address,
        else
                return ERROR_FAIL;
 
        else
                return ERROR_FAIL;
 
+       struct aice_port_s *aice = target_to_aice(target);
+       /* give arbitrary initial value to avoid warning messages */
+       enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU;
        int result;
 
        int result;
 
+       if (nds32->hit_syscall) {
+               /* Use bus mode to access memory during virtual hosting */
+               origin_access_channel = memory->access_channel;
+               memory->access_channel = NDS_MEMORY_ACC_BUS;
+               aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
+       }
+
        result = nds32_read_memory(target, address, size, count, buffer);
 
        result = nds32_read_memory(target, address, size, count, buffer);
 
+       if (nds32->hit_syscall) {
+               /* Restore access_channel after virtual hosting */
+               memory->access_channel = origin_access_channel;
+               aice_memory_access(aice, origin_access_channel);
+       }
+
        return result;
 }
 
        return result;
 }
 
@@ -527,5 +677,8 @@ int nds32_v3_init_target(struct command_context *cmd_ctx,
 
        nds32_init(nds32);
 
 
        nds32_init(nds32);
 
+       target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
+       target->fileio_info->identifier = NULL;
+
        return ERROR_OK;
 }
        return ERROR_OK;
 }
index c37798afb52897920861930359b65d42bcf53bba..d72d986915fb0246caf49b73a20c354eb1e146c0 100644 (file)
@@ -508,4 +508,7 @@ struct target_type nds32_v3m_target = {
        .target_create = nds32_v3m_target_create,
        .init_target = nds32_v3_init_target,
        .examine = nds32_v3m_examine,
        .target_create = nds32_v3m_target_create,
        .init_target = nds32_v3_init_target,
        .examine = nds32_v3m_examine,
+
+       .get_gdb_fileio_info = nds32_get_gdb_fileio_info,
+       .gdb_fileio_end = nds32_gdb_fileio_end,
 };
 };
index 4c31fbea23fb05463ba802a94fd19f22c31fc1ae..442f0d9f1cb5f4c93d37a053cf5b8dcc4f89441d 100644 (file)
@@ -68,6 +68,10 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
 static int target_mem2array(Jim_Interp *interp, struct target *target,
                int argc, Jim_Obj * const *argv);
 static int target_register_user_commands(struct command_context *cmd_ctx);
 static int target_mem2array(Jim_Interp *interp, struct target *target,
                int argc, Jim_Obj * const *argv);
 static int target_register_user_commands(struct command_context *cmd_ctx);
+static int target_get_gdb_fileio_info_default(struct target *target,
+               struct gdb_fileio_info *fileio_info);
+static int target_gdb_fileio_end_default(struct target *target, int retcode,
+               int fileio_errno, bool ctrl_c);
 
 /* targets */
 extern struct target_type arm7tdmi_target;
 
 /* targets */
 extern struct target_type arm7tdmi_target;
@@ -1065,6 +1069,24 @@ int target_step(struct target *target,
        return target->type->step(target, current, address, handle_breakpoints);
 }
 
        return target->type->step(target, current, address, handle_breakpoints);
 }
 
+int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
+{
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target %s is not halted", target->cmd_name);
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       return target->type->get_gdb_fileio_info(target, fileio_info);
+}
+
+int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c)
+{
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target %s is not halted", target->cmd_name);
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       return target->type->gdb_fileio_end(target, retcode, fileio_errno, ctrl_c);
+}
+
 /**
  * Reset the @c examined flag for the given target.
  * Pure paranoia -- targets are zeroed on allocation.
 /**
  * Reset the @c examined flag for the given target.
  * Pure paranoia -- targets are zeroed on allocation.
@@ -1151,6 +1173,12 @@ static int target_init_one(struct command_context *cmd_ctx,
        if (target->type->bulk_write_memory == NULL)
                target->type->bulk_write_memory = target_bulk_write_memory_default;
 
        if (target->type->bulk_write_memory == NULL)
                target->type->bulk_write_memory = target_bulk_write_memory_default;
 
+       if (target->type->get_gdb_fileio_info == NULL)
+               target->type->get_gdb_fileio_info = target_get_gdb_fileio_info_default;
+
+       if (target->type->gdb_fileio_end == NULL)
+               target->type->gdb_fileio_end = target_gdb_fileio_end_default;
+
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
 
@@ -1700,6 +1728,20 @@ int target_arch_state(struct target *target)
        return retval;
 }
 
        return retval;
 }
 
+static int target_get_gdb_fileio_info_default(struct target *target,
+               struct gdb_fileio_info *fileio_info)
+{
+       LOG_ERROR("Not implemented: %s", __func__);
+       return ERROR_FAIL;
+}
+
+static int target_gdb_fileio_end_default(struct target *target,
+               int retcode, int fileio_errno, bool ctrl_c)
+{
+       LOG_ERROR("Not implemented: %s", __func__);
+       return ERROR_OK;
+}
+
 /* Single aligned words are guaranteed to use 16 or 32 bit access
  * mode respectively, otherwise data is handled as quickly as
  * possible
 /* Single aligned words are guaranteed to use 16 or 32 bit access
  * mode respectively, otherwise data is handled as quickly as
  * possible
index 09895bbabd86953617b7ed72901c5f3aee7b6d71..ee282b193e36af31b7aef169606bd668ec4d25d4 100644 (file)
@@ -41,6 +41,7 @@ struct watchpoint;
 struct mem_param;
 struct reg_param;
 struct target_list;
 struct mem_param;
 struct reg_param;
 struct target_list;
+struct gdb_fileio_info;
 
 /*
  * TARGET_UNKNOWN = 0: we don't know anything about the target yet
 
 /*
  * TARGET_UNKNOWN = 0: we don't know anything about the target yet
@@ -191,6 +192,9 @@ struct target {
         * the target attached to the gdb is changing dynamically by changing
         * gdb_service->target pointer */
        struct gdb_service *gdb_service;
         * the target attached to the gdb is changing dynamically by changing
         * gdb_service->target pointer */
        struct gdb_service *gdb_service;
+
+       /* file-I/O information for host to do syscall */
+       struct gdb_fileio_info *fileio_info;
 };
 
 struct target_list {
 };
 
 struct target_list {
@@ -198,6 +202,14 @@ struct target_list {
        struct target_list *next;
 };
 
        struct target_list *next;
 };
 
+struct gdb_fileio_info {
+       char *identifier;
+       uint32_t param_1;
+       uint32_t param_2;
+       uint32_t param_3;
+       uint32_t param_4;
+};
+
 /** Returns the instance-specific name of the specified target. */
 static inline const char *target_name(struct target *target)
 {
 /** Returns the instance-specific name of the specified target. */
 static inline const char *target_name(struct target *target)
 {
@@ -534,6 +546,22 @@ int target_blank_check_memory(struct target *target,
                uint32_t address, uint32_t size, uint32_t *blank);
 int target_wait_state(struct target *target, enum target_state state, int ms);
 
                uint32_t address, uint32_t size, uint32_t *blank);
 int target_wait_state(struct target *target, enum target_state state, int ms);
 
+/**
+ * Obtain file-I/O information from target for GDB to do syscall.
+ *
+ * This routine is a wrapper for target->type->get_gdb_fileio_info.
+ */
+int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
+
+/**
+ * Pass GDB file-I/O response to target after finishing host syscall.
+ *
+ * This routine is a wrapper for target->type->gdb_fileio_end.
+ */
+int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
+
+
+
 /** Return the *name* of this targets current state */
 const char *target_state_name(struct target *target);
 
 /** Return the *name* of this targets current state */
 const char *target_state_name(struct target *target);
 
index 0b8d5daa1b59e122008b881391e43fb5c6eb2624..21439b656aa396dff6db63ba18e207dfd6dc2c57 100644 (file)
@@ -264,6 +264,15 @@ struct target_type {
         * circumstances.
         */
        int (*check_reset)(struct target *target);
         * circumstances.
         */
        int (*check_reset)(struct target *target);
+
+       /* get GDB file-I/O parameters from target
+        */
+       int (*get_gdb_fileio_info)(struct target *target, struct gdb_fileio_info *fileio_info);
+
+       /* pass GDB file-I/O response to target
+        */
+       int (*gdb_fileio_end)(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
+
 };
 
 #endif /* TARGET_TYPE_H */
 };
 
 #endif /* TARGET_TYPE_H */

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)