2010-06-11 Stan Shebs <stan@codesourcery.com>
authorStan Shebs <shebs@codesourcery.com>
Sat, 12 Jun 2010 00:05:22 +0000 (00:05 +0000)
committerStan Shebs <shebs@codesourcery.com>
Sat, 12 Jun 2010 00:05:22 +0000 (00:05 +0000)
Add per-operation permission flags.

* target.h (struct target_ops): New method to_set_permissions.
(target_set_permissions): New macro.
(target_insert_breakpoint): Change macro to function.
(target_remove_breakpoint): Ditto.
(target_stop): Ditto.
(may_write_registers): Declare.
(may_write_memory): Declare.
(may_insert_breakpoints): Declare.
(may_insert_tracepoints): Declare.
(may_insert_fast_tracepoints): Declare.
(may_stop): Declare.
* target.c (may_write_registers, may_write_registers_1): New globals.
(may_write_memory, may_write_memory_1): New globals.
(may_insert_breakpoints, may_insert_breakpoints_1): New globals.
(may_insert_tracepoints, may_insert_tracepoints_1): New globals.
(may_insert_fast_tracepoints, may_insert_fast_tracepoints_1): New
globals.
(may_stop, may_stop_1): New global.
(target_xfer_partial): Test for write permission.
(target_store_registers): Ditto.
(target_insert_breakpoint): New function.
(target_remove_breakpoint): New function.
(target_stop): New function.
(_initialize_targets): Add new set/show variables.
(set_write_memory_permission): New function.
(update_target_permissions): New function.
(set_target_permissions): New function.
(update_current_target): Default to_set_permissions.
(_initialize_targets): Use new globals and setter function.
* tracepoint.c (start_tracing): Test for permission.
* inferior.h (update_observer_mode): Declare.
* infrun.c (non_stop_1): Define earlier.
(observer_mode, observer_mode_1): New globals.
(set_observer_mode, show_observer_mode): New functions.
(update_observer_mode): New function.
(_initialize_infrun): Define "set observer" command.
* remote.c (PACKET_QAllow): New optional packet.
(remote_protocol_features): Add QAllow.
(remote_set_permissions): New function.
(remote_start_remote): Call it.
(init_remote_ops): Add it to target vector.
(_initialize_remote): Add config command for QAllow.

* gdb.texinfo (Observer Mode): New section.
(General Query Packets): Document QAllow.

* gdb.base/permissions.exp: New file.

gdb/ChangeLog
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/inferior.h
gdb/infrun.c
gdb/remote.c
gdb/target.c
gdb/target.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/permissions.exp [new file with mode: 0644]
gdb/tracepoint.c

