Index: gdb/doc/gdb.texinfo =================================================================== *** gdb/doc/gdb.texinfo (revision 250339) --- gdb/doc/gdb.texinfo (revision 250340) *************** you examine the stopped thread in the de *** 4550,4555 **** --- 4550,4556 ---- * Background Execution:: Running your program asynchronously * Thread-Specific Breakpoints:: Controlling breakpoints * Interrupted System Calls:: GDB may interfere with system calls + * Observation Mode:: GDB does not alter program behavior @end menu @node All-Stop Mode *************** monitor certain events such as thread cr *** 4880,4885 **** --- 4881,4970 ---- When such an event happens, a system call in another thread may return prematurely, even though your program does not appear to stop. + @node Observation Mode + @subsection Observation 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{observation 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 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 Index: gdb/target.c =================================================================== *** gdb/target.c (revision 250339) --- gdb/target.c (revision 250340) *************** static int trust_readonly = 0; *** 189,194 **** --- 189,206 ---- static int show_memory_breakpoints = 0; + static int may_write_registers = 1; + + static int may_write_memory = 1; + + static int may_insert_breakpoints = 1; + + /* static */ int may_insert_tracepoints = 1; + + /* static */ int may_insert_fast_tracepoints = 1; + + static int may_stop = 1; + /* Non-zero if we want to see trace of target level stuff. */ static int targetdebug = 0; *************** target_xfer_partial (struct target_ops * *** 1168,1173 **** --- 1180,1189 ---- 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 *** 1692,1697 **** --- 1708,1741 ---- return extract_unsigned_integer (buf, len); } + int + target_insert_breakpoint (struct bp_target_info *bp_tgt) + { + if (!may_insert_breakpoints) + { + warning (_("May not insert breakpoints")); + return 1; + } + + return (*current_target.to_insert_breakpoint) (bp_tgt); + } + + int + target_remove_breakpoint (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) (bp_tgt); + } + static void target_info (char *args, int from_tty) { *************** target_find_new_threads (void) *** 2654,2659 **** --- 2698,2715 ---- } } + 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_fetch_registers (struct regcache *** 2756,2763 **** void target_store_registers (struct regcache *regcache, int regno) { - struct target_ops *t; for (t = current_target.beneath; t != NULL; t = t->beneath) { if (t->to_store_registers != NULL) --- 2812,2822 ---- void target_store_registers (struct regcache *regcache, int regno) { struct target_ops *t; + + if (!may_write_registers) + error (_("Writing to registers is not allowed (regno %d)"), regno); + for (t = current_target.beneath; t != NULL; t = t->beneath) { if (t->to_store_registers != NULL) *************** Tells gdb whether to control the inferio *** 3360,3364 **** --- 3419,3478 ---- &setlist, &showlist); + add_setshow_boolean_cmd ("may-write-registers", class_support, + &may_write_registers, _("\ + 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."), + NULL, NULL, + &setlist, &showlist); + + add_setshow_boolean_cmd ("may-write-memory", class_support, + &may_write_memory, _("\ + 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."), + NULL, NULL, + &setlist, &showlist); + + add_setshow_boolean_cmd ("may-insert-breakpoints", class_support, + &may_insert_breakpoints, _("\ + 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."), + NULL, NULL, + &setlist, &showlist); + + add_setshow_boolean_cmd ("may-insert-tracepoints", class_support, + &may_insert_tracepoints, _("\ + 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."), + NULL, NULL, + &setlist, &showlist); + + add_setshow_boolean_cmd ("may-insert-fast-tracepoints", class_support, + &may_insert_fast_tracepoints, _("\ + 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."), + NULL, NULL, + &setlist, &showlist); + + add_setshow_boolean_cmd ("may-interrupt", class_support, + &may_stop, _("\ + Set permission to interrupt the target."), _("\ + Show permission to interrupt 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."), + NULL, NULL, + &setlist, &showlist); + + target_dcache = dcache_init (); } Index: gdb/target.h =================================================================== *** gdb/target.h (revision 250339) --- gdb/target.h (revision 250340) *************** extern void print_section_info (struct t *** 735,748 **** /* 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(bp_tgt) \ ! (*current_target.to_insert_breakpoint) (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(bp_tgt) \ ! (*current_target.to_remove_breakpoint) (bp_tgt) /* Initialize the terminal settings we record for the inferior, before we actually run the inferior. */ --- 735,746 ---- /* 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 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 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 *** 917,923 **** 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 --- 915,921 ---- 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 Index: gdb/tracepoint.c =================================================================== *** gdb/tracepoint.c (revision 250339) --- gdb/tracepoint.c (revision 250340) *************** *** 26,31 **** --- 26,33 ---- #include "gdbcmd.h" #include "value.h" #include "target.h" + extern int may_insert_tracepoints; + extern int may_insert_fast_tracepoints; #include "language.h" #include "gdb_string.h" #include "inferior.h" *************** remote_set_transparent_ranges (void) *** 1501,1507 **** to the target. If no errors, Tell target to start a new trace experiment. */ ! void download_tracepoint (struct breakpoint *t); static void trace_start_command (char *args, int from_tty) --- 1503,1509 ---- to the target. If no errors, Tell target to start a new trace experiment. */ ! int download_tracepoint (struct breakpoint *t); static void trace_start_command (char *args, int from_tty) *************** trace_start_command (char *args, int fro *** 1511,1516 **** --- 1513,1519 ---- int ix; struct breakpoint *t; struct trace_state_variable *tsv; + int any_downloaded = 0; dont_repeat (); /* Like "run", dangerous to repeat accidentally. */ *************** trace_start_command (char *args, int fro *** 1524,1533 **** tp_vec = all_tracepoints (); for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++) { ! download_tracepoint (t); } VEC_free (breakpoint_p, tp_vec); /* Init any trace state variables that start with nonzero values. */ for (tsv = tvariables; tsv; tsv = tsv->next) { --- 1527,1541 ---- tp_vec = all_tracepoints (); for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++) { ! if (download_tracepoint (t)) ! any_downloaded = 1; } VEC_free (breakpoint_p, tp_vec); + /* No point in tracing without any tracepoints... */ + if (!any_downloaded) + error ("No tracepoints downloaded, not starting trace"); + /* Init any trace state variables that start with nonzero values. */ for (tsv = tvariables; tsv; tsv = tsv->next) { *************** trace_start_command (char *args, int fro *** 1559,1567 **** error (_("Trace can only be run on remote targets.")); } ! /* Send the definition of a single tracepoint to the target. */ ! void download_tracepoint (struct breakpoint *t) { CORE_ADDR tpaddr; --- 1567,1576 ---- error (_("Trace can only be run on remote targets.")); } ! /* Send the definition of a single tracepoint to the target. Return 1 ! if successful, 0 if not. */ ! int download_tracepoint (struct breakpoint *t) { CORE_ADDR tpaddr; *************** download_tracepoint (struct breakpoint * *** 1574,1579 **** --- 1583,1597 ---- struct agent_expr *aexpr; struct cleanup *aexpr_chain = NULL; + if ((t->type == bp_fast_tracepoint + ? !may_insert_fast_tracepoints + : !may_insert_tracepoints)) + { + warning (_("May not insert %stracepoints, skipping tracepoint %d"), + (t->type == bp_fast_tracepoint ? "fast " : ""), t->number); + return 0; + } + tpaddr = t->loc->address; sprintf_vma (tmp, (t->loc ? tpaddr : 0)); sprintf (buf, "QTDP:%x:%s:%c:%lx:%x", t->number, *************** download_tracepoint (struct breakpoint * *** 1617,1623 **** error (_("Target does not support tracepoints.")); if (!t->actions && !*default_collect) ! return; encode_actions (t, &tdp_actions, &stepping_actions); old_chain = make_cleanup (free_actions_list_cleanup_wrapper, --- 1635,1641 ---- error (_("Target does not support tracepoints.")); if (!t->actions && !*default_collect) ! return 1; encode_actions (t, &tdp_actions, &stepping_actions); old_chain = make_cleanup (free_actions_list_cleanup_wrapper, *************** download_tracepoint (struct breakpoint * *** 1660,1665 **** --- 1678,1684 ---- } } do_cleanups (old_chain); + return 1; } /* tstop command */