semihosting
This commit is contained in:
parent
d63e870e82
commit
9f8c7be360
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue