2004-02-15 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / target.c
index 9559914b7757b4b52d27acd0f97db8c565c4b1a1..ff47ac13bf711e54bfd8d31b478e22451032f0ac 100644 (file)
@@ -1,7 +1,7 @@
 /* Select target systems and architectures at runtime for GDB.
 
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
    Contributed by Cygnus Support.
 
@@ -36,8 +36,8 @@
 #include "dcache.h"
 #include <signal.h>
 #include "regcache.h"
-
-extern int errno;
+#include "gdb_assert.h"
+#include "gdbcore.h"
 
 static void target_info (char *, int);
 
@@ -71,7 +71,11 @@ static struct target_ops *find_default_run_target (char *);
 
 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
@@ -159,8 +163,6 @@ static int debug_to_thread_alive (ptid_t);
 
 static void debug_to_stop (void);
 
-static int debug_to_query (int /*char */ , char *, char *, int *);
-
 /* Pointer to array of target architecture structures; the size of the
    array; the current index into the array; the allocated size of the 
    array.  */
@@ -215,6 +217,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;
@@ -422,7 +428,7 @@ update_current_target (void)
       INHERIT (to_pid_to_str, t);
       INHERIT (to_extra_thread_info, t);
       INHERIT (to_stop, t);
-      INHERIT (to_query, t);
+      /* Do not inherit to_xfer_partial.  */
       INHERIT (to_rcmd, t);
       INHERIT (to_enable_exception_callback, t);
       INHERIT (to_get_current_exception_event, t);
@@ -448,8 +454,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)               \
@@ -604,6 +610,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);
@@ -675,8 +682,7 @@ push_target (struct target_ops *t)
       struct target_ops *tmp = (*cur);
       (*cur) = (*cur)->beneath;
       tmp->beneath = NULL;
-      if (tmp->to_close)
-       (tmp->to_close) (0);
+      target_close (tmp, 0);
     }
 
   /* We have removed all targets in our stratum, now add the new one.  */
@@ -701,9 +707,6 @@ unpush_target (struct target_ops *t)
   struct target_ops **cur;
   struct target_ops *tmp;
 
-  if (t->to_close)
-    t->to_close (0);           /* Let it clean up */
-
   /* Look for the specified target.  Note that we assume that a target
      can only occur once in the target stack. */
 
@@ -716,6 +719,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;
@@ -729,7 +740,7 @@ unpush_target (struct target_ops *t)
 void
 pop_target (void)
 {
-  (current_target.to_close) (0);       /* Let it clean up */
+  target_close (&current_target, 0);   /* Let it clean up */
   if (unpush_target (target_stack) == 1)
     return;
 
@@ -815,6 +826,21 @@ done:
   return nbytes_read;
 }
 
+/* Find a section containing ADDR.  */
+struct section_table *
+target_section_by_addr (struct target_ops *target, CORE_ADDR addr)
+{
+  struct section_table *secp;
+  for (secp = target->to_sections;
+       secp < target->to_sections_end;
+       secp++)
+    {
+      if (addr >= secp->addr && addr < secp->endaddr)
+       return secp;
+    }
+  return NULL;
+}
+
 /* Read LEN bytes of target memory at address MEMADDR, placing the results in
    GDB's memory at MYADDR.  Returns either 0 for success or an errno value
    if any error occurs.
@@ -862,22 +888,15 @@ do_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
 
   if (!write && trust_readonly)
     {
+      struct section_table *secp;
       /* User-settable option, "trust-readonly-sections".  If true,
          then memory from any SEC_READONLY bfd section may be read
-         directly from the bfd file. */
-
-      struct section_table *secp;
-
-      for (secp = current_target.to_sections;
-          secp < current_target.to_sections_end;
-          secp++)
-       {
-         if (bfd_get_section_flags (secp->bfd, secp->the_bfd_section) 
-             & SEC_READONLY)
-           if (memaddr >= secp->addr && memaddr < secp->endaddr)
-             return xfer_memory (memaddr, myaddr, len, 0, 
-                                 attrib, &current_target);
-       }
+         directly from the bfd file.  */
+      secp = target_section_by_addr (&current_target, memaddr);
+      if (secp != NULL
+         && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
+             & SEC_READONLY))
+       return xfer_memory (memaddr, myaddr, len, 0, attrib, &current_target);
     }
 
   /* The quick case is that the top target can handle the transfer.  */
@@ -1056,6 +1075,141 @@ target_write_memory_partial (CORE_ADDR memaddr, char *buf, int len, int *err)
   return target_xfer_memory_partial (memaddr, buf, len, 1, 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)
