Static tracepoints support, and UST integration.
[deliverable/binutils-gdb.git] / gdb / target.c
index 1ba8b3555a37af809700c103dfc3789071ec53df..7c9793db607fa039f82859116e8c0035fb67e2d4 100644 (file)
@@ -1,7 +1,7 @@
 /* Select target systems and architectures at runtime for GDB.
 
    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
    Contributed by Cygnus Support.
 #include "solib.h"
 #include "exec.h"
 #include "inline-frame.h"
+#include "tracepoint.h"
 
 static void target_info (char *, int);
 
-static void kill_or_be_killed (int);
-
 static void default_terminal_info (char *, int);
 
 static int default_watchpoint_addr_within_range (struct target_ops *,
@@ -57,7 +56,7 @@ static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int);
 
 static int nosymbol (char *, CORE_ADDR *);
 
-static void tcomplain (void) ATTR_NORETURN;
+static void tcomplain (void) ATTRIBUTE_NORETURN;
 
 static int nomemory (CORE_ADDR, char *, int, int, struct target_ops *);
 
@@ -73,8 +72,6 @@ static void target_command (char *, int);
 
 static struct target_ops *find_default_run_target (char *);
 
-static void nosupport_runtime (void);
-
 static LONGEST default_xfer_partial (struct target_ops *ops,
                                     enum target_object object,
                                     const char *annex, gdb_byte *readbuf,
@@ -198,6 +195,22 @@ static int trust_readonly = 0;
 
 static int show_memory_breakpoints = 0;
 
+/* These globals control whether GDB attempts to perform these
+   operations; they are useful for targets that need to prevent
+   inadvertant disruption, such as in non-stop mode.  */
+
+int may_write_registers = 1;
+
+int may_write_memory = 1;
+
+int may_insert_breakpoints = 1;
+
+int may_insert_tracepoints = 1;
+
+int may_insert_fast_tracepoints = 1;
+
+int may_stop = 1;
+
 /* Non-zero if we want to see trace of target level stuff.  */
 
 static int targetdebug = 0;
