This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: add file I/O support when debugging an embedded target via jtag


>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

    >> Date: Tue, 12 Aug 2008 17:33:20 +0100
    >> From: Bart Veer <bartv@ecoscentric.com>
    >> 
    >> +When set, if the target halts at a well-defined location GDB\n\
    Eli>                                                            ^
    Eli> Need a comma here.

    <snip>
    
    >> +depends on the embedded OS or run-time being used.  If the
    >> +functionality has not yet been ported then a reference implementation
    Eli>                                         ^
    Eli> Missing comma.

    Eli> Otherwise, the doco part is okay with me, assuming that the
    Eli> code is approved.

Following on from
http://sourceware.org/ml/gdb-patches/2008-08/msg00315.html, I have not
heard anything about the code in the last two weeks. Do you know if
anybody is looking at it? Also, if there is a likelihood that the
patch will be accepted then I should probably get started on the
assignment paperwork.

In the meantime, please find below an updated version of the patch
which incorporates your documentation comments and which applies to
current CVS.

Thanks,
	Bart Veer
	
----------------------------------------------------------------------------
Top-level ChangeLog entry:

2008-08-31  Bart Veer  <bartv@ecoscentric.co.uk>

	* target.h: add new stratum process_override
	* remote-fileio.h, remote.c: add putpkt argument to
	remote_fileio_request()
	* remote-fileio.c: the putpkt function is supplied by the
	caller. Use target_read_memory() and target_write_memory()
	instead of assuming the remote protocol.
	* hwdebug-fileio.c: new module supporting file I/O operations
	when the remote protocol server does not provide the necessary
	support.
	* Makefile.in: add hwdebug-fileio.c

doc ChangeLog entry:

2008-08-31  Bart Veer  <bartv@ecoscentric.co.uk>

	* gdb.texinfo: document h/w debug file I/O support.
	* hwdebug-example.c: example target-side code for the h/w
	debug file I/O support.

Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.130
diff -u -p -r1.130 target.h
--- target.h	19 Aug 2008 13:22:14 -0000	1.130
+++ target.h	31 Aug 2008 11:30:39 -0000
@@ -62,6 +62,7 @@ enum strata
     file_stratum,		/* Executable files, etc */
     core_stratum,		/* Core dump files */
     process_stratum,		/* Executing processes */
+    process_override_stratum,   /* Tweak process settings */
     thread_stratum		/* Executing threads */
   };
 
Index: remote-fileio.c
===================================================================
RCS file: /cvs/src/src/gdb/remote-fileio.c,v
retrieving revision 1.28
diff -u -p -r1.28 remote-fileio.c
--- remote-fileio.c	5 Mar 2008 17:21:10 -0000	1.28
+++ remote-fileio.c	31 Aug 2008 11:30:23 -0000
@@ -29,6 +29,7 @@
 #include "exceptions.h"
 #include "remote-fileio.h"
 #include "event-loop.h"
+#include "target.h"
 
 #include <fcntl.h>
 #include <sys/time.h>
@@ -48,6 +49,8 @@ static struct {
 
 static int remote_fio_system_call_allowed = 0;
 
+static int (*target_putpkt_fn) (char*);
+
 static struct async_signal_handler *sigint_fileio_token;
 
 static int
@@ -549,7 +552,7 @@ remote_fileio_reply (int retcode, int er
         strcat (buf, ",C");
     }
   remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
-  putpkt (buf);
+  (*target_putpkt_fn) (buf);
 }
 
 static void
@@ -577,29 +580,11 @@ remote_fileio_return_success (int retcod
   remote_fileio_reply (retcode, 0);
 }
 
-/* Wrapper function for remote_write_bytes() which has the disadvantage to
-   write only one packet, regardless of the requested number of bytes to
-   transfer.  This wrapper calls remote_write_bytes() as often as needed. */
-static int
-remote_fileio_write_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
-{
-  int ret = 0, written;
-
-  while (len > 0 && (written = remote_write_bytes (memaddr, myaddr, len)) > 0)
-    {
-      len -= written;
-      memaddr += written;
-      myaddr += written;
-      ret += written;
-    }
-  return ret;
-}
-
 static void
 remote_fileio_func_open (char *buf)
 {
   CORE_ADDR ptrval;
-  int length, retlength;
+  int length;
   long num;
   int flags, fd;
   mode_t mode;
@@ -627,10 +612,9 @@ remote_fileio_func_open (char *buf)
     }
   mode = remote_fileio_mode_to_host (num, 1);
 
-  /* Request pathname using 'm' packet */
+  /* Request pathname */
   pathname = alloca (length);