+{
+  gdb_assert (ops->to_xfer_partial != NULL);
+  return ops->to_xfer_partial (ops, object, annex, buf, NULL, offset, len);
+}
+
+LONGEST
+target_write_partial (struct target_ops *ops,
+                     enum target_object object,
+                     const char *annex, const void *buf,
+                     ULONGEST offset, LONGEST 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.  */
+LONGEST
+target_read (struct target_ops *ops,
+            enum target_object object,
+            const char *annex, void *buf,
+            ULONGEST offset, LONGEST len)
+{
+  LONGEST xfered = 0;
+  while (xfered < len)
+    {
+      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)
+       /* Call memory_error?  */
+       return -1;
+      xfered += xfer;
+      QUIT;
+    }
+  return len;
+}
+
+LONGEST
+target_write (struct target_ops *ops,
+             enum target_object object,
+             const char *annex, const void *buf,
+             ULONGEST offset, LONGEST len)
+{
+  LONGEST xfered = 0;
+  while (xfered < len)
+    {
+      LONGEST xfer = target_write_partial (ops, object, annex,
+                                          (bfd_byte *) buf + xfered,
+                                          offset + xfered, len - xfered);
+      /* Call an observer, notifying them of the xfer progress?  */
+      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)
 {
@@ -1134,7 +1288,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)
@@ -1206,7 +1360,7 @@ find_default_create_inferior (char *exec_file, char *allargs, char **env)
 static int
 default_region_size_ok_for_hw_watchpoint (int byte_count)
 {
-  return (byte_count <= DEPRECATED_REGISTER_SIZE);
+  return (byte_count <= TYPE_LENGTH (builtin_type_void_data_ptr));
 }
 
 static int
@@ -1447,24 +1601,6 @@ normal_pid_to_str (ptid_t ptid)
   return buf;
 }
 
-/* Some targets (such as ttrace-based HPUX) don't allow us to request
-   notification of inferior events such as fork and vork immediately
-   after the inferior is created.  (This because of how gdb gets an
-   inferior created via invoking a shell to do it.  In such a scenario,
-   if the shell init file has commands in it, the shell will fork and
-   exec for each of those commands, and we will see each such fork
-   event.  Very bad.)
-
-   This function is used by all targets that allow us to request
-   notification of forks, etc at inferior creation time; e.g., in
-   target_acknowledge_forked_child.
- */
-static void
-normal_target_post_startup_inferior (ptid_t ptid)
-{
-  /* This space intentionally left blank. */
-}
-
 /* Error-catcher for target_find_memory_regions */
 static int dummy_find_memory_regions (int (*ignore1) (), void *ignore2)
 {
@@ -1494,6 +1630,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
@@ -1511,11 +1648,19 @@ debug_to_open (char *args, int from_tty)
 static void
 debug_to_close (int quitting)
 {
-  debug_target.to_close (quitting);
-
+  target_close (&debug_target, quitting);
   fprintf_unfiltered (gdb_stdlog, "target_close (%d)\n", quitting);
 }
 
+void
+target_close (struct target_ops *targ, int quitting)
+{
+  if (targ->to_xclose != NULL)
+    targ->to_xclose (targ, quitting);
+  else if (targ->to_close != NULL)
+    targ->to_close (quitting);
+}
+
 static void
 debug_to_attach (char *args, int from_tty)
 {
@@ -2128,14 +2273,21 @@ debug_to_stop (void)
   fprintf_unfiltered (gdb_stdlog, "target_stop ()\n");
 }
 
-static int
-debug_to_query (int type, char *req, char *resp, int *siz)
+static LONGEST
+debug_to_xfer_partial (struct target_ops *ops, enum target_object object,
+                      const char *annex, void *readbuf, const void *writebuf,
+                      ULONGEST offset, LONGEST len)
 {
-  int retval;
+  LONGEST retval;
 
-  retval = debug_target.to_query (type, req, resp, siz);
+  retval = debug_target.to_xfer_partial (&debug_target, object, annex,
+                                        readbuf, writebuf, offset, len);
 
-  fprintf_unfiltered (gdb_stdlog, "target_query (%c, %s, %s,  %d) = %d\n", type, req, resp, *siz, retval);
+  fprintf_unfiltered (gdb_stdlog,
+                     "target_xfer_partial (%d, %s, 0x%lx,  0x%lx,  0x%s, %s) = %s\n",
+                     (int) object, (annex ? annex : "(null)"),
+                     (long) readbuf, (long) writebuf, paddr_nz (offset),
+                     paddr_d (len), paddr_d (retval));
 
   return retval;
 }
@@ -2237,7 +2389,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_query = debug_to_query;
+  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.05702 seconds and 4 git commands to generate.