From 8851504a41e1cd80e91f4fa533cc4fc146bcbad0 Mon Sep 17 00:00:00 2001 From: Koen De Vleeschauwer Date: Wed, 15 Apr 2020 19:23:44 +0200 Subject: [PATCH] new semihosting commands --- src/gdb_main.c | 32 +++++++- src/include/target.h | 1 + src/target/cortexm.c | 147 ++++++++++++++++++++++++++++++++--- src/target/target.c | 9 +++ src/target/target_internal.h | 3 + 5 files changed, 181 insertions(+), 11 deletions(-) diff --git a/src/gdb_main.c b/src/gdb_main.c index af1edf9..c0575a6 100644 --- a/src/gdb_main.c +++ b/src/gdb_main.c @@ -25,6 +25,7 @@ */ #include "general.h" +#include "ctype.h" #include "hex_utils.h" #include "gdb_if.h" #include "gdb_packet.h" @@ -429,9 +430,37 @@ handle_v_packet(char *packet, int plen) else gdb_putpacketz("E01"); - } else if (!strcmp(packet, "vRun;")) { + } else if (!strncmp(packet, "vRun", 4)) { + /* Parse command line for get_cmdline semihosting call */ + char cmdline[83]; + char *pbuf = cmdline; + char *tok = packet + 4; + if (*tok == ';') tok++; + *cmdline='\0'; + while(*tok != '\0') { + if(strlen(cmdline)+3 >= sizeof(cmdline)) break; + if (*tok == ';') { + *pbuf++=' '; + *pbuf='\0'; + tok++; + continue; + } + if (isxdigit(*tok) && isxdigit(*(tok+1))) { + unhexify(pbuf, tok, 2); + if ((*pbuf == ' ') || (*pbuf == '\\')) { + *(pbuf+1)=*pbuf; + *pbuf++='\\'; + } + pbuf++; + tok+=2; + *pbuf='\0'; + continue; + } + break; + } /* Run target program. For us (embedded) this means reset. */ if(cur_target) { + target_set_cmdline(cur_target, cmdline); target_reset(cur_target); gdb_putpacketz("T05"); } else if(last_target) { @@ -440,6 +469,7 @@ handle_v_packet(char *packet, int plen) /* If we were able to attach to the target again */ if (cur_target) { + target_set_cmdline(cur_target, cmdline); target_reset(cur_target); gdb_putpacketz("T05"); } else gdb_putpacketz("E01"); diff --git a/src/include/target.h b/src/include/target.h index d052ab1..3510250 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -80,6 +80,7 @@ void target_reset(target *t); 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); /* Break-/watchpoint functions */ enum target_breakwatch { diff --git a/src/target/cortexm.c b/src/target/cortexm.c index b81b4d1..70e38d0 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -3,10 +3,10 @@ * * Copyright (C) 2012 Black Sphere Technologies Ltd. * Written by Gareth McMullin + * and Koen De Vleeschauwer. * * This program is free software: you can redistribute it and/or modify - * it under tSchreibe Objekte: 100% (21/21), 3.20 KiB | 3.20 MiB/s, Fertig. -he terms of the GNU General Public License as published by + * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * @@ -1009,11 +1009,14 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[]) #endif /* Semihosting support */ -/* ARM Semihosting syscall numbers, from ARM doc DUI0471C, Chapter 8 */ -#define SYS_CLOSE 0x02 +/* ARM Semihosting syscall numbers, from "Semihosting for AArch32 and AArch64 Version 3.0" */ + #define SYS_CLOCK 0x10 +#define SYS_CLOSE 0x02 #define SYS_ELAPSED 0x30 #define SYS_ERRNO 0x13 +#define SYS_EXIT 0x18 +#define SYS_EXIT_EXTENDED 0x20 #define SYS_FLEN 0x0C #define SYS_GET_CMDLINE 0x15 #define SYS_HEAPINFO 0x16 @@ -1033,6 +1036,28 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[]) #define SYS_WRITEC 0x03 #define SYS_WRITE0 0x04 +#if !defined(PC_HOSTED) +/* probe memory access functions */ +static void probe_mem_read(target *t __attribute__((unused)), void *probe_dest, target_addr target_src, size_t len) +{ + uint8_t *dst = (uint8_t *)probe_dest; + uint8_t *src = (uint8_t *)target_src; + + DEBUG("probe_mem_read\n"); + while (len--) *dst++=*src++; + return; +} + +static void probe_mem_write(target *t __attribute__((unused)), target_addr target_dest, const void *probe_src, size_t len) +{ + uint8_t *dst = (uint8_t *)target_dest; + uint8_t *src = (uint8_t *)probe_src; + + DEBUG("probe_mem_write\n"); + while (len--) *dst++=*src++; + return; +} +#endif static int cortexm_hostio_request(target *t) { uint32_t arm_regs[t->regs_size]; @@ -1073,6 +1098,7 @@ static int cortexm_hostio_request(target *t) ret++; break; } + /* FIXME handle requests for special filename ':semihosting-features' */ ret = tc_open(t, params[0], params[2] + 1, pflag, 0644); if (ret != -1) @@ -1093,8 +1119,24 @@ static int cortexm_hostio_request(target *t) ret = params[2] - ret; break; case SYS_WRITEC: /* writec */ - ret = tc_write(t, 2, arm_regs[1], 1); + ret = tc_write(t, STDERR_FILENO, arm_regs[1], 1); break; + case SYS_WRITE0:{ /* write0 */ + ret = -1; + target_addr str_begin = arm_regs[1]; + target_addr str_end = str_begin; + while (target_mem_read8(t, str_end) != 0) { + if (target_check_error(t)) break; + str_end++; + } + int len = str_end - str_begin; + if (len != 0) { + int rc = tc_write(t, STDERR_FILENO, str_begin, len); + if (rc != len) break; + } + ret = 0; + break; + } case SYS_ISTTY: /* isatty */ ret = tc_isatty(t, params[0] - 1); break; @@ -1112,17 +1154,102 @@ static int cortexm_hostio_request(target *t) ret = tc_system(t, params[0] - 1, params[1] + 1); break; - case SYS_FLEN: /* Not supported, fake success */ - t->tc->errno_ = 0; - break; + case SYS_FLEN: +#if defined(PC_HOSTED) + t->tc->errno_ = 0; + break; +#else + { /* file length */ + ret = -1; + uint32_t fio_stat[16]; /* same size as fio_stat in gdb/include/gdb/fileio.h */ + //DEBUG("SYS_FLEN fio_stat addr %p\n", fio_stat); + 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_fstat(t, params[0] - 1, (target_addr)fio_stat); /* write fstat() result in fio_stat[] */ + t->mem_read = saved_mem_read; + t->mem_write = saved_mem_write; + if (rc) break; /* tc_fstat() failed */ + uint32_t fst_size_msw = fio_stat[7]; /* most significant 32 bits of fst_size in fio_stat */ + uint32_t fst_size_lsw = fio_stat[8]; /* least significant 32 bits of fst_size in fio_stat */ + if (fst_size_msw != 0) break; /* file size too large for uint32_t return type */ + ret = __builtin_bswap32(fst_size_lsw); /* convert from bigendian to target order */ + break; + } + case SYS_TIME: { /* gettimeofday */ + 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); + 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[] */ + 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 */ + break; + } + + case SYS_READC: { /* readc */ + 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); + 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_read(t, params[0] - 1, (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; + else ret = -1; + break; + } +#endif case SYS_ERRNO: /* Return last errno from GDB */ ret = t->tc->errno_; break; - case SYS_TIME: /* gettimeofday */ - /* FIXME How do we use gdb's gettimeofday? */ + case SYS_EXIT: /* _exit() */ + tc_printf(t, "_exit(0x%x)\n", params[0]); + target_halt_resume(t, 1); + ret = 0; break; + + case SYS_GET_CMDLINE: { /* get_cmdline */ + uint32_t retval[2]; + ret = -1; + target_addr buf_ptr = params[0]; + target_addr buf_len = params[1]; + if (strlen(t->cmdline)+1 > buf_len) break; + if(target_mem_write(t, buf_ptr, t->cmdline, strlen(t->cmdline)+1)) break; + retval[0] = buf_ptr; + retval[1] = strlen(t->cmdline)+1; + if(target_mem_write(t, arm_regs[1], retval, sizeof(retval))) break; + ret = 0; + break; + } + + // not implemented yet: + case SYS_HEAPINFO: /* heapinfo */ + case SYS_CLOCK: /* clock */ + case SYS_ELAPSED: /* elapsed */ + case SYS_ISERROR: /* iserror */ + case SYS_TICKFREQ: /* tickfreq */ + case SYS_TMPNAM: /* tmpnam */ + ret = -1; + break; + } arm_regs[0] = ret; diff --git a/src/target/target.c b/src/target/target.c index 56e54b0..5c0ca57 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -401,6 +401,15 @@ enum target_halt_reason target_halt_poll(target *t, target_addr *watch) void target_halt_resume(target *t, bool step) { t->halt_resume(t, step); } +/* Command line for semihosting get_cmdline */ +void target_set_cmdline(target *t, char *cmdline) { + uint32_t len_dst; + len_dst = sizeof(t->cmdline)-1; + strncpy(t->cmdline, cmdline, len_dst -1); + t->cmdline[strlen(t->cmdline)]='\0'; + DEBUG("cmdline: >%s<\n", t->cmdline); + } + /* 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 15a4729..7be19ed 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -72,6 +72,8 @@ struct breakwatch { uint32_t reserved[4]; /* for use by the implementing driver */ }; +#define MAX_CMDLINE 81 + struct target_s { bool attached; struct target_controller *tc; @@ -118,6 +120,7 @@ struct target_s { /* Other stuff */ const char *driver; const char *core; + char cmdline[MAX_CMDLINE]; struct target_command_s *commands; struct target_s *next;