2004-01-17 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / target.c
index 2677fb3f92c956df433838156113f3dc7664a10e..cc3b747d4b8cc930fcfcbf2820a4640115fa80bb 100644 (file)
@@ -36,6 +36,8 @@
 #include "dcache.h"
 #include <signal.h>
 #include "regcache.h"
+#include "gdb_assert.h"
+#include "gdbcore.h"
 
 static void target_info (char *, int);
 
@@ -71,6 +73,12 @@ static void nosupport_runtime (void);
 
 static void normal_target_post_startup_inferior (ptid_t ptid);
 
+static LONGEST default_xfer_partial (struct target_ops *ops,
+                                    enum target_object object,
+                                    const char *annex, void *readbuf,
+                                    const void *writebuf,
+                                    ULONGEST offset, LONGEST len);
+
 /* Transfer LEN bytes between target address MEMADDR and GDB address
    MYADDR.  Returns 0 for success, errno code for failure (which
    includes partial transfers -- if you want a more useful response to
@@ -211,6 +219,10 @@ target_command (char *arg, int from_tty)
 void
 add_target (struct target_ops *t)
 {
+  /* Provide default values for all "must have" methods.  */
+  if (t->to_xfer_partial == NULL)
+    t->to_xfer_partial = default_xfer_partial;
+
   if (!target_structs)
     {
       target_struct_allocsize = DEFAULT_ALLOCSIZE;
@@ -418,8 +430,7 @@ update_current_target (void)
       INHERIT (to_pid_to_str, t);
       INHERIT (to_extra_thread_info, t);
       INHERIT (to_stop, t);
-      /* Do not inherit to_read_partial.  */
-      /* Do not inherit to_write_partial.  */
+      /* Do not inherit to_xfer_partial.  */
       INHERIT (to_rcmd, t);
       INHERIT (to_enable_exception_callback, t);
       INHERIT (to_get_current_exception_event, t);
@@ -445,8 +456,8 @@ update_current_target (void)
 #undef INHERIT
 
   /* Clean up a target struct so it no longer has any zero pointers in
-     it.  We default entries, at least to stubs that print error
-     messages.  */
+     it.  Some entries are defaulted to a method that print an error,
+     others are hard-wired to a standard recursive default.  */
 
 #define de_fault(field, value) \
   if (!current_target.field)               \
@@ -601,6 +612,7 @@ update_current_target (void)
   de_fault (to_stop, 
            (void (*) (void)) 
            target_ignore);
+  current_target.to_xfer_partial = default_xfer_partial;
   de_fault (to_rcmd, 
            (void (*) (char *, struct ui_file *)) 
            tcomplain);
@@ -697,8 +709,6 @@ unpush_target (struct target_ops *t)
   struct target_ops **cur;
   struct target_ops *tmp;
 
-  target_close (t, 0);
-
   /* Look for the specified target.  Note that we assume that a target
      can only occur once in the target stack. */
 
@@ -711,6 +721,14 @@ unpush_target (struct target_ops *t)
   if ((*cur) == NULL)
     return 0;                  /* Didn't find target_ops, quit now */
 
+  /* NOTE: cagney/2003-12-06: In '94 the close call was made
+     unconditional by moving it to before the above check that the
+     target was in the target stack (something about "Change the way
+     pushing and popping of targets work to support target overlays
+     and inheritance").  This doesn't make much sense - only open
+     targets should be closed.  */
+  target_close (t, 0);
+
   /* Unchain the target */
   tmp = (*cur);
   (*cur) = (*cur)->beneath;
@@ -1061,24 +1079,60 @@ target_write_memory_partial (CORE_ADDR memaddr, char *buf, int len, int *err)
 
 /* More generic transfers.  */
 
+static LONGEST
+default_xfer_partial (struct target_ops *ops, enum target_object object,
+                     const char *annex, void *readbuf, 
+                     const void *writebuf, ULONGEST offset, LONGEST len)
+{
+  if (object == TARGET_OBJECT_MEMORY
+      && ops->to_xfer_memory != NULL)
+    /* If available, fall back to the target's "to_xfer_memory"
+       method.  */
+    {
+      int xfered = -1;
+      errno = 0;
+      if (writebuf != NULL)
+       {
+         void *buffer = xmalloc (len);
+         struct cleanup *cleanup = make_cleanup (xfree, buffer);
+         memcpy (buffer, writebuf, len);
+         xfered = ops->to_xfer_memory (offset, buffer, len, 1/*write*/, NULL,
+                                       ops);
+         do_cleanups (cleanup);
+       }
+      if (readbuf != NULL)
+       xfered = ops->to_xfer_memory (offset, readbuf, len, 0/*read*/, NULL,
+                                     ops);
+      if (xfered > 0)
+       return xfered;
+      else if (xfered == 0 && errno == 0)
+       /* "to_xfer_memory" uses 0, cross checked against ERRNO as one
+           indication of an error.  */
+       return 0;
+      else
+       return -1;
+    }
+  else if (ops->beneath != NULL)
+    return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+                                         readbuf, writebuf, offset, len);
+  else
+    return -1;
+}
+
+/* Target vector read/write partial wrapper functions.
+
+   NOTE: cagney/2003-10-21: I wonder if having "to_xfer_partial
+   (inbuf, outbuf)", instead of separate read/write methods, make life
+   easier.  */
+
 LONGEST
 target_read_partial (struct target_ops *ops,
                     enum target_object object,
                     const char *annex, void *buf,
                     ULONGEST offset, LONGEST len)
 {
-  struct target_ops *op;
-
-  /* Find the first target stratum that can handle the request.  */
-  for (op = ops;
-       op != NULL && op->to_read_partial == NULL;
-       op = op->beneath)
-    ;
-  if (op == NULL)
-    return -1;
-  
-  /* Now apply the operation at that level.  */
-  return op->to_read_partial (op, object, annex, buf, offset, len);
+  gdb_assert (ops->to_xfer_partial != NULL);
+  return ops->to_xfer_partial (ops, object, annex, buf, NULL, offset, len);
 }
 
 LONGEST