@@ -460,6 +473,7 @@ target_create_inferior (char *exec_file, char *args,
                        char **env, int from_tty)
 {
   struct target_ops *t;
+
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
       if (t->to_create_inferior != NULL)       
@@ -481,8 +495,10 @@ void
 target_terminal_inferior (void)
 {
   /* A background resume (``run&'') should leave GDB in control of the
-     terminal.  */
-  if (target_is_async_p () && !sync_execution)
+     terminal. Use target_can_async_p, not target_is_async_p, since at
+     this point the target is not async yet.  However, if sync_execution
+     is not set, we know it will become async prior to resume.  */
+  if (target_can_async_p () && !sync_execution)
     return;
 
   /* If GDB is resuming the inferior in the foreground, install
@@ -517,49 +533,12 @@ nosymbol (char *name, CORE_ADDR *addrp)
   return 1;                    /* Symbol does not exist in target env */
 }
 
-static void
-nosupport_runtime (void)
-{
-  if (ptid_equal (inferior_ptid, null_ptid))
-    noprocess ();
-  else
-    error (_("No run-time support for this"));
-}
-
-
 static void
 default_terminal_info (char *args, int from_tty)
 {
   printf_unfiltered (_("No saved terminal information.\n"));
 }
 
-/* This is the default target_create_inferior and target_attach function.
-   If the current target is executing, it asks whether to kill it off.
-   If this function returns without calling error(), it has killed off
-   the target, and the operation should be attempted.  */
-
-static void
-kill_or_be_killed (int from_tty)
-{
-  if (target_has_execution)
-    {
-      printf_unfiltered (_("You are already running a program:\n"));
-      target_files_info ();
-      if (query (_("Kill it? ")))
-       {
-         target_kill ();
-         if (target_has_execution)
-           error (_("Killing the program did not help."));
-         return;
-       }
-      else
-       {
-         error (_("Program not killed."));
-       }
-    }
-  tcomplain ();
-}
-
 /* A default implementation for the to_get_ada_task_ptid target method.
 
    This function builds the PTID by using both LWP and TID as part of
@@ -649,7 +628,7 @@ update_current_target (void)
       INHERIT (to_remove_exec_catchpoint, t);
       INHERIT (to_set_syscall_catchpoint, t);
       INHERIT (to_has_exited, t);
-      /* Do not inherit to_mourn_inferiour.  */
+      /* Do not inherit to_mourn_inferior.  */
       INHERIT (to_can_run, t);
       INHERIT (to_notice_signals, t);
       /* Do not inherit to_thread_alive.  */
@@ -674,6 +653,8 @@ update_current_target (void)
       INHERIT (to_async_mask, t);
       INHERIT (to_find_memory_regions, t);
       INHERIT (to_make_corefile_notes, t);
+      INHERIT (to_get_bookmark, t);
+      INHERIT (to_goto_bookmark, t);
       /* Do not inherit to_get_thread_local_address.  */
       INHERIT (to_can_execute_reverse, t);
       INHERIT (to_thread_architecture, t);
@@ -681,6 +662,25 @@ update_current_target (void)
       INHERIT (to_get_ada_task_ptid, t);
       /* Do not inherit to_search_memory.  */
       INHERIT (to_supports_multi_process, t);
+      INHERIT (to_trace_init, t);
+      INHERIT (to_download_tracepoint, t);
+      INHERIT (to_download_trace_state_variable, t);
+      INHERIT (to_trace_set_readonly_regions, t);
+      INHERIT (to_trace_start, t);
+      INHERIT (to_get_trace_status, t);
+      INHERIT (to_trace_stop, t);
+      INHERIT (to_trace_find, t);
+      INHERIT (to_get_trace_state_variable_value, t);
+      INHERIT (to_save_trace_data, t);
+      INHERIT (to_upload_tracepoints, t);
+      INHERIT (to_upload_trace_state_variables, t);
+      INHERIT (to_get_raw_trace_data, t);
+      INHERIT (to_set_disconnected_tracing, t);
+      INHERIT (to_set_circular_trace_buffer, t);
+      INHERIT (to_get_tib_address, t);
+      INHERIT (to_set_permissions, t);
+      INHERIT (to_static_tracepoint_marker_at, t);
+      INHERIT (to_static_tracepoint_markers_by_strid, t);
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -829,6 +829,63 @@ update_current_target (void)
   de_fault (to_supports_multi_process,
            (int (*) (void))
            return_zero);
+  de_fault (to_trace_init,
+           (void (*) (void))
+           tcomplain);
+  de_fault (to_download_tracepoint,
+           (void (*) (struct breakpoint *))
+           tcomplain);
+  de_fault (to_download_trace_state_variable,
+           (void (*) (struct trace_state_variable *))
+           tcomplain);
+  de_fault (to_trace_set_readonly_regions,
+           (void (*) (void))
+           tcomplain);
+  de_fault (to_trace_start,
+           (void (*) (void))
+           tcomplain);
+  de_fault (to_get_trace_status,
+           (int (*) (struct trace_status *))
+           return_minus_one);
+  de_fault (to_trace_stop,
+           (void (*) (void))
+           tcomplain);
+  de_fault (to_trace_find,
+           (int (*) (enum trace_find_type, int, ULONGEST, ULONGEST, int *))
+           return_minus_one);
+  de_fault (to_get_trace_state_variable_value,
+           (int (*) (int, LONGEST *))
+           return_zero);
+  de_fault (to_save_trace_data,
+           (int (*) (const char *))
+           tcomplain);
+  de_fault (to_upload_tracepoints,
+           (int (*) (struct uploaded_tp **))
+           return_zero);
+  de_fault (to_upload_trace_state_variables,
+           (int (*) (struct uploaded_tsv **))
+           return_zero);
+  de_fault (to_get_raw_trace_data,
+           (LONGEST (*) (gdb_byte *, ULONGEST, LONGEST))
+           tcomplain);
+  de_fault (to_set_disconnected_tracing,
+           (void (*) (int))
+           target_ignore);
+  de_fault (to_set_circular_trace_buffer,
+           (void (*) (int))
+           target_ignore);
+  de_fault (to_get_tib_address,
+           (int (*) (ptid_t, CORE_ADDR *))
+           tcomplain);
+  de_fault (to_set_permissions,
+           (void (*) (void))
+           target_ignore);
+  de_fault (to_static_tracepoint_marker_at,
+           (int (*) (CORE_ADDR, struct static_tracepoint_marker *))
+           return_zero);
+  de_fault (to_static_tracepoint_markers_by_strid,
+           (VEC(static_tracepoint_marker_p) * (*) (const char *))
+           tcomplain);
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
@@ -843,14 +900,11 @@ update_current_target (void)
 /* Push a new target type into the stack of the existing target accessors,
    possibly superseding some of the existing accessors.
 
-   Result is zero if the pushed target ended up on top of the stack,
-   nonzero if at least one target is on top of it.
-
    Rather than allow an empty stack, we always have the dummy target at
    the bottom stratum, so we can call the function vectors without
    checking them.  */
 
-int
+void
 push_target (struct target_ops *t)
 {
   struct target_ops **cur;
@@ -880,6 +934,7 @@ push_target (struct target_ops *t)
       /* There's already something at this stratum level.  Close it,
          and un-hook it from the stack.  */
       struct target_ops *tmp = (*cur);
+
       (*cur) = (*cur)->beneath;
       tmp->beneath = NULL;
       target_close (tmp, 0);
@@ -890,9 +945,6 @@ push_target (struct target_ops *t)
   (*cur) = t;
 
   update_current_target ();
-
-  /* Not on top?  */
-  return (t != target_stack);
 }
 
 /* Remove a target_ops vector from the stack, wherever it may be.
@@ -948,7 +1000,8 @@ pop_target (void)
   fprintf_unfiltered (gdb_stderr,
                      "pop_target couldn't find target %s\n",
                      current_target.to_shortname);
-  internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
+  internal_error (__FILE__, __LINE__,
+                 _("failed internal consistency check"));
 }
 
 void
@@ -1120,6 +1173,7 @@ target_read_string (CORE_ADDR memaddr, char **string, int len, int *errnop)
       if (bufptr - buffer + tlen > buffer_allocated)
        {
          unsigned int bytes;
+
          bytes = bufptr - buffer;
          buffer_allocated *= 2;
          buffer = xrealloc (buffer, buffer_allocated);
@@ -1181,8 +1235,8 @@ target_section_by_addr (struct target_ops *target, CORE_ADDR addr)
   return NULL;
 }
 
-/* Perform a partial memory transfer.  The arguments and return
-   value are just as for target_xfer_partial.  */
+/* Perform a partial memory transfer.
+   For docs see target.h, to_xfer_partial.  */
 
 static LONGEST
 memory_xfer_partial (struct target_ops *ops, enum target_object object,
@@ -1203,11 +1257,13 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
   if (readbuf != NULL && overlay_debugging)
     {
       struct obj_section *section = find_pc_overlay (memaddr);
+
       if (pc_in_unmapped_range (memaddr, section))
        {
          struct target_section_table *table
            = target_get_section_table (ops);
          const char *section_name = section->the_bfd_section->name;
+
          memaddr = overlay_mapped_address (memaddr, section);
          return section_table_xfer_memory_partial (readbuf, writebuf,
                                                    memaddr, len,
@@ -1267,9 +1323,16 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
       return -1;
     }
 
-  inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
+  if (!ptid_equal (inferior_ptid, null_ptid))
+    inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
+  else
+    inf = NULL;
 
   if (inf != NULL
+      /* The dcache reads whole cache lines; that doesn't play well
+        with reading from a trace buffer, because reading outside of
+        the collected memory range fails.  */
+      && get_traceframe_number () == -1
       && (region->attrib.cache
          || (stack_cache_enabled_p && object == TARGET_OBJECT_STACK_MEMORY)))
     {
@@ -1351,12 +1414,14 @@ struct cleanup *
 make_show_memory_breakpoints_cleanup (int show)
 {
   int current = show_memory_breakpoints;
-  show_memory_breakpoints = show;
 
+  show_memory_breakpoints = show;
   return make_cleanup (restore_show_memory_breakpoints,
                       (void *) (uintptr_t) current);
 }
 
+/* For docs see target.h, to_xfer_partial.  */
+
 static LONGEST
 target_xfer_partial (struct target_ops *ops,
                     enum target_object object, const char *annex,
@@ -1367,6 +1432,10 @@ target_xfer_partial (struct target_ops *ops,
 
   gdb_assert (ops->to_xfer_partial != NULL);
 
+  if (writebuf && !may_write_memory)
+    error (_("Writing to memory is not allowed (addr %s, len %s)"),
+          core_addr_to_string_nz (offset), plongest (len));
+
   /* If this is a memory transfer, let the memory-specific code
      have a look at it instead.  Memory transfers are more
      complicated.  */
@@ -1471,6 +1540,11 @@ target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
     return EIO;
 }
 
+/* Write LEN bytes from MYADDR to target memory at address MEMADDR.
+   Returns either 0 for success or an errno value if any error occurs.
+   If an error occurs, no guarantee is made about how much data got written.
+   Callers that can deal with partial writes should call target_write.  */
+
 int
 target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
 {
@@ -1539,13 +1613,13 @@ target_flash_erase (ULONGEST address, LONGEST length)
 
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     if (t->to_flash_erase != NULL)
-       {
-         if (targetdebug)
-           fprintf_unfiltered (gdb_stdlog, "target_flash_erase (%s, %s)\n",
-                                hex_string (address), phex (length, 0));
-         t->to_flash_erase (t, address, length);
-         return;
-       }
+      {
+       if (targetdebug)
+         fprintf_unfiltered (gdb_stdlog, "target_flash_erase (%s, %s)\n",
+                             hex_string (address), phex (length, 0));
+       t->to_flash_erase (t, address, length);
+       return;
+      }
 
   tcomplain ();
 }
@@ -1557,12 +1631,12 @@ target_flash_done (void)
 
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     if (t->to_flash_done != NULL)
-       {
-         if (targetdebug)
-           fprintf_unfiltered (gdb_stdlog, "target_flash_done\n");
-         t->to_flash_done (t);
-         return;
-       }
+      {
+       if (targetdebug)
+         fprintf_unfiltered (gdb_stdlog, "target_flash_done\n");
+       t->to_flash_done (t);
+       return;
+      }
 
   tcomplain ();
 }
@@ -1589,11 +1663,13 @@ default_xfer_partial (struct target_ops *ops, enum target_object object,
        "deprecated_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->deprecated_xfer_memory (offset, buffer, len,
                                                1/*write*/, NULL, ops);
@@ -1634,11 +1710,7 @@ current_xfer_partial (struct target_ops *ops, enum target_object object,
     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.  */
+/* Target vector read/write partial wrapper functions.  */
 
 static LONGEST
 target_read_partial (struct target_ops *ops,
@@ -1659,6 +1731,9 @@ target_write_partial (struct target_ops *ops,
 }
 
 /* Wrappers to perform the full transfer.  */
+
+/* For docs on target_read see target.h.  */
+
 LONGEST
 target_read (struct target_ops *ops,
             enum target_object object,
@@ -1666,11 +1741,13 @@ target_read (struct target_ops *ops,
             ULONGEST offset, LONGEST len)
 {
   LONGEST xfered = 0;
+
   while (xfered < len)
     {
       LONGEST xfer = target_read_partial (ops, object, annex,
                                          (gdb_byte *) buf + xfered,
                                          offset + xfered, len - xfered);
+
       /* Call an observer, notifying them of the xfer progress?  */
       if (xfer == 0)
        return xfered;
@@ -1689,11 +1766,13 @@ target_read_until_error (struct target_ops *ops,
                         ULONGEST offset, LONGEST len)
 {
   LONGEST xfered = 0;
+
   while (xfered < len)
     {
       LONGEST xfer = target_read_partial (ops, object, annex,
                                          (gdb_byte *) buf + xfered,
                                          offset + xfered, len - xfered);
+
       /* Call an observer, notifying them of the xfer progress?  */
       if (xfer == 0)
        return xfered;
@@ -1747,7 +1826,6 @@ target_read_until_error (struct target_ops *ops,
   return len;
 }
 
-
 /* An alternative to target_write with progress callbacks.  */
 
 LONGEST
@@ -1783,6 +1861,8 @@ target_write_with_progress (struct target_ops *ops,
   return len;
 }
 
+/* For docs on target_write see target.h.  */
+
 LONGEST
 target_write (struct target_ops *ops,
              enum target_object object,
@@ -1909,8 +1989,8 @@ get_target_memory (struct target_ops *ops, CORE_ADDR addr, gdb_byte *buf,
 }
 
 ULONGEST
-get_target_memory_unsigned (struct target_ops *ops,
-                           CORE_ADDR addr, int len, enum bfd_endian byte_order)
+get_target_memory_unsigned (struct target_ops *ops, CORE_ADDR addr,
+                           int len, enum bfd_endian byte_order)
 {
   gdb_byte buf[sizeof (ULONGEST)];
 
@@ -1919,6 +1999,36 @@ get_target_memory_unsigned (struct target_ops *ops,
   return extract_unsigned_integer (buf, len, byte_order);
 }
 
+int
+target_insert_breakpoint (struct gdbarch *gdbarch,
+                         struct bp_target_info *bp_tgt)
+{
+  if (!may_insert_breakpoints)
+    {
+      warning (_("May not insert breakpoints"));
+      return 1;
+    }
+
+  return (*current_target.to_insert_breakpoint) (gdbarch, bp_tgt);
+}
+
+int
+target_remove_breakpoint (struct gdbarch *gdbarch,
+                         struct bp_target_info *bp_tgt)
+{
+  /* This is kind of a weird case to handle, but the permission might
+     have been changed after breakpoints were inserted - in which case
+     we should just take the user literally and assume that any
+     breakpoints should be left in place.  */
+  if (!may_insert_breakpoints)
+    {
+      warning (_("May not remove breakpoints"));
+      return 1;
+    }
+
+  return (*current_target.to_remove_breakpoint) (gdbarch, bp_tgt);
+}
+
 static void
 target_info (char *args, int from_tty)
 {
@@ -2046,7 +2156,9 @@ target_detach (char *args, int from_tty)
   else
     /* If we're in breakpoints-always-inserted mode, have to remove
        them before detaching.  */
-    remove_breakpoints ();
+    remove_breakpoints_pid (PIDGET (inferior_ptid));
+
+  prepare_for_detach ();
 
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
@@ -2148,6 +2260,7 @@ target_resume (ptid_t ptid, int step, enum target_signal signal)
                                step ? "step" : "continue",
                                target_signal_to_name (signal));
 
+         registers_changed_ptid (ptid);
          set_executing (ptid, 1);
          set_running (ptid, 1);
          clear_inline_frame_state (ptid);
@@ -2170,6 +2283,7 @@ target_follow_fork (int follow_child)
       if (t->to_follow_fork != NULL)
        {
          int retval = t->to_follow_fork (t, follow_child);
+
          if (targetdebug)
            fprintf_unfiltered (gdb_stdlog, "target_follow_fork (%d) = %d\n",
                                follow_child, retval);
@@ -2186,6 +2300,7 @@ void
 target_mourn_inferior (void)
 {
   struct target_ops *t;
+
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
       if (t->to_mourn_inferior != NULL)        
@@ -2204,7 +2319,7 @@ target_mourn_inferior (void)
     }
 
   internal_error (__FILE__, __LINE__,
-                 "could not find a target to follow mourn inferiour");
+                 "could not find a target to follow mourn inferior");
 }
 
 /* Look for a target which can describe architectural features, starting
@@ -2286,6 +2401,7 @@ simple_search_memory (struct target_ops *ops,
       if (found_ptr != NULL)
        {
          CORE_ADDR found_addr = start_addr + (found_ptr - search_buf);
+
          *found_addrp = found_addr;
          do_cleanups (old_cleanups);
          return 1;
@@ -2302,7 +2418,7 @@ simple_search_memory (struct target_ops *ops,
       if (search_space_len >= pattern_len)
        {
          unsigned keep_len = search_buf_size - chunk_size;
-         CORE_ADDR read_addr = start_addr + keep_len;
+         CORE_ADDR read_addr = start_addr + chunk_size + keep_len;
          int nr_to_read;
 
          /* Copy the trailing part of the previous iteration to the front
@@ -2519,6 +2635,7 @@ int
 target_supports_non_stop (void)
 {
   struct target_ops *t;
+
   for (t = &current_target; t != NULL; t = t->beneath)
     if (t->to_supports_non_stop)
       return t->to_supports_non_stop ();
@@ -2530,7 +2647,6 @@ target_supports_non_stop (void)
 char *
 target_get_osdata (const char *type)
 {
-  char *document;
   struct target_ops *t;
 
   /* If we're already connected to something that can get us OS
@@ -2547,6 +2663,42 @@ target_get_osdata (const char *type)
   return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type);
 }
 
+/* Determine the current address space of thread PTID.  */
+
+struct address_space *
+target_thread_address_space (ptid_t ptid)
+{
+  struct address_space *aspace;
+  struct inferior *inf;
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    {
+      if (t->to_thread_address_space != NULL)
+       {
+         aspace = t->to_thread_address_space (t, ptid);
+         gdb_assert (aspace);
+
+         if (targetdebug)
+           fprintf_unfiltered (gdb_stdlog,
+                               "target_thread_address_space (%s) = %d\n",
+                               target_pid_to_str (ptid),
+                               address_space_num (aspace));
+         return aspace;
+       }
+    }
+
+  /* Fall-back to the "main" address space of the inferior.  */
+  inf = find_inferior_pid (ptid_get_pid (ptid));
+
+  if (inf == NULL || inf->aspace == NULL)
+    internal_error (__FILE__, __LINE__, "\
+Can't determine the current address space of thread %s\n",
+                   target_pid_to_str (ptid));
+
+  return inf->aspace;
+}
+
 static int
 default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 {
@@ -2658,7 +2810,7 @@ generic_mourn_inferior (void)
   if (!ptid_equal (ptid, null_ptid))
     {
       int pid = ptid_get_pid (ptid);
-      delete_inferior (pid);
+      exit_inferior (pid);
     }
 
   breakpoint_init_inferior (inf_exited);
@@ -2712,20 +2864,37 @@ dummy_pid_to_str (struct target_ops *ops, ptid_t ptid)
   return normal_pid_to_str (ptid);
 }
 
-/* Error-catcher for target_find_memory_regions */
-static int dummy_find_memory_regions (int (*ignore1) (), void *ignore2)
+/* Error-catcher for target_find_memory_regions.  */
+static int
+dummy_find_memory_regions (int (*ignore1) (), void *ignore2)
 {
-  error (_("No target."));
+  error (_("Command not implemented for this target."));
   return 0;
 }
 
-/* Error-catcher for target_make_corefile_notes */
-static char * dummy_make_corefile_notes (bfd *ignore1, int *ignore2)
+/* Error-catcher for target_make_corefile_notes.  */
+static char *
+dummy_make_corefile_notes (bfd *ignore1, int *ignore2)
 {
-  error (_("No target."));
+  error (_("Command not implemented for this target."));
   return NULL;
 }
 
+/* Error-catcher for target_get_bookmark.  */
+static gdb_byte *
+dummy_get_bookmark (char *ignore1, int ignore2)
+{
+  tcomplain ();
+  return NULL;
+}
+
+/* Error-catcher for target_goto_bookmark.  */
+static void
+dummy_goto_bookmark (gdb_byte *ignore, int from_tty)
+{
+  tcomplain ();
+}
+
 /* Set up the handful of non-empty slots needed by the dummy target
    vector.  */
 
@@ -2746,12 +2915,17 @@ 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_get_bookmark = dummy_get_bookmark;
+  dummy_target.to_goto_bookmark = dummy_goto_bookmark;
   dummy_target.to_xfer_partial = default_xfer_partial;
   dummy_target.to_has_all_memory = (int (*) (struct target_ops *)) return_zero;
   dummy_target.to_has_memory = (int (*) (struct target_ops *)) return_zero;
   dummy_target.to_has_stack = (int (*) (struct target_ops *)) return_zero;
   dummy_target.to_has_registers = (int (*) (struct target_ops *)) return_zero;
   dummy_target.to_has_execution = (int (*) (struct target_ops *)) return_zero;
+  dummy_target.to_stopped_by_watchpoint = return_zero;
+  dummy_target.to_stopped_data_address =
+    (int (*) (struct target_ops *, CORE_ADDR *)) return_zero;
   dummy_target.to_magic = OPS_MAGIC;
 }
 \f
@@ -2779,6 +2953,7 @@ void
 target_attach (char *args, int from_tty)
 {
   struct target_ops *t;
+
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
       if (t->to_attach != NULL)        
@@ -2799,6 +2974,7 @@ int
 target_thread_alive (ptid_t ptid)
 {
   struct target_ops *t;
+
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
       if (t->to_thread_alive != NULL)
@@ -2821,6 +2997,7 @@ void
 target_find_new_threads (void)
 {
   struct target_ops *t;
+
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
       if (t->to_find_new_threads != NULL)
@@ -2834,6 +3011,18 @@ target_find_new_threads (void)
     }
 }
 
+void
+target_stop (ptid_t ptid)
+{
+  if (!may_stop)
+    {
+      warning (_("May not interrupt or stop the target, ignoring attempt"));
+      return;
+    }
+
+  (*current_target.to_stop) (ptid);
+}
+
 static void
 debug_to_post_attach (int pid)
 {
@@ -2889,6 +3078,7 @@ debug_print_register (const char * func,
                      struct regcache *regcache, int regno)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
   fprintf_unfiltered (gdb_stdlog, "%s ", func);
   if (regno >= 0 && regno < gdbarch_num_regs (gdbarch)
       && gdbarch_register_name (gdbarch, regno) != NULL
@@ -2902,6 +3092,7 @@ debug_print_register (const char * func,
       enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
       int i, size = register_size (gdbarch, regno);
       unsigned char buf[MAX_REGISTER_SIZE];
+
       regcache_raw_collect (regcache, regno, buf);
       fprintf_unfiltered (gdb_stdlog, " = ");
       for (i = 0; i < size; i++)
@@ -2911,6 +3102,7 @@ debug_print_register (const char * func,
       if (size <= sizeof (LONGEST))
        {
          ULONGEST val = extract_unsigned_integer (buf, size, byte_order);
+
          fprintf_unfiltered (gdb_stdlog, " %s %s",
                              core_addr_to_string_nz (val), plongest (val));
        }
@@ -2922,6 +3114,7 @@ void
 target_fetch_registers (struct regcache *regcache, int regno)
 {
   struct target_ops *t;
+
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
       if (t->to_fetch_registers != NULL)
@@ -2937,8 +3130,11 @@ target_fetch_registers (struct regcache *regcache, int regno)
 void
 target_store_registers (struct regcache *regcache, int regno)
 {
-
   struct target_ops *t;
+
+  if (!may_write_registers)
+    error (_("Writing to registers is not allowed (regno %d)"), regno);
+
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
       if (t->to_store_registers != NULL)
@@ -2955,6 +3151,50 @@ target_store_registers (struct regcache *regcache, int regno)
   noprocess ();
 }
 
+int
+target_core_of_thread (ptid_t ptid)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    {
+      if (t->to_core_of_thread != NULL)
+       {
+         int retval = t->to_core_of_thread (t, ptid);
+
+         if (targetdebug)
+           fprintf_unfiltered (gdb_stdlog, "target_core_of_thread (%d) = %d\n",
+                               PIDGET (ptid), retval);
+         return retval;
+       }
+    }
+
+  return -1;
+}
+
+int
+target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    {
+      if (t->to_verify_memory != NULL)
+       {
+         int retval = t->to_verify_memory (t, data, memaddr, size);
+
+         if (targetdebug)
+           fprintf_unfiltered (gdb_stdlog, "target_verify_memory (%s, %s) = %d\n",
+                               paddress (target_gdbarch, memaddr),
+                               pulongest (size),
+                               retval);
+         return retval;
+       }
+    }
+
+  tcomplain ();
+}
+
 static void
 debug_to_prepare_to_store (struct regcache *regcache)
 {
@@ -3512,6 +3752,62 @@ show_maintenance_target_async_permitted (struct ui_file *file, int from_tty,
 Controlling the inferior in asynchronous mode is %s.\n"), value);
 }
 
+/* Temporary copies of permission settings.  */
+
+static int may_write_registers_1 = 1;
+static int may_write_memory_1 = 1;
+static int may_insert_breakpoints_1 = 1;
+static int may_insert_tracepoints_1 = 1;
+static int may_insert_fast_tracepoints_1 = 1;
+static int may_stop_1 = 1;
+
+/* Make the user-set values match the real values again.  */
+
+void
+update_target_permissions (void)
+{
+  may_write_registers_1 = may_write_registers;
+  may_write_memory_1 = may_write_memory;
+  may_insert_breakpoints_1 = may_insert_breakpoints;
+  may_insert_tracepoints_1 = may_insert_tracepoints;
+  may_insert_fast_tracepoints_1 = may_insert_fast_tracepoints;
+  may_stop_1 = may_stop;
+}
+
+/* The one function handles (most of) the permission flags in the same
+   way.  */
+
+static void
+set_target_permissions (char *args, int from_tty,
+                       struct cmd_list_element *c)
+{
+  if (target_has_execution)
+    {
+      update_target_permissions ();
+      error (_("Cannot change this setting while the inferior is running."));
+    }
+
+  /* Make the real values match the user-changed values.  */
+  may_write_registers = may_write_registers_1;
+  may_insert_breakpoints = may_insert_breakpoints_1;
+  may_insert_tracepoints = may_insert_tracepoints_1;
+  may_insert_fast_tracepoints = may_insert_fast_tracepoints_1;
+  may_stop = may_stop_1;
+  update_observer_mode ();
+}
+
+/* Set memory write permission independently of observer mode.  */
+
+static void
+set_write_memory_permission (char *args, int from_tty,
+                       struct cmd_list_element *c)
+{
+  /* Make the real values match the user-changed values.  */
+  may_write_memory = may_write_memory_1;
+  update_observer_mode ();
+}
+
+
 void
 initialize_targets (void)
 {
@@ -3570,5 +3866,60 @@ By default, caching for stack access is on."),
                           show_stack_cache_enabled_p,
                           &setlist, &showlist);
 
+  add_setshow_boolean_cmd ("may-write-registers", class_support,
+                          &may_write_registers_1, _("\
+Set permission to write into registers."), _("\
+Show permission to write into registers."), _("\
+When this permission is on, GDB may write into the target's registers.\n\
+Otherwise, any sort of write attempt will result in an error."),
+                          set_target_permissions, NULL,
+                          &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("may-write-memory", class_support,
+                          &may_write_memory_1, _("\
+Set permission to write into target memory."), _("\
+Show permission to write into target memory."), _("\
+When this permission is on, GDB may write into the target's memory.\n\
+Otherwise, any sort of write attempt will result in an error."),
+                          set_write_memory_permission, NULL,
+                          &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("may-insert-breakpoints", class_support,
+                          &may_insert_breakpoints_1, _("\
+Set permission to insert breakpoints in the target."), _("\
+Show permission to insert breakpoints in the target."), _("\
+When this permission is on, GDB may insert breakpoints in the program.\n\
+Otherwise, any sort of insertion attempt will result in an error."),
+                          set_target_permissions, NULL,
+                          &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("may-insert-tracepoints", class_support,
+                          &may_insert_tracepoints_1, _("\
+Set permission to insert tracepoints in the target."), _("\
+Show permission to insert tracepoints in the target."), _("\
+When this permission is on, GDB may insert tracepoints in the program.\n\
+Otherwise, any sort of insertion attempt will result in an error."),
+                          set_target_permissions, NULL,
+                          &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("may-insert-fast-tracepoints", class_support,
+                          &may_insert_fast_tracepoints_1, _("\
+Set permission to insert fast tracepoints in the target."), _("\
+Show permission to insert fast tracepoints in the target."), _("\
+When this permission is on, GDB may insert fast tracepoints.\n\
+Otherwise, any sort of insertion attempt will result in an error."),
+                          set_target_permissions, NULL,
+                          &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("may-interrupt", class_support,
+                          &may_stop_1, _("\
+Set permission to interrupt or signal the target."), _("\
+Show permission to interrupt or signal the target."), _("\
+When this permission is on, GDB may interrupt/stop the target's execution.\n\
+Otherwise, any attempt to interrupt or stop will be ignored."),
+                          set_target_permissions, NULL,
+                          &setlist, &showlist);
+
+
   target_dcache = dcache_init ();
 }
This page took 0.034788 seconds and 4 git commands to generate.