ipdbg: fix double free of virtual-ir data
[openocd.git] / src / target / semihosting_common.c
index 2df6e38aeaadbfd10dceb847770b06ff82a17004..f7acc6092de688b683bc97aaab6b40781c6a735e 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2018 by Liviu Ionescu                                   *
  *   <ilg@livius.net>                                                      *
  *                                                                         *
  *   Copyright (C) 2016 by Square, Inc.                                    *
  *   Steven Stallion <stallion@squareup.com>                               *
- *                                                                         *
- *   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     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 /**
@@ -50,6 +39,7 @@
 
 #include <helper/binarybuffer.h>
 #include <helper/log.h>
+#include <server/gdb_server.h>
 #include <sys/stat.h>
 
 /**
@@ -103,19 +93,6 @@ static int semihosting_common_fileio_info(struct target *target,
 static int semihosting_common_fileio_end(struct target *target, int result,
        int fileio_errno, bool ctrl_c);
 
-static int semihosting_read_fields(struct target *target, size_t number,
-       uint8_t *fields);
-static int semihosting_write_fields(struct target *target, size_t number,
-       uint8_t *fields);
-static uint64_t semihosting_get_field(struct target *target, size_t index,
-       uint8_t *fields);
-static void semihosting_set_field(struct target *target, uint64_t value,
-       size_t index,
-       uint8_t *fields);
-
-/* Attempts to include gdb_server.h failed. */
-extern int gdb_actual_connections;
-
 /**
  * Initialize common semihosting support.
  *
@@ -166,6 +143,7 @@ int semihosting_common_init(struct target *target, void *setup,
 
        semihosting->setup = setup;
        semihosting->post_result = post_result;
+       semihosting->user_command_extension = NULL;
 
        target->semihosting = semihosting;
 
@@ -245,7 +223,10 @@ static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void *
                return semihosting_redirect_write(semihosting, buf, size);
 
        /* default write */
-       return write(fd, buf, size);
+       int result = write(fd, buf, size);
+       if (result == -1)
+               semihosting->sys_errno = errno;
+       return result;
 }
 
 static ssize_t semihosting_redirect_read(struct semihosting *semihosting, void *buf, int size)
@@ -290,7 +271,8 @@ static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd,
 
        /* default read */
        ssize_t result = read(fd, buf, size);
-       semihosting->sys_errno = errno;
+       if (result == -1)
+               semihosting->sys_errno = errno;
 
        return result;
 }
@@ -316,6 +298,66 @@ static inline int semihosting_getchar(struct semihosting *semihosting, int fd)
  */
 static char *semihosting_user_op_params;
 
