aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Shebs <shebs@codesourcery.com>2010-06-12 00:05:22 +0000
committerStan Shebs <shebs@codesourcery.com>2010-06-12 00:05:22 +0000
commitd914c394a99165d5406c625a3675761e728b33b7 (patch)
tree9076dfce3479288e1a9c2cd8c075015657ebe9c9
parent139f2ac873b8899228e9f99dc3b50d3416336bc7 (diff)
downloadgdb-d914c394a99165d5406c625a3675761e728b33b7.zip
gdb-d914c394a99165d5406c625a3675761e728b33b7.tar.gz
gdb-d914c394a99165d5406c625a3675761e728b33b7.tar.bz2
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. * gdb.texinfo (Observer Mode): New section. (General Query Packets): Document QAllow. * gdb.base/permissions.exp: New file.
-rw-r--r--gdb/ChangeLog47
-rw-r--r--gdb/doc/ChangeLog5
-rw-r--r--gdb/doc/gdb.texinfo118
-rw-r--r--gdb/inferior.h2
-rw-r--r--gdb/infrun.c93
-rw-r--r--gdb/remote.c43
-rw-r--r--gdb/target.c180
-rw-r--r--gdb/target.h25
-rw-r--r--gdb/testsuite/ChangeLog6
-rw-r--r--gdb/testsuite/gdb.base/permissions.exp101
-rw-r--r--gdb/tracepoint.c26
11 files changed, 634 insertions, 12 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f0de274..03bc857 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 071a409..0525c5f 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -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'.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index fa7a0ec..6ac7d16 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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::
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 17b2c6f..77262eb 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -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) */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9f4c298..f4a5628 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -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);
}
diff --git a/gdb/remote.c b/gdb/remote.c
index 276e581..35d517d 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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
diff --git a/gdb/target.c b/gdb/target.c
index bacda54..7aa77e6 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -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 ();
}
diff --git a/gdb/target.h b/gdb/target.h
index 6f4b660..870a1eb6 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -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);
+
/* Imported from machine dependent code */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index ac4ff9c..00c588c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -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
index 0000000..c150093
--- /dev/null
+++ b/gdb/testsuite/gdb.base/permissions.exp
@@ -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.
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 0fb779e..3aff49b 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -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;