index f0de274..03bc857 100644 (file)
@@ -1,3 +1,50 @@
+2010-06-11  Stan Shebs  <stan@codesourcery.com>
+
+       Add per-operation permission flags.
+
+       * target.h (struct target_ops): New method to_set_permissions.
+       (target_set_permissions): New macro.
+       (target_insert_breakpoint): Change macro to function.
+       (target_remove_breakpoint): Ditto.
+       (target_stop): Ditto.
+       (may_write_registers): Declare.
+       (may_write_memory): Declare.
+       (may_insert_breakpoints): Declare.
+       (may_insert_tracepoints): Declare.
+       (may_insert_fast_tracepoints): Declare.
+       (may_stop): Declare.
+       * target.c (may_write_registers, may_write_registers_1): New globals.
+       (may_write_memory, may_write_memory_1): New globals.
+       (may_insert_breakpoints, may_insert_breakpoints_1): New globals.
+       (may_insert_tracepoints, may_insert_tracepoints_1): New globals.
+       (may_insert_fast_tracepoints, may_insert_fast_tracepoints_1): New
+       globals.
+       (may_stop, may_stop_1): New global.
+       (target_xfer_partial): Test for write permission.
+       (target_store_registers): Ditto.
+       (target_insert_breakpoint): New function.
+       (target_remove_breakpoint): New function.
+       (target_stop): New function.
+       (_initialize_targets): Add new set/show variables.
+       (set_write_memory_permission): New function.
+       (update_target_permissions): New function.
+       (set_target_permissions): New function.
+       (update_current_target): Default to_set_permissions.
+       (_initialize_targets): Use new globals and setter function.
+       * tracepoint.c (start_tracing): Test for permission.
+       * inferior.h (update_observer_mode): Declare.
+       * infrun.c (non_stop_1): Define earlier.
+       (observer_mode, observer_mode_1): New globals.
+       (set_observer_mode, show_observer_mode): New functions.
+       (update_observer_mode): New function.
+       (_initialize_infrun): Define "set observer" command.
+       * remote.c (PACKET_QAllow): New optional packet.
+       (remote_protocol_features): Add QAllow.
+       (remote_set_permissions): New function.
+       (remote_start_remote): Call it.
+       (init_remote_ops): Add it to target vector.
+       (_initialize_remote): Add config command for QAllow.
+
 2010-06-11  Tom Tromey  <tromey@redhat.com>
 
        * dwarf2read.c (dwarf2_add_member_fn): Handle correct form of
