From d914c394a99165d5406c625a3675761e728b33b7 Mon Sep 17 00:00:00 2001 From: Stan Shebs Date: Sat, 12 Jun 2010 00:05:22 +0000 Subject: [PATCH] 2010-06-11 Stan Shebs 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 | 47 +++++++ gdb/doc/ChangeLog | 5 + gdb/doc/gdb.texinfo | 118 ++++++++++++++++ gdb/inferior.h | 2 + gdb/infrun.c | 93 ++++++++++++- gdb/remote.c | 43 ++++++ gdb/target.c | 180 +++++++++++++++++++++++++ gdb/target.h | 25 +++- gdb/testsuite/ChangeLog | 6 +- gdb/testsuite/gdb.base/permissions.exp | 101 ++++++++++++++ gdb/tracepoint.c | 26 +++- 11 files changed, 634 insertions(+), 12 deletions(-) create mode 100644 gdb/testsuite/gdb.base/permissions.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f0de274bd36..03bc8572e08 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,50 @@ +2010-06-11 Stan Shebs + + 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 * dwarf2read.c (dwarf2_add_member_fn): Handle correct form of diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 071a409ae36..0525c5f9247 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2010-06-11 Stan Shebs + + * gdb.texinfo (Observer Mode): New section. + (General Query Packets): Document QAllow. + 2010-06-04 Doug Evans * gdb.texinfo (Python API): New node `Disabling Pretty-Printers'. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index fa7a0ec66bd..6ac7d16e1d6 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 17b2c6fbfce..77262eb9ea4 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 9f4c298ebee..f4a562828cd 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 276e5816cfc..35d517dd7ef 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 bacda5468ea..7aa77e662a6 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 6f4b6609e8c..870a1eb699b 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 ac4ff9c8714..00c588c8f8d 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,4 +1,8 @@ -:010-06-11 Ulrich Weigand +2010-06-11 Stan Shebs + + * gdb.base/permissions.exp: New file. + +2010-06-11 Ulrich Weigand * 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 00000000000..c150093d44f --- /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 . + +# 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 0fb779e113a..3aff49b2d4a 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; -- 2.30.2