+const char *semihosting_opcode_to_str(const uint64_t opcode)
+{
+       switch (opcode) {
+               case SEMIHOSTING_SYS_CLOSE:
+                       return "CLOSE";
+               case SEMIHOSTING_SYS_CLOCK:
+                       return "CLOCK";
+               case SEMIHOSTING_SYS_ELAPSED:
+                       return "ELAPSED";
+               case SEMIHOSTING_SYS_ERRNO:
+                       return "ERRNO";
+               case SEMIHOSTING_SYS_EXIT:
+                       return "EXIT";
+               case SEMIHOSTING_SYS_EXIT_EXTENDED:
+                       return "EXIT_EXTENDED";
+               case SEMIHOSTING_SYS_FLEN:
+                       return "FLEN";
+               case SEMIHOSTING_SYS_GET_CMDLINE:
+                       return "GET_CMDLINE";
+               case SEMIHOSTING_SYS_HEAPINFO:
+                       return "HEAPINFO";
+               case SEMIHOSTING_SYS_ISERROR:
+                       return "ISERROR";
+               case SEMIHOSTING_SYS_ISTTY:
+                       return "ISTTY";
+               case SEMIHOSTING_SYS_OPEN:
+                       return "OPEN";
+               case SEMIHOSTING_SYS_READ:
+                       return "READ";
+               case SEMIHOSTING_SYS_READC:
+                       return "READC";
+               case SEMIHOSTING_SYS_REMOVE:
+                       return "REMOVE";
+               case SEMIHOSTING_SYS_RENAME:
+                       return "RENAME";
+               case SEMIHOSTING_SYS_SEEK:
+                       return "SEEK";
+               case SEMIHOSTING_SYS_SYSTEM:
+                       return "SYSTEM";
+               case SEMIHOSTING_SYS_TICKFREQ:
+                       return "TICKFREQ";
+               case SEMIHOSTING_SYS_TIME:
+                       return "TIME";
+               case SEMIHOSTING_SYS_TMPNAM:
+                       return "TMPNAM";
+               case SEMIHOSTING_SYS_WRITE:
+                       return "WRITE";
+               case SEMIHOSTING_SYS_WRITEC:
+                       return "WRITEC";
+               case SEMIHOSTING_SYS_WRITE0:
+                       return "WRITE0";
+               case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X1FF:
+                       return "USER_CMD";
+               case SEMIHOSTING_ARM_RESERVED_START ... SEMIHOSTING_ARM_RESERVED_END:
+                       return "ARM_RESERVED_CMD";
+               default:
+                       return "<unknown>";
+       }
+}
+
 /**
  * Portable implementation of ARM semihosting calls.
  * Performs the currently pending semihosting operation
@@ -345,8 +387,9 @@ int semihosting_common(struct target *target)
        /* Enough space to hold 4 long words. */
        uint8_t fields[4*8];
 
-       LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op,
-               semihosting->param);
+       LOG_DEBUG("op=0x%x (%s), param=0x%" PRIx64, semihosting->op,
+                         semihosting_opcode_to_str(semihosting->op),
+                         semihosting->param);
 
        switch (semihosting->op) {
 
@@ -410,12 +453,7 @@ int semihosting_common(struct target *target)
                                                        (fd == 0) ? "stdin" :
                                                        (fd == 1) ? "stdout" : "stderr");
                                        /* Just pretend success */
-                                       if (semihosting->is_fileio) {
-                                               semihosting->result = 0;
-                                       } else {
-                                               semihosting->result = 0;
-                                               semihosting->sys_errno = 0;
-                                       }
+                                       semihosting->result = 0;
                                        break;
                                }
                                /* Close the descriptor */
@@ -425,8 +463,9 @@ int semihosting_common(struct target *target)
                                        fileio_info->param_1 = fd;
                                } else {
                                        semihosting->result = close(fd);
-                                       semihosting->sys_errno = errno;
-                                       LOG_DEBUG("close(%d)=%d", fd, (int)semihosting->result);
+                                       if (semihosting->result == -1)
+                                               semihosting->sys_errno = errno;
+                                       LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result);
                                }
                        }
                        break;
