semihosting: improve handling of console I/O

This implements special handling for SYS_OPEN to catch requests for
":tt" which is reserved by ARM for console input/output. They're
mapped to the appropriate GDB file descriptors automatically.

An additional file handle offset is introduced because ARM doesn't
consider zero handle to be valid.

Signed-off-by: Paul Fertser <fercerpav@gmail.com>
This commit is contained in:
Paul Fertser 2013-04-15 21:42:46 +04:00 committed by Gareth McMullin
parent 5020d1f05d
commit df32aad757
2 changed files with 42 additions and 16 deletions

18
README
View File

@ -47,15 +47,19 @@ RAM.
Semihosting support Semihosting support
=================== ===================
Basic armv6m/armv7m semihosting is supported, i.e. you can build your Standard ARMv6-M/ARMv7-M semihosting is supported, i.e. you can build
application in a special way to use host's stdin and stdout right your application in a special way to have calls to certain functions
inside gdb simply by calling printf(), scanf() and other input-output (open(), close(), read(), write(), lseek(), rename(), unlink(),
functions. To make use of it, add --specs=rdimon.specs and -lrdimon to stat(), isatty(), system()) executed on the debugging host itself. To
make use of these facilities, add --specs=rdimon.specs and -lrdimon to
the linker flags for your firmware. the linker flags for your firmware.
All writes are treated as writes to the stdout, all reads are done If you're going to use stdin, stdout or stderr (e.g. via
from stdin; SYS_ISTTY always returns true, SYS_ERRNO -- EINTR; printf()/scanf()) and you're not using newlib's crt0 (by specifying
SYS_OPEN and SYS_FLEN return dummy non-zero values. -nostartfiles), you need to add this to your initialisation:
void initialise_monitor_handles(void);
initialise_monitor_handles();
Project layout Project layout
============== ==============

View File

@ -28,6 +28,7 @@
* Issues: * Issues:
* There are way too many magic numbers used here. * There are way too many magic numbers used here.
*/ */
#include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -949,41 +950,60 @@ static int cortexm_hostio_request(target *t)
FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a*/ FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a*/
FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a+*/ FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a+*/
}; };
uint32_t pflag = flags[params[1] >> 1];
char filename[4];
target_mem_read_bytes(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;
else
arm_regs[0] = STDERR_FILENO;
arm_regs[0]++;
target_regs_write(t, arm_regs);
return 1;
}
gdb_putpacket_f("Fopen,%08X/%X,%08X,%08X", gdb_putpacket_f("Fopen,%08X/%X,%08X,%08X",
params[0], params[2] + 1, params[0], params[2] + 1,
flags[params[1] >> 1], 0644); pflag, 0644);
break; break;
} }
case SYS_CLOSE: /* close */ case SYS_CLOSE: /* close */
gdb_putpacket_f("Fclose,%08X", params[0]); gdb_putpacket_f("Fclose,%08X", params[0] - 1);
break; break;
case SYS_READ: /* read */ case SYS_READ: /* read */
priv->byte_count = params[2]; priv->byte_count = params[2];
gdb_putpacket_f("Fread,%08X,%08X,%08X", gdb_putpacket_f("Fread,%08X,%08X,%08X",
params[0], params[1], params[2]); params[0] - 1, params[1], params[2]);
break; break;
case SYS_WRITE: /* write */ case SYS_WRITE: /* write */
priv->byte_count = params[2]; priv->byte_count = params[2];
gdb_putpacket_f("Fwrite,%08X,%08X,%08X", gdb_putpacket_f("Fwrite,%08X,%08X,%08X",
params[0], params[1], params[2]); params[0] - 1, params[1], params[2]);
break; break;
case SYS_ISTTY: /* isatty */ case SYS_ISTTY: /* isatty */
gdb_putpacket_f("Fisatty,%08X", params[0]); gdb_putpacket_f("Fisatty,%08X", params[0] - 1);
break; break;
case SYS_SEEK: /* lseek */ case SYS_SEEK: /* lseek */
gdb_putpacket_f("Flseek,%08X,%08X,%08X", gdb_putpacket_f("Flseek,%08X,%08X,%08X",
params[0], params[1], FILEIO_SEEK_SET); params[0] - 1, params[1], FILEIO_SEEK_SET);
break; break;
case SYS_RENAME:/* rename */ case SYS_RENAME:/* rename */
gdb_putpacket_f("Frename,%08X/%X,%08X/%X", gdb_putpacket_f("Frename,%08X/%X,%08X/%X",
params[0], params[1] + 1, params[0] - 1, params[1] + 1,
params[2], params[3] + 1); params[2], params[3] + 1);
break; break;
case SYS_REMOVE:/* unlink */ case SYS_REMOVE:/* unlink */
gdb_putpacket_f("Funlink,%08X/%X", params[0], params[1] + 1); gdb_putpacket_f("Funlink,%08X/%X", params[0] - 1,
params[1] + 1);
break; break;
case SYS_SYSTEM:/* system */ case SYS_SYSTEM:/* system */
gdb_putpacket_f("Fsystem,%08X/%X", params[0], params[1] + 1); gdb_putpacket_f("Fsystem,%08X/%X", params[0] - 1,
params[1] + 1);
break; break;
case SYS_FLEN: /* Not supported, fake success */ case SYS_FLEN: /* Not supported, fake success */
@ -1015,6 +1035,8 @@ static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode)
if (((priv->syscall == SYS_READ) || (priv->syscall == SYS_WRITE)) && if (((priv->syscall == SYS_READ) || (priv->syscall == SYS_WRITE)) &&
(retcode > 0)) (retcode > 0))
retcode = priv->byte_count - retcode; retcode = priv->byte_count - retcode;
if ((priv->syscall == SYS_OPEN) && (retcode != -1))
retcode++;
arm_regs[0] = retcode; arm_regs[0] = retcode;
target_regs_write(t, arm_regs); target_regs_write(t, arm_regs);
priv->errno = errcode; priv->errno = errcode;