Overhaul of semihosting. Remove dependence of target on gdb_packet.

This commit is contained in:
Gareth McMullin 2016-07-01 16:50:19 +12:00
parent b03cc59bea
commit b644724520
8 changed files with 384 additions and 127 deletions

View File

@ -31,6 +31,7 @@ SRC = \
exception.c \
gdb_if.c \
gdb_main.c \
gdb_hostio.c \
gdb_packet.c \
hex_utils.c \
jtag_scan.c \

View File

@ -30,14 +30,10 @@
#include "adiv5.h"
#include "target.h"
#include "target_internal.h"
#include "gdb_packet.h"
#include "cortexm.h"
#include <unistd.h>
/* On some systems this is a macro and causes problems */
#undef errno
static char cortexm_driver_str[] = "ARM Cortex-M";
static bool cortexm_vector_catch(target *t, int argc, char *argv[]);
@ -78,7 +74,6 @@ static int cortexm_check_hw_wp(target *t, uint32_t *addr);
#define CORTEXM_MAX_BREAKPOINTS 6 /* architecture says up to 127, no implementation has > 6 */
static int cortexm_hostio_request(target *t);
static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode);
struct cortexm_priv {
ADIv5_AP_t *ap;
@ -97,10 +92,6 @@ struct cortexm_priv {
unsigned hw_breakpoint_max;
/* Copy of DEMCR for vector-catch */
uint32_t demcr;
/* Semihosting state */
uint32_t syscall;
uint32_t errno;
uint32_t byte_count;
};
/* Register number tables */
@ -255,8 +246,6 @@ bool cortexm_probe(ADIv5_AP_t *ap)
t->halt_resume = cortexm_halt_resume;
t->regs_size = sizeof(regnum_cortex_m);
t->hostio_reply = cortexm_hostio_reply;
target_add_commands(t, cortexm_cmd_list, cortexm_driver_str);
/* Probe for FP extension */
@ -531,12 +520,11 @@ static int cortexm_halt_wait(target *t)
uint16_t bkpt_instr;
bkpt_instr = target_mem_read16(t, pc);
if (bkpt_instr == 0xBEAB) {
int n = cortexm_hostio_request(t);
if (n > 0) {
if (cortexm_hostio_request(t)) {
return SIGINT;
} else {
target_halt_resume(t, priv->stepping);
return 0;
} else if (n < 0) {
return -1;
}
}
}
@ -876,40 +864,30 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[])
#define SYS_WRITEC 0x03
#define SYS_WRITE0 0x04
#define FILEIO_O_RDONLY 0
#define FILEIO_O_WRONLY 1
#define FILEIO_O_RDWR 2
#define FILEIO_O_APPEND 0x008
#define FILEIO_O_CREAT 0x200
#define FILEIO_O_TRUNC 0x400
#define FILEIO_SEEK_SET 0
#define FILEIO_SEEK_CUR 1
#define FILEIO_SEEK_END 2
static int cortexm_hostio_request(target *t)
{
struct cortexm_priv *priv = t->priv;
uint32_t arm_regs[t->regs_size];
uint32_t params[4];
t->tc->interrupted = false;
target_regs_read(t, arm_regs);
target_mem_read(t, params, arm_regs[1], sizeof(params));
priv->syscall = arm_regs[0];
uint32_t syscall = arm_regs[0];
int32_t ret = 0;
DEBUG("syscall 0x%x (%x %x %x %x)\n", priv->syscall,
DEBUG("syscall 0x%x (%x %x %x %x)\n", syscall,
params[0], params[1], params[2], params[3]);
switch (priv->syscall) {
switch (syscall) {
case SYS_OPEN:{ /* open */
/* Translate stupid fopen modes to open flags.
* See DUI0471C, Table 8-3 */
const uint32_t flags[] = {
FILEIO_O_RDONLY, /* r, rb */
FILEIO_O_RDWR, /* r+, r+b */
FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_TRUNC,/*w*/
FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_TRUNC,/*w+*/
FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a*/
FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a+*/
TARGET_O_RDONLY, /* r, rb */
TARGET_O_RDWR, /* r+, r+b */
TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC,/*w*/
TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC,/*w+*/
TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND,/*a*/
TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND,/*a+*/
};
uint32_t pflag = flags[params[1] >> 1];
char filename[4];
@ -917,91 +895,70 @@ static int cortexm_hostio_request(target *t)
target_mem_read(t, filename, params[0], sizeof(filename));
/* handle requests for console i/o */
if (!strcmp(filename, ":tt")) {
if (pflag == FILEIO_O_RDONLY)
arm_regs[0] = STDIN_FILENO;
else if (pflag & FILEIO_O_TRUNC)
arm_regs[0] = STDOUT_FILENO;
if (pflag == TARGET_O_RDONLY)
ret = STDIN_FILENO;
else if (pflag & TARGET_O_TRUNC)
ret = STDOUT_FILENO;
else
arm_regs[0] = STDERR_FILENO;
arm_regs[0]++;
target_regs_write(t, arm_regs);
return 1;
ret = STDERR_FILENO;
ret++;
break;
}
gdb_putpacket_f("Fopen,%08X/%X,%08X,%08X",
params[0], params[2] + 1,
pflag, 0644);
ret = tc_open(t, params[0], params[2] + 1, pflag, 0644);
if (ret != -1)
ret++;
break;
}
case SYS_CLOSE: /* close */
gdb_putpacket_f("Fclose,%08X", params[0] - 1);
ret = tc_close(t, params[0] - 1);
break;
case SYS_READ: /* read */
priv->byte_count = params[2];
gdb_putpacket_f("Fread,%08X,%08X,%08X",
params[0] - 1, params[1], params[2]);
ret = tc_read(t, params[0] - 1, params[1], params[2]);
if (ret > 0)
ret = params[2] - ret;
break;
case SYS_WRITE: /* write */
priv->byte_count = params[2];
gdb_putpacket_f("Fwrite,%08X,%08X,%08X",
params[0] - 1, params[1], params[2]);
ret = tc_write(t, params[0] - 1, params[1], params[2]);
if (ret > 0)
ret = params[2] - ret;
break;
case SYS_WRITEC: /* writec */
gdb_putpacket_f("Fwrite,2,%08X,1", arm_regs[1]);
ret = tc_write(t, 2, arm_regs[1], 1);
break;
case SYS_ISTTY: /* isatty */
gdb_putpacket_f("Fisatty,%08X", params[0] - 1);
ret = tc_isatty(t, params[0] - 1);
break;
case SYS_SEEK: /* lseek */
gdb_putpacket_f("Flseek,%08X,%08X,%08X",
params[0] - 1, params[1], FILEIO_SEEK_SET);
ret = tc_lseek(t, params[0] - 1, params[1], TARGET_SEEK_SET);
break;
case SYS_RENAME:/* rename */
gdb_putpacket_f("Frename,%08X/%X,%08X/%X",
params[0] - 1, params[1] + 1,
ret = tc_rename(t, params[0] - 1, params[1] + 1,
params[2], params[3] + 1);
break;
case SYS_REMOVE:/* unlink */
gdb_putpacket_f("Funlink,%08X/%X", params[0] - 1,
params[1] + 1);
ret = tc_unlink(t, params[0] - 1, params[1] + 1);
break;
case SYS_SYSTEM:/* system */
gdb_putpacket_f("Fsystem,%08X/%X", params[0] - 1,
params[1] + 1);
ret = tc_system(t, params[0] - 1, params[1] + 1);
break;
case SYS_FLEN: /* Not supported, fake success */
priv->errno = 0;
return 1;
t->tc->errno_ = 0;
break;
case SYS_ERRNO: /* Return last errno from GDB */
arm_regs[0] = priv->errno;
target_regs_write(t, arm_regs);
return 1;
ret = t->tc->errno_;
break;
case SYS_TIME: /* gettimeofday */
/* FIXME How do we use gdb's gettimeofday? */
default:
return 0;
break;
}
return -1;
}
static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode)
{
struct cortexm_priv *priv = t->priv;
uint32_t arm_regs[t->regs_size];
DEBUG("syscall return ret=%d errno=%d\n", retcode, errcode);
target_regs_read(t, arm_regs);
if (((priv->syscall == SYS_READ) || (priv->syscall == SYS_WRITE)) &&
(retcode > 0))
retcode = priv->byte_count - retcode;
if ((priv->syscall == SYS_OPEN) && (retcode != -1))
retcode++;
arm_regs[0] = retcode;
arm_regs[0] = ret;
target_regs_write(t, arm_regs);
priv->errno = errcode;
return t->tc->interrupted;
}

132
src/gdb_hostio.c Normal file
View File

@ -0,0 +1,132 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2016 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "general.h"
#include "target.h"
#include "gdb_main.h"
#include "gdb_hostio.h"
#include "gdb_packet.h"
int gdb_main_loop(struct target_controller *, bool in_syscall);
int hostio_reply(struct target_controller *tc, char *pbuf, int len)
{
(void)len;
int retcode, items;
char c, *p;
if (pbuf[1] == '-')
p = &pbuf[2];
else
p = &pbuf[1];
items = sscanf(p, "%x,%x,%c", &retcode, &tc->errno_, &c);
if (pbuf[1] == '-')
retcode = -retcode;
/* if break is requested */
tc->interrupted = items == 3 && c == 'C';
return retcode;
}
/* Interface to host system calls */
int hostio_open(struct target_controller *tc,
target_addr path, unsigned path_len,
enum target_open_flags flags, mode_t mode)
{
gdb_putpacket_f("Fopen,%08X/%X,%08X,%08X", path, path_len, flags, mode);;;;
return gdb_main_loop(tc, true);
}
int hostio_close(struct target_controller *tc, int fd)
{
gdb_putpacket_f("Fclose,%08X", fd);
return gdb_main_loop(tc, true);
}
int hostio_read(struct target_controller *tc,
int fd, target_addr buf, unsigned int count)
{
gdb_putpacket_f("Fread,%08X,%08X,%08X", fd, buf, count);
return gdb_main_loop(tc, true);
}
int hostio_write(struct target_controller *tc,
int fd, target_addr buf, unsigned int count)
{
gdb_putpacket_f("Fwrite,%08X,%08X,%08X", fd, buf, count);
return gdb_main_loop(tc, true);
}
long hostio_lseek(struct target_controller *tc,
int fd, long offset, enum target_seek_flag flag)
{
gdb_putpacket_f("Flseek,%08X,%08X,%08X", fd, offset, flag);
return gdb_main_loop(tc, true);
}
int hostio_rename(struct target_controller *tc,
target_addr oldpath, unsigned old_len,
target_addr newpath, unsigned new_len)
{
gdb_putpacket_f("Frename,%08X/%X,%08X/%X",
oldpath, old_len, newpath, new_len);
return gdb_main_loop(tc, true);
}
int hostio_unlink(struct target_controller *tc,
target_addr path, unsigned path_len)
{
gdb_putpacket_f("Funlink,%08X/%X", path, path_len);
return gdb_main_loop(tc, true);
}
int hostio_stat(struct target_controller *tc,
target_addr path, unsigned path_len, target_addr buf)
{
gdb_putpacket_f("Fstat,%08X/%X,%08X", path, path_len, buf);
return gdb_main_loop(tc, true);
}
int hostio_fstat(struct target_controller *tc, int fd, target_addr buf)
{
gdb_putpacket_f("Ffstat,%X,%08X", fd, buf);
return gdb_main_loop(tc, true);
}
int hostio_gettimeofday(struct target_controller *tc,
target_addr tv, target_addr tz)
{
gdb_putpacket_f("Fgettimeofday,%08X,%08X", tv, tz);
return gdb_main_loop(tc, true);
}
int hostio_isatty(struct target_controller *tc, int fd)
{
gdb_putpacket_f("Fisatty,%08X", fd);
return gdb_main_loop(tc, true);
}
int hostio_system(struct target_controller *tc,
target_addr cmd, unsigned cmd_len)
{
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
return gdb_main_loop(tc, true);
}

53
src/gdb_hostio.h Normal file
View File

@ -0,0 +1,53 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2016 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDB_SYSCALLS_H
#define __GDB_SYSCALLS_H
#include "target.h"
int hostio_reply(struct target_controller *tc, char *packet, int len);
/* Interface to host system calls */
int hostio_open(struct target_controller *,
target_addr path, unsigned path_len,
enum target_open_flags flags, mode_t mode);
int hostio_close(struct target_controller *, int fd);
int hostio_read(struct target_controller *,
int fd, target_addr buf, unsigned int count);
int hostio_write(struct target_controller *,
int fd, target_addr buf, unsigned int count);
long hostio_lseek(struct target_controller *,
int fd, long offset, enum target_seek_flag flag);
int hostio_rename(struct target_controller *,
target_addr oldpath, unsigned old_len,
target_addr newpath, unsigned new_len);
int hostio_unlink(struct target_controller *,
target_addr path, unsigned path_len);
int hostio_stat(struct target_controller *,
target_addr path, unsigned path_len, target_addr buf);
int hostio_fstat(struct target_controller *, int fd, target_addr buf);
int hostio_gettimeofday(struct target_controller *,
target_addr tv, target_addr tz);
int hostio_isatty(struct target_controller *, int fd);
int hostio_system(struct target_controller *,
target_addr cmd, unsigned cmd_len);
#endif

View File

@ -29,6 +29,7 @@
#include "gdb_if.h"
#include "gdb_packet.h"
#include "gdb_main.h"
#include "gdb_hostio.h"
#include "target.h"
#include "command.h"
#include "crc32.h"
@ -67,14 +68,25 @@ static void gdb_target_printf(struct target_controller *tc,
static struct target_controller gdb_controller = {
.destroy_callback = gdb_target_destroy_callback,
.printf = gdb_target_printf,
.open = hostio_open,
.close = hostio_close,
.read = hostio_read,
.write = hostio_write,
.lseek = hostio_lseek,
.rename = hostio_rename,
.unlink = hostio_unlink,
.stat = hostio_stat,
.fstat = hostio_fstat,
.gettimeofday = hostio_gettimeofday,
.isatty = hostio_isatty,
.system = hostio_system,
};
void
gdb_main(void)
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
{
int size;
bool single_step = false;
char last_activity = 0;
DEBUG("Entring GDB protocol main loop\n");
/* GDB protocol main loop */
@ -82,7 +94,6 @@ gdb_main(void)
SET_IDLE_STATE(1);
size = gdb_getpacket(pbuf, BUF_SIZE);
SET_IDLE_STATE(0);
continue_activity:
switch(pbuf[0]) {
/* Implementation of these is mandatory! */
case 'g': { /* 'g': Read general registers */
@ -154,13 +165,11 @@ gdb_main(void)
break;
}
last_activity = pbuf[0];
/* Wait for target halt */
while(!(sig = target_halt_wait(cur_target))) {
unsigned char c = gdb_if_getchar_to(0);
if((c == '\x03') || (c == '\x04')) {
target_halt_request(cur_target);
last_activity = 's';
}
}
SET_RUN_STATE(0);
@ -184,28 +193,14 @@ gdb_main(void)
}
break;
}
case 'F': { /* Semihosting call finished */
int retcode, errcode, items;
char c, *p;
if (pbuf[1] == '-')
p = &pbuf[2];
else
p = &pbuf[1];
items = sscanf(p, "%x,%x,%c", &retcode, &errcode, &c);
if (pbuf[1] == '-')
retcode = -retcode;
target_hostio_reply(cur_target, retcode, errcode);
/* if break is requested */
if (items == 3 && c == 'C') {
gdb_putpacketz("T02");
break;
case 'F': /* Semihosting call finished */
if (in_syscall) {
return hostio_reply(tc, pbuf, size);
} else {
DEBUG("*** F packet when not in syscall! '%s'\n", pbuf);
gdb_putpacketz("");
}
pbuf[0] = last_activity;
goto continue_activity;
}
break;
/* Optional GDB packet support */
case '!': /* Enable Extended GDB Protocol. */
@ -480,3 +475,8 @@ handle_z_packet(char *packet, int plen)
gdb_putpacketz("E01");
}
void gdb_main(void)
{
gdb_main_loop(&gdb_controller, false);
}

View File

@ -25,7 +25,10 @@
#ifndef __TARGET_H
#define __TARGET_H
#include <stdarg.h>
typedef struct target_s target;
typedef uint32_t target_addr;
int adiv5_swdp_scan(void);
int jtag_scan(const uint8_t *lrlens);
@ -33,9 +36,51 @@ int jtag_scan(const uint8_t *lrlens);
bool target_foreach(void (*cb)(int i, target *t, void *context), void *context);
void target_list_free(void);
enum target_open_flags {
TARGET_O_RDONLY = 0,
TARGET_O_WRONLY = 1,
TARGET_O_RDWR = 2,
TARGET_O_APPEND = 0x008,
TARGET_O_CREAT = 0x200,
TARGET_O_TRUNC = 0x400,
};
enum target_seek_flag {
TARGET_SEEK_SET = 0,
TARGET_SEEK_CUR = 1,
TARGET_SEEK_END = 2,
};
struct target_controller {
void (*destroy_callback)(struct target_controller *, target *t);
void (*printf)(struct target_controller *, const char *fmt, va_list);
/* Interface to host system calls */
int (*open)(struct target_controller *,
target_addr path, unsigned path_len,
enum target_open_flags flags, mode_t mode);
int (*close)(struct target_controller *, int fd);
int (*read)(struct target_controller *,
int fd, target_addr buf, unsigned int count);
int (*write)(struct target_controller *,
int fd, target_addr buf, unsigned int count);
long (*lseek)(struct target_controller *,
int fd, long offset, enum target_seek_flag flag);
int (*rename)(struct target_controller *,
target_addr oldpath, unsigned old_len,
target_addr newpath, unsigned new_len);
int (*unlink)(struct target_controller *,
target_addr path, unsigned path_len);
int (*stat)(struct target_controller *,
target_addr path, unsigned path_len, target_addr buf);
int (*fstat)(struct target_controller *, int fd, target_addr buf);
int (*gettimeofday)(struct target_controller *,
target_addr tv, target_addr tz);
int (*isatty)(struct target_controller *, int fd);
int (*system)(struct target_controller *,
target_addr cmd, unsigned cmd_len);
int errno_;
bool interrupted;
};
/* Halt/resume functions */
@ -72,9 +117,6 @@ int target_flash_erase(target *t, uint32_t addr, size_t len);
int target_flash_write(target *t, uint32_t dest, const void *src, size_t len);
int target_flash_done(target *t);
/* Host I/O */
void target_hostio_reply(target *t, int32_t retcode, uint32_t errcode);
/* Accessor functions */
int target_regs_size(target *t);
const char *target_tdesc(target *t);

View File

@ -344,12 +344,6 @@ int target_check_hw_wp(target *t, uint32_t *addr)
return t->check_hw_wp(t, addr);
}
/* Host I/O */
void target_hostio_reply(target *t, int32_t retcode, uint32_t errcode)
{
t->hostio_reply(t, retcode, errcode);
}
/* Accessor functions */
int target_regs_size(target *t)
{
@ -429,3 +423,66 @@ void tc_printf(target *t, const char *fmt, ...)
va_end(ap);
}
/* Interface to host system calls */
int tc_open(target *t, target_addr path, unsigned plen,
enum target_open_flags flags, mode_t mode)
{
return t->tc->open(t->tc, path, plen, flags, mode);
}
int tc_close(target *t, int fd)
{
return t->tc->close(t->tc, fd);
}
int tc_read(target *t, int fd, target_addr buf, unsigned int count)
{
return t->tc->read(t->tc, fd, buf, count);
}
int tc_write(target *t, int fd, target_addr buf, unsigned int count)
{
return t->tc->write(t->tc, fd, buf, count);
}
long tc_lseek(target *t, int fd, long offset, enum target_seek_flag flag)
{
return t->tc->lseek(t->tc, fd, offset, flag);
}
int tc_rename(target *t, target_addr oldpath, unsigned oldlen,
target_addr newpath, unsigned newlen)
{
return t->tc->rename(t->tc, oldpath, oldlen, newpath, newlen);
}
int tc_unlink(target *t, target_addr path, unsigned plen)
{
return t->tc->unlink(t->tc, path, plen);
}
int tc_stat(target *t, target_addr path, unsigned plen, target_addr buf)
{
return t->tc->stat(t->tc, path, plen, buf);
}
int tc_fstat(target *t, int fd, target_addr buf)
{
return t->tc->fstat(t->tc, fd, buf);
}
int tc_gettimeofday(target *t, target_addr tv, target_addr tz)
{
return t->tc->gettimeofday(t->tc, tv, tz);
}
int tc_isatty(target *t, int fd)
{
return t->tc->isatty(t->tc, fd);
}
int tc_system(target *t, target_addr cmd, unsigned cmdlen)
{
return t->tc->system(t->tc, cmd, cmdlen);
}

View File

@ -113,9 +113,7 @@ struct target_s {
struct target_ram *ram;
struct target_flash *flash;
/* Host I/O support */
void (*hostio_reply)(target *t, int32_t retcode, uint32_t errcode);
/* Other stuff */
const char *driver;
struct target_command_s *commands;
@ -143,6 +141,23 @@ void target_mem_write8(target *t, uint32_t addr, uint8_t value);
/* Access to host controller interface */
void tc_printf(target *t, const char *fmt, ...);
/* Interface to host system calls */
int tc_open(target *, target_addr path, unsigned plen,
enum target_open_flags flags, mode_t mode);
int tc_close(target *t, int fd);
int tc_read(target *t, int fd, target_addr buf, unsigned int count);
int tc_write(target *t, int fd, target_addr buf, unsigned int count);
long tc_lseek(target *t, int fd, long offset,
enum target_seek_flag flag);
int tc_rename(target *t, target_addr oldpath, unsigned oldlen,
target_addr newpath, unsigned newlen);
int tc_unlink(target *t, target_addr path, unsigned plen);
int tc_stat(target *t, target_addr path, unsigned plen, target_addr buf);
int tc_fstat(target *t, int fd, target_addr buf);
int tc_gettimeofday(target *t, target_addr tv, target_addr tz);
int tc_isatty(target *t, int fd);
int tc_system(target *t, target_addr cmd, unsigned cmdlen);
/* Probe for various targets.
* Actual functions implemented in their respective drivers.
*/