index 071a409..0525c5f 100644 (file)
@@ -1,3 +1,8 @@
+2010-06-11  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.texinfo (Observer Mode): New section.
+       (General Query Packets): Document QAllow.
+        
 2010-06-04  Doug Evans  <dje@google.com>
 
        * gdb.texinfo (Python API): New node `Disabling Pretty-Printers'.
index fa7a0ec..6ac7d16 100644 (file)
@@ -4958,6 +4958,7 @@ you examine the stopped thread in the debugger.
 * Background Execution::       Running your program asynchronously
 * Thread-Specific Breakpoints::        Controlling breakpoints
 * Interrupted System Calls::   GDB may interfere with system calls
+* Observer Mode::               GDB does not alter program behavior
 @end menu
 
 @node All-Stop Mode
@@ -5318,6 +5319,103 @@ monitor certain events such as thread creation and thread destruction.
 When such an event happens, a system call in another thread may return
 prematurely, even though your program does not appear to stop.
 
+@node Observer Mode
+@subsection Observer Mode
+
+If you want to build on non-stop mode and observe program behavior
+without any chance of disruption by @value{GDBN}, you can set
+variables to disable all of the debugger's attempts to modify state,
+whether by writing memory, inserting breakpoints, etc.  These operate
+at a low level, intercepting operations from all commands.
+
+When all of these are set to @code{off}, then @value{GDBN} is said to
+be @dfn{observer mode}.  As a convenience, the variable
+@code{observer} can be set to disable these, plus enable non-stop
+mode.
+
+Note that @value{GDBN} will not prevent you from making nonsensical
+combinations of these settings. For instance, if you have enabled
+@code{may-insert-breakpoints} but disabled @code{may-write-memory},
+then breakpoints that work by writing trap instructions into the code
+stream will still not be able to be placed.
+
+@table @code
+
+@kindex observer
+@item set observer on
+@itemx set observer off
+When set to @code{on}, this disables all the permission variables
+below (except for @code{insert-fast-tracepoints}), plus enables
+non-stop debugging.  Setting this to @code{off} switches back to
+normal debugging, though remaining in non-stop mode.
+
+@item show observer
+Show whether observer mode is on or off.
+
+@kindex may-write-registers
+@item set may-write-registers on
+@itemx set may-write-registers off
+This controls whether @value{GDBN} will attempt to alter the values of
+registers, such as with assignment expressions in @code{print}, or the
+@code{jump} command.  It defaults to @code{on}.
+
+@item show may-write-registers
+Show the current permission to write registers.
+
+@kindex may-write-memory
+@item set may-write-memory on
+@itemx set may-write-memory off
+This controls whether @value{GDBN} will attempt to alter the contents
+of memory, such as with assignment expressions in @code{print}.  It
+defaults to @code{on}.
+
+@item show may-write-memory
+Show the current permission to write memory.
+
+@kindex may-insert-breakpoints
+@item set may-insert-breakpoints on
+@itemx set may-insert-breakpoints off
+This controls whether @value{GDBN} will attempt to insert breakpoints.
+This affects all breakpoints, including internal breakpoints defined
+by @value{GDBN}.  It defaults to @code{on}.
+
+@item show may-insert-breakpoints
+Show the current permission to insert breakpoints.
+
+@kindex may-insert-tracepoints
+@item set may-insert-tracepoints on
+@itemx set may-insert-tracepoints off
+This controls whether @value{GDBN} will attempt to insert (regular)
+tracepoints at the beginning of a tracing experiment.  It affects only
+non-fast tracepoints, fast tracepoints being under the control of
+@code{may-insert-fast-tracepoints}.  It defaults to @code{on}.
+
+@item show may-insert-tracepoints
+Show the current permission to insert tracepoints.
+
+@kindex may-insert-fast-tracepoints
+@item set may-insert-fast-tracepoints on
+@itemx set may-insert-fast-tracepoints off
+This controls whether @value{GDBN} will attempt to insert fast
+tracepoints at the beginning of a tracing experiment.  It affects only
+fast tracepoints, regular (non-fast) tracepoints being under the
+control of @code{may-insert-tracepoints}.  It defaults to @code{on}.
+
+@item show may-insert-fast-tracepoints
+Show the current permission to insert fast tracepoints.
+
+@kindex may-interrupt
+@item set may-interrupt on
+@itemx set may-interrupt off
+This controls whether @value{GDBN} will attempt to interrupt or stop
+program execution.  When this variable is @code{off}, the
+@code{interrupt} command will have no effect, nor will
+@kbd{Ctrl-c}. It defaults to @code{on}.
+
+@item show may-interrupt
+Show the current permission to interrupt or stop the program.
+
+@end table
 
 @node Reverse Execution
 @chapter Running programs backward
@@ -31190,6 +31288,18 @@ Here are the currently defined query and set packets:
 
 @table @samp
 
+@item QAllow:@var{op}:@var{val}@dots{}
+@cindex @samp{QAllow} packet
+Specify which operations @value{GDBN} expects to request of the
+target, as a semicolon-separated list of operation name and value
+pairs.  Possible values for @var{op} include @samp{WriteReg},
+@samp{WriteMem}, @samp{InsertBreak}, @samp{InsertTrace},
+@samp{InsertFastTrace}, and @samp{Stop}. @var{val} is either 0,
+indicating that @value{GDBN} will not request the operation, or 1,
+indicating that it may.  (The target can then use this to set up its
+own internals optimally, for instance if the debugger never expects to
+insert breakpoints, it may not need to install its own trap handler.)
+
 @item qC
 @cindex current thread, remote request
 @cindex @samp{qC} packet
@@ -31711,6 +31821,11 @@ These are the currently defined stub features and their properties:
 @tab @samp{-}
 @tab No
 
+@item @samp{QAllow}
+@tab No
+@tab @samp{-}
+@tab No
+
 @end multitable
 
 These are the currently defined stub features, in more detail:
@@ -31808,6 +31923,9 @@ The remote stub accepts and implements the reverse step packet
 The remote stub understands the @samp{QTDPsrc} packet that supplies
 the source form of tracepoint definitions.
 
+@item QAllow
+The remote stub understands the @samp{QAllow} packet.
+
 @end table
 
 @item qSymbol::
index 17b2c6f..77262eb 100644 (file)
@@ -628,4 +628,6 @@ extern int number_of_inferiors (void);
 
 extern struct inferior *add_inferior_with_spaces (void);
 
+extern void update_observer_mode (void);
+
 #endif /* !defined (INFERIOR_H) */
index 9f4c298..f4a5628 100644 (file)
@@ -178,6 +178,85 @@ show_debug_infrun (struct ui_file *file, int from_tty,
 #define SOLIB_IN_DYNAMIC_LINKER(pid,pc) 0
 #endif
 
+/* "Observer mode" is somewhat like a more extreme version of
+   non-stop, in which all GDB operations that might affect the
+   target's execution have been disabled.  */
+
+static int non_stop_1 = 0;
+
+int observer_mode = 0;
+static int observer_mode_1 = 0;
+
+static void
+set_observer_mode (char *args, int from_tty,
+                  struct cmd_list_element *c)
+{
+  extern int pagination_enabled;
+
+  if (target_has_execution)
+    {
+      observer_mode_1 = observer_mode;
+      error (_("Cannot change this setting while the inferior is running."));
+    }
+
+  observer_mode = observer_mode_1;
+
+  may_write_registers = !observer_mode;
+  may_write_memory = !observer_mode;
+  may_insert_breakpoints = !observer_mode;
+  may_insert_tracepoints = !observer_mode;
+  /* We can insert fast tracepoints in or out of observer mode,
+     but enable them if we're going into this mode.  */
+  if (observer_mode)
+    may_insert_fast_tracepoints = 1;
+  may_stop = !observer_mode;
+  update_target_permissions ();
+
+  /* Going *into* observer mode we must force non-stop, then
+     going out we leave it that way.  */
+  if (observer_mode)
+    {
+      target_async_permitted = 1;
+      pagination_enabled = 0;
+      non_stop = non_stop_1 = 1;
+    }
+
+  if (from_tty)
+    printf_filtered (_("Observer mode is now %s.\n"),
+                    (observer_mode ? "on" : "off"));
+}
+
+static void
+show_observer_mode (struct ui_file *file, int from_tty,
+                   struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Observer mode is %s.\n"), value);
+}
+
+/* This updates the value of observer mode based on changes in
+   permissions.  Note that we are deliberately ignoring the values of
+   may-write-registers and may-write-memory, since the user may have
+   reason to enable these during a session, for instance to turn on a
+   debugging-related global.  */
+
+void
+update_observer_mode (void)
+{
+  int newval;
+
+  newval = (!may_insert_breakpoints
+           && !may_insert_tracepoints
+           && may_insert_fast_tracepoints
+           && !may_stop
+           && non_stop);
+
+  /* Let the user know if things change.  */
+  if (newval != observer_mode)
+    printf_filtered (_("Observer mode is now %s.\n"),
+                    (newval ? "on" : "off"));
+
+  observer_mode = observer_mode_1 = newval;
+}
 
 /* Tables of how to react to signals; the user sets them.  */
 
@@ -6423,7 +6502,6 @@ show_exec_direction_func (struct ui_file *out, int from_tty,
 /* User interface for non-stop mode.  */
 
 int non_stop = 0;
-static int non_stop_1 = 0;
 
 static void
 set_non_stop (char *args, int from_tty,
@@ -6725,4 +6803,17 @@ Tells gdb whether to detach the child of a fork."),
      isn't initialized yet.  At this point, we're quite sure there
      isn't another convenience variable of the same name.  */
   create_internalvar_type_lazy ("_siginfo", siginfo_make_value);
+
+  add_setshow_boolean_cmd ("observer", no_class,
+                          &observer_mode_1, _("\
+Set whether gdb controls the inferior in observer mode."), _("\
+Show whether gdb controls the inferior in observer mode."), _("\
+In observer mode, GDB can get data from the inferior, but not\n\
+affect its execution.  Registers and memory may not be changed,\n\
+breakpoints may not be set, and the program cannot be interrupted\n\
+or signalled."),
+                          set_observer_mode,
+                          show_observer_mode,
+                          &setlist,
+                          &showlist);
 }
index 276e581..35d517d 100644 (file)
@@ -212,6 +212,8 @@ static void show_remote_protocol_packet_cmd (struct ui_file *file,
 static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid);
 static ptid_t read_ptid (char *buf, char **obuf);
 
+static void remote_set_permissions (void);
+
 struct remote_state;
 static int remote_get_trace_status (struct trace_status *ts);
 
@@ -1213,6 +1215,7 @@ enum {
   PACKET_bc,
   PACKET_bs,
   PACKET_TracepointSource,
+  PACKET_QAllow,
   PACKET_MAX
 };
 
@@ -3047,6 +3050,10 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
      which later probes to skip.  */
   remote_query_supported ();
 
+  /* If the stub wants to get a QAllow, compose one and send it.  */
+  if (remote_protocol_packets[PACKET_QAllow].support != PACKET_DISABLE)
+    remote_set_permissions ();
+
   /* Next, we possibly activate noack mode.
 
      If the QStartNoAckMode packet configuration is set to AUTO,
@@ -3393,6 +3400,36 @@ Some events may be lost, rendering further debugging impossible."));
   return serial_open (name);
 }
 
+/* Inform the target of our permission settings.  The permission flags
+   work without this, but if the target knows the settings, it can do
+   a couple things.  First, it can add its own check, to catch cases
+   that somehow manage to get by the permissions checks in target
+   methods.  Second, if the target is wired to disallow particular
+   settings (for instance, a system in the field that is not set up to
+   be able to stop at a breakpoint), it can object to any unavailable
+   permissions.  */
+
+void
+remote_set_permissions (void)
+{
+  struct remote_state *rs = get_remote_state ();
+
+  sprintf (rs->buf, "QAllow:"
+          "WriteReg:%x;WriteMem:%x;"
+          "InsertBreak:%x;InsertTrace:%x;"
+          "InsertFastTrace:%x;Stop:%x",
+          may_write_registers, may_write_memory,
+          may_insert_breakpoints, may_insert_tracepoints,
+          may_insert_fast_tracepoints, may_stop);
+  putpkt (rs->buf);
+  getpkt (&rs->buf, &rs->buf_size, 0);
+
+  /* If the target didn't like the packet, warn the user.  Do not try
+     to undo the user's settings, that would just be maddening.  */
+  if (strcmp (rs->buf, "OK") != 0)
+    warning ("Remote refused setting permissions with: %s", rs->buf);
+}
+
 /* This type describes each known response to the qSupported
    packet.  */
 struct protocol_feature
@@ -3564,6 +3601,8 @@ static struct protocol_feature remote_protocol_features[] = {
     PACKET_bs },
   { "TracepointSource", PACKET_DISABLE, remote_supported_packet,
     PACKET_TracepointSource },
+  { "QAllow", PACKET_DISABLE, remote_supported_packet,
+    PACKET_QAllow },
 };
 
 static char *remote_support_xml;
@@ -10061,6 +10100,7 @@ Specify the serial device it is connected to\n\
   remote_ops.to_core_of_thread = remote_core_of_thread;
   remote_ops.to_verify_memory = remote_verify_memory;
   remote_ops.to_get_tib_address = remote_get_tib_address;
+  remote_ops.to_set_permissions = remote_set_permissions;
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -10536,6 +10576,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_TracepointSource],
                         "TracepointSource", "TracepointSource", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_QAllow],
+                        "QAllow", "allow", 0);
+
   /* Keep the old ``set remote Z-packet ...'' working.  Each individual
      Z sub-packet has its own set and show commands, but users may
      have sets to this variable in their .gdbinit files (or in their
index bacda54..7aa77e6 100644 (file)
@@ -195,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;
@@ -662,6 +678,7 @@ update_current_target (void)
       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_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -858,6 +875,9 @@ update_current_target (void)
   de_fault (to_get_tib_address,
            (int (*) (ptid_t, CORE_ADDR *))
            tcomplain);
+  de_fault (to_set_permissions,
+           (void (*) (void))
+           target_ignore);
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
@@ -1404,6 +1424,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.  */
@@ -1967,6 +1991,36 @@ get_target_memory_unsigned (struct target_ops *ops, CORE_ADDR addr,
   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)
 {
@@ -2949,6 +3003,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)
 {
@@ -3058,6 +3124,9 @@ 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)
@@ -3675,6 +3744,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)
 {
@@ -3733,5 +3858,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 ();
 }
index 6f4b660..870a1eb 100644 (file)
@@ -686,6 +686,9 @@ struct target_ops
        a Windows OS specific feature.  */
     int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
 
+    /* Send the new settings of write permission variables.  */
+    void (*to_set_permissions) (void);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -889,14 +892,14 @@ extern int inferior_has_called_syscall (ptid_t pid, int *syscall_number);
 /* Insert a breakpoint at address BP_TGT->placed_address in the target
    machine.  Result is 0 for success, or an errno value.  */
 
-#define        target_insert_breakpoint(gdbarch, bp_tgt)       \
-     (*current_target.to_insert_breakpoint) (gdbarch, bp_tgt)
+extern int target_insert_breakpoint (struct gdbarch *gdbarch,
+                                    struct bp_target_info *bp_tgt);
 
 /* Remove a breakpoint at address BP_TGT->placed_address in the target
    machine.  Result is 0 for success, or an errno value.  */
 
-#define        target_remove_breakpoint(gdbarch, bp_tgt)       \
-     (*current_target.to_remove_breakpoint) (gdbarch, bp_tgt)
+extern int target_remove_breakpoint (struct gdbarch *gdbarch,
+                                    struct bp_target_info *bp_tgt);
 
 /* Initialize the terminal settings we record for the inferior,
    before we actually run the inferior.  */
@@ -1091,7 +1094,7 @@ extern void target_find_new_threads (void);
    Unix, this should act like SIGSTOP).  This function is normally
    used by GUIs to implement a stop button.  */
 
-#define target_stop(ptid) (*current_target.to_stop) (ptid)
+extern void target_stop (ptid_t ptid);
 
 /* Send the specified COMMAND to the target's monitor
    (shell,interpreter) for execution.  The result of the query is
@@ -1378,6 +1381,9 @@ extern int target_search_memory (CORE_ADDR start_addr,
 #define target_get_tib_address(ptid, addr) \
   (*current_target.to_get_tib_address) ((ptid), (addr))
 
+#define target_set_permissions() \
+  (*current_target.to_set_permissions) ()
+
 /* Command logging facility.  */
 
 #define target_log_command(p)                                          \
@@ -1540,6 +1546,15 @@ extern enum target_signal target_signal_from_command (int);
    to restore it back to the current value.  */
 extern struct cleanup *make_show_memory_breakpoints_cleanup (int show);
 
+extern int may_write_registers;
+extern int may_write_memory;
+extern int may_insert_breakpoints;
+extern int may_insert_tracepoints;
+extern int may_insert_fast_tracepoints;
+extern int may_stop;
+
+extern void update_target_permissions (void);
+
 \f
 /* Imported from machine dependent code */
 
index ac4ff9c..00c588c 100644 (file)
@@ -1,4 +1,8 @@
-:010-06-11  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
+2010-06-11  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.base/permissions.exp: New file.
+
+2010-06-11  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
 
        * gdb.base/valgrind-db-attach.exp: Fail gracefully if valgrind
        does not support ELF executable class.
diff --git a/gdb/testsuite/gdb.base/permissions.exp b/gdb/testsuite/gdb.base/permissions.exp
new file mode 100644 (file)
index 0000000..c150093
--- /dev/null
@@ -0,0 +1,101 @@
+# Copyright 2010 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Tests for permissions and observer mode.
+
+# The permissions flags are only fully functional with stubs or targets
+# that can run asynchronously.
+
+set testfile permission
+set srcfile start.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}] != "" } {
+     untested permissions.exp
+     return -1
+    }
+
+if [get_compiler_info $binfile] {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+gdb_test "show may-write-registers" \
+    "Permission to write into registers is on."
+
+gdb_test "show may-write-memory" \
+    "Permission to write into target memory is on."
+
+gdb_test "show may-insert-breakpoints" \
+    "Permission to insert breakpoints in the target is on."
+
+gdb_test "show may-insert-tracepoints" \
+    "Permission to insert tracepoints in the target is on."
+
+gdb_test "show may-insert-fast-tracepoints" \
+    "Permission to insert fast tracepoints in the target is on."
+
+gdb_test "show may-interrupt" \
+    "Permission to interrupt or signal the target is on."
+
+gdb_test "set observer on" "Observer mode is now on." "enable observer mode"
+
+gdb_test "show may-write-memory" \
+    "Permission to write into target memory is off."
+
+gdb_test "show may-write-registers" \
+    "Permission to write into registers is off."
+
+gdb_test "show may-insert-breakpoints" \
+    "Permission to insert breakpoints in the target is off."
+
+gdb_test "show may-insert-tracepoints" \
+    "Permission to insert tracepoints in the target is off."
+
+gdb_test "show may-insert-fast-tracepoints" \
+    "Permission to insert fast tracepoints in the target is on."
+
+gdb_test "show may-interrupt" \
+    "Permission to interrupt or signal the target is off."
+
+gdb_test "set observer off" "Observer mode is now off." "disable observer mode"
+
+# Go back to all-stop mode.
+
+gdb_test_no_output "set non-stop off"
+
+gdb_load ${binfile}
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+gdb_test "print x = 45" "$decimal = 45" "set a global"
+
+gdb_test "print x" "$decimal = 45"
+
+gdb_test "set may-write-memory off"
+
+gdb_test "print x = 92" "Writing to memory is not allowed.*" \
+    "try to set a global"
+
+gdb_test "print x" "$decimal = 45"
+
+# FIXME Add tests for other flags when a testsuite-able target becomes
+# available.
index 0fb779e..3aff49b 100644 (file)
@@ -1490,7 +1490,7 @@ start_tracing (void)
   int ix;
   struct breakpoint *t;
   struct trace_state_variable *tsv;
-  int any_enabled = 0;
+  int any_enabled = 0, num_to_download = 0;
   
   tp_vec = all_tracepoints ();
 
@@ -1504,10 +1504,15 @@ start_tracing (void)
   for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
     {
       if (t->enable_state == bp_enabled)
-       {
-         any_enabled = 1;
-         break;
-       }
+       any_enabled = 1;
+
+      if ((t->type == bp_fast_tracepoint
+          ? may_insert_fast_tracepoints
+          : may_insert_tracepoints))
+       ++num_to_download;
+      else
+       warning (_("May not insert %stracepoints, skipping tracepoint %d"),
+                (t->type == bp_fast_tracepoint ? "fast " : ""), t->number);
     }
 
   /* No point in tracing with only disabled tracepoints.  */
@@ -1517,10 +1522,21 @@ start_tracing (void)
       error (_("No tracepoints enabled, not starting trace"));
     }
 
+  if (num_to_download <= 0)
+    {
+      VEC_free (breakpoint_p, tp_vec);
+      error (_("No tracepoints that may be downloaded, not starting trace"));
+    }
+
   target_trace_init ();
 
   for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
     {
+      if ((t->type == bp_fast_tracepoint
+          ? !may_insert_fast_tracepoints
+          : !may_insert_tracepoints))
+       continue;
+
       t->number_on_target = 0;
       target_download_tracepoint (t);
       t->number_on_target = t->number;