-  retlength = remote_read_bytes (ptrval, (gdb_byte *) pathname, length);
-  if (retlength != length)
+  if (target_read_memory (ptrval, (gdb_byte *) pathname, length) )
     {
       remote_fileio_ioerror ();
       return;
@@ -698,7 +682,7 @@ remote_fileio_func_read (char *buf)
   long target_fd, num;
   LONGEST lnum;
   CORE_ADDR ptrval;
-  int fd, ret, retlength;
+  int fd, ret;
   gdb_byte *buffer;
   size_t length;
   off_t old_offset, new_offset;
@@ -797,9 +781,11 @@ remote_fileio_func_read (char *buf)
 
   if (ret > 0)
     {
-      retlength = remote_fileio_write_bytes (ptrval, buffer, ret);
-      if (retlength != ret)
-	ret = -1; /* errno has been set to EIO in remote_fileio_write_bytes() */
+        if ( target_write_memory (ptrval, buffer, ret) )
+        {
+            errno = EIO;
+            ret = -1;
+        }
     }
 
   if (ret < 0)
@@ -816,7 +802,7 @@ remote_fileio_func_write (char *buf)
   long target_fd, num;
   LONGEST lnum;
   CORE_ADDR ptrval;
-  int fd, ret, retlength;
+  int fd, ret;
   gdb_byte *buffer;
   size_t length;
 
@@ -848,8 +834,7 @@ remote_fileio_func_write (char *buf)
   length = (size_t) num;
     
   buffer = (gdb_byte *) xmalloc (length);
-  retlength = remote_read_bytes (ptrval, buffer, length);
-  if (retlength != length)
+  if ( target_read_memory (ptrval, buffer, length))
     {
       xfree (buffer);
       remote_fileio_ioerror ();
@@ -942,7 +927,7 @@ static void
 remote_fileio_func_rename (char *buf)
 {
   CORE_ADDR old_ptr, new_ptr;
-  int old_len, new_len, retlength;
+  int old_len, new_len;
   char *oldpath, *newpath;
   int ret, of, nf;
   struct stat ost, nst;
@@ -961,19 +946,17 @@ remote_fileio_func_rename (char *buf)
       return;
     }
   
-  /* Request oldpath using 'm' packet */
+  /* Request oldpath */
   oldpath = alloca (old_len);
-  retlength = remote_read_bytes (old_ptr, (gdb_byte *) oldpath, old_len);
-  if (retlength != old_len)
+  if (target_read_memory (old_ptr, (gdb_byte*) oldpath, old_len))
     {
       remote_fileio_ioerror ();
       return;
     }
   
-  /* Request newpath using 'm' packet */
+  /* Request newpath */
   newpath = alloca (new_len);
-  retlength = remote_read_bytes (new_ptr, (gdb_byte *) newpath, new_len);
-  if (retlength != new_len)
+  if (target_read_memory (new_ptr, (gdb_byte *) newpath, new_len))
     {
       remote_fileio_ioerror ();
       return;
@@ -1036,7 +1019,7 @@ static void
 remote_fileio_func_unlink (char *buf)
 {
   CORE_ADDR ptrval;
-  int length, retlength;
+  int length;
   char *pathname;
   int ret;
   struct stat st;
@@ -1047,10 +1030,9 @@ remote_fileio_func_unlink (char *buf)
       remote_fileio_ioerror ();
       return;
     }
-  /* Request pathname using 'm' packet */
+  /* Request pathname */
   pathname = alloca (length);
-  retlength = remote_read_bytes (ptrval, (gdb_byte *) pathname, length);
-  if (retlength != length)
+  if (target_read_memory (ptrval, (gdb_byte *) pathname, length))
     {
       remote_fileio_ioerror ();
       return;
@@ -1077,7 +1059,7 @@ static void
 remote_fileio_func_stat (char *buf)
 {
   CORE_ADDR statptr, nameptr;
-  int ret, namelength, retlength;
+  int ret, namelength;
   char *pathname;
   LONGEST lnum;
   struct stat st;
@@ -1098,10 +1080,9 @@ remote_fileio_func_stat (char *buf)
     }
   statptr = (CORE_ADDR) lnum;
   
-  /* Request pathname using 'm' packet */
+  /* Request pathname */
   pathname = alloca (namelength);
-  retlength = remote_read_bytes (nameptr, (gdb_byte *) pathname, namelength);
-  if (retlength != namelength)
+  if (target_read_memory (nameptr, (gdb_byte *) pathname, namelength))
     {
       remote_fileio_ioerror ();
       return;
@@ -1125,12 +1106,10 @@ remote_fileio_func_stat (char *buf)
     {
       remote_fileio_to_fio_stat (&st, &fst);
       remote_fileio_to_fio_uint (0, fst.fst_dev);
-      
-      retlength = remote_fileio_write_bytes (statptr,
-					     (gdb_byte *) &fst, sizeof fst);
-      if (retlength != sizeof fst)
+
+      if (target_write_memory (statptr, (gdb_byte *) &fst, sizeof fst) )
 	{
-	  remote_fileio_return_errno (-1);
+        remote_fileio_ioerror ();
 	  return;
 	}
     }
@@ -1141,7 +1120,7 @@ static void
 remote_fileio_func_fstat (char *buf)
 {
   CORE_ADDR ptrval;
-  int fd, ret, retlength;
+  int fd, ret;
   long target_fd;
   LONGEST lnum;
   struct stat st;
@@ -1210,10 +1189,9 @@ remote_fileio_func_fstat (char *buf)
     {
       remote_fileio_to_fio_stat (&st, &fst);
 
-      retlength = remote_fileio_write_bytes (ptrval, (gdb_byte *) &fst, sizeof fst);
-      if (retlength != sizeof fst)
+      if (target_write_memory (ptrval, (gdb_byte *) &fst, sizeof fst))
 	{
-	  remote_fileio_return_errno (-1);
+	  remote_fileio_ioerror ();
 	  return;
 	}
     }
@@ -1225,7 +1203,7 @@ remote_fileio_func_gettimeofday (char *b
 {
   LONGEST lnum;
   CORE_ADDR ptrval;
-  int ret, retlength;
+  int ret;
   struct timeval tv;
   struct fio_timeval ftv;
 
@@ -1262,10 +1240,9 @@ remote_fileio_func_gettimeofday (char *b
     {
       remote_fileio_to_fio_timeval (&tv, &ftv);
 
-      retlength = remote_fileio_write_bytes (ptrval, (gdb_byte *) &ftv, sizeof ftv);
-      if (retlength != sizeof ftv)
+      if (target_write_memory (ptrval, (gdb_byte *) &ftv, sizeof ftv))
 	{
-	  remote_fileio_return_errno (-1);
+        remote_fileio_ioerror ();
 	  return;
 	}
     }
@@ -1306,10 +1283,9 @@ remote_fileio_func_system (char *buf)
 
   if (length)
     {
-      /* Request commandline using 'm' packet */
+      /* Request commandline */
       cmdline = alloca (length);
-      retlength = remote_read_bytes (ptrval, (gdb_byte *) cmdline, length);
-      if (retlength != length)
+      if (target_read_memory (ptrval, (gdb_byte *) cmdline, length))
 	{
 	  remote_fileio_ioerror ();
 	  return;
@@ -1405,10 +1381,12 @@ remote_fileio_reset (void)
 }
 
 void
-remote_fileio_request (char *buf)
+remote_fileio_request (char *buf, int (*putpkt_fn)(char*))
 {
   int ex;
 
+  target_putpkt_fn = putpkt_fn;
+
   remote_fileio_sig_init ();
 
   remote_fio_ctrl_c_flag = 0;
Index: remote-fileio.h
===================================================================
RCS file: /cvs/src/src/gdb/remote-fileio.h,v
retrieving revision 1.8
diff -u -p -r1.8 remote-fileio.h
--- remote-fileio.h	1 Jan 2008 22:53:12 -0000	1.8
+++ remote-fileio.h	31 Aug 2008 11:30:23 -0000
@@ -26,7 +26,7 @@ struct cmd_list_element;
 
 /* Unified interface to remote fileio, called in remote.c from
    remote_wait () and remote_async_wait () */
-extern void remote_fileio_request (char *buf);
+extern void remote_fileio_request (char *buf, int (*putpkt_fn)(char*));
 
 /* Cleanup any remote fileio state.  */
 extern void remote_fileio_reset (void);
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.308
diff -u -p -r1.308 remote.c
--- remote.c	27 Aug 2008 13:25:21 -0000	1.308
+++ remote.c	31 Aug 2008 11:30:32 -0000
@@ -3497,7 +3497,7 @@ remote_wait (ptid_t ptid, struct target_
 	  status->value.sig = TARGET_SIGNAL_0;
 	  goto got_status;
 	case 'F':		/* File-I/O request.  */
-	  remote_fileio_request (buf);
+	  remote_fileio_request (buf, &putpkt);
 	  continue;
 	case 'T':		/* Status with PC, SP, FP, ...  */
 	  {
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1048
diff -u -p -r1.1048 Makefile.in
--- Makefile.in	20 Aug 2008 10:18:23 -0000	1.1048
+++ Makefile.in	31 Aug 2008 11:30:21 -0000
@@ -445,7 +445,8 @@ SER_HARDWIRE = @SER_HARDWIRE@
 
 # The `remote' debugging target is supported for most architectures,
 # but not all (e.g. 960)
-REMOTE_OBS = remote.o dcache.o tracepoint.o ax-general.o ax-gdb.o remote-fileio.o
+REMOTE_OBS = remote.o dcache.o tracepoint.o ax-general.o ax-gdb.o \
+	remote-fileio.o hwdebug-fileio.o
 
 # This is remote-sim.o if a simulator is to be linked in.
 SIM_OBS = @SIM_OBS@
@@ -655,7 +656,8 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
 	user-regs.c \
 	valarith.c valops.c valprint.c value.c varobj.c vec.c \
 	wrapper.c \
-	xml-tdesc.c xml-support.c
+	xml-tdesc.c xml-support.c \
+	hwdebug-fileio.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
Index: hwdebug-fileio.c
===================================================================
RCS file: hwdebug-fileio.c
diff -N hwdebug-fileio.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ hwdebug-fileio.c	31 Aug 2008 11:30:21 -0000
@@ -0,0 +1,620 @@
+/* File I/O support for when not using the remote protocol.
+
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "defs.h"
+#include "gdbarch.h"
+#include "target.h"
+#include "command.h"
+#include "gdbtypes.h"
+#include "remote-fileio.h"
+#include "exceptions.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "value.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "observer.h"
+#include "gdbcmd.h"
+
+static int hwdebug_unpack_int32 (const gdb_byte *, int);
+static int hwdebug_unpack_int64 (const gdb_byte *, int);
+static int hwdebug_unpack_voidptr (const gdb_byte *, int);
+static int hwdebug_unpack_charptr (const gdb_byte *, int);
+static int hwdebug_handle_request (void);
+static int hwdebug_putpkt (char *);
+static int hwdebug_update_target_data (void);
+
+static void hwdebug_push_target_vec (void);
+static ptid_t hwdebug_wait (ptid_t, struct target_waitstatus *);
+static void hwdebug_resume (ptid_t, int, enum target_signal);
+static void hwdebug_load (char *, int);
+static LONGEST hwdebug_xfer_partial (struct target_ops *, enum target_object,
+				     const char *, gdb_byte *,
+				     const gdb_byte *, ULONGEST, LONGEST);
+static void hwdebug_set (char *, int, struct cmd_list_element *);
+static void hwdebug_executable_changed (void);
+
+void _initialize_hwdebug_fileio (void);
+
+/* ----------------------------------------------------------------------------
+   This module's functionality is disabled by default.  It must be
+   explicitly enabled with a set hwdebug. */
+static int hwdebug_enabled = 0;
+
+/* A set of h/w debug-specific target operations, overriding certain
+   remote protocol or equivalent operations. */
+static struct target_ops hwdebug_ops;
+
+/* Operations that are currently pending, for example clearing the
+   target-side disabled flag on the next continue. */
+static int update_needed__gdb_hwdebug_disabled = 0;
+
+// Has remote-fileio.c requested a ctrl-C?
+static int ctrlc_pending = 0;
+
+/* Space for local copies of the target-side request and reply.
+   Sizes and padding may depend on the architecture. */
+static gdb_byte *request_copy = NULL;
+static gdb_byte *reply_copy = NULL;
+
+/* Space for the remote protocol string generated from request_copy.
+   The largest request is Frename,ptr/len,ptr/len.  Allow for 64-bit
+   pointers, 32-bit integers, and a \0 ->
+   (1 + 6 + 1 + 16 + 1 + 8 + 1 + 16 + 1 + 8 + 1) == 60 
+   The unpacking process may consume one extra byte. */
+#define REQUEST_MAX     61
+static char request_str[REQUEST_MAX];
+
+// Does the target executable provide all required functionality?
+static int target_has_hwdebug_support = 0;
+
+/* Various target-side addresses, types, etc. that are needed.  These
+   are calculated only when h/w debugging is enabled or when the
+   executable is changed, to keep file I/O turnaround as quick as
+   possible. */
+static CORE_ADDR _gdb_hwdebug_disabled;
+static CORE_ADDR _gdb_hwdebug_breakpoint;
+static int has_gdb_hwdebug_continue = 0;
+static CORE_ADDR _gdb_hwdebug_continue;
+static CORE_ADDR _gdb_hwdebug_request;
+static int sizeof_request;
+static int offset_request_op;
+static CORE_ADDR _gdb_hwdebug_reply;
+static int sizeof_reply;
+static int offset_reply_result;
+static int offset_reply_errcode;
+
+/* Details of the supported commands and arguments.  The array must be kept
+   in the same order as the target-side command numbering.  The argument names
+   correspond to the target_side _gdb_hwdebug_request.data fields. */
+static struct
+{
+  const char *name;
+  struct
+  {
+    const char *field;
+    int (*unpack_fn) (const gdb_byte *, int);
+    int offset;
+  } args[5];
+} known_requests[] =
+{
+  {
+    "open",
+    {
+      { "d_open.path", &hwdebug_unpack_charptr, 0},
+      { "d_open.pathlen", &hwdebug_unpack_int32, 0},
+      { "d_open.flags", &hwdebug_unpack_int32, 0},
+      { "d_open.mode", &hwdebug_unpack_int32, 0},
+      { NULL}
+    },
+  },
+  {
+    "close",
+    {
+      { "d_close.fd", &hwdebug_unpack_int32, 0},
+      { NULL}
+    },
+  },
+  {
+    "read",
+    {
+      { "d_read.fd", &hwdebug_unpack_int32, 0},
+      { "d_read.buf", &hwdebug_unpack_voidptr, 0},
+      { "d_read.count", &hwdebug_unpack_int32, 0},
+      { NULL}
+    },
+  },
+  {
+    "write",
+    {
+      { "d_write.fd", &hwdebug_unpack_int32, 0},
+      { "d_write.buf", &hwdebug_unpack_voidptr, 0},
+      { "d_write.count", &hwdebug_unpack_int32, 0},
+      { NULL}
+    },
+  },
+  {
+    "lseek",
+    {
+      { "d_lseek.fd", &hwdebug_unpack_int32, 0},
+      { "d_lseek.offset", &hwdebug_unpack_int64, 0},
+      { "d_lseek.flag", &hwdebug_unpack_int32, 0},
+      { NULL}
+    },
+  },
+  {
+    "rename",
+    {
+      { "d_rename.oldpath", &hwdebug_unpack_charptr, 0},
+      { "d_rename.oldpathlen", &hwdebug_unpack_int32, 0},
+      { "d_rename.newpath", &hwdebug_unpack_charptr, 0},
+      { "d_rename.newpathlen", &hwdebug_unpack_int32, 0},
+      { NULL}
+    },
+  },
+  {
+    "unlink",
+    {
+      { "d_unlink.path", &hwdebug_unpack_charptr, 0},
+      { "d_unlink.pathlen", &hwdebug_unpack_int32, 0},
+      { NULL}
+    },
+  },
+  {
+    "stat",
+    {
+      { "d_stat.path", &hwdebug_unpack_charptr, 0},
+      { "d_stat.pathlen", &hwdebug_unpack_int32, 0},
+      { "d_stat.buf", &hwdebug_unpack_voidptr, 0},
+      { NULL}
+    },
+  },
+  {
+    "fstat",
+    {
+      { "d_fstat.fd", &hwdebug_unpack_int32, 0},
+      { "d_fstat.buf", &hwdebug_unpack_voidptr, 0},
+      { NULL}
+    },
+  },
+  {
+    "gettimeofday",
+    {
+      { "d_gettimeofday.tv", &hwdebug_unpack_voidptr, 0},
+      { "d_gettimeofday.tz", &hwdebug_unpack_voidptr, 0},
+      { NULL}
+    },
+  },
+  {
+    "isatty",
+    {
+      { "d_isatty.fd", &hwdebug_unpack_int32, 0},
+      { NULL}
+    },
+  },
+  {
+    "system",
+    {
+      { "d_system.command", &hwdebug_unpack_charptr, 0},
+      { "d_system.commandlen", &hwdebug_unpack_int32, 0},
+      { NULL}
+    },
+  }
+};
+
+#define NUMBER_REQUESTS (sizeof(known_requests) / sizeof(known_requests[0]))
+
+
+// ----------------------------------------------------------------------------
+/* These unpack routines interpret a field in the local copy of the
+   _gdb_hwdebug_request structure and update the current remote protocol
+   request string at offset IDX. */
+
+static int
+hwdebug_unpack_int32 (const gdb_byte * src, int idx)
+{
+  ULONGEST val = extract_unsigned_integer (src, 4);
+  char *str = phex_nz (val, 4);
+  return xsnprintf (request_str + idx, REQUEST_MAX - idx, "%s,", str);
+}
+
+static int
+hwdebug_unpack_int64 (const gdb_byte * src, int idx)
+{
+  ULONGEST val = extract_unsigned_integer (src, 8);
+  char *str = phex_nz (val, 8);
+  return xsnprintf (request_str + idx, REQUEST_MAX - idx, "%s,", str);
+}
+
+static int
+hwdebug_unpack_charptr (const gdb_byte * src, int idx)
+{
+  CORE_ADDR addr = extract_typed_address (src, builtin_type_void_data_ptr);
+  char *str = paddr_nz (addr);
+  return xsnprintf (request_str + idx, REQUEST_MAX - idx, "%s/", str);
+}
+
+static int
+hwdebug_unpack_voidptr (const gdb_byte * src, int idx)
+{
+  CORE_ADDR addr = extract_typed_address (src, builtin_type_void_data_ptr);
+  char *str = paddr_nz (addr);
+  return xsnprintf (request_str + idx, REQUEST_MAX - idx, "%s,", str);
+}
+
+/* There is a file I/O request encoded in struct _gdb_hwdebug_request
+   on the target.  To avoid unnecessary traffic the whole structure is
+   transferred in one go. */
+
+static int
+hwdebug_handle_request (void)
+{
+  LONGEST tmp;
+  int op, i, idx;
+  int (*unpack_fn) (const gdb_byte *, int);
+
+  target_read_memory (_gdb_hwdebug_request, request_copy, sizeof_request);
+  tmp = extract_unsigned_integer (request_copy + offset_request_op, 4);
+  op = longest_to_int (tmp);
+
+  if ((op < 0) || (op >= NUMBER_REQUESTS))
+    {
+      warning (_("target request for unknown file I/O operation %d"), op);
+      return 0;
+    }
+  idx = xsnprintf (request_str, REQUEST_MAX, "F%s,", known_requests[op].name);
+  for (i = 0; known_requests[op].args[i].field; i++)
+    {
+      unpack_fn = known_requests[op].args[i].unpack_fn;
+      idx += (*unpack_fn) (request_copy + known_requests[op].args[i].offset,
+			   idx);
+    }
+  // The last unpack will have left a trailing ','
+  request_str[--idx] = '\0';
+
+  // Now call into remote-fileio.c to perform the I/O operation.
+  remote_fileio_request (request_str, &hwdebug_putpkt);
+
+  // And make the calling code return control to the target.
+  return 1;
+}
+
+/* Send a response back to the target.  The reply packet has the form
+   F<code>,<errno>,<ctrl-C>, with only code required. */
+
+static int
+hwdebug_putpkt (char *buf_arg)
+{
+  const char *buf = (const char *) buf_arg;
+  LONGEST result = 0;
+  LONGEST errcode = 0;
+
+  result = strtoulst (buf + 1, &buf, 16);
+  if (*buf == ',')
+    {
+      errcode = strtoulst (buf + 1, &buf, 16);
+      if ((buf[0] == ',') && (buf[1] == 'C'))
+	ctrlc_pending = 1;
+    }
+  store_signed_integer (reply_copy + offset_reply_result, 8, result);
+  store_signed_integer (reply_copy + offset_reply_errcode, 4, errcode);
+  target_write_memory (_gdb_hwdebug_reply, reply_copy, sizeof_reply);
+  return 1;
+}
+
+/* Update all the symbols etc. needed to allow subsequent file I/O requests
+   to be handled as efficiently as possible. */
+
+static int
+hwdebug_update_target_data (void)
+{
+  volatile struct gdb_exception e;
+  struct minimal_symbol *minsym;
+  int i, j;
+
+  /* Assume failure, the flag is set only when all the way through extracting
+     the required fields. */
+  target_has_hwdebug_support = 0;
+
+  minsym = lookup_minimal_symbol ("_gdb_hwdebug_disabled", NULL, NULL);
+  if (!minsym)
+    {
+      warning (_("missing target-side symbol _gdb_hwdebug_disabled"));
+      return 0;
+    }
+  _gdb_hwdebug_disabled = SYMBOL_VALUE_ADDRESS (minsym);
+
+  minsym = lookup_minimal_symbol ("_gdb_hwdebug_breakpoint", NULL, NULL);
+  if (!minsym)
+    {
+      warning (_("missing target-side symbol _gdb_hwdebug_breakpoint"));
+      return 0;
+    }
+  _gdb_hwdebug_breakpoint = SYMBOL_VALUE_ADDRESS (minsym);
+
+  // _gdb_hwdebug_continue is optional.
+  has_gdb_hwdebug_continue = 0;
+  minsym = lookup_minimal_symbol ("_gdb_hwdebug_continue", NULL, NULL);
+  if (minsym)
+    {
+      _gdb_hwdebug_continue = SYMBOL_VALUE_ADDRESS (minsym);
+      has_gdb_hwdebug_continue = 1;
+    }
+
+  minsym = lookup_minimal_symbol ("_gdb_hwdebug_request", NULL, NULL);
+  if (!minsym)
+    {
+      warning (_("missing target-side symbol _gdb_hwdebug_request"));
+      return 0;
+    }
+  _gdb_hwdebug_request = SYMBOL_VALUE_ADDRESS (minsym);
+
+  minsym = lookup_minimal_symbol ("_gdb_hwdebug_reply", NULL, NULL);
+  if (!minsym)
+    {
+      warning (_("missing target-side symbol _gdb_hwdebug_reply"));
+      return 0;
+    }
+  _gdb_hwdebug_reply = SYMBOL_VALUE_ADDRESS (minsym);
+
+  TRY_CATCH (e, RETURN_MASK_ERROR)
+  {
+    sizeof_request =
+      longest_to_int (parse_and_eval_long ("sizeof(_gdb_hwdebug_request)"));
+    offset_request_op =
+      longest_to_int (parse_and_eval_long
+		      ("(char*)&_gdb_hwdebug_request.op - (char*)&_gdb_hwdebug_request"));
+    sizeof_reply =
+      longest_to_int (parse_and_eval_long ("sizeof(_gdb_hwdebug_reply)"));
+    offset_reply_result =
+      longest_to_int (parse_and_eval_long
+		      ("(char*)&_gdb_hwdebug_reply.result - (char*)&_gdb_hwdebug_reply"));
+    offset_reply_errcode =
+      longest_to_int (parse_and_eval_long
+		      ("(char*)&_gdb_hwdebug_reply.errcode - (char*)&_gdb_hwdebug_reply"));
+
+    // Make sure we have enough space for copies of the target-side structures.
+    if (request_copy)
+      xfree (request_copy);
+    request_copy = XCALLOC (sizeof_request, gdb_byte);
+    if (reply_copy)
+      xfree (reply_copy);
+    reply_copy = XCALLOC (sizeof_reply, gdb_byte);
+
+    // Now to calculate all the argument offsets.
+    for (i = 0; i < NUMBER_REQUESTS; i++)
+      {
+	for (j = 0; known_requests[i].args[j].field; j++)
+	  {
+	    LONGEST offset;
+	    char expr[128];
+	    xsnprintf (expr, 128,
+		       "(char*)&_gdb_hwdebug_request.data.%s - (char*)&_gdb_hwdebug_request",
+		       known_requests[i].args[j].field);
+	    offset = parse_and_eval_long (expr);
+	    known_requests[i].args[j].offset = longest_to_int (offset);
+	  }
+      }
+  }
+  if (RETURN_ERROR == e.reason)
+    {
+      warning (_("target-side h/w data structure mismatch, %s"), e.message);
+      return 0;
+    }
+
+  // All the required info is present and has been extracted.
+  target_has_hwdebug_support = 1;
+  return 1;
+}
+
+/* Target Operations.
+
+   When suitably compiled the target-side includes a h/w breakpoint
+   instruction @ _gdb_hwdebug_breakpoint.  This gets executed whenever
+   the target-side performs a file I/O operation, for example when a
+   buffer full of diagnostic output has been collected.  The breakpoint
+   only gets executed when the global flag _gdb_hwdebug_disabled is clear,
+   which happens here in the resume code.  This allows the application
+   to run either stand-alone or under gdb control.
+
+   Three target vector operations need to be intercepted for this to
+   work.  The resume operation clears the target-side _gdb_hwdebug_disabled
+   flag if necessary, then chains to the original resume.  The wait
+   operation repeatedly chains to the original wait.  If it detects
+   the target-side code has halted @ _gdb_hwdebug_breakpoint then it
+   takes the appropriate action requested by the target and automatically
+   resumes the target.  Otherwise it passes the wait result back to
+   higher-level code.  The load operation is intercepted to cope with
+   the same executable being loaded multiple times in one debug session,
+   overwriting the _gdb_hwdebug_disabled flag. */
+
+static void
+hwdebug_push_target_vec (void)
+{
+  static int pushed = 0;
+  if (pushed)
+    return;
+  pushed = 1;
+
+  memset (&hwdebug_ops, 0, sizeof (struct target_ops));
+  hwdebug_ops.to_shortname = "hwdebug I/O";
+  hwdebug_ops.to_longname = "hwdebug I/O extensions";
+  hwdebug_ops.to_doc =
+    "Enable hardware debug I/O extensions on an existing target \n\
+connection.";
+  hwdebug_ops.to_resume = &hwdebug_resume;
+  hwdebug_ops.to_wait = &hwdebug_wait;
+  hwdebug_ops.to_load = &hwdebug_load;
+  // This operation does not get inherited automatically so we
+  // need a chaining dummy.
+  hwdebug_ops.to_xfer_partial = &hwdebug_xfer_partial;
+  hwdebug_ops.to_stratum = process_override_stratum;
+  hwdebug_ops.to_magic = OPS_MAGIC;
+  push_target (&hwdebug_ops);
+
+}
+
+static int hwdebug_last_step;
+static int hwdebug_last_sig;
+
+static void
+hwdebug_resume (ptid_t ptid, int step, enum target_signal sig)
+{
+  struct target_ops *orig_ops;
+
+  if (update_needed__gdb_hwdebug_disabled && target_has_hwdebug_support)
+    {
+      gdb_byte newval[4];
+      store_signed_integer (newval, 4, hwdebug_enabled ? 0 : 1);
+      target_write_memory (_gdb_hwdebug_disabled, newval, 4);
+      update_needed__gdb_hwdebug_disabled = 0;
+    }
+
+  /* Remember the args so that wait() below can automatically resume
+     the target with the same options. That may or may not be the
+     right thing to do for signals, but those are not really supported
+     anyway. */
+  hwdebug_last_step = step;
+  hwdebug_last_sig = sig;
+  // Chain to the original resume operation.
+  orig_ops = find_target_beneath (&hwdebug_ops);
+  (orig_ops->to_resume) (ptid, step, sig);
+}
+
+static ptid_t
+hwdebug_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+  ptid_t result;
+  struct target_ops *orig_ops = find_target_beneath (&hwdebug_ops);
+  CORE_ADDR pc;
+
+  while (1)
+    {
+      ctrlc_pending = 0;
+      result = (*orig_ops->to_wait) (ptid, status);
+      if (!hwdebug_enabled || !target_has_hwdebug_support)
+	break;
+
+      /* If the target has stopped @ _gdb_hwdebug_breakpoint then it is
+         making a file I/O request. For anything else just return
+         control to the user. */
+      pc = read_pc ();
+      if (pc != _gdb_hwdebug_breakpoint)
+	break;
+
+      /* Issuing the hardware breakpoint may have had side effects like
+         pushing some state on to the stack.  Also on some architectures
+         the current PC may still be set to the breakpoint instruction
+         instead of the next one.  If the target provides a label
+         _gdb_hwdebug_continue then that code will take whatever clean-up
+         action is needed. */
+      if (has_gdb_hwdebug_continue)
+	write_pc (_gdb_hwdebug_continue);
+
+      /* For a faulty request the called code should have issued a warning,
+         and it is safer to transfer control to the user rather than let
+         the target continue in an indeterminate state. */
+      if (!hwdebug_handle_request ())
+	break;
+
+      /* If remote-fileio.c has requested a ctrl-C via the reply putpkt(),
+         the target is still halted and should be in a state where it
+         can resume safely with the appropriate error code etc.  So just
+         transfer control to the user here, no action is needed on the
+         target-side. */
+      if (ctrlc_pending)
+	break;
+
+      // As per wait_for_inferior ()
+      overlay_cache_invalid = 1;
+      registers_changed ();
+
+      // Automatically resume the target and wait again.
+      hwdebug_resume (ptid, hwdebug_last_step, hwdebug_last_sig);
+    }
+
+  /* The target has halted for reasons other than the h/w debug support code,
+     e.g. an ordinary breakpoint.  Return to higher-level gdb code. */
+  return result;
+}
+
+static void
+hwdebug_load (char *name, int from_tty)
+{
+  /* Loading will have invalidated the target-side _gdb_hwdebug_disabled
+     flag, so reset it during the next resume. */
+  struct target_ops *orig_ops = find_target_beneath (&hwdebug_ops);
+  update_needed__gdb_hwdebug_disabled = 1;
+  (orig_ops->to_load) (name, from_tty);
+}
+
+// xfer_partial is always needed in a target_ops but can just chain.
+
+static LONGEST
+hwdebug_xfer_partial (struct target_ops *ops, enum target_object object,
+		      const char *annex, gdb_byte * readbuf,
+		      const gdb_byte * writebuf, ULONGEST offset, LONGEST len)
+{
+  gdb_assert (ops->beneath->to_xfer_partial);
+  return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+					readbuf, writebuf, offset, len);
+}
+
+static void
+hwdebug_set (char *args, int from_tty, struct cmd_list_element *c)
+{
+  if (hwdebug_enabled)
+    {
+      /* We may or may not already have symbol table info etc.,
+         which may or may not correspond to the current executable.
+         Make sure that the info is accurate. */
+      if (!hwdebug_update_target_data ())
+	{
+	  warning (_("cannot enable h/w debug, missing target-side support"));
+	  hwdebug_enabled = 0;
+	}
+      else
+	{
+	  hwdebug_push_target_vec ();
+	  /* During the next continue, update the target-side
+	     _gdb_hwdebug_disabled flag to activate the h/w debug
+	     functionality. */
+	  update_needed__gdb_hwdebug_disabled = 1;
+	}
+    }
+  else
+    {
+      /* If hwdebug is disabled then we don't care about the accuracy
+         of symbol table info.  The target vector entries must be kept
+         in place so that target-side _gdb_hwdebug_disabled gets
+         set again during the next resume. */
+      update_needed__gdb_hwdebug_disabled = 1;
+    }
+}
+
+void
+_initialize_hwdebug_fileio (void)
+{
+  add_setshow_boolean_cmd ("hwdebug", class_obscure, &hwdebug_enabled, _("\
+Set use of h/w debug file I/O support."), _("\
+Show use of h/w debug file I/O support."), _("\
+When set, if the target halts at a well-defined location, GDB\n\
+will treat that as a request for file I/O.  The request will be\n\
+handled and the target will be resumed automatically."), &hwdebug_set, NULL, &setlist, &showlist);
+}
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.520
diff -u -p -r1.520 gdb.texinfo
--- doc/gdb.texinfo	26 Aug 2008 17:30:35 -0000	1.520
+++ doc/gdb.texinfo	31 Aug 2008 11:31:25 -0000
@@ -13341,6 +13341,7 @@ configuration of @value{GDBN}; use @code
 * Server::	                Using the gdbserver program
 * Remote Configuration::        Remote configuration
 * Remote Stub::                 Implementing a remote stub
+* Hardware Debug Support::      Extra support for hardware debuggers
 @end menu
 
 @node Connecting
@@ -14226,6 +14227,7 @@ but in general the stubs are likely to u
 subroutines which @code{@value{NGCC}} generates as inline code.
 
 
+
 @node Debug Session
 @subsection Putting it All Together
 
@@ -14285,6 +14287,42 @@ Start @value{GDBN} on the host, and conn
 
 @end enumerate
 
+@node Hardware Debug Support
+@section Extra support for hardware debuggers
+
+@cindex hardware debuggers support
+@kindex hwdebug
+When @value{GDBN} interacts with a server or stub running on the
+remote target, the target-side application can perform a number of
+host-side file I/O operations,  see @ref{File-I/O Remote Protocol
+Extension}.  Remote debugging can also involve a separate server that
+controls the target via a hardware debug mechanism, for example jtag
+or BDM.  If so, then target-side code may be unable to generate the
+remote protocol messages directly.  Instead, it can send the request
+by triggering a breakpoint or processor exception at a well-known
+location named @code{_gdb_hwdebug_break}.  This functionality is
+disabled by default, allowing the application to run stand-alone as
+well as inside a debug session.  It can be enabled by a @kbd{set
+hwdebug on} command, or disabled by @kbd{set hwdebug off}.
+
+Exact usage depends on the application being debugged.  Amongst other
+things, @kbd{set hwdebug} clears a flag @code{_gdb_hwdebug_disabled}
+on the target.  If the application is loaded into RAM, then there are
+no problems.  However, if it is programmed into flash and restarted
+from the reset vector inside the debug session, then typically the
+target-side initialization code will reset the disabled flag to its
+default state, undoing the effect of @kbd{set hwdebug}.  Instead, it
+will be necessary to set a hardware breakpoint at a suitably early
+point in the application startup and invoke @kbd{set hwdebug} when
+that breakpoint is hit.
+
+The target-side API for accessing the hardware debug file I/O
+functionality depends on the embedded OS or run-time being used.  If
+the functionality has not yet been ported, then a reference
+implementation can be found in @file{doc/hwdebug-example.c} in the
+@value{GDBN} sources.
+
+
 @node Configurations
 @chapter Configuration-Specific Information
 
@@ -27136,8 +27174,8 @@ is defined as follows:
 
 @smallexample
 struct timeval @{
-    time_t tv_sec;  /* second */
-    long   tv_usec; /* microsecond */
+    time_t       tv_sec;  /* second */
+    unsigned int tv_usec; /* microsecond */
 @};
 @end smallexample
 
Index: doc/hwdebug-example.c
===================================================================
RCS file: doc/hwdebug-example.c
diff -N doc/hwdebug-example.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ doc/hwdebug-example.c	31 Aug 2008 11:31:27 -0000
@@ -0,0 +1,815 @@
+/* Example target-side code for hwdebug-fileio.c
+
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+/* ----------------------------------------------------------------------------
+   This section contains everything that is OS or target-specific: data
+   types, locking, and how to invoke a hardware breakpoint. */
+#include <cyg/infra/cyg_type.h>
+#include <cyg/hal/hal_intr.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+typedef cyg_uint32 uint32_t;
+typedef cyg_int32 int32_t;
+typedef cyg_uint64 uint64_t;
+typedef cyg_int64 int64_t;
+
+/* Locking is kept simple - just disable interrupts for the duration
+   of the I/O operation.  The target is going to be blocked for a
+   large number of cycles anyway while the I/O operation takes place. */
+#define HAL_GDB_HWDEBUG_LOCK()                              \
+    int __gdb_hwdebug_lock_ints_state;                      \
+    HAL_DISABLE_INTERRUPTS(__gdb_hwdebug_lock_ints_state)
+
+#define HAL_GDB_HWDEBUG_UNLOCK()                            \
+    HAL_RESTORE_INTERRUPTS(__gdb_hwdebug_lock_ints_state)
+
+/* This macro is used to get the attention of the hardware debug unit.
+ * Depending on the architecture and possibly the specific processor
+ * variant this may involve a custom breakpoint instruction, an
+ * illegal instruction trap, or some other kind of processor
+ * exception.  A likely candidate is whatever instruction gdb uses for
+ * a software breakpoint.  This macro uses inline assembler.  On some
+ * architectures a function call may be necessary instead.
+ *
+ * At least one label should be associated with the hardware
+ * breakpoint: _gdb_hwdebug_breakpoint.  This label should correspond
+ * to the address that will be reported to gdb. Typically it will be
+ * either the address of the breakpoint instruction or, as on M68K,
+ * that of the next instruction.
+ *
+ * If _gdb_hwdebug_breakpoint corresponds to the breakpoint instruction
+ * itself then the target cannot just be resumed: it would just execute
+ * the breakpoint again, triggering another file I/O operation, ad
+ * infinitum.  To avoid this HAL_HWBREAKPOINT() can define a label
+ * _gdb_hwdebug_continue.  gdb will detect the presence of that label
+ * and set the program counter to its address before resuming the target.
+ * On some architectures executing the breakpoint instruction may have
+ * side effects like pushing extra state on to the stack.  If so then
+ * the code @ _gdb_hwdebug_continue can undo those.
+ *
+ * The M68K breakpoint instruction has no side effects and the address
+ * reported to gdb is that of the next instruction, so there is no need
+ * to provide a _gdb_hwdebug_continue label. It is provided here merely
+ * as an example.  */
+
+#if defined(CYGPKG_HAL_M68K_MCF52xx)
+# define HAL_HWBREAKPOINT()                                 \
+    CYG_MACRO_START                                         \
+        __asm__ volatile (                                  \
+        " halt\n"                                           \
+        ".globl _gdb_hwdebug_breakpoint\n"                  \
+        ".type  _gdb_hwdebug_breakpoint, function\n"        \
+        "_gdb_hwdebug_breakpoint:\n"                        \
+        ".globl _gdb_hwdebug_continue\n"                    \
+        ".type  _gdb_hwdebug_continue, function\n"          \
+        "_gdb_hwdebug_continue:\n"                          \
+        : : : "memory"                                      \
+            );                                              \
+    CYG_MACRO_END
+
+#else
+# error The H/W debug file I/O support has not yet been ported to this architecture.
+#endif
+
+/* ----------------------------------------------------------------------------
+   This section contains definitions which typically would be exported in
+   a header file.  The exact names will depend on the conventions used by
+   the embedded OS or run-time.  The definitions can be used for either a
+   h/w debug implementation or for an application running on top of gdb stubs. */
+
+#define HAL_GDB_FILEIO_STDIN        0
+#define HAL_GDB_FILEIO_STDOUT       1
+#define HAL_GDB_FILEIO_STDERR       2
+
+#define HAL_GDB_FILEIO_O_RDONLY     0x0000
+#define HAL_GDB_FILEIO_O_WRONLY     0x0001
+#define HAL_GDB_FILEIO_O_RDWR       0x0002
+#define HAL_GDB_FILEIO_O_APPEND     0x0008
+#define HAL_GDB_FILEIO_O_CREAT      0x0200
+#define HAL_GDB_FILEIO_O_TRUNC      0x0400
+#define HAL_GDB_FILEIO_O_EXCL       0x0800
+
+#define HAL_GDB_FILEIO_S_IFREG      0100000
+#define HAL_GDB_FILEIO_S_IFDIR       040000
+#define HAL_GDB_FILEIO_S_IRUSR         0400
+#define HAL_GDB_FILEIO_S_IWUSR         0200
+#define HAL_GDB_FILEIO_S_IXUSR         0100
+#define HAL_GDB_FILEIO_S_IRGRP          040
+#define HAL_GDB_FILEIO_S_IWGRP          020
+#define HAL_GDB_FILEIO_S_IXGRP          010
+#define HAL_GDB_FILEIO_S_IROTH           04
+#define HAL_GDB_FILEIO_S_IWOTH           02
+#define HAL_GDB_FILEIO_S_IXOTH           01
+
+#define HAL_GDB_FILEIO_ENOERR        0
+#define HAL_GDB_FILEIO_EPERM         1
+#define HAL_GDB_FILEIO_ENOENT        2
+#define HAL_GDB_FILEIO_EINTR         4
+#define HAL_GDB_FILEIO_EBADF         9
+#define HAL_GDB_FILEIO_EACCES       13
+#define HAL_GDB_FILEIO_EFAULT       14
+#define HAL_GDB_FILEIO_EBUSY        16
+#define HAL_GDB_FILEIO_EEXIST       17
+#define HAL_GDB_FILEIO_ENODEV       19
+#define HAL_GDB_FILEIO_ENOTDIR      20
+#define HAL_GDB_FILEIO_EISDIR       21
+#define HAL_GDB_FILEIO_EINVAL       22
+#define HAL_GDB_FILEIO_ENFILE       23
+#define HAL_GDB_FILEIO_EMFILE       24
+#define HAL_GDB_FILEIO_EFBIG        27
+#define HAL_GDB_FILEIO_ENOSPC       28
+#define HAL_GDB_FILEIO_ESPIPE       29
+#define HAL_GDB_FILEIO_EROFS        30
+#define HAL_GDB_FILEIO_ENAMETOOLONG 91
+#define HAL_GDB_FILEIO_EUNKNOWN     9999
+
+#define HAL_GDB_FILEIO_ENOSYS       38
+
+#define HAL_GDB_FILEIO_SEEK_SET     0
+#define HAL_GDB_FILEIO_SEEK_CUR     1
+#define HAL_GDB_FILEIO_SEEK_END     2
+
+struct hal_gdb_fileio_stat
+{
+  uint32_t st_dev;
+  uint32_t st_ino;
+  uint32_t st_mode;
+  uint32_t st_nlink;
+  uint32_t st_uid;
+  uint32_t st_gid;
+  uint32_t st_rdev;
+  uint64_t st_size;
+  uint64_t st_blksize;
+  uint64_t st_blocks;
+  uint32_t st_atime;
+  uint32_t st_mtime;
+  uint32_t st_ctime;
+};
+
+struct hal_gdb_fileio_timeval
+{
+  uint32_t tv_sec;
+  // The protocol makes this a uint64_t, but 32 bits are plenty.
+  uint32_t tv_usec;
+};
+
+/* ----------------------------------------------------------------------------
+   This is an example implementation of the h/w debug file I/O functionality.
+   The matching gdb code expects to find variables _gdb_hwdebug_disabled,
+   _gdb_hwdebug_request and _gdb_hwdebug_reply, with the types given here.
+   That includes the types and names of all the structure fields.  gdb also
+   expects to find a label _gdb_hwdebug_break and optionally
+   _gdb_hwdebug_continue, as described earlier.
+
+   As long as these conditions are satisfied the code can be rewritten as
+   appropriate for the embedded OS or run-time, for example to match the
+   conventions for naming, error handling, and so on. */
+
+#define HAL_GDB_FILEIO_OPEN          0
+#define HAL_GDB_FILEIO_CLOSE         1
+#define HAL_GDB_FILEIO_READ          2
+#define HAL_GDB_FILEIO_WRITE         3
+#define HAL_GDB_FILEIO_LSEEK         4
+#define HAL_GDB_FILEIO_RENAME        5
+#define HAL_GDB_FILEIO_UNLINK        6
+#define HAL_GDB_FILEIO_STAT          7
+#define HAL_GDB_FILEIO_FSTAT         8
+#define HAL_GDB_FILEIO_GETTIMEOFDAY  9
+#define HAL_GDB_FILEIO_ISATTY       10
+#define HAL_GDB_FILEIO_SYSTEM       11
+
+static volatile uint32_t _gdb_hwdebug_disabled = 1;
+
+static struct
+{
+  uint32_t op;
+  union
+  {
+    struct
+    {
+      const char *path;
+      uint32_t pathlen;
+      int32_t flags;
+      int32_t mode;
+    } d_open;
+    struct
+    {
+      int32_t fd;
+    } d_close;
+    struct
+    {
+      int32_t fd;
+      void *buf;
+      uint32_t count;
+    } d_read;
+    struct
+    {
+      int32_t fd;
+      const void *buf;
+      uint32_t count;
+    } d_write;
+    struct
+    {
+      int32_t fd;
+      int64_t offset;
+      int32_t flag;
+    } d_lseek;
+    struct
+    {
+      const char *oldpath;
+      uint32_t oldpathlen;
+      const char *newpath;
+      uint32_t newpathlen;
+    } d_rename;
+    struct
+    {
+      const char *path;
+      uint32_t pathlen;
+    } d_unlink;
+    struct
+    {
+      const char *path;
+      uint32_t pathlen;
+      void *buf;
+    } d_stat;
+    struct
+    {
+      int32_t fd;
+      void *buf;
+    } d_fstat;
+    struct
+    {
+      void *tv;
+      void *tz;
+    } d_gettimeofday;
+    struct
+    {
+      int32_t fd;
+    } d_isatty;
+    struct
+    {
+      const char *command;
+      uint32_t commandlen;
+    } d_system;
+  } data;
+} _gdb_hwdebug_request;
+
+/* This definition of a reply allows for a result field of up to 64 bits,
+   e.g. an lseek64() offset, and the error code. This is not really needed
+   with current I/O operations. A single 32-bit field, -ve for errors,
+   0 or +ve for success, would work for everything except seeks within
+   a file >= 2GB. However it leaves room for future expansion of the
+   protocol. */
+static struct
+{
+  int64_t result;
+  int32_t errcode;
+} _gdb_hwdebug_reply;
+
+
+/* The convention adopted here is that a return code >= 0 indicates
+   success and < 0 indicates failure, with the absolute value of the
+   return code giving the error number.  For most operations this will be
+   fine, for example an embedded target is unlikely to attempt to read
+   2GB of data in one go.  However it does limit lseek() operations to
+   files smaller than 2GB.  Note that, if desired, some of the calling
+   functions can ignore the return code and instead examine
+   _gdb_hwdebug_reply directly before releasing the lock.  */
+
+static int
+_gdb_hwdebug_call (void)
+{
+  int result;
+  if (_gdb_hwdebug_disabled)
+    return -HAL_GDB_FILEIO_ENOSYS;
+  HAL_HWBREAKPOINT ();
+  result = (int) _gdb_hwdebug_reply.result;
+  if (result < 0)
+    result = -_gdb_hwdebug_reply.errcode;
+  return result;
+}
+
+/* The actual I/O operations. */
+
+int
+hal_gdb_fileio_open (const char *path, int flags, int mode)
+{
+  int result;
+
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_OPEN;
+  _gdb_hwdebug_request.data.d_open.path = path;
+  _gdb_hwdebug_request.data.d_open.pathlen = strlen (path) + 1;
+  _gdb_hwdebug_request.data.d_open.flags = flags;
+  _gdb_hwdebug_request.data.d_open.mode = mode;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  return result;
+}
+
+int
+hal_gdb_fileio_close (int fd)
+{
+  int result;
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_CLOSE;
+  _gdb_hwdebug_request.data.d_close.fd = fd;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  return result;
+}
+
+int
+hal_gdb_fileio_read (int fd, void *buf, int count)
+{
+  int result;
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_READ;
+  _gdb_hwdebug_request.data.d_read.fd = fd;
+  _gdb_hwdebug_request.data.d_read.buf = buf;
+  _gdb_hwdebug_request.data.d_read.count = count;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  return result;
+}
+
+int
+hal_gdb_fileio_write (int fd, const void *buf, int count)
+{
+  int result;
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_WRITE;
+  _gdb_hwdebug_request.data.d_write.fd = fd;
+  _gdb_hwdebug_request.data.d_write.buf = buf;
+  _gdb_hwdebug_request.data.d_write.count = count;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  return result;
+}
+
+/* The request is defined in terms of a 64-bit offset, but
+   the reply from gdb only contains a uint32_t offset.
+   That means a file size limit of 4GB.  The convention used
+   in this code further limits file sizes to 2GB, but that
+   could be changed by e.g. extracting the full 32-bit
+   return code from _gdb_hwdebug_reply before releasing the
+   lock. */
+int32_t
+hal_gdb_fileio_lseek (int fd, int32_t offset, int flag)
+{
+  int32_t result;
+
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_LSEEK;
+  _gdb_hwdebug_request.data.d_lseek.fd = fd;
+  _gdb_hwdebug_request.data.d_lseek.offset = (int64_t) offset;
+  _gdb_hwdebug_request.data.d_lseek.flag = flag;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  return result;
+}
+
+int
+hal_gdb_fileio_rename (const char *oldpath, const char *newpath)
+{
+  int result;
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_RENAME;
+  _gdb_hwdebug_request.data.d_rename.oldpath = oldpath;
+  _gdb_hwdebug_request.data.d_rename.oldpathlen = strlen (oldpath) + 1;
+  _gdb_hwdebug_request.data.d_rename.newpath = newpath;
+  _gdb_hwdebug_request.data.d_rename.newpathlen = strlen (newpath) + 1;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  return result;
+}
+
+int
+hal_gdb_fileio_unlink (const char *path)
+{
+  int result;
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_UNLINK;
+  _gdb_hwdebug_request.data.d_unlink.path = path;
+  _gdb_hwdebug_request.data.d_unlink.pathlen = strlen (path) + 1;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  return result;
+}
+
+/* The host-side packs the stat data into a 64-byte buffer with all
+   integers and long longs in big-endian format. This may not map
+   exactly onto the hal_gdb_fileio_stat structure, e.g. there may
+   be padding between the st_rdev and st_size fields. For now
+   always do an explicit unpack. It should be possible to optimize
+   the code on some big-endian targets.  */
+
+static uint32_t
+hal_gdb_fileio_unpack32 (unsigned char *buf)
+{
+  uint32_t result;
+  result = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
+  return result;
+}
+
+static uint64_t
+hal_gdb_fileio_unpack64 (unsigned char *buf)
+{
+  uint64_t result;
+  result = ((uint64_t) buf[0] << 56) | ((uint64_t) buf[1] << 48) |
+    ((uint64_t) buf[2] << 40) | ((uint64_t) buf[3] << 32) |
+    ((uint64_t) buf[4] << 24) | ((uint64_t) buf[5] << 16) |
+    ((uint64_t) buf[6] << 8) | ((uint64_t) buf[7] << 0);
+  return result;
+}
+
+static void
+hal_gdb_fileio_unpack_stat (unsigned char *buf,
+			    struct hal_gdb_fileio_stat *stat)
+{
+  stat->st_dev = hal_gdb_fileio_unpack32 (buf + 0);
+  stat->st_ino = hal_gdb_fileio_unpack32 (buf + 4);
+  stat->st_mode = hal_gdb_fileio_unpack32 (buf + 8);
+  stat->st_nlink = hal_gdb_fileio_unpack32 (buf + 12);
+  stat->st_uid = hal_gdb_fileio_unpack32 (buf + 16);
+  stat->st_gid = hal_gdb_fileio_unpack32 (buf + 20);
+  stat->st_rdev = hal_gdb_fileio_unpack32 (buf + 24);
+  stat->st_size = hal_gdb_fileio_unpack64 (buf + 28);
+  stat->st_blksize = hal_gdb_fileio_unpack64 (buf + 36);
+  stat->st_blocks = hal_gdb_fileio_unpack64 (buf + 44);
+  stat->st_atime = hal_gdb_fileio_unpack32 (buf + 52);
+  stat->st_mtime = hal_gdb_fileio_unpack32 (buf + 56);
+  stat->st_ctime = hal_gdb_fileio_unpack32 (buf + 60);
+}
+
+int
+hal_gdb_fileio_stat (const char *path, struct hal_gdb_fileio_stat *stat)
+{
+  int result;
+  // There is a choice here between 64 bytes of extra stack space or
+  // 64 bytes of static data protected within the lock.
+  unsigned char buf[64];
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_STAT;
+  _gdb_hwdebug_request.data.d_stat.path = path;
+  _gdb_hwdebug_request.data.d_stat.pathlen = strlen (path) + 1;
+  _gdb_hwdebug_request.data.d_stat.buf = buf;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  if (HAL_GDB_FILEIO_ENOERR == result)
+    {
+      hal_gdb_fileio_unpack_stat (buf, stat);
+    }
+  return result;
+}
+
+int
+hal_gdb_fileio_fstat (int fd, struct hal_gdb_fileio_stat * stat)
+{
+  int result;
+  unsigned char buf[64];
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_FSTAT;
+  _gdb_hwdebug_request.data.d_fstat.fd = fd;
+  _gdb_hwdebug_request.data.d_fstat.buf = buf;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  if (HAL_GDB_FILEIO_ENOERR == result)
+    {
+      hal_gdb_fileio_unpack_stat (buf, stat);
+    }
+  return result;
+}
+
+int
+hal_gdb_fileio_gettimeofday (struct hal_gdb_fileio_timeval * tv, void *tz)
+{
+  unsigned char buf[12];
+  int result;
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_GETTIMEOFDAY;
+  _gdb_hwdebug_request.data.d_gettimeofday.tv = buf;
+  _gdb_hwdebug_request.data.d_gettimeofday.tz = tz;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  if (HAL_GDB_FILEIO_ENOERR == result)
+    {
+      tv->tv_sec = hal_gdb_fileio_unpack32 (buf);
+      tv->tv_usec = hal_gdb_fileio_unpack64 (&(buf[4]));
+    }
+  return result;
+}
+
+int
+hal_gdb_fileio_isatty (int fd)
+{
+  int result;
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_ISATTY;
+  _gdb_hwdebug_request.data.d_isatty.fd = fd;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  return result;
+}
+
+int
+hal_gdb_fileio_system (const char *command)
+{
+  int result;
+  HAL_GDB_HWDEBUG_LOCK ();
+  _gdb_hwdebug_request.op = HAL_GDB_FILEIO_SYSTEM;
+  _gdb_hwdebug_request.data.d_system.command = command;
+  _gdb_hwdebug_request.data.d_system.commandlen = strlen (command) + 1;
+  result = _gdb_hwdebug_call ();
+  HAL_GDB_HWDEBUG_UNLOCK ();
+  return result;
+}
+
+/* ----------------------------------------------------------------------------
+   Basic test code. */
+
+#define TEST1   "/tmp/gdb_fio.tst"
+#define TEST2   "/tmp/gdb_fio2.tst"
+#define BUFSIZE 512
+static unsigned char testbuf1[BUFSIZE];
+static unsigned char testbuf2[BUFSIZE];
+
+int
+main (int argc, char **argv)
+{
+  struct hal_gdb_fileio_timeval tv;
+  struct hal_gdb_fileio_stat stat;
+  char *msg = "console message: Hello world.\n";
+  int result;
+  int i;
+  int fd;
+
+  printf ("Testing GDB file I/O support.\n");
+  result = hal_gdb_fileio_write (HAL_GDB_FILEIO_STDOUT, msg, strlen (msg));
+  if (result != strlen (msg))
+    {
+      fprintf (stderr, "FAIL: write to stdout unsuccessful.\n");
+      exit (EXIT_FAILURE);
+    }
+
+  result = hal_gdb_fileio_gettimeofday (&tv, NULL);
+  if (-HAL_GDB_FILEIO_ENOSYS == result)
+    {
+      fprintf (stderr, "FAIL: file I/O support is disabled.\n");
+      exit (EXIT_FAILURE);
+    }
+  // Show that time is monotonically increasing.
+  for (i = 0; i < 10; i++)
+    {
+      result = hal_gdb_fileio_gettimeofday (&tv, NULL);
+      if (-HAL_GDB_FILEIO_ENOERR != result)
+	{
+	  fprintf (stderr,
+		   "FAIL: unexpected result %d from gettimeofday().\n",
+		   result);
+	  exit (EXIT_FAILURE);
+	}
+      printf ("Read time: tv_sec %d, tv_usec %d\n", tv.tv_sec, tv.tv_usec);
+    }
+
+  // Look for a file that probably exists.
+  result = hal_gdb_fileio_stat ("/etc/motd", &stat);
+  if (-HAL_GDB_FILEIO_ENOENT == result)
+    {
+      printf ("WARNING: tried to stat \"/etc/motd\": no such file.\n");
+    }
+  else if (HAL_GDB_FILEIO_ENOERR != result)
+    {
+      fprintf (stderr,
+	       "FAIL: unexpected result %d calling stat(\"/etc/motd\", );\n",
+	       result);
+      exit (EXIT_FAILURE);
+    }
+  else
+    {
+      printf ("stat on /etc/motd\n");
+      printf ("  st_dev %#x, st_ino %#x, st_mode %#x, st_nlink %#x\n",
+	      (int) stat.st_dev, (int) stat.st_ino,
+	      (int) stat.st_mode, (int) stat.st_nlink);
+      printf ("  st_uid %#x, st_gid %#x, st_rdev %#x\n",
+	      (int) stat.st_uid, (int) stat.st_gid, (int) stat.st_rdev);
+      printf ("  st_size %lld, st_blksize %lld, st_blocks %lld\n",
+	      (long long) stat.st_size, (long long) stat.st_blksize,
+	      (long long) stat.st_blocks);
+      printf ("  st_atime %#x, st_mtime %#x, st_ctime %#x\n",
+	      (int) stat.st_atime, (int) stat.st_mtime, (int) stat.st_ctime);
+
+      fd = hal_gdb_fileio_open ("/etc/motd", -HAL_GDB_FILEIO_O_RDONLY, 0);
+      if (fd < 0)
+	{
+	  printf ("WARNING: unable to open(\"/etc/motd\", );\n");
+	}
+      else
+	{
+	  result = hal_gdb_fileio_fstat (fd, &stat);
+	  if (result != HAL_GDB_FILEIO_ENOERR)
+	    {
+	      fprintf (stderr,
+		       "FAIL: unexpected result %d calling fstat() for \"/etc/motd\".\n",
+		       result);
+	      exit (EXIT_FAILURE);
+	    }
+	  else
+	    {
+	      printf ("fstat on /etc/motd\n");
+	      printf ("  st_dev %#x, st_ino %#x, st_mode %#x, st_nlink %#x\n",
+		      (int) stat.st_dev, (int) stat.st_ino,
+		      (int) stat.st_mode, (int) stat.st_nlink);
+	      printf ("  st_uid %#x, st_gid %#x, st_rdev %#x\n",
+		      (int) stat.st_uid, (int) stat.st_gid,
+		      (int) stat.st_rdev);
+	      printf ("  st_size %lld, st_blksize %lld, st_blocks %lld\n",
+		      (long long) stat.st_size, (long long) stat.st_blksize,
+		      (long long) stat.st_blocks);
+	      printf ("  st_atime %#x, st_mtime %#x, st_ctime %#x\n",
+		      (int) stat.st_atime, (int) stat.st_mtime,
+		      (int) stat.st_ctime);
+	    }
+	  result = hal_gdb_fileio_close (fd);
+	  if (result != HAL_GDB_FILEIO_ENOERR)
+	    {
+	      fprintf (stderr,
+		       "FAIL: unexpected result %d closing \"/etc/motd\".\n",
+		       result);
+	      exit (EXIT_FAILURE);
+	    }
+	}
+    }
+
+  result = hal_gdb_fileio_stat (TEST1, &stat);
+  if (result != -HAL_GDB_FILEIO_ENOENT)
+    {
+      fprintf (stderr, "Cannot proceed: file " TEST1 " already exists.\n");
+      exit (EXIT_FAILURE);
+    }
+  result = hal_gdb_fileio_stat (TEST2, &stat);
+  if (result != -HAL_GDB_FILEIO_ENOENT)
+    {
+      fprintf (stderr, "Cannot proceed: file " TEST2 " already exists.\n");
+      exit (EXIT_FAILURE);
+    }
+  fd = hal_gdb_fileio_open (TEST1,
+			    HAL_GDB_FILEIO_O_WRONLY | HAL_GDB_FILEIO_O_CREAT,
+			    HAL_GDB_FILEIO_S_IRUSR | HAL_GDB_FILEIO_S_IWUSR);
+  if (fd < 0)
+    {
+      fprintf (stderr,
+	       "FAIL: unexpected error %d creating new file " TEST1 ".\n",
+	       fd);
+      exit (EXIT_FAILURE);
+    }
+  result = hal_gdb_fileio_isatty (fd);
+  if (result < 0)
+    {
+      fprintf (stderr,
+	       "FAIL: unexpected error %d calling isatty() on " TEST1 ".\n",
+	       result);
+    }
+  else if (result)
+    {
+      fprintf (stderr,
+	       "FAIL: isatty() failed, claims file " TEST1 " is a tty.\n");
+    }
+  result = hal_gdb_fileio_isatty (1);
+  if (result < 0)
+    {
+      fprintf (stderr,
+	       "FAIL: unexpected error %d calling isatty() on  stdout.\n",
+	       result);
+    }
+  else if (!result)
+    {
+      fprintf (stderr,
+	       "FAIL: isatty() failed, claims stdout is not a tty.\n");
+    }
+
+  for (i = 0; i < BUFSIZE; i++)
+    {
+      testbuf1[i] = (unsigned char) (i & 0x00FF);
+    }
+  result = hal_gdb_fileio_write (fd, testbuf1, BUFSIZE);
+  if (BUFSIZE != result)
+    {
+      fprintf (stderr,
+	       "FAIL: tried to write %d bytes to " TEST1 ", result %d.\n",
+	       BUFSIZE, result);
+      exit (EXIT_FAILURE);
+    }
+  result = hal_gdb_fileio_close (fd);
+  if (HAL_GDB_FILEIO_ENOERR != result)
+    {
+      fprintf (stderr, "FAIL: unexpected error %d calling close().\n",
+	       result);
+      exit (EXIT_FAILURE);
+    }
+  result = hal_gdb_fileio_stat (TEST1, &stat);
+  if (result < 0)
+    {
+      fprintf (stderr, "FAIL: stat(\"" TEST1 "\") failed with %d.\n", result);
+      exit (EXIT_FAILURE);
+    }
+  if (BUFSIZE != stat.st_size)
+    {
+      fprintf (stderr, "FAIL: " TEST1 " should be %d bytes, not %lld.\n",
+	       BUFSIZE, stat.st_size);
+      exit (EXIT_FAILURE);
+    }
+
+  fd = hal_gdb_fileio_open (TEST1, HAL_GDB_FILEIO_O_RDONLY, 0);
+  if (fd < 0)
+    {
+      fprintf (stderr,
+	       "FAIL: failed to open " TEST1 " read-only, result %d.\n", fd);
+      exit (EXIT_FAILURE);
+    }
+  result = hal_gdb_fileio_read (fd, testbuf2, BUFSIZE);
+  if (BUFSIZE != result)
+    {
+      fprintf (stderr,
+	       "FAIL: tried to read %d bytes from " TEST1 ", result %d.\n",
+	       BUFSIZE, result);
+      exit (EXIT_FAILURE);
+    }
+  for (i = 0; i < BUFSIZE; i++)
+    {
+      if (testbuf1[i] != testbuf2[i])
+	{
+	  fprintf (stderr,
+		   "FAIL: discrepancy @ offset %d in " TEST1
+		   ", expected %#x, got %#x.\n", i, testbuf1[i], testbuf2[i]);
+	  exit (EXIT_FAILURE);
+	}
+    }
+  result = hal_gdb_fileio_lseek (fd, BUFSIZE / 2, HAL_GDB_FILEIO_SEEK_SET);
+  if (result < 0)
+    {
+      fprintf (stderr, "FAIL: unexpected result %d from lseek.\n", result);
+      exit (EXIT_FAILURE);
+    }
+  else if (result != (BUFSIZE / 2))
+    {
+      fprintf (stderr,
+	       "FAIL: unexpected position %d from lseek, should be %d.\n",
+	       result, BUFSIZE / 2);
+      exit (EXIT_FAILURE);
+    }
+  hal_gdb_fileio_close (fd);
+
+  result = hal_gdb_fileio_rename (TEST1, TEST2);
+  if (result < 0)
+    {
+      fprintf (stderr,
+	       "FAIL: rename from " TEST1 " to " TEST2 " failed with %d.\n",
+	       result);
+      exit (EXIT_FAILURE);
+    }
+  result = hal_gdb_fileio_unlink (TEST2);
+  if (result < 0)
+    {
+      fprintf (stderr, "FAIL: unlink for " TEST2 " failed with %d.\n",
+	       result);
+      exit (EXIT_FAILURE);
+    }
+  printf ("I/O operations successful.\n");
+
+  // This may or may not succeed, depending on the system-call-allowed flag
+  result = hal_gdb_fileio_system ("cat /etc/motd");
+  if (result == -HAL_GDB_FILEIO_EPERM)
+    {
+      printf
+	("system() call failed, gdb's remote system-call-allowed flag is not set.\n");
+    }
+  else if (result < 0)
+    {
+      fprintf (stderr, "system() call failed with unexpected result %d.\n",
+	       result);
+    }
+  else
+    {
+      printf ("system() call succeeded.\n");
+    }
+
+  return EXIT_SUCCESS;
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]