This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] Observer mode, for real this time
- From: Stan Shebs <stan at codesourcery dot com>
- To: gdb-patches at sourceware dot org
- Date: Fri, 04 Jun 2010 15:12:56 -0700
- Subject: [PATCH] Observer mode, for real this time
Here is the complete patch for observer mode and permission flags, as
originally presented in
http://sourceware.org/ml/gdb-patches/2010-04/msg00961.html . This patch
includes some behavioral tweaks made in response to user feedback, and a
bit of testsuite - not very much though, since full support requires a
target-side agent that can start up and interact with GDB without
bothering the inferior.
Stan
2010-06-04 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.
Index: inferior.h
===================================================================
RCS file: /cvs/src/src/gdb/inferior.h,v
retrieving revision 1.143
diff -p -r1.143 inferior.h
*** inferior.h 25 Mar 2010 20:48:53 -0000 1.143
--- inferior.h 3 Jun 2010 23:44:48 -0000
*************** extern int number_of_inferiors (void);
*** 628,631 ****
--- 628,633 ----
extern struct inferior *add_inferior_with_spaces (void);
+ extern void update_observer_mode (void);
+
#endif /* !defined (INFERIOR_H) */
Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.441
diff -p -r1.441 infrun.c
*** infrun.c 17 May 2010 10:40:06 -0000 1.441
--- infrun.c 3 Jun 2010 23:44:48 -0000
*************** show_debug_infrun (struct ui_file *file,
*** 178,183 ****
--- 178,262 ----
#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. */
*************** show_exec_direction_func (struct ui_file
*** 6423,6429 ****
/* 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,
--- 6502,6507 ----
*************** Tells gdb whether to detach the child of
*** 6725,6728 ****
--- 6803,6819 ----
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: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.415
diff -p -r1.415 remote.c
*** remote.c 2 Jun 2010 22:21:53 -0000 1.415
--- remote.c 3 Jun 2010 23:44:49 -0000
*************** static void show_remote_protocol_packet_
*** 212,217 ****
--- 212,219 ----
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);
*************** enum {
*** 1213,1218 ****
--- 1215,1221 ----
PACKET_bc,
PACKET_bs,
PACKET_TracepointSource,
+ PACKET_QAllow,
PACKET_MAX
};
*************** remote_start_remote (struct ui_out *uiou
*** 3046,3051 ****
--- 3049,3058 ----
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,
*************** Some events may be lost, rendering furth
*** 3392,3397 ****
--- 3399,3434 ----
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
*************** static struct protocol_feature remote_pr
*** 3563,3568 ****
--- 3600,3607 ----
PACKET_bs },
{ "TracepointSource", PACKET_DISABLE, remote_supported_packet,
PACKET_TracepointSource },
+ { "QAllow", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QAllow },
};
static char *remote_support_xml;
*************** Specify the serial device it is connecte
*** 10060,10065 ****
--- 10099,10105 ----
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
*************** Show the maximum size of the address (in
*** 10535,10540 ****
--- 10575,10583 ----
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: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.255
diff -p -r1.255 target.c
*** target.c 23 May 2010 14:23:31 -0000 1.255
--- target.c 3 Jun 2010 23:44:49 -0000
*************** static int trust_readonly = 0;
*** 195,200 ****
--- 195,216 ----
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;
*************** update_current_target (void)
*** 662,667 ****
--- 678,684 ----
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. */
*************** update_current_target (void)
*** 858,863 ****
--- 875,883 ----
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
*************** target_xfer_partial (struct target_ops *
*** 1404,1409 ****
--- 1424,1433 ----
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. */
*************** get_target_memory_unsigned (struct targe
*** 1967,1972 ****
--- 1991,2026 ----
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)
{
*************** target_find_new_threads (void)
*** 2949,2954 ****
--- 3003,3020 ----
}
}
+ 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)
{
*************** target_store_registers (struct regcache
*** 3058,3063 ****
--- 3124,3132 ----
{
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)
*************** show_maintenance_target_async_permitted
*** 3675,3680 ****
--- 3744,3805 ----
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)
{
*************** By default, caching for stack access is
*** 3733,3737 ****
--- 3858,3917 ----
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: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.182
diff -p -r1.182 target.h
*** target.h 23 May 2010 14:23:31 -0000 1.182
--- target.h 3 Jun 2010 23:44:49 -0000
*************** struct target_ops
*** 686,691 ****
--- 686,694 ----
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?
*/
*************** extern int inferior_has_called_syscall (
*** 889,902 ****
/* 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)
/* 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)
/* Initialize the terminal settings we record for the inferior,
before we actually run the inferior. */
--- 892,905 ----
/* Insert a breakpoint at address BP_TGT->placed_address in the target
machine. Result is 0 for success, or an errno value. */
! 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. */
! 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. */
*************** extern void target_find_new_threads (voi
*** 1091,1097 ****
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)
/* Send the specified COMMAND to the target's monitor
(shell,interpreter) for execution. The result of the query is
--- 1094,1100 ----
Unix, this should act like SIGSTOP). This function is normally
used by GUIs to implement a stop button. */
! 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
*************** extern int target_search_memory (CORE_AD
*** 1378,1383 ****
--- 1381,1389 ----
#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) \
*************** extern enum target_signal target_signal_
*** 1540,1545 ****
--- 1546,1560 ----
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 */
Index: tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.c,v
retrieving revision 1.188
diff -p -r1.188 tracepoint.c
*** tracepoint.c 27 May 2010 22:06:00 -0000 1.188
--- tracepoint.c 3 Jun 2010 23:44:49 -0000
*************** start_tracing (void)
*** 1490,1496 ****
int ix;
struct breakpoint *t;
struct trace_state_variable *tsv;
! int any_enabled = 0;
tp_vec = all_tracepoints ();
--- 1490,1496 ----
int ix;
struct breakpoint *t;
struct trace_state_variable *tsv;
! int any_enabled = 0, num_to_download = 0;
tp_vec = all_tracepoints ();
*************** start_tracing (void)
*** 1504,1513 ****
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
{
if (t->enable_state == bp_enabled)
! {
! any_enabled = 1;
! break;
! }
}
/* No point in tracing with only disabled tracepoints. */
--- 1504,1518 ----
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
{
if (t->enable_state == bp_enabled)
! 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. */
*************** start_tracing (void)
*** 1517,1526 ****
--- 1522,1542 ----
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;
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.720
diff -p -r1.720 gdb.texinfo
*** doc/gdb.texinfo 2 Jun 2010 19:37:56 -0000 1.720
--- doc/gdb.texinfo 3 Jun 2010 23:44:49 -0000
*************** you examine the stopped thread in the de
*** 4958,4963 ****
--- 4958,4964 ----
* 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
*************** monitor certain events such as thread cr
*** 5318,5323 ****
--- 5319,5421 ----
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
*************** Here are the currently defined query and
*** 31168,31173 ****
--- 31266,31283 ----
@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
*************** These are the currently defined stub fea
*** 31689,31694 ****
--- 31799,31809 ----
@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:
*************** The remote stub accepts and implements t
*** 31786,31791 ****
--- 31901,31909 ----
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: testsuite/gdb.base/permissions.exp
===================================================================
RCS file: testsuite/gdb.base/permissions.exp
diff -N testsuite/gdb.base/permissions.exp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.base/permissions.exp 3 Jun 2010 23:44:49 -0000
***************
*** 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.