This is an automated email from Gerrit.

Tarek BOCHKATI (tarek.bouchk...@gmail.com) just uploaded a new patch set to 
Gerrit, which you can find at http://openocd.zylin.com/5562

-- gerrit

commit 15c6994b0faaee6367742ce94013c0a88c4351cc
Author: Tarek BOCHKATI <tarek.bouchk...@gmail.com>
Date:   Thu Apr 2 16:15:35 2020 +0200

    semihosting: add the possibility to redirect semihosting print output
    
    add a new command semihosting_print_redirect to redirect semihosting
    print output to a file or over TCP
    
    Change-Id: I37053463667ba109d52429d4f98bc98d0ede298d
    Signed-off-by: Tarek BOCHKATI <tarek.bouchk...@gmail.com>

diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c
index a02f2df..0596af6 100644
--- a/src/target/semihosting_common.c
+++ b/src/target/semihosting_common.c
@@ -111,6 +111,9 @@ int semihosting_common_init(struct target *target, void 
*setup,
        }
 
        semihosting->is_active = false;
+       semihosting->redirect_channel = SEMIHOSTING_REDIRECT_CONSOLE;
+       semihosting->redirect_file = NULL;
+       semihosting->redirect_connection = NULL;
        semihosting->is_fileio = false;
        semihosting->hit_fileio = false;
        semihosting->is_resumable = false;
@@ -136,6 +139,24 @@ int semihosting_common_init(struct target *target, void 
*setup,
        return ERROR_OK;
 }
 
+static int semihosting_putchar(struct semihosting *semihosting, int c)
+{
+       switch (semihosting->redirect_channel) {
+       case SEMIHOSTING_REDIRECT_CONSOLE:
+               return putchar(c);
+       case SEMIHOSTING_REDIRECT_FILE:
+               if (semihosting->redirect_file)
+                       return fputc(c, semihosting->redirect_file);
+               break;
+       case SEMIHOSTING_REDIRECT_TCP:
+               if (semihosting->redirect_connection)
+                       if (connection_write(semihosting->redirect_connection, 
&c, 1) == 1)
+                               return c;
+       }
+
+       return EOF;
+}
+
 /**
  * Portable implementation of ARM semihosting calls.
  * Performs the currently pending semihosting operation
@@ -145,7 +166,7 @@ int semihosting_common(struct target *target)
 {
        struct semihosting *semihosting = target->semihosting;
        if (!semihosting) {
-               /* Silently ignore if the semhosting field was not set. */
+               /* Silently ignore if the semihosting field was not set. */
                return ERROR_OK;
        }
 
@@ -1199,7 +1220,7 @@ int semihosting_common(struct target *target)
                                retval = target_read_memory(target, addr, 1, 1, 
&c);
                                if (retval != ERROR_OK)
                                        return retval;
-                               putchar(c);
+                               semihosting_putchar(semihosting, c);
                                semihosting->result = 0;
                        }
                        break;
@@ -1243,7 +1264,7 @@ int semihosting_common(struct target *target)
                                                return retval;
                                        if (!c)
                                                break;
-                                       putchar(c);
+                                       semihosting_putchar(semihosting, c);
                                } while (1);
                                semihosting->result = 0;
                        }
@@ -1457,6 +1478,42 @@ static void semihosting_set_field(struct target *target, 
uint64_t value,
                target_buffer_set_u32(target, fields + (index * 4), value);
 }
 
+/* -------------------------------------------------------------------------
+ * Semihosting redirect over TCP functions */
+
+struct semihosting_redirect_service {
+       struct semihosting *semihosting;
+};
+
+static int semihosting_new_connection(struct connection *connection)
+{
+       struct semihosting_redirect_service *service = 
connection->service->priv;
+       service->semihosting->redirect_connection = connection;
+       return ERROR_OK;
+}
+
+static int semihosting_connection_input(struct connection *connection)
+{
+       /* create a dummy buffer to check if the connection is still active */
+       const int buf_len = 100;
+       unsigned char buf[buf_len];
+       int bytes_read = connection_read(connection, buf, buf_len);
+
+       if (bytes_read == 0)
+               return ERROR_SERVER_REMOTE_CLOSED;
+       else if (bytes_read == -1) {
+               LOG_ERROR("error during read: %s", strerror(errno));
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
+
+       return ERROR_OK;
+}
+
+static int semihosting_connection_closed(struct connection *connection)
+{
+       /* nothing to do, no connection->priv to free */
+       return ERROR_OK;
+}
 
 /* -------------------------------------------------------------------------
  * Common semihosting commands handlers. */
@@ -1502,6 +1559,66 @@ static 
__COMMAND_HANDLER(handle_common_semihosting_command)
        return ERROR_OK;
 }
 