@@ -513,7 +552,7 @@ int semihosting_common(struct target *target)
                                        int code = semihosting_get_field(target, 1, fields);
 
                                        if (type == ADP_STOPPED_APPLICATION_EXIT) {
-                                               if (!gdb_actual_connections)
+                                               if (!gdb_get_actual_connections())
                                                        exit(code);
                                                else {
                                                        fprintf(stderr,
@@ -528,7 +567,7 @@ int semihosting_common(struct target *target)
                                }
                        } else {
                                if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) {
-                                       if (!gdb_actual_connections)
+                                       if (!gdb_get_actual_connections())
                                                exit(0);
                                        else {
                                                fprintf(stderr,
@@ -537,14 +576,14 @@ int semihosting_common(struct target *target)
                                } else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) {
                                        /* Chosen more or less arbitrarily to have a nicer message,
                                         * otherwise all other return the same exit code 1. */
-                                       if (!gdb_actual_connections)
+                                       if (!gdb_get_actual_connections())
                                                exit(1);
                                        else {
                                                fprintf(stderr,
                                                        "semihosting: *** application exited with error ***\n");
                                        }
                                } else {
-                                       if (!gdb_actual_connections)
+                                       if (!gdb_get_actual_connections())
                                                exit(1);
                                        else {
                                                fprintf(stderr,
@@ -604,7 +643,7 @@ int semihosting_common(struct target *target)
                                int code = semihosting_get_field(target, 1, fields);
 
                                if (type == ADP_STOPPED_APPLICATION_EXIT) {
-                                       if (!gdb_actual_connections)
+                                       if (!gdb_get_actual_connections())
                                                exit(code);
                                        else {
                                                fprintf(stderr,
@@ -651,10 +690,10 @@ int semihosting_common(struct target *target)
                                semihosting->result = fstat(fd, &buf);
                                if (semihosting->result == -1) {
                                        semihosting->sys_errno = errno;
-                                       LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result);
+                                       LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result);
                                        break;
                                }
-                               LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result);
+                               LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result);
                                semihosting->result = buf.st_size;
                        }
                        break;
@@ -711,8 +750,7 @@ int semihosting_common(struct target *target)
                                        if (retval != ERROR_OK)
                                                return retval;
                                }
-                               LOG_DEBUG("SYS_GET_CMDLINE=[%s],%d", arg,
-                                       (int)semihosting->result);
+                               LOG_DEBUG("SYS_GET_CMDLINE=[%s], %" PRId64, arg, semihosting->result);
                        }
                        break;
 
@@ -802,9 +840,11 @@ int semihosting_common(struct target *target)
                                if (retval != ERROR_OK)
                                        return retval;
                                int fd = semihosting_get_field(target, 0, fields);
-                               semihosting->result = isatty(fd);
-                               semihosting->sys_errno = errno;
-                               LOG_DEBUG("isatty(%d)=%d", fd, (int)semihosting->result);
+                               // isatty() on Windows may return any non-zero value if fd is a terminal
+                               semihosting->result = isatty(fd) ? 1 : 0;
+                               if (semihosting->result == 0)
+                                       semihosting->sys_errno = errno;
+                               LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result);
                        }
                        break;
 
