semihosting: fix handling of errno

This patch fixes the handling of errno by setting the sys_errn
only if error has actually occurred during the semihosting call.
It also fixes few issues where error was not set in the first place.

Change-Id: I2fbe562f3ec5e6220b800de04cd33aa1f409c7a0
Signed-off-by: Marek Vrbka <marek.vrbka@codasip.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/7730
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Jan Matyas <jan.matyas@codasip.com>
This commit is contained in:
Marek Vrbka 2023-06-01 12:42:03 +02:00 committed by Antonio Borneo
parent 6ef75352f1
commit 56fd04832a
1 changed files with 47 additions and 32 deletions

View File

@ -223,7 +223,10 @@ static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void *
return semihosting_redirect_write(semihosting, buf, size); return semihosting_redirect_write(semihosting, buf, size);
/* default write */ /* 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) 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 */ /* default read */
ssize_t result = read(fd, buf, size); ssize_t result = read(fd, buf, size);
semihosting->sys_errno = errno; if (result == -1)
semihosting->sys_errno = errno;
return result; return result;
} }
@ -449,12 +453,7 @@ int semihosting_common(struct target *target)
(fd == 0) ? "stdin" : (fd == 0) ? "stdin" :
(fd == 1) ? "stdout" : "stderr"); (fd == 1) ? "stdout" : "stderr");
/* Just pretend success */ /* Just pretend success */
if (semihosting->is_fileio) { semihosting->result = 0;
semihosting->result = 0;
} else {
semihosting->result = 0;
semihosting->sys_errno = 0;
}
break; break;
} }
/* Close the descriptor */ /* Close the descriptor */
@ -464,7 +463,8 @@ int semihosting_common(struct target *target)
fileio_info->param_1 = fd; fileio_info->param_1 = fd;
} else { } else {
semihosting->result = close(fd); semihosting->result = close(fd);
semihosting->sys_errno = errno; if (semihosting->result == -1)
semihosting->sys_errno = errno;
LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result); LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result);
} }
} }
@ -842,7 +842,8 @@ int semihosting_common(struct target *target)
int fd = semihosting_get_field(target, 0, fields); int fd = semihosting_get_field(target, 0, fields);
// isatty() on Windows may return any non-zero value if fd is a terminal // isatty() on Windows may return any non-zero value if fd is a terminal
semihosting->result = isatty(fd) ? 1 : 0; 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); LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result);
} }
break; break;
@ -934,14 +935,16 @@ int semihosting_common(struct target *target)
semihosting->result = -1; semihosting->result = -1;
semihosting->sys_errno = EINVAL; semihosting->sys_errno = EINVAL;
} else if (strcmp((char *)fn, ":tt") == 0) { } else if (strcmp((char *)fn, ":tt") == 0) {
if (mode == 0) if (mode == 0) {
semihosting->result = 0; semihosting->result = 0;
else if (mode == 4) } else if (mode == 4) {
semihosting->result = 1; semihosting->result = 1;
else if (mode == 8) } else if (mode == 8) {
semihosting->result = 2; semihosting->result = 2;
else } else {
semihosting->result = -1; semihosting->result = -1;
semihosting->sys_errno = EINVAL;
}
} else { } else {
semihosting->hit_fileio = true; semihosting->hit_fileio = true;
fileio_info->identifier = "open"; fileio_info->identifier = "open";
@ -956,25 +959,23 @@ int semihosting_common(struct target *target)
* - 0-3 ("r") for stdin, * - 0-3 ("r") for stdin,
* - 4-7 ("w") for stdout, * - 4-7 ("w") for stdout,
* - 8-11 ("a") for stderr */ * - 8-11 ("a") for stderr */
int fd;
if (mode < 4) { if (mode < 4) {
int fd = dup(STDIN_FILENO); fd = dup(STDIN_FILENO);
semihosting->result = fd;
semihosting->stdin_fd = fd; semihosting->stdin_fd = fd;
semihosting->sys_errno = errno; LOG_DEBUG("dup(STDIN)=%d", fd);
LOG_DEBUG("dup(STDIN)=%" PRId64, semihosting->result);
} else if (mode < 8) { } else if (mode < 8) {
int fd = dup(STDOUT_FILENO); fd = dup(STDOUT_FILENO);
semihosting->result = fd;
semihosting->stdout_fd = fd; semihosting->stdout_fd = fd;
semihosting->sys_errno = errno; LOG_DEBUG("dup(STDOUT)=%d", fd);
LOG_DEBUG("dup(STDOUT)=%" PRId64, semihosting->result);
} else { } else {
int fd = dup(STDERR_FILENO); fd = dup(STDERR_FILENO);
semihosting->result = fd;
semihosting->stderr_fd = fd; semihosting->stderr_fd = fd;
semihosting->sys_errno = errno; LOG_DEBUG("dup(STDERR)=%d", fd);
LOG_DEBUG("dup(STDERR)=%" PRId64, semihosting->result);
} }
semihosting->result = fd;
if (fd == -1)
semihosting->sys_errno = errno;
} else { } else {
/* cygwin requires the permission setting /* cygwin requires the permission setting
* otherwise it will fail to reopen a previously * otherwise it will fail to reopen a previously
@ -982,7 +983,8 @@ int semihosting_common(struct target *target)
semihosting->result = open((char *)fn, semihosting->result = open((char *)fn,
open_host_modeflags[mode], open_host_modeflags[mode],
0644); 0644);
semihosting->sys_errno = errno; if (semihosting->result == -1)
semihosting->sys_errno = errno;
LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result); LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result);
} }
} }
@ -1131,7 +1133,8 @@ int semihosting_common(struct target *target)
} }
fn[len] = 0; fn[len] = 0;
semihosting->result = remove((char *)fn); 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); LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result);
free(fn); free(fn);
@ -1200,7 +1203,9 @@ int semihosting_common(struct target *target)
fn2[len2] = 0; fn2[len2] = 0;
semihosting->result = rename((char *)fn1, semihosting->result = rename((char *)fn1,
(char *)fn2); (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); LOG_DEBUG("rename('%s', '%s')=%" PRId64 " %d", fn1, fn2, semihosting->result, errno);
free(fn1); free(fn1);
free(fn2); free(fn2);
@ -1245,7 +1250,8 @@ int semihosting_common(struct target *target)
fileio_info->param_3 = SEEK_SET; fileio_info->param_3 = SEEK_SET;
} else { } else {
semihosting->result = lseek(fd, pos, SEEK_SET); 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); LOG_DEBUG("lseek(%d, %d)=%" PRId64, fd, (int)pos, semihosting->result);
if (semihosting->result == pos) if (semihosting->result == pos)
semihosting->result = 0; semihosting->result = 0;
@ -1383,7 +1389,6 @@ int semihosting_common(struct target *target)
return retval; return retval;
} }
semihosting->result = semihosting_write(semihosting, fd, buf, len); semihosting->result = semihosting_write(semihosting, fd, buf, len);
semihosting->sys_errno = errno;
LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64, LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64,
fd, fd,
addr, addr,
@ -1671,7 +1676,6 @@ static int semihosting_common_fileio_end(struct target *target, int result,
semihosting->hit_fileio = false; semihosting->hit_fileio = false;
semihosting->result = result; semihosting->result = result;
semihosting->sys_errno = fileio_errno;
/* /*
* Some fileio results do not match up with what the semihosting * Some fileio results do not match up with what the semihosting
@ -1693,6 +1697,17 @@ static int semihosting_common_fileio_end(struct target *target, int result,
break; 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); return semihosting->post_result(target);
} }