+static __COMMAND_HANDLER(handle_common_semihosting_print_redirect_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+
+       if (target == NULL) {
+               LOG_ERROR("No target selected");
+               return ERROR_FAIL;
+       }
+
+       struct semihosting *semihosting = target->semihosting;
+       if (!semihosting) {
+               command_print(CMD, "semihosting not supported for current 
target");
+               return ERROR_FAIL;
+       }
+
+       if (!semihosting->is_active) {
+               command_print(CMD, "semihosting not yet enabled for current 
target");
+               return ERROR_FAIL;
+       }
+
+       enum semihosting_redirect_channel channel = 
SEMIHOSTING_REDIRECT_CONSOLE;
+
+       if (CMD_ARGC > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       else if (CMD_ARGC == 1) {
+               if (strcmp(CMD_ARGV[0], "console")) {
+                       if (CMD_ARGV[0][0] == ':') {
+                               channel = SEMIHOSTING_REDIRECT_TCP;
+                               struct semihosting_redirect_service *service =
+                                               malloc(sizeof(struct 
semihosting_redirect_service));
+                               if (!service) {
+                                       LOG_ERROR("Failed to allocate 
semihosting redirect service.");
+                                       return ERROR_FAIL;
+                               }
+                               service->semihosting = semihosting;
+
+                               int ret = add_service("semihosting_redirect", 
&(CMD_ARGV[0][1]), 1,
+                                               semihosting_new_connection, 
semihosting_connection_input,
+                                               semihosting_connection_closed, 
NULL);
+                               if (ret != ERROR_OK) {
+                                       LOG_ERROR("Can't configure semihosting 
TCP port");
+                                       return ERROR_FAIL;
+                               }
+                       } else {
+                               channel = SEMIHOSTING_REDIRECT_FILE;
+                               semihosting->redirect_file = fopen(CMD_ARGV[0], 
"ab");
+                               if (!semihosting->redirect_file) {
+                                       LOG_ERROR("Can't open semihosting 
redirect file");
+                                       return ERROR_FAIL;
+                               }
+                       }
+               }
+       }
+
+       semihosting->redirect_channel = channel;
+
+
+       return ERROR_OK;
+}
+
 static __COMMAND_HANDLER(handle_common_semihosting_fileio_command)
 {
        struct target *target = get_current_target(CMD_CTX);
@@ -1597,28 +1714,35 @@ static 
__COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command)
 
 const struct command_registration semihosting_common_handlers[] = {
        {
-               "semihosting",
+               .name = "semihosting",
                .handler = handle_common_semihosting_command,
                .mode = COMMAND_EXEC,
                .usage = "['enable'|'disable']",
                .help = "activate support for semihosting operations",
        },
        {
-               "semihosting_cmdline",
+               .name = "semihosting_print_redirect",
+               .handler = handle_common_semihosting_print_redirect_command,
+               .mode = COMMAND_EXEC,
+               .usage = "[console|file|:<port>]",
+               .help = "redirect semihosting print",
+       },
+       {
+               .name = "semihosting_cmdline",
                .handler = handle_common_semihosting_cmdline,
                .mode = COMMAND_EXEC,
                .usage = "arguments",
                .help = "command line arguments to be passed to program",
        },
        {
-               "semihosting_fileio",
+               .name = "semihosting_fileio",
                .handler = handle_common_semihosting_fileio_command,
                .mode = COMMAND_EXEC,
                .usage = "['enable'|'disable']",
                .help = "activate support for semihosting fileio operations",
        },
        {
-               "semihosting_resexit",
+               .name = "semihosting_resexit",
                .handler = handle_common_semihosting_resumable_exit_command,
                .mode = COMMAND_EXEC,
                .usage = "['enable'|'disable']",
diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h
index 8fb5e0c..27f0a47 100644
--- a/src/target/semihosting_common.h
+++ b/src/target/semihosting_common.h
@@ -25,6 +25,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <time.h>
+#include <server/server.h>
 
 /*
  * According to:
@@ -88,6 +89,12 @@ enum semihosting_reported_exceptions {
        ADP_STOPPED_RUN_TIME_ERROR = ((2 << 16) + 35),
 };
 
+enum semihosting_redirect_channel {
+       SEMIHOSTING_REDIRECT_CONSOLE,
+       SEMIHOSTING_REDIRECT_FILE,
+       SEMIHOSTING_REDIRECT_TCP,
+};
+
 struct target;
 
 /*
@@ -98,6 +105,15 @@ struct semihosting {
        /** A flag reporting whether semihosting is active. */
        bool is_active;
 
+       /** Redirection configuration, to console by default */
+       enum semihosting_redirect_channel redirect_channel;
+
+       /** Handle to redirect semihosting print via file */
+       FILE *redirect_file;
+
+       /** Handle to redirect semihosting print via tcp */
+       struct connection *redirect_connection;
+
        /** A flag reporting whether semihosting fileio is active. */
        bool is_fileio;
 

-- 


_______________________________________________
OpenOCD-devel mailing list
OpenOCD-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to