@@ -877,9 +917,11 @@ int semihosting_common(struct target *target)
                                        semihosting->result = -1;
                                        semihosting->sys_errno = ENOMEM;
                                } else {
-                                       strncpy((char *)fn, semihosting->basedir, basedir_len);
-                                       if (fn[basedir_len - 1] != '/')
-                                               fn[basedir_len++] = '/';
+                                       if (basedir_len > 0) {
+                                               strcpy((char *)fn, semihosting->basedir);
+                                               if (fn[basedir_len - 1] != '/')
+                                                       fn[basedir_len++] = '/';
+                                       }
                                        retval = target_read_memory(target, addr, 1, len, fn + basedir_len);
                                        if (retval != ERROR_OK) {
                                                free(fn);
@@ -893,14 +935,16 @@ int semihosting_common(struct target *target)
                                                        semihosting->result = -1;
                                                        semihosting->sys_errno = EINVAL;
                                                } else if (strcmp((char *)fn, ":tt") == 0) {
-                                                       if (mode == 0)
+                                                       if (mode == 0) {
                                                                semihosting->result = 0;
-                                                       else if (mode == 4)
+                                                       } else if (mode == 4) {
                                                                semihosting->result = 1;
-                                                       else if (mode == 8)
+                                                       } else if (mode == 8) {
                                                                semihosting->result = 2;
-                                                       else
+                                                       } else {
                                                                semihosting->result = -1;
+                                                               semihosting->sys_errno = EINVAL;
+                                                       }
                                                } else {
                                                        semihosting->hit_fileio = true;
                                                        fileio_info->identifier = "open";
@@ -915,28 +959,23 @@ int semihosting_common(struct target *target)
                                                         * - 0-3 ("r") for stdin,
                                                         * - 4-7 ("w") for stdout,
                                                         * - 8-11 ("a") for stderr */
+                                                       int fd;
                                                        if (mode < 4) {
-                                                               int fd = dup(STDIN_FILENO);
-                                                               semihosting->result = fd;
+                                                               fd = dup(STDIN_FILENO);
                                                                semihosting->stdin_fd = fd;
-                                                               semihosting->sys_errno = errno;
-                                                               LOG_DEBUG("dup(STDIN)=%d",
-                                                                       (int)semihosting->result);
+                                                               LOG_DEBUG("dup(STDIN)=%d", fd);
                                                        } else if (mode < 8) {
-                                                               int fd = dup(STDOUT_FILENO);
-                                                               semihosting->result = fd;
+                                                               fd = dup(STDOUT_FILENO);
                                                                semihosting->stdout_fd = fd;
-                                                               semihosting->sys_errno = errno;
-                                                               LOG_DEBUG("dup(STDOUT)=%d",
-                                                                       (int)semihosting->result);
+                                                               LOG_DEBUG("dup(STDOUT)=%d", fd);
                                                        } else {
-                                                               int fd = dup(STDERR_FILENO);
-                                                               semihosting->result = fd;
+                                                               fd = dup(STDERR_FILENO);
                                                                semihosting->stderr_fd = fd;
-                                                               semihosting->sys_errno = errno;
-                                                               LOG_DEBUG("dup(STDERR)=%d",
-                                                                       (int)semihosting->result);
+                                                               LOG_DEBUG("dup(STDERR)=%d", fd);
                                                        }
+                                                       semihosting->result = fd;
+                                                       if (fd == -1)
+                                                               semihosting->sys_errno = errno;
                                                } else {
                                                        /* cygwin requires the permission setting
                                                         * otherwise it will fail to reopen a previously
@@ -944,9 +983,9 @@ int semihosting_common(struct target *target)
                                                        semihosting->result = open((char *)fn,
                                                                        open_host_modeflags[mode],
                                                                        0644);
-                                                       semihosting->sys_errno = errno;
-                                                       LOG_DEBUG("open('%s')=%d", fn,
-                                                               (int)semihosting->result);
+                                                       if (semihosting->result == -1)
+                                                               semihosting->sys_errno = errno;
+                                                       LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result);
                                                }
                                        }
                                        free(fn);
@@ -1009,11 +1048,11 @@ int semihosting_common(struct target *target)
                                                semihosting->sys_errno = ENOMEM;
                                        } else {
                                                semihosting->result = semihosting_read(semihosting, fd, buf, len);
-                                               LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%d",
+                                               LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%" PRId64,
                                                        fd,
                                                        addr,
                                                        len,
-                                                       (int)semihosting->result);
+                                                       semihosting->result);
                                                if (semihosting->result >= 0) {
                                                        retval = target_write_buffer(target, addr,
                                                                        semihosting->result,
@@ -1049,7 +1088,7 @@ int semihosting_common(struct target *target)
                                return ERROR_FAIL;
                        }
                        semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd);
-                       LOG_DEBUG("getchar()=%d", (int)semihosting->result);
+                       LOG_DEBUG("getchar()=%" PRId64, semihosting->result);
                        break;
 
                case SEMIHOSTING_SYS_REMOVE:    /* 0x0E */
@@ -1094,9 +1133,9 @@ int semihosting_common(struct target *target)
                                                }
                                                fn[len] = 0;
                                                semihosting->result = remove((char *)fn);
-                                               semihosting->sys_errno = errno;
-                                               LOG_DEBUG("remove('%s')=%d", fn,
-                                                       (int)semihosting->result);
+                                               if (semihosting->result == -1)
+                                                       semihosting->sys_errno = errno;
+                                               LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result);
 
                                                free(fn);
                                        }
@@ -1164,10 +1203,10 @@ int semihosting_common(struct target *target)
                                                fn2[len2] = 0;
                                                semihosting->result = rename((char *)fn1,
                                                                (char *)fn2);
