gdb: add default description reg types
[fw/openocd] / src / server / gdb_server.c
index 8eacf8c388c4b549af590eada61db30aa7abc7db..a9681c79716ea36f6c91d80b8ce0841e6f4c1ab7 100644 (file)
@@ -125,6 +125,9 @@ static int gdb_report_data_abort;
 /* 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) {
@@ -691,28 +694,17 @@ static int gdb_output(struct command_context *context, const char *line)
        return ERROR_OK;
 }
 
-static void gdb_frontend_halted(struct target *target, struct connection *connection)
+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;
 
-       /* In the GDB protocol when we are stepping or continuing execution,
-        * we have a lingering reply. Upon receiving a halted event
-        * when we have that lingering packet, we reply to the original
-        * step or continue packet.
-        *
-        * Executing monitor commands can bring the target in and
-        * out of the running state so we'll see lots of TARGET_EVENT_XXX
-        * 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);
-
+       if (target->debug_reason == DBG_REASON_EXIT) {
+               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00");
+       } else {
                if (gdb_connection->ctrl_c) {
                        signal_var = 0x2;
                        gdb_connection->ctrl_c = 0;
@@ -747,18 +739,135 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec
 
                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);
+}
 
-               gdb_put_packet(connection, sig_reply, sig_reply_len);
+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;
+
+       /* In the GDB protocol when we are stepping or continuing execution,
+        * we have a lingering reply. Upon receiving a halted event
+        * when we have that lingering packet, we reply to the original
+        * step or continue packet.
+        *
+        * Executing monitor commands can bring the target in and
+        * out of the running state so we'll see lots of TARGET_EVENT_XXX
+        * that are to be ignored.
+        */
+       if (gdb_connection->frontend_state == TARGET_RUNNING) {
+               /* stop forwarding log packets! */
+               log_remove_callback(gdb_log_callback, connection);
+
+               /* 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);
+       }
+}
+
 static int gdb_target_callback_event_handler(struct target *target,
                enum target_event event, void *priv)
 {
        int retval;
        struct connection *connection = priv;
+       struct gdb_service *gdb_service = connection->service->priv;
+
+       if (gdb_service->target != target)
+               return ERROR_OK;
 
        switch (event) {
                case TARGET_EVENT_GDB_HALT:
@@ -797,7 +906,7 @@ static int gdb_new_connection(struct connection *connection)
        gdb_connection->closed = 0;
        gdb_connection->busy = 0;
        gdb_connection->noack_mode = 0;
-       gdb_connection->sync = true;
+       gdb_connection->sync = false;
        gdb_connection->mem_write_error = false;
        gdb_connection->attached = true;
 
@@ -1391,6 +1500,7 @@ static int gdb_step_continue_packet(struct connection *connection,
        } 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 */
@@ -1718,6 +1828,8 @@ static int gdb_memory_map(struct connection *connection,
 static const char *gdb_get_reg_type_name(enum reg_type type)
 {
        switch (type) {
+               case REG_TYPE_INT:
+                       return "int";
                case REG_TYPE_INT8:
                        return "int8";
                case REG_TYPE_INT16:
@@ -1742,6 +1854,8 @@ static const char *gdb_get_reg_type_name(enum reg_type type)
                        return "code_ptr";
                case REG_TYPE_DATA_PTR:
                        return "data_ptr";
+               case REG_TYPE_FLOAT:
+                       return "float";
                case REG_TYPE_IEEE_SINGLE:
                        return "ieee_single";
                case REG_TYPE_IEEE_DOUBLE:
@@ -2315,6 +2429,54 @@ static int gdb_detach(struct connection *connection)
        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)
 {
@@ -2541,6 +2703,19 @@ static int gdb_input_inner(struct connection *connection)
                                        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]);
@@ -2765,16 +2940,16 @@ COMMAND_HANDLER(handle_gdb_save_tdesc_command)
 
        int retval = fileio_open(&fileio, tdesc_filename, FILEIO_WRITE, FILEIO_TEXT);
 
-       free(tdesc_filename);
-
        if (retval != ERROR_OK) {
                LOG_WARNING("Can't open %s for writing", tdesc_filename);
+               free(tdesc_filename);
                return ERROR_FAIL;
        }
 
        retval = fileio_write(&fileio, tdesc_length, tdesc, &size_written);
 
        fileio_close(&fileio);
+       free(tdesc_filename);
 
        if (retval != ERROR_OK) {
                LOG_WARNING("Error while writing the tdesc file");