@@ -1087,17 +1141,8 @@ target_write_partial (struct target_ops *ops,
                      const char *annex, const void *buf,
                      ULONGEST offset, LONGEST len)
 {
-  struct target_ops *op;
-
-  /* Find the first target stratum that can handle the request.  */
-  for (op = ops;
-       op != NULL && op->to_write_partial == NULL;
-       op = op->beneath)
-    ;
-  if (op == NULL)
-    return -1;
-  
-  return op->to_write_partial (op, object, annex, buf, offset, len);
+  gdb_assert (ops->to_xfer_partial != NULL);
+  return ops->to_xfer_partial (ops, object, annex, NULL, buf, offset, len);
 }
 
 /* Wrappers to perform the full transfer.  */
@@ -1110,12 +1155,13 @@ target_read (struct target_ops *ops,
   LONGEST xfered = 0;
   while (xfered < len)
     {
-      LONGEST xfer = target_write_partial (ops, object, annex,
-                                          (bfd_byte *) buf + xfered,
-                                          offset + xfered, len - xfered);
+      LONGEST xfer = target_read_partial (ops, object, annex,
+                                         (bfd_byte *) buf + xfered,
+                                         offset + xfered, len - xfered);
       /* Call an observer, notifying them of the xfer progress?  */
-      if (xfer < 0)
-       return xfer;
+      if (xfer <= 0)
+       /* Call memory_error?  */
+       return -1;
       xfered += xfer;
       QUIT;
     }
@@ -1135,14 +1181,37 @@ target_write (struct target_ops *ops,
                                           (bfd_byte *) buf + xfered,
                                           offset + xfered, len - xfered);
       /* Call an observer, notifying them of the xfer progress?  */
-      if (xfer < 0)
-       return xfer;
+      if (xfer <= 0)
+       /* Call memory_error?  */
+       return -1;
       xfered += xfer;
       QUIT;
     }
   return len;
 }
 