-                                               semihosting->sys_errno = errno;
-                                               LOG_DEBUG("rename('%s', '%s')=%d", fn1, fn2,
-                                                       (int)semihosting->result);
-
+                                               // rename() on Windows returns nonzero on error
+                                               if (semihosting->result != 0)
+                                                       semihosting->sys_errno = errno;
+                                               LOG_DEBUG("rename('%s', '%s')=%" PRId64 " %d", fn1, fn2, semihosting->result, errno);
                                                free(fn1);
                                                free(fn2);
                                        }
@@ -1211,9 +1250,9 @@ int semihosting_common(struct target *target)
                                        fileio_info->param_3 = SEEK_SET;
                                } else {
                                        semihosting->result = lseek(fd, pos, SEEK_SET);
-                                       semihosting->sys_errno = errno;
-                                       LOG_DEBUG("lseek(%d, %d)=%d", fd, (int)pos,
-                                               (int)semihosting->result);
+                                       if (semihosting->result == -1)
+                                               semihosting->sys_errno = errno;
+                                       LOG_DEBUG("lseek(%d, %d)=%" PRId64, fd, (int)pos, semihosting->result);
                                        if (semihosting->result == pos)
                                                semihosting->result = 0;
                                }
@@ -1272,9 +1311,7 @@ int semihosting_common(struct target *target)
                                                        cmd[len] = 0;
                                                        semihosting->result = system(
                                                                        (const char *)cmd);
-                                                       LOG_DEBUG("system('%s')=%d",
-                                                               cmd,
-                                                               (int)semihosting->result);
+                                                       LOG_DEBUG("system('%s')=%" PRId64, cmd, semihosting->result);
                                                }
 
                                                free(cmd);
@@ -1352,12 +1389,11 @@ int semihosting_common(struct target *target)
                                                        return retval;
                                                }
                                                semihosting->result = semihosting_write(semihosting, fd, buf, len);
-                                               semihosting->sys_errno = errno;
-                                               LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%d",
+                                               LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64,
                                                        fd,
                                                        addr,
                                                        len,
-                                                       (int)semihosting->result);
+                                                       semihosting->result);
                                                if (semihosting->result >= 0) {
                                                        /* The number of bytes that are NOT written.
                                                         * */
@@ -1446,7 +1482,7 @@ int semihosting_common(struct target *target)
                        }
                        break;
 
-               case SEMIHOSTING_USER_CMD_0x100 ... SEMIHOSTING_USER_CMD_0x107:
+               case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X107:
                        /**
                         * This is a user defined operation (while user cmds 0x100-0x1ff
                         * are possible, only 0x100-0x107 are currently implemented).
@@ -1465,9 +1501,14 @@ int semihosting_common(struct target *target)
                         * Return
                         * On exit, the RETURN REGISTER contains the return status.
                         */
