ipdbg: fix double free of virtual-ir data
[openocd.git] / src / target / semihosting_common.c
index 6c91876c7365d2ef92839728f947f83ee233814e..f7acc6092de688b683bc97aaab6b40781c6a735e 100644 (file)
@@ -223,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)
@@ -268,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;
 }
@@ -294,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
@@ -323,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) {
 
@@ -388,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 */
@@ -403,7 +463,8 @@ int semihosting_common(struct target *target)
                                        fileio_info->param_1 = fd;
                                } else {
                                        semihosting->result = close(fd);
-                                       semihosting->sys_errno = errno;
+                                       if (semihosting->result == -1)
+                                               semihosting->sys_errno = errno;
                                        LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result);
                                }
                        }
@@ -781,7 +842,8 @@ int semihosting_common(struct target *target)
                                int fd = semihosting_get_field(target, 0, fields);
                                // isatty() on Windows may return any non-zero value if fd is a terminal
                                semihosting->result = isatty(fd) ? 1 : 0;
-                               semihosting->sys_errno = errno;
+                               if (semihosting->result == 0)
+                                       semihosting->sys_errno = errno;
                                LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result);
                        }
                        break;
@@ -873,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";
@@ -895,25 +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)=%" PRId64, 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)=%" PRId64, 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)=%" PRId64, 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
@@ -921,7 +983,8 @@ int semihosting_common(struct target *target)
                                                        semihosting->result = open((char *)fn,
                                                                        open_host_modeflags[mode],
                                                                        0644);
-                                                       semihosting->sys_errno = errno;
+                                                       if (semihosting->result == -1)
+                                                               semihosting->sys_errno = errno;
                                                        LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result);
                                                }
                                        }
@@ -1070,7 +1133,8 @@ int semihosting_common(struct target *target)
                                                }
                                                fn[len] = 0;
                                                semihosting->result = remove((char *)fn);
-                                               semihosting->sys_errno = errno;
+                                               if (semihosting->result == -1)
+                                                       semihosting->sys_errno = errno;
                                                LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result);
 
                                                free(fn);
@@ -1139,7 +1203,9 @@ int semihosting_common(struct target *target)
                                                fn2[len2] = 0;
                                                semihosting->result = rename((char *)fn1,
                                                                (char *)fn2);
-                                               semihosting->sys_errno = errno;
+                                               // 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);
@@ -1184,7 +1250,8 @@ int semihosting_common(struct target *target)
                                        fileio_info->param_3 = SEEK_SET;
                                } else {
                                        semihosting->result = lseek(fd, pos, SEEK_SET);
-                                       semihosting->sys_errno = errno;
+                                       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;
@@ -1322,7 +1389,6 @@ 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)=%" PRId64,
                                                        fd,
                                                        addr,
@@ -1470,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;
@@ -1609,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
@@ -1631,6 +1697,17 @@ 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);
 }
 

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)