+/* Memory transfer methods.  */
+
+void
+get_target_memory (struct target_ops *ops, CORE_ADDR addr, void *buf,
+                  LONGEST len)
+{
+  if (target_read (ops, TARGET_OBJECT_MEMORY, NULL, buf, addr, len)
+      != len)
+    memory_error (EIO, addr);
+}
+
+ULONGEST
+get_target_memory_unsigned (struct target_ops *ops,
+                           CORE_ADDR addr, int len)
+{
+  char buf[sizeof (ULONGEST)];
+
+  gdb_assert (len <= sizeof (buf));
+  get_target_memory (ops, addr, buf, len);
+  return extract_unsigned_integer (buf, len);
+}
+
 static void
 target_info (char *args, int from_tty)
 {
@@ -1221,7 +1290,7 @@ target_disconnect (char *args, int from_tty)
 void
 target_link (char *modname, CORE_ADDR *t_reloc)
 {
-  if (STREQ (current_target.to_shortname, "rombug"))
+  if (DEPRECATED_STREQ (current_target.to_shortname, "rombug"))
     {
       (current_target.to_lookup_symbol) (modname, t_reloc);
       if (*t_reloc == 0)
@@ -1581,6 +1650,7 @@ init_dummy_target (void)
   dummy_target.to_stratum = dummy_stratum;
   dummy_target.to_find_memory_regions = dummy_find_memory_regions;
   dummy_target.to_make_corefile_notes = dummy_make_corefile_notes;
+  dummy_target.to_xfer_partial = default_xfer_partial;
   dummy_target.to_magic = OPS_MAGIC;
 }
 \f
@@ -2224,40 +2294,19 @@ debug_to_stop (void)
 }
 
 static LONGEST
-debug_to_read_partial (struct target_ops *ops,
-                      enum target_object object,
-                      const char *annex, void *buf,
+debug_to_xfer_partial (struct target_ops *ops, enum target_object object,
+                      const char *annex, void *readbuf, const void *writebuf,
                       ULONGEST offset, LONGEST len)
 {
   LONGEST retval;
 
-  retval = target_read_partial (&debug_target, object, annex, buf, offset,
-                               len);
-
-  fprintf_unfiltered (gdb_stdlog,
-                     "target_read_partial (%d, %s, 0x%lx,  0x%s, %s) = %s\n",
-                     (int) object, (annex ? annex : "(null)"),
-                     (long) buf, paddr_nz (offset),
-                     paddr_d (len), paddr_d (retval));
-
-  return retval;
-}
-
-static LONGEST
-debug_to_write_partial (struct target_ops *ops,
-                       enum target_object object,
-                       const char *annex, const void *buf,
-                       ULONGEST offset, LONGEST len)
-{
-  LONGEST retval;
-
-  retval = target_write_partial (&debug_target, object, annex, buf, offset,
-                               len);
+  retval = debug_target.to_xfer_partial (&debug_target, object, annex,
+                                        readbuf, writebuf, offset, len);
 
   fprintf_unfiltered (gdb_stdlog,
-                     "target_write_partial (%d, %s, 0x%lx,  0x%s, %s) = %s\n",
+                     "target_xfer_partial (%d, %s, 0x%lx,  0x%lx,  0x%s, %s) = %s\n",
                      (int) object, (annex ? annex : "(null)"),
-                     (long) buf, paddr_nz (offset),
+                     (long) readbuf, (long) writebuf, paddr_nz (offset),
                      paddr_d (len), paddr_d (retval));
 
   return retval;
@@ -2360,8 +2409,7 @@ setup_target_debug (void)
   current_target.to_thread_alive = debug_to_thread_alive;
   current_target.to_find_new_threads = debug_to_find_new_threads;
   current_target.to_stop = debug_to_stop;
-  current_target.to_read_partial = debug_to_read_partial;
-  current_target.to_write_partial = debug_to_write_partial;
+  current_target.to_xfer_partial = debug_to_xfer_partial;
   current_target.to_rcmd = debug_to_rcmd;
   current_target.to_enable_exception_callback = debug_to_enable_exception_callback;
   current_target.to_get_current_exception_event = debug_to_get_current_exception_event;
This page took 0.028317 seconds and 4 git commands to generate.