-               {
-                       assert(!semihosting_user_op_params);
+                       if (semihosting->user_command_extension) {
+                               retval = semihosting->user_command_extension(target);
+                               if (retval != ERROR_NOT_IMPLEMENTED)
+                                       break;
+                               /* If custom user command not handled, we are looking for the TCL handler */
+                       }
 
+                       assert(!semihosting_user_op_params);
                        retval = semihosting_read_fields(target, 2, fields);
                        if (retval != ERROR_OK) {
                                LOG_ERROR("Failed to read fields for user defined command"
@@ -1495,8 +1536,9 @@ int semihosting_common(struct target *target)
                        retval = target_read_buffer(target, addr, len,
                                        (uint8_t *)(semihosting_user_op_params));
                        if (retval != ERROR_OK) {
-                               LOG_ERROR("Failed to read from target, semihosting op=0x%x",
-                                               semihosting->op);
+                               LOG_ERROR("Failed to read from target, semihosting op=0x%x (%s)",
+                                               semihosting->op,
+                                               semihosting_opcode_to_str(semihosting->op));
                                free(semihosting_user_op_params);
                                semihosting_user_op_params = NULL;
                                return retval;
@@ -1505,11 +1547,8 @@ int semihosting_common(struct target *target)
                        target_handle_event(target, semihosting->op);
                        free(semihosting_user_op_params);
                        semihosting_user_op_params = NULL;
-
                        semihosting->result = 0;
                        break;
-               }
-
 
                case SEMIHOSTING_SYS_ELAPSED:   /* 0x30 */
                /*
@@ -1637,7 +1676,6 @@ static int semihosting_common_fileio_end(struct target *target, int result,
        semihosting->hit_fileio = false;
 
        semihosting->result = result;
-       semihosting->sys_errno = fileio_errno;
 
        /*
         * Some fileio results do not match up with what the semihosting
@@ -1646,17 +1684,11 @@ static int semihosting_common_fileio_end(struct target *target, int result,
         */
        switch (semihosting->op) {
                case SEMIHOSTING_SYS_WRITE:     /* 0x05 */
+               case SEMIHOSTING_SYS_READ:      /* 0x06 */
                        if (result < 0)
-                               semihosting->result = fileio_info->param_3;
+                               semihosting->result = fileio_info->param_3;  /* Zero bytes read/written. */
                        else
-                               semihosting->result = 0;
-                       break;
-
-               case SEMIHOSTING_SYS_READ:      /* 0x06 */
-                       if (result == (int)fileio_info->param_3)
-                               semihosting->result = 0;
-                       if (result <= 0)
-                               semihosting->result = fileio_info->param_3;
+                               semihosting->result = (int64_t)fileio_info->param_3 - result;
                        break;
 
                case SEMIHOSTING_SYS_SEEK:      /* 0x0a */
@@ -1665,13 +1697,27 @@ static int semihosting_common_fileio_end(struct target *target, int result,
                        break;
        }
 
+       bool fileio_failed = false;
+       if (semihosting->op == SEMIHOSTING_SYS_ISTTY)
+               fileio_failed = (semihosting->result == 0);
+       else if (semihosting->op == SEMIHOSTING_SYS_RENAME)
+               fileio_failed = (semihosting->result != 0);
+       else
+               fileio_failed = (semihosting->result == -1);
+
+       if (fileio_failed)
+               semihosting->sys_errno = fileio_errno;
+
        return semihosting->post_result(target);
 }
 
+/* -------------------------------------------------------------------------
+ * Utility functions. */
+
 /**
  * Read all fields of a command from target to buffer.
  */
-static int semihosting_read_fields(struct target *target, size_t number,
+int semihosting_read_fields(struct target *target, size_t number,
        uint8_t *fields)
 {
        struct semihosting *semihosting = target->semihosting;
@@ -1683,7 +1729,7 @@ static int semihosting_read_fields(struct target *target, size_t number,
 /**
  * Write all fields of a command from buffer to target.
  */
-static int semihosting_write_fields(struct target *target, size_t number,
+int semihosting_write_fields(struct target *target, size_t number,
        uint8_t *fields)
 {
        struct semihosting *semihosting = target->semihosting;
@@ -1695,7 +1741,7 @@ static int semihosting_write_fields(struct target *target, size_t number,
 /**
  * Extract a field from the buffer, considering register size and endianness.
  */
-static uint64_t semihosting_get_field(struct target *target, size_t index,
+uint64_t semihosting_get_field(struct target *target, size_t index,
        uint8_t *fields)
 {
        struct semihosting *semihosting = target->semihosting;
@@ -1708,7 +1754,7 @@ static uint64_t semihosting_get_field(struct target *target, size_t index,
 /**
  * Store a field in the buffer, considering register size and endianness.
  */
-static void semihosting_set_field(struct target *target, uint64_t value,
+void semihosting_set_field(struct target *target, uint64_t value,
        size_t index,
        uint8_t *fields)
 {
@@ -1832,7 +1878,7 @@ COMMAND_HANDLER(handle_common_semihosting_redirect_command)
 {
        struct target *target = get_current_target(CMD_CTX);
 
-       if (target == NULL) {
+       if (!target) {
                LOG_ERROR("No target selected");
                return ERROR_FAIL;
        }

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)