From 9f8c7be360b37065dc39d71c89a052b14edbdf4f Mon Sep 17 00:00:00 2001 From: Koen De Vleeschauwer Date: Thu, 30 Apr 2020 16:33:38 +0200 Subject: [PATCH] semihosting --- src/command.c | 16 ++++++ src/include/target.h | 11 ++-- src/target/cortexm.c | 102 ++++++++++++++++++++++++++++------- src/target/target.c | 10 ++++ src/target/target_internal.h | 1 + 5 files changed, 118 insertions(+), 22 deletions(-) diff --git a/src/command.c b/src/command.c index 0d4d0cb..dda2e8c 100644 --- a/src/command.c +++ b/src/command.c @@ -59,6 +59,7 @@ static bool cmd_target_power(target *t, int argc, const char **argv); #ifdef PLATFORM_HAS_TRACESWO static bool cmd_traceswo(target *t, int argc, const char **argv); #endif +static bool cmd_heapinfo(target *t, int argc, const char **argv); #if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED) static bool cmd_debug_bmp(target *t, int argc, const char **argv); #endif @@ -83,6 +84,7 @@ const struct command_s cmd_list[] = { {"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, Manchester mode" }, #endif #endif + {"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" }, #if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED) {"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"}, #endif @@ -402,3 +404,17 @@ static bool cmd_debug_bmp(target *t, int argc, const char **argv) return true; } #endif +static bool cmd_heapinfo(target *t, int argc, const char **argv) +{ + if (t == NULL) gdb_out("not attached\n"); + else if (argc == 5) { + target_addr heap_base = strtoul(argv[1], NULL, 16); + target_addr heap_limit = strtoul(argv[2], NULL, 16); + target_addr stack_base = strtoul(argv[3], NULL, 16); + target_addr stack_limit = strtoul(argv[4], NULL, 16); + gdb_outf("heapinfo heap_base: %p heap_limit: %p stack_base: %p stack_limit: %p\n", + heap_base, heap_limit, stack_base, stack_limit); + target_set_heapinfo(t, heap_base, heap_limit, stack_base, stack_limit); + } else gdb_outf("heapinfo heap_base heap_limit stack_base stack_limit\n"); + return true; +} diff --git a/src/include/target.h b/src/include/target.h index 3510250..cc6131e 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -81,6 +81,8 @@ void target_halt_request(target *t); enum target_halt_reason target_halt_poll(target *t, target_addr *watch); void target_halt_resume(target *t, bool step); void target_set_cmdline(target *t, char *cmdline); +void target_set_heapinfo(target *t, target_addr heap_base, target_addr heap_limit, + target_addr stack_base, target_addr stack_limit); /* Break-/watchpoint functions */ enum target_breakwatch { @@ -97,11 +99,12 @@ int target_breakwatch_clear(target *t, enum target_breakwatch, target_addr, size void target_command_help(target *t); int target_command(target *t, int argc, const char *argv[]); - +/* keep target_errno in sync with errno values in gdb/include/gdb/fileio.h */ enum target_errno { TARGET_EPERM = 1, TARGET_ENOENT = 2, TARGET_EINTR = 4, + TARGET_EIO = 5, TARGET_EBADF = 9, TARGET_EACCES = 13, TARGET_EFAULT = 14, @@ -111,13 +114,15 @@ enum target_errno { TARGET_ENOTDIR = 20, TARGET_EISDIR = 21, TARGET_EINVAL = 22, - TARGET_EMFILE = 24, TARGET_ENFILE = 23, + TARGET_EMFILE = 24, TARGET_EFBIG = 27, TARGET_ENOSPC = 28, TARGET_ESPIPE = 29, TARGET_EROFS = 30, - TARGET_ENAMETOOLONG = 36, + TARGET_ENOSYS = 88, + TARGET_ENAMETOOLONG = 91, + TARGET_EUNKNOWN = 9999, }; enum target_open_flags { diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 70e38d0..e047def 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -1110,12 +1110,12 @@ static int cortexm_hostio_request(target *t) break; case SYS_READ: /* read */ ret = tc_read(t, params[0] - 1, params[1], params[2]); - if (ret > 0) + if (ret >= 0) ret = params[2] - ret; break; case SYS_WRITE: /* write */ ret = tc_write(t, params[0] - 1, params[1], params[2]); - if (ret > 0) + if (ret >= 0) ret = params[2] - ret; break; case SYS_WRITEC: /* writec */ @@ -1141,17 +1141,19 @@ static int cortexm_hostio_request(target *t) ret = tc_isatty(t, params[0] - 1); break; case SYS_SEEK: /* lseek */ - ret = tc_lseek(t, params[0] - 1, params[1], TARGET_SEEK_SET); + if (tc_lseek(t, params[0] - 1, params[1], TARGET_SEEK_SET) == (long)params[1]) ret = 0; + else ret = -1; break; case SYS_RENAME:/* rename */ - ret = tc_rename(t, params[0] - 1, params[1] + 1, + ret = tc_rename(t, params[0], params[1] + 1, params[2], params[3] + 1); break; case SYS_REMOVE:/* unlink */ - ret = tc_unlink(t, params[0] - 1, params[1] + 1); + ret = tc_unlink(t, params[0], params[1] + 1); break; case SYS_SYSTEM:/* system */ - ret = tc_system(t, params[0] - 1, params[1] + 1); + /* before use first enable system calls with the following gdb command: 'set remote system-call-allowed 1' */ + ret = tc_system(t, params[0], params[1] + 1); break; case SYS_FLEN: @@ -1180,27 +1182,39 @@ static int cortexm_hostio_request(target *t) break; } - case SYS_TIME: { /* gettimeofday */ + case SYS_CLOCK: /* clock */ + case SYS_TIME: { /* time */ + /* use same code for SYS_CLOCK and SYS_TIME, more compact */ ret = -1; - uint32_t fio_timeval[3]; /* same size as fio_timeval in gdb/include/gdb/fileio.h */ - //DEBUG("SYS_TIME fio_timeval addr %p\n", fio_timeval); + struct __attribute__((packed, aligned(4))) { + uint32_t ftv_sec; + uint64_t ftv_usec; + } fio_timeval; + //DEBUG("SYS_TIME fio_timeval addr %p\n", &fio_timeval); void (*saved_mem_read)(target *t, void *dest, target_addr src, size_t len); void (*saved_mem_write)(target *t, target_addr dest, const void *src, size_t len); saved_mem_read = t->mem_read; saved_mem_write = t->mem_write; t->mem_read = probe_mem_read; t->mem_write = probe_mem_write; - int rc = tc_gettimeofday(t, (target_addr) fio_timeval, (target_addr) NULL); /* write gettimeofday() result in fio_timeval[] */ + int rc = tc_gettimeofday(t, (target_addr) &fio_timeval, (target_addr) NULL); /* write gettimeofday() result in fio_timeval[] */ t->mem_read = saved_mem_read; t->mem_write = saved_mem_write; if (rc) break; /* tc_gettimeofday() failed */ - uint32_t ftv_sec = fio_timeval[0]; /* time in seconds, first field in fio_timeval */ - ret = __builtin_bswap32(ftv_sec); /* convert from bigendian to target order */ + uint32_t sec = __builtin_bswap32(fio_timeval.ftv_sec); /* convert from bigendian to target order */ + uint64_t usec = __builtin_bswap64(fio_timeval.ftv_usec); + if (syscall == SYS_TIME) { /* SYS_TIME: time in seconds */ + ret = sec; + } else { /* SYS_CLOCK: time in hundredths of seconds */ + uint64_t csec64 = (sec * 1000000ull + usec)/10000ull; + uint32_t csec = csec64 & 0x7fffffff; + ret = csec; + } break; } case SYS_READC: { /* readc */ - uint8_t ch; + uint8_t ch='?'; //DEBUG("SYS_READC ch addr %p\n", &ch); void (*saved_mem_read)(target *t, void *dest, target_addr src, size_t len); void (*saved_mem_write)(target *t, target_addr dest, const void *src, size_t len); @@ -1208,7 +1222,7 @@ static int cortexm_hostio_request(target *t) saved_mem_write = t->mem_write; t->mem_read = probe_mem_read; t->mem_write = probe_mem_write; - int rc = tc_read(t, params[0] - 1, (target_addr) &ch, 1); /* read a character in ch */ + int rc = tc_read(t, STDIN_FILENO, (target_addr) &ch, 1); /* read a character in ch */ t->mem_read = saved_mem_read; t->mem_write = saved_mem_write; if (rc == 1) ret = ch; @@ -1223,7 +1237,11 @@ static int cortexm_hostio_request(target *t) case SYS_EXIT: /* _exit() */ tc_printf(t, "_exit(0x%x)\n", params[0]); target_halt_resume(t, 1); - ret = 0; + break; + + case SYS_EXIT_EXTENDED: /* _exit() */ + tc_printf(t, "_exit(0x%x%08x)\n", params[1], params[0]); /* exit() with 64bit exit value */ + target_halt_resume(t, 1); break; case SYS_GET_CMDLINE: { /* get_cmdline */ @@ -1240,13 +1258,59 @@ static int cortexm_hostio_request(target *t) break; } - // not implemented yet: + case SYS_ISERROR: { /* iserror */ + int errno = params[0]; + ret = (errno == TARGET_EPERM) || + (errno == TARGET_ENOENT) || + (errno == TARGET_EINTR) || + (errno == TARGET_EIO) || + (errno == TARGET_EBADF) || + (errno == TARGET_EACCES) || + (errno == TARGET_EFAULT) || + (errno == TARGET_EBUSY) || + (errno == TARGET_EEXIST) || + (errno == TARGET_ENODEV) || + (errno == TARGET_ENOTDIR) || + (errno == TARGET_EISDIR) || + (errno == TARGET_EINVAL) || + (errno == TARGET_ENFILE) || + (errno == TARGET_EMFILE) || + (errno == TARGET_EFBIG) || + (errno == TARGET_ENOSPC) || + (errno == TARGET_ESPIPE) || + (errno == TARGET_EROFS) || + (errno == TARGET_ENOSYS) || + (errno == TARGET_ENAMETOOLONG) || + (errno == TARGET_EUNKNOWN); + break; + } + case SYS_HEAPINFO: /* heapinfo */ - case SYS_CLOCK: /* clock */ + target_mem_write(t, arm_regs[1], &t->heapinfo, sizeof(t->heapinfo)); /* See newlib/libc/sys/arm/crt0.S */ + break; + + case SYS_TMPNAM: { /* tmpnam */ + /* Given a target identifier between 0 and 255, returns a temporary name. + * FIXME: add directory prefix */ + target_addr buf_ptr = params[0]; + int target_id = params[1]; + int buf_size = params[2]; + char fnam[]="tempXX.tmp"; + ret = -1; + if (buf_ptr == 0) break; + if (buf_size <= 0) break; + if ((target_id < 0) || (target_id > 255)) break; /* target id out of range */ + fnam[5]='A'+(target_id&0xF); /* create filename */ + fnam[4]='A'+(target_id>>4&0xF); + if (strlen(fnam)+1>(uint32_t)buf_size) break; /* target buffer too small */ + if(target_mem_write(t, buf_ptr, fnam, strlen(fnam)+1)) break; /* copy filename to target */ + ret = 0; + break; + } + + // not implemented yet: case SYS_ELAPSED: /* elapsed */ - case SYS_ISERROR: /* iserror */ case SYS_TICKFREQ: /* tickfreq */ - case SYS_TMPNAM: /* tmpnam */ ret = -1; break; diff --git a/src/target/target.c b/src/target/target.c index 5c0ca57..7171da8 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -410,6 +410,16 @@ void target_set_cmdline(target *t, char *cmdline) { DEBUG("cmdline: >%s<\n", t->cmdline); } +/* Set heapinfo for semihosting */ +void target_set_heapinfo(target *t, target_addr heap_base, target_addr heap_limit, + target_addr stack_base, target_addr stack_limit) { + if (t == NULL) return; + t->heapinfo[0] = heap_base; + t->heapinfo[1] = heap_limit; + t->heapinfo[2] = stack_base; + t->heapinfo[3] = stack_limit; +} + /* Break-/watchpoint functions */ int target_breakwatch_set(target *t, enum target_breakwatch type, target_addr addr, size_t len) diff --git a/src/target/target_internal.h b/src/target/target_internal.h index 7be19ed..7aa2c8a 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -121,6 +121,7 @@ struct target_s { const char *driver; const char *core; char cmdline[MAX_CMDLINE]; + target_addr heapinfo[4]; struct target_command_s *commands; struct target_s *next;