X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=031544633e9e76b81508c2dde6ff9194c0d3f6b7;hb=8464be768129e057bc92e27de51317b99717da8f;hp=3d6812d2e3bf42bfbb1974979c54c3312f24ccaa;hpb=268a4a75bdc5271819e657da07b868c8bddc500f;p=binutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 3d6812d2e3b..031544633e9 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -51,6 +51,7 @@ #include "record.h" #include "inline-frame.h" #include "jit.h" +#include "tracepoint.h" /* Prototypes for local functions */ @@ -68,8 +69,6 @@ static int hook_stop_stub (void *); static int restore_selected_frame (void *); -static void build_infrun (void); - static int follow_fork (void); static void set_schedlock_func (char *args, int from_tty, @@ -84,6 +83,16 @@ static void xdb_handle_command (char *args, int from_tty); static int prepare_to_proceed (int); +static void print_exited_reason (int exitstatus); + +static void print_signal_exited_reason (enum target_signal siggnal); + +static void print_no_history_reason (void); + +static void print_signal_received_reason (enum target_signal siggnal); + +static void print_end_stepping_range_reason (void); + void _initialize_infrun (void); void nullify_last_target_wait_ptid (void); @@ -120,7 +129,7 @@ show_debug_displaced (struct ui_file *file, int from_tty, fprintf_filtered (file, _("Displace stepping debugging is %s.\n"), value); } -static int debug_infrun = 0; +int debug_infrun = 0; static void show_debug_infrun (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -179,16 +188,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. */ -/* Convert the #defines into values. This is temporary until wfi control - flow is completely sorted out. */ +static int non_stop_1 = 0; -#ifndef CANNOT_STEP_HW_WATCHPOINTS -#define CANNOT_STEP_HW_WATCHPOINTS 0 -#else -#undef CANNOT_STEP_HW_WATCHPOINTS -#define CANNOT_STEP_HW_WATCHPOINTS 1 -#endif +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. */ @@ -226,7 +304,7 @@ static struct symbol *step_start_function; /* Nonzero if we want to give control to the user when we're notified of shared library events by the dynamic linker. */ -static int stop_on_solib_events; +int stop_on_solib_events; static void show_stop_on_solib_events (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -661,7 +739,6 @@ show_follow_exec_mode_string (struct ui_file *file, int from_tty, static void follow_exec (ptid_t pid, char *execd_pathname) { - struct target_ops *tgt; struct thread_info *th = inferior_thread (); struct inferior *inf = current_inferior (); @@ -721,6 +798,7 @@ follow_exec (ptid_t pid, char *execd_pathname) char *name = alloca (strlen (gdb_sysroot) + strlen (execd_pathname) + 1); + strcpy (name, gdb_sysroot); strcat (name, execd_pathname); execd_pathname = name; @@ -737,7 +815,6 @@ follow_exec (ptid_t pid, char *execd_pathname) if (follow_exec_mode_string == follow_exec_mode_new) { struct program_space *pspace; - struct inferior *new_inf; /* The user wants to keep the old inferior and program spaces around. Create a new fresh one, and switch to it. */ @@ -893,32 +970,118 @@ static ptid_t deferred_step_ptid; displaced step operation on it. See displaced_step_prepare and displaced_step_fixup for details. */ -/* If this is not null_ptid, this is the thread carrying out a - displaced single-step. This thread's state will require fixing up - once it has completed its step. */ -static ptid_t displaced_step_ptid; - struct displaced_step_request { ptid_t ptid; struct displaced_step_request *next; }; -/* A queue of pending displaced stepping requests. */ -struct displaced_step_request *displaced_step_request_queue; +/* Per-inferior displaced stepping state. */ +struct displaced_step_inferior_state +{ + /* Pointer to next in linked list. */ + struct displaced_step_inferior_state *next; + + /* The process this displaced step state refers to. */ + int pid; + + /* A queue of pending displaced stepping requests. One entry per + thread that needs to do a displaced step. */ + struct displaced_step_request *step_request_queue; + + /* If this is not null_ptid, this is the thread carrying out a + displaced single-step in process PID. This thread's state will + require fixing up once it has completed its step. */ + ptid_t step_ptid; + + /* The architecture the thread had when we stepped it. */ + struct gdbarch *step_gdbarch; + + /* The closure provided gdbarch_displaced_step_copy_insn, to be used + for post-step cleanup. */ + struct displaced_step_closure *step_closure; + + /* The address of the original instruction, and the copy we + made. */ + CORE_ADDR step_original, step_copy; + + /* Saved contents of copy area. */ + gdb_byte *step_saved_copy; +}; + +/* The list of states of processes involved in displaced stepping + presently. */ +static struct displaced_step_inferior_state *displaced_step_inferior_states; + +/* Get the displaced stepping state of process PID. */ + +static struct displaced_step_inferior_state * +get_displaced_stepping_state (int pid) +{ + struct displaced_step_inferior_state *state; + + for (state = displaced_step_inferior_states; + state != NULL; + state = state->next) + if (state->pid == pid) + return state; + + return NULL; +} + +/* Add a new displaced stepping state for process PID to the displaced + stepping state list, or return a pointer to an already existing + entry, if it already exists. Never returns NULL. */ + +static struct displaced_step_inferior_state * +add_displaced_stepping_state (int pid) +{ + struct displaced_step_inferior_state *state; + + for (state = displaced_step_inferior_states; + state != NULL; + state = state->next) + if (state->pid == pid) + return state; + + state = xcalloc (1, sizeof (*state)); + state->pid = pid; + state->next = displaced_step_inferior_states; + displaced_step_inferior_states = state; + + return state; +} + +/* Remove the displaced stepping state of process PID. */ + +static void +remove_displaced_stepping_state (int pid) +{ + struct displaced_step_inferior_state *it, **prev_next_p; -/* The architecture the thread had when we stepped it. */ -static struct gdbarch *displaced_step_gdbarch; + gdb_assert (pid != 0); -/* The closure provided gdbarch_displaced_step_copy_insn, to be used - for post-step cleanup. */ -static struct displaced_step_closure *displaced_step_closure; + it = displaced_step_inferior_states; + prev_next_p = &displaced_step_inferior_states; + while (it) + { + if (it->pid == pid) + { + *prev_next_p = it->next; + xfree (it); + return; + } -/* The address of the original instruction, and the copy we made. */ -static CORE_ADDR displaced_step_original, displaced_step_copy; + prev_next_p = &it->next; + it = *prev_next_p; + } +} -/* Saved contents of copy area. */ -static gdb_byte *displaced_step_saved_copy; +static void +infrun_inferior_exit (struct inferior *inf) +{ + remove_displaced_stepping_state (inf->pid); +} /* Enum strings for "set|show displaced-stepping". */ @@ -975,23 +1138,25 @@ use_displaced_stepping (struct gdbarch *gdbarch) /* Clean out any stray displaced stepping state. */ static void -displaced_step_clear (void) +displaced_step_clear (struct displaced_step_inferior_state *displaced) { /* Indicate that there is no cleanup pending. */ - displaced_step_ptid = null_ptid; + displaced->step_ptid = null_ptid; - if (displaced_step_closure) + if (displaced->step_closure) { - gdbarch_displaced_step_free_closure (displaced_step_gdbarch, - displaced_step_closure); - displaced_step_closure = NULL; + gdbarch_displaced_step_free_closure (displaced->step_gdbarch, + displaced->step_closure); + displaced->step_closure = NULL; } } static void -displaced_step_clear_cleanup (void *ignore) +displaced_step_clear_cleanup (void *arg) { - displaced_step_clear (); + struct displaced_step_inferior_state *state = arg; + + displaced_step_clear (state); } /* Dump LEN bytes at BUF in hex to FILE, followed by a newline. */ @@ -1030,15 +1195,18 @@ displaced_step_prepare (ptid_t ptid) CORE_ADDR original, copy; ULONGEST len; struct displaced_step_closure *closure; + struct displaced_step_inferior_state *displaced; /* We should never reach this function if the architecture does not support displaced stepping. */ gdb_assert (gdbarch_displaced_step_copy_insn_p (gdbarch)); - /* For the first cut, we're displaced stepping one thread at a - time. */ + /* We have to displaced step one thread at a time, as we only have + access to a single scratch space per inferior. */ - if (!ptid_equal (displaced_step_ptid, null_ptid)) + displaced = add_displaced_stepping_state (ptid_get_pid (ptid)); + + if (!ptid_equal (displaced->step_ptid, null_ptid)) { /* Already waiting for a displaced step to finish. Defer this request and place in queue. */ @@ -1053,16 +1221,16 @@ displaced_step_prepare (ptid_t ptid) new_req->ptid = ptid; new_req->next = NULL; - if (displaced_step_request_queue) + if (displaced->step_request_queue) { - for (req = displaced_step_request_queue; + for (req = displaced->step_request_queue; req && req->next; req = req->next) ; req->next = new_req; } else - displaced_step_request_queue = new_req; + displaced->step_request_queue = new_req; return 0; } @@ -1074,7 +1242,7 @@ displaced_step_prepare (ptid_t ptid) target_pid_to_str (ptid)); } - displaced_step_clear (); + displaced_step_clear (displaced); old_cleanups = save_inferior_ptid (); inferior_ptid = ptid; @@ -1085,15 +1253,17 @@ displaced_step_prepare (ptid_t ptid) len = gdbarch_max_insn_length (gdbarch); /* Save the original contents of the copy area. */ - displaced_step_saved_copy = xmalloc (len); + displaced->step_saved_copy = xmalloc (len); ignore_cleanups = make_cleanup (free_current_contents, - &displaced_step_saved_copy); - read_memory (copy, displaced_step_saved_copy, len); + &displaced->step_saved_copy); + read_memory (copy, displaced->step_saved_copy, len); if (debug_displaced) { fprintf_unfiltered (gdb_stdlog, "displaced: saved %s: ", paddress (gdbarch, copy)); - displaced_step_dump_bytes (gdb_stdlog, displaced_step_saved_copy, len); + displaced_step_dump_bytes (gdb_stdlog, + displaced->step_saved_copy, + len); }; closure = gdbarch_displaced_step_copy_insn (gdbarch, @@ -1104,13 +1274,13 @@ displaced_step_prepare (ptid_t ptid) /* Save the information we need to fix things up if the step succeeds. */ - displaced_step_ptid = ptid; - displaced_step_gdbarch = gdbarch; - displaced_step_closure = closure; - displaced_step_original = original; - displaced_step_copy = copy; + displaced->step_ptid = ptid; + displaced->step_gdbarch = gdbarch; + displaced->step_closure = closure; + displaced->step_original = original; + displaced->step_copy = copy; - make_cleanup (displaced_step_clear_cleanup, 0); + make_cleanup (displaced_step_clear_cleanup, displaced); /* Resume execution at the copy. */ regcache_write_pc (regcache, copy); @@ -1130,6 +1300,7 @@ static void write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr, const gdb_byte *myaddr, int len) { struct cleanup *ptid_cleanup = save_inferior_ptid (); + inferior_ptid = ptid; write_memory (memaddr, myaddr, len); do_cleanups (ptid_cleanup); @@ -1139,34 +1310,41 @@ static void displaced_step_fixup (ptid_t event_ptid, enum target_signal signal) { struct cleanup *old_cleanups; + struct displaced_step_inferior_state *displaced + = get_displaced_stepping_state (ptid_get_pid (event_ptid)); + + /* Was any thread of this process doing a displaced step? */ + if (displaced == NULL) + return; /* Was this event for the pid we displaced? */ - if (ptid_equal (displaced_step_ptid, null_ptid) - || ! ptid_equal (displaced_step_ptid, event_ptid)) + if (ptid_equal (displaced->step_ptid, null_ptid) + || ! ptid_equal (displaced->step_ptid, event_ptid)) return; - old_cleanups = make_cleanup (displaced_step_clear_cleanup, 0); + old_cleanups = make_cleanup (displaced_step_clear_cleanup, displaced); /* Restore the contents of the copy area. */ { - ULONGEST len = gdbarch_max_insn_length (displaced_step_gdbarch); - write_memory_ptid (displaced_step_ptid, displaced_step_copy, - displaced_step_saved_copy, len); + ULONGEST len = gdbarch_max_insn_length (displaced->step_gdbarch); + + write_memory_ptid (displaced->step_ptid, displaced->step_copy, + displaced->step_saved_copy, len); if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: restored %s\n", - paddress (displaced_step_gdbarch, - displaced_step_copy)); + paddress (displaced->step_gdbarch, + displaced->step_copy)); } /* Did the instruction complete successfully? */ if (signal == TARGET_SIGNAL_TRAP) { /* Fix up the resulting state. */ - gdbarch_displaced_step_fixup (displaced_step_gdbarch, - displaced_step_closure, - displaced_step_original, - displaced_step_copy, - get_thread_regcache (displaced_step_ptid)); + gdbarch_displaced_step_fixup (displaced->step_gdbarch, + displaced->step_closure, + displaced->step_original, + displaced->step_copy, + get_thread_regcache (displaced->step_ptid)); } else { @@ -1174,17 +1352,19 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal) relocate the PC. */ struct regcache *regcache = get_thread_regcache (event_ptid); CORE_ADDR pc = regcache_read_pc (regcache); - pc = displaced_step_original + (pc - displaced_step_copy); + + pc = displaced->step_original + (pc - displaced->step_copy); regcache_write_pc (regcache, pc); } do_cleanups (old_cleanups); - displaced_step_ptid = null_ptid; + displaced->step_ptid = null_ptid; /* Are there any pending displaced stepping requests? If so, run - one now. */ - while (displaced_step_request_queue) + one now. Leave the state object around, since we're likely to + need it again soon. */ + while (displaced->step_request_queue) { struct displaced_step_request *head; ptid_t ptid; @@ -1193,9 +1373,9 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal) CORE_ADDR actual_pc; struct address_space *aspace; - head = displaced_step_request_queue; + head = displaced->step_request_queue; ptid = head->ptid; - displaced_step_request_queue = head->next; + displaced->step_request_queue = head->next; xfree (head); context_switch (ptid); @@ -1226,8 +1406,8 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal) displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf)); } - if (gdbarch_displaced_step_hw_singlestep - (gdbarch, displaced_step_closure)) + if (gdbarch_displaced_step_hw_singlestep (gdbarch, + displaced->step_closure)) target_resume (ptid, 1, TARGET_SIGNAL_0); else target_resume (ptid, 0, TARGET_SIGNAL_0); @@ -1266,6 +1446,7 @@ static void infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) { struct displaced_step_request *it; + struct displaced_step_inferior_state *displaced; if (ptid_equal (inferior_ptid, old_ptid)) inferior_ptid = new_ptid; @@ -1273,15 +1454,20 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) if (ptid_equal (singlestep_ptid, old_ptid)) singlestep_ptid = new_ptid; - if (ptid_equal (displaced_step_ptid, old_ptid)) - displaced_step_ptid = new_ptid; - if (ptid_equal (deferred_step_ptid, old_ptid)) deferred_step_ptid = new_ptid; - for (it = displaced_step_request_queue; it; it = it->next) - if (ptid_equal (it->ptid, old_ptid)) - it->ptid = new_ptid; + for (displaced = displaced_step_inferior_states; + displaced; + displaced = displaced->next) + { + if (ptid_equal (displaced->step_ptid, old_ptid)) + displaced->step_ptid = new_ptid; + + for (it = displaced->step_request_queue; it; it = it->next) + if (ptid_equal (it->ptid, old_ptid)) + it->ptid = new_ptid; + } } @@ -1339,7 +1525,8 @@ maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc) { int hw_step = 1; - if (gdbarch_software_single_step_p (gdbarch) + if (execution_direction == EXEC_FORWARD + && gdbarch_software_single_step_p (gdbarch) && gdbarch_software_single_step (gdbarch, get_current_frame ())) { hw_step = 0; @@ -1379,18 +1566,6 @@ resume (int step, enum target_signal sig) "trap_expected=%d\n", step, sig, tp->trap_expected); - /* Some targets (e.g. Solaris x86) have a kernel bug when stepping - over an instruction that causes a page fault without triggering - a hardware watchpoint. The kernel properly notices that it shouldn't - stop, because the hardware watchpoint is not triggered, but it forgets - the step request and continues the program normally. - Work around the problem by removing hardware watchpoints if a step is - requested, GDB will check for a hardware watchpoint trigger after the - step anyway. */ - if (CANNOT_STEP_HW_WATCHPOINTS && step) - remove_hw_watchpoints (); - - /* Normally, by the time we reach `resume', the breakpoints are either removed or inserted, as appropriate. The exception is if we're sitting at a permanent breakpoint; we need to step over it, but permanent @@ -1418,6 +1593,8 @@ a command like `return' or `jump' to continue execution.")); || (step && gdbarch_software_single_step_p (gdbarch))) && sig == TARGET_SIGNAL_0) { + struct displaced_step_inferior_state *displaced; + if (!displaced_step_prepare (inferior_ptid)) { /* Got placed in displaced stepping queue. Will be resumed @@ -1431,8 +1608,9 @@ a command like `return' or `jump' to continue execution.")); return; } - step = gdbarch_displaced_step_hw_singlestep - (gdbarch, displaced_step_closure); + displaced = get_displaced_stepping_state (ptid_get_pid (inferior_ptid)); + step = gdbarch_displaced_step_hw_singlestep (gdbarch, + displaced->step_closure); } /* Do we need to do it the hard way, w/temp breakpoints? */ @@ -1642,7 +1820,10 @@ prepare_to_proceed (int step) /* Make sure we were stopped at a breakpoint. */ if (wait_status.kind != TARGET_WAITKIND_STOPPED - || wait_status.value.sig != TARGET_SIGNAL_TRAP) + || (wait_status.value.sig != TARGET_SIGNAL_TRAP + && wait_status.value.sig != TARGET_SIGNAL_ILL + && wait_status.value.sig != TARGET_SIGNAL_SEGV + && wait_status.value.sig != TARGET_SIGNAL_EMT)) { return 0; } @@ -1760,6 +1941,16 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) "infrun: proceed (addr=%s, signal=%d, step=%d)\n", paddress (gdbarch, addr), siggnal, step); + /* We're handling a live event, so make sure we're doing live + debugging. If we're looking at traceframes while the target is + running, we're going to need to get back to that mode after + handling the event. */ + if (non_stop) + { + make_cleanup_restore_current_traceframe (); + set_traceframe_number (-1); + } + if (non_stop) /* In non-stop, each thread is handled individually. The context must already be set to the right thread here. */ @@ -1856,13 +2047,14 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) or a return command, we often end up a few instructions forward, still within the original line we started. - An attempt was made to have init_execution_control_state () refresh - the prev_pc value before calculating the line number. This approach - did not work because on platforms that use ptrace, the pc register - cannot be read unless the inferior is stopped. At that point, we - are not guaranteed the inferior is stopped and so the regcache_read_pc () - call can fail. Setting the prev_pc value here ensures the value is - updated correctly when the inferior is stopped. */ + An attempt was made to refresh the prev_pc at the same time the + execution_control_state is initialized (for instance, just before + waiting for an inferior event). But this approach did not work + because of platforms that use ptrace, where the pc register cannot + be read unless the inferior is stopped. At that point, we are not + guaranteed the inferior is stopped and so the regcache_read_pc() call + can fail. Setting the prev_pc value here ensures the value is updated + correctly when the inferior is stopped. */ tp->prev_pc = regcache_read_pc (get_current_regcache ()); /* Fill in with reasonable starting values. */ @@ -1892,8 +2084,8 @@ void start_remote (int from_tty) { struct inferior *inferior; - init_wait_for_inferior (); + init_wait_for_inferior (); inferior = current_inferior (); inferior->stop_soon = STOP_QUIETLY_REMOTE; @@ -1940,8 +2132,6 @@ init_wait_for_inferior (void) previous_inferior_ptid = null_ptid; init_infwait_state (); - displaced_step_clear (); - /* Discard any skipped inlined frames. */ clear_inline_frame_state (minus_one_ptid); } @@ -1959,22 +2149,6 @@ enum infwait_states infwait_nonstep_watch_state }; -/* Why did the inferior stop? Used to print the appropriate messages - to the interface from within handle_inferior_event(). */ -enum inferior_stop_reason -{ - /* Step, next, nexti, stepi finished. */ - END_STEPPING_RANGE, - /* Inferior terminated by signal. */ - SIGNAL_EXITED, - /* Inferior exited. */ - EXITED, - /* Inferior received signal, and user asked to be notified. */ - SIGNAL_RECEIVED, - /* Reverse execution -- target ran out of history info. */ - NO_HISTORY -}; - /* The PTID we'll do a target_wait on.*/ ptid_t waiton_ptid; @@ -1999,8 +2173,6 @@ struct execution_control_state int wait_some_more; }; -static void init_execution_control_state (struct execution_control_state *ecs); - static void handle_inferior_event (struct execution_control_state *ecs); static void handle_step_into_function (struct gdbarch *gdbarch, @@ -2017,8 +2189,6 @@ static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR); static void stop_stepping (struct execution_control_state *ecs); static void prepare_to_wait (struct execution_control_state *ecs); static void keep_going (struct execution_control_state *ecs); -static void print_stop_reason (enum inferior_stop_reason stop_reason, - int stop_info); /* Callback for iterate over threads. If the thread is stopped, but the user/frontend doesn't know about that yet, go through @@ -2087,28 +2257,34 @@ infrun_thread_stop_requested_callback (struct thread_info *info, void *arg) static void infrun_thread_stop_requested (ptid_t ptid) { - struct displaced_step_request *it, *next, *prev = NULL; + struct displaced_step_inferior_state *displaced; /* PTID was requested to stop. Remove it from the displaced stepping queue, so we don't try to resume it automatically. */ - for (it = displaced_step_request_queue; it; it = next) + + for (displaced = displaced_step_inferior_states; + displaced; + displaced = displaced->next) { - next = it->next; + struct displaced_step_request *it, **prev_next_p; - if (ptid_equal (it->ptid, ptid) - || ptid_equal (minus_one_ptid, ptid) - || (ptid_is_pid (ptid) - && ptid_get_pid (ptid) == ptid_get_pid (it->ptid))) + it = displaced->step_request_queue; + prev_next_p = &displaced->step_request_queue; + while (it) { - if (displaced_step_request_queue == it) - displaced_step_request_queue = it->next; + if (ptid_match (it->ptid, ptid)) + { + *prev_next_p = it->next; + it->next = NULL; + xfree (it); + } else - prev->next = it->next; + { + prev_next_p = &it->next; + } - xfree (it); + it = *prev_next_p; } - else - prev = it; } iterate_over_threads (infrun_thread_stop_requested_callback, &ptid); @@ -2152,6 +2328,7 @@ delete_step_thread_step_resume_breakpoint (void) longjmp-resume breakpoint of the thread that just stopped stepping. */ struct thread_info *tp = inferior_thread (); + delete_step_resume_breakpoint (tp); } else @@ -2207,6 +2384,92 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid, ui_file_delete (tmp_stream); } +/* Prepare and stabilize the inferior for detaching it. E.g., + detaching while a thread is displaced stepping is a recipe for + crashing it, as nothing would readjust the PC out of the scratch + pad. */ + +void +prepare_for_detach (void) +{ + struct inferior *inf = current_inferior (); + ptid_t pid_ptid = pid_to_ptid (inf->pid); + struct cleanup *old_chain_1; + struct displaced_step_inferior_state *displaced; + + displaced = get_displaced_stepping_state (inf->pid); + + /* Is any thread of this process displaced stepping? If not, + there's nothing else to do. */ + if (displaced == NULL || ptid_equal (displaced->step_ptid, null_ptid)) + return; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "displaced-stepping in-process while detaching"); + + old_chain_1 = make_cleanup_restore_integer (&inf->detaching); + inf->detaching = 1; + + while (!ptid_equal (displaced->step_ptid, null_ptid)) + { + struct cleanup *old_chain_2; + struct execution_control_state ecss; + struct execution_control_state *ecs; + + ecs = &ecss; + memset (ecs, 0, sizeof (*ecs)); + + overlay_cache_invalid = 1; + + /* We have to invalidate the registers BEFORE calling + target_wait because they can be loaded from the target while + in target_wait. This makes remote debugging a bit more + efficient for those targets that provide critical registers + as part of their normal status mechanism. */ + + registers_changed (); + + if (deprecated_target_wait_hook) + ecs->ptid = deprecated_target_wait_hook (pid_ptid, &ecs->ws, 0); + else + ecs->ptid = target_wait (pid_ptid, &ecs->ws, 0); + + if (debug_infrun) + print_target_wait_results (pid_ptid, ecs->ptid, &ecs->ws); + + /* If an error happens while handling the event, propagate GDB's + knowledge of the executing state to the frontend/user running + state. */ + old_chain_2 = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid); + + /* In non-stop mode, each thread is handled individually. + Switch early, so the global state is set correctly for this + thread. */ + if (non_stop + && ecs->ws.kind != TARGET_WAITKIND_EXITED + && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED) + context_switch (ecs->ptid); + + /* Now figure out what to do with the result of the result. */ + handle_inferior_event (ecs); + + /* No error, don't finish the state yet. */ + discard_cleanups (old_chain_2); + + /* Breakpoints and watchpoints are not installed on the target + at this point, and signals are passed directly to the + inferior, so this must mean the process is gone. */ + if (!ecs->wait_some_more) + { + discard_cleanups (old_chain_1); + error (_("Program exited while detaching")); + } + } + + discard_cleanups (old_chain_1); +} + /* Wait for control to return from inferior to debugger. If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals @@ -2403,15 +2666,6 @@ set_step_info (struct frame_info *frame, struct symtab_and_line sal) tp->current_line = sal.line; } -/* Prepare an execution control state for looping through a - wait_for_inferior-type loop. */ - -static void -init_execution_control_state (struct execution_control_state *ecs) -{ - ecs->random_signal = 0; -} - /* Clear context switchable stepping state. */ void @@ -2547,6 +2801,7 @@ adjust_pc_after_break (struct execution_control_state *ecs) || (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc))) { struct cleanup *old_cleanups = NULL; + if (RECORD_IS_USED) old_cleanups = record_gdb_operation_disable_set (); @@ -2700,6 +2955,7 @@ handle_inferior_event (struct execution_control_state *ecs) && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED) { struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid)); + gdb_assert (inf); stop_soon = inf->stop_soon; } @@ -2711,7 +2967,7 @@ handle_inferior_event (struct execution_control_state *ecs) target_last_waitstatus = ecs->ws; /* Always clear state belonging to the previous time we stopped. */ - stop_stack_dummy = 0; + stop_stack_dummy = STOP_NONE; /* If it's a new process, add it to the thread database */ @@ -2733,6 +2989,33 @@ handle_inferior_event (struct execution_control_state *ecs) breakpoint_retire_moribund (); + /* First, distinguish signals caused by the debugger from signals + that have to do with the program's own actions. Note that + breakpoint insns may cause SIGTRAP or SIGILL or SIGEMT, depending + on the operating system version. Here we detect when a SIGILL or + SIGEMT is really a breakpoint and change it to SIGTRAP. We do + something similar for SIGSEGV, since a SIGSEGV will be generated + when we're trying to execute a breakpoint instruction on a + non-executable stack. This happens for call dummy breakpoints + for architectures like SPARC that place call dummies on the + stack. */ + if (ecs->ws.kind == TARGET_WAITKIND_STOPPED + && (ecs->ws.value.sig == TARGET_SIGNAL_ILL + || ecs->ws.value.sig == TARGET_SIGNAL_SEGV + || ecs->ws.value.sig == TARGET_SIGNAL_EMT)) + { + struct regcache *regcache = get_thread_regcache (ecs->ptid); + + if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), + regcache_read_pc (regcache))) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: Treating signal as SIGTRAP\n"); + ecs->ws.value.sig = TARGET_SIGNAL_TRAP; + } + } + /* Mark the non-executing threads accordingly. In all-stop, all threads of all processes are stopped when we get any event reported. In non-stop mode, only the event thread stops. If @@ -2866,7 +3149,7 @@ handle_inferior_event (struct execution_control_state *ecs) set_current_program_space (current_inferior ()->pspace); handle_vfork_child_exec_or_exit (0); target_terminal_ours (); /* Must do this before mourn anyway */ - print_stop_reason (EXITED, ecs->ws.value.integer); + print_exited_reason (ecs->ws.value.integer); /* Record the exit code in the convenience variable $_exitcode, so that the user can inspect this again later. */ @@ -2875,6 +3158,7 @@ handle_inferior_event (struct execution_control_state *ecs) gdb_flush (gdb_stdout); target_mourn_inferior (); singlestep_breakpoints_inserted_p = 0; + cancel_single_step_breakpoints (); stop_print_frame = 0; stop_stepping (ecs); return; @@ -2896,8 +3180,9 @@ handle_inferior_event (struct execution_control_state *ecs) may be needed. */ target_mourn_inferior (); - print_stop_reason (SIGNAL_EXITED, ecs->ws.value.sig); + print_signal_exited_reason (ecs->ws.value.sig); singlestep_breakpoints_inserted_p = 0; + cancel_single_step_breakpoints (); stop_stepping (ecs); return; @@ -2935,6 +3220,13 @@ handle_inferior_event (struct execution_control_state *ecs) detach_breakpoints (child_pid); } + if (singlestep_breakpoints_inserted_p) + { + /* Pull the single step breakpoints out of the target. */ + remove_single_step_breakpoints (); + singlestep_breakpoints_inserted_p = 0; + } + /* In case the event is caught by a catchpoint, remember that the event is to be followed at the next resume of the thread, and not immediately. */ @@ -3024,6 +3316,9 @@ handle_inferior_event (struct execution_control_state *ecs) reinit_frame_cache (); } + singlestep_breakpoints_inserted_p = 0; + cancel_single_step_breakpoints (); + stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); /* Do whatever is necessary to the parent branch of the vfork. */ @@ -3085,7 +3380,7 @@ handle_inferior_event (struct execution_control_state *ecs) case TARGET_WAITKIND_NO_HISTORY: /* Reverse execution: target ran out of history info. */ stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); - print_stop_reason (NO_HISTORY, 0); + print_no_history_reason (); stop_stepping (ecs); return; } @@ -3144,6 +3439,7 @@ targets should add new threads to the thread list themselves in non-stop mode.") if (target_stopped_by_watchpoint ()) { CORE_ADDR addr; + fprintf_unfiltered (gdb_stdlog, "infrun: stopped by watchpoint\n"); if (target_stopped_data_address (¤t_target, &addr)) @@ -3482,6 +3778,7 @@ targets should add new threads to the thread list themselves in non-stop mode.") the instruction and once for the delay slot. */ int step_through_delay = gdbarch_single_step_through_delay (gdbarch, frame); + if (debug_infrun && step_through_delay) fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n"); if (ecs->event_thread->step_range_end == 0 && step_through_delay) @@ -3512,27 +3809,7 @@ targets should add new threads to the thread list themselves in non-stop mode.") 3) set ecs->random_signal to 1, and the decision between 1 and 2 will be made according to the signal handling tables. */ - /* First, distinguish signals caused by the debugger from signals - that have to do with the program's own actions. Note that - breakpoint insns may cause SIGTRAP or SIGILL or SIGEMT, depending - on the operating system version. Here we detect when a SIGILL or - SIGEMT is really a breakpoint and change it to SIGTRAP. We do - something similar for SIGSEGV, since a SIGSEGV will be generated - when we're trying to execute a breakpoint instruction on a - non-executable stack. This happens for call dummy breakpoints - for architectures like SPARC that place call dummies on the - stack. - - If we're doing a displaced step past a breakpoint, then the - breakpoint is always inserted at the original instruction; - non-standard signals can't be explained by the breakpoint. */ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP - || (! ecs->event_thread->trap_expected - && breakpoint_inserted_here_p (get_regcache_aspace (get_current_regcache ()), - stop_pc) - && (ecs->event_thread->stop_signal == TARGET_SIGNAL_ILL - || ecs->event_thread->stop_signal == TARGET_SIGNAL_SEGV - || ecs->event_thread->stop_signal == TARGET_SIGNAL_EMT)) || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP || stop_soon == STOP_QUIETLY_REMOTE) { @@ -3665,6 +3942,7 @@ process_event_stop_test: { /* Signal not for debugging purposes. */ int printed = 0; + struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid)); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: random signal %d\n", @@ -3676,14 +3954,15 @@ process_event_stop_test: { printed = 1; target_terminal_ours_for_output (); - print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal); + print_signal_received_reason (ecs->event_thread->stop_signal); } /* Always stop on signals if we're either just gaining control of the program, or the user explicitly requested this thread to remain stopped. */ if (stop_soon != NO_STOP_QUIETLY || ecs->event_thread->stop_requested - || signal_stop_state (ecs->event_thread->stop_signal)) + || (!inf->detaching + && signal_stop_state (ecs->event_thread->stop_signal))) { stop_stepping (ecs); return; @@ -3768,9 +4047,15 @@ process_event_stop_test: if (what.call_dummy) { - stop_stack_dummy = 1; + stop_stack_dummy = what.call_dummy; } + /* If we hit an internal event that triggers symbol changes, the + current frame will be invalidated within bpstat_what (e.g., if + we hit an internal solib event). Re-fetch it. */ + frame = get_current_frame (); + gdbarch = get_frame_arch (frame); + switch (what.main_action) { case BPSTAT_WHAT_SET_LONGJMP_RESUME: @@ -3813,7 +4098,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); delete_step_resume_breakpoint (ecs->event_thread); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; @@ -3875,66 +4160,6 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); } break; - case BPSTAT_WHAT_CHECK_SHLIBS: - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_SHLIBS\n"); - - /* Check for any newly added shared libraries if we're - supposed to be adding them automatically. Switch - terminal for any messages produced by - breakpoint_re_set. */ - target_terminal_ours_for_output (); - /* NOTE: cagney/2003-11-25: Make certain that the target - stack's section table is kept up-to-date. Architectures, - (e.g., PPC64), use the section table to perform - operations such as address => section name and hence - require the table to contain all sections (including - those found in shared libraries). */ -#ifdef SOLIB_ADD - SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); -#else - solib_add (NULL, 0, ¤t_target, auto_solib_add); -#endif - target_terminal_inferior (); - - /* If requested, stop when the dynamic linker notifies - gdb of events. This allows the user to get control - and place breakpoints in initializer routines for - dynamically loaded objects (among other things). */ - if (stop_on_solib_events || stop_stack_dummy) - { - stop_stepping (ecs); - return; - } - else - { - /* We want to step over this breakpoint, then keep going. */ - ecs->event_thread->stepping_over_breakpoint = 1; - break; - } - } - break; - - case BPSTAT_WHAT_CHECK_JIT: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_JIT\n"); - - /* Switch terminal for any messages produced by breakpoint_re_set. */ - target_terminal_ours_for_output (); - - jit_event_handler (gdbarch); - - target_terminal_inferior (); - - /* We want to step over this breakpoint, then keep going. */ - ecs->event_thread->stepping_over_breakpoint = 1; - - break; - - case BPSTAT_WHAT_LAST: - /* Not a real code, but listed here to shut up gcc -Wall. */ - case BPSTAT_WHAT_KEEP_CHECKING: break; } @@ -3951,6 +4176,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); if (!non_stop) { struct thread_info *tp; + tp = iterate_over_threads (currently_stepping_or_nexting_callback, ecs->event_thread); if (tp) @@ -4066,6 +4292,12 @@ infrun: not switching back to stepped thread, it has vanished\n"); return; } + /* Re-fetch current thread's frame in case the code above caused + the frame cache to be re-initialized, making our FRAME variable + a dangling pointer. */ + frame = get_current_frame (); + gdbarch = get_frame_arch (frame); + /* If stepping through a line, keep going if still within it. Note that step_range_end is the address of the first instruction @@ -4096,7 +4328,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); && execution_direction == EXEC_REVERSE) { ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); } else @@ -4134,6 +4366,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); /* Set up a step-resume breakpoint at the address indicated by SKIP_SOLIB_RESOLVER. */ struct symtab_and_line sr_sal; + init_sal (&sr_sal); sr_sal.pc = pc_after_resolver; sr_sal.pspace = get_frame_program_space (frame); @@ -4205,7 +4438,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); well. FENN */ /* And this works the same backward as frontward. MVS */ ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4272,6 +4505,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc)) { struct symtab_and_line sr_sal; + init_sal (&sr_sal); sr_sal.pc = ecs->stop_func_start; sr_sal.pspace = get_frame_program_space (frame); @@ -4310,7 +4544,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); && step_stop_if_no_debug) { ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4320,6 +4554,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); /* Set a breakpoint at callee's start address. From there we can step once and be back in the caller. */ struct symtab_and_line sr_sal; + init_sal (&sr_sal); sr_sal.pc = ecs->stop_func_start; sr_sal.pspace = get_frame_program_space (frame); @@ -4358,6 +4593,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); Set a breakpoint at its start and continue, then one more step will take us out. */ struct symtab_and_line sr_sal; + init_sal (&sr_sal); sr_sal.pc = ecs->stop_func_start; sr_sal.pspace = get_frame_program_space (frame); @@ -4375,6 +4611,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); { /* Determine where this trampoline returns. */ CORE_ADDR real_stop_pc; + real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc); if (debug_infrun) @@ -4431,7 +4668,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); is set, we stop the step so that the user has a chance to switch in assembly mode. */ ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4452,7 +4689,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stepi/nexti\n"); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4466,7 +4703,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n"); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4499,7 +4736,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); step_into_inline_frame (ecs->ptid); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4514,7 +4751,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); else { ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); } return; @@ -4541,7 +4778,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); else { ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); } return; @@ -4558,7 +4795,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different line\n"); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4659,7 +4896,7 @@ handle_step_into_function (struct gdbarch *gdbarch, { /* We are already there: stop now. */ ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4691,7 +4928,7 @@ handle_step_into_function_backward (struct gdbarch *gdbarch, struct execution_control_state *ecs) { struct symtab *s; - struct symtab_and_line stop_func_sal, sr_sal; + struct symtab_and_line stop_func_sal; s = find_pc_symtab (stop_pc); if (s && s->language != language_asm) @@ -4705,7 +4942,7 @@ handle_step_into_function_backward (struct gdbarch *gdbarch, { /* We're there already. Just stop stepping now. */ ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); } else @@ -4883,6 +5120,7 @@ keep_going (struct execution_control_state *ecs) if (ecs->event_thread->stepping_over_breakpoint) { struct regcache *thread_regcache = get_thread_regcache (ecs->ptid); + if (!use_displaced_stepping (get_regcache_arch (thread_regcache))) /* Since we can't do a displaced step, we have to remove the breakpoint while we step it. To keep things @@ -4892,6 +5130,7 @@ keep_going (struct execution_control_state *ecs) else { struct gdb_exception e; + /* Stop stepping when inserting breakpoints has failed. */ TRY_CATCH (e, RETURN_MASK_ERROR) @@ -4948,116 +5187,121 @@ prepare_to_wait (struct execution_control_state *ecs) ecs->wait_some_more = 1; } -/* Print why the inferior has stopped. We always print something when - the inferior exits, or receives a signal. The rest of the cases are - dealt with later on in normal_stop() and print_it_typical(). Ideally - there should be a call to this function from handle_inferior_event() - each time stop_stepping() is called.*/ +/* Several print_*_reason functions to print why the inferior has stopped. + We always print something when the inferior exits, or receives a signal. + The rest of the cases are dealt with later on in normal_stop and + print_it_typical. Ideally there should be a call to one of these + print_*_reason functions functions from handle_inferior_event each time + stop_stepping is called. */ + +/* Print why the inferior has stopped. + We are done with a step/next/si/ni command, print why the inferior has + stopped. For now print nothing. Print a message only if not in the middle + of doing a "step n" operation for n > 1. */ + static void -print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info) +print_end_stepping_range_reason (void) { - switch (stop_reason) + if ((!inferior_thread ()->step_multi || !inferior_thread ()->stop_step) + && ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE)); +} + +/* The inferior was terminated by a signal, print why it stopped. */ + +static void +print_signal_exited_reason (enum target_signal siggnal) +{ + annotate_signalled (); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", async_reason_lookup (EXEC_ASYNC_EXITED_SIGNALLED)); + ui_out_text (uiout, "\nProgram terminated with signal "); + annotate_signal_name (); + ui_out_field_string (uiout, "signal-name", + target_signal_to_name (siggnal)); + annotate_signal_name_end (); + ui_out_text (uiout, ", "); + annotate_signal_string (); + ui_out_field_string (uiout, "signal-meaning", + target_signal_to_string (siggnal)); + annotate_signal_string_end (); + ui_out_text (uiout, ".\n"); + ui_out_text (uiout, "The program no longer exists.\n"); +} + +/* The inferior program is finished, print why it stopped. */ + +static void +print_exited_reason (int exitstatus) +{ + annotate_exited (exitstatus); + if (exitstatus) + { + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_EXITED)); + ui_out_text (uiout, "\nProgram exited with code "); + ui_out_field_fmt (uiout, "exit-code", "0%o", (unsigned int) exitstatus); + ui_out_text (uiout, ".\n"); + } + else { - case END_STEPPING_RANGE: - /* We are done with a step/next/si/ni command. */ - /* For now print nothing. */ - /* Print a message only if not in the middle of doing a "step n" - operation for n > 1 */ - if (!inferior_thread ()->step_multi - || !inferior_thread ()->stop_step) - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE)); - break; - case SIGNAL_EXITED: - /* The inferior was terminated by a signal. */ - annotate_signalled (); if (ui_out_is_mi_like_p (uiout)) ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_EXITED_SIGNALLED)); - ui_out_text (uiout, "\nProgram terminated with signal "); + (uiout, "reason", async_reason_lookup (EXEC_ASYNC_EXITED_NORMALLY)); + ui_out_text (uiout, "\nProgram exited normally.\n"); + } + /* Support the --return-child-result option. */ + return_child_result_value = exitstatus; +} + +/* Signal received, print why the inferior has stopped. The signal table + tells us to print about it. */ + +static void +print_signal_received_reason (enum target_signal siggnal) +{ + annotate_signal (); + + if (siggnal == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout)) + { + struct thread_info *t = inferior_thread (); + + ui_out_text (uiout, "\n["); + ui_out_field_string (uiout, "thread-name", + target_pid_to_str (t->ptid)); + ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num); + ui_out_text (uiout, " stopped"); + } + else + { + ui_out_text (uiout, "\nProgram received signal "); annotate_signal_name (); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED)); ui_out_field_string (uiout, "signal-name", - target_signal_to_name (stop_info)); + target_signal_to_name (siggnal)); annotate_signal_name_end (); ui_out_text (uiout, ", "); annotate_signal_string (); ui_out_field_string (uiout, "signal-meaning", - target_signal_to_string (stop_info)); + target_signal_to_string (siggnal)); annotate_signal_string_end (); - ui_out_text (uiout, ".\n"); - ui_out_text (uiout, "The program no longer exists.\n"); - break; - case EXITED: - /* The inferior program is finished. */ - annotate_exited (stop_info); - if (stop_info) - { - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_EXITED)); - ui_out_text (uiout, "\nProgram exited with code "); - ui_out_field_fmt (uiout, "exit-code", "0%o", - (unsigned int) stop_info); - ui_out_text (uiout, ".\n"); - } - else - { - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_EXITED_NORMALLY)); - ui_out_text (uiout, "\nProgram exited normally.\n"); - } - /* Support the --return-child-result option. */ - return_child_result_value = stop_info; - break; - case SIGNAL_RECEIVED: - /* Signal received. The signal table tells us to print about - it. */ - annotate_signal (); + } + ui_out_text (uiout, ".\n"); +} - if (stop_info == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout)) - { - struct thread_info *t = inferior_thread (); +/* Reverse execution: target ran out of history info, print why the inferior + has stopped. */ - ui_out_text (uiout, "\n["); - ui_out_field_string (uiout, "thread-name", - target_pid_to_str (t->ptid)); - ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num); - ui_out_text (uiout, " stopped"); - } - else - { - ui_out_text (uiout, "\nProgram received signal "); - annotate_signal_name (); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED)); - ui_out_field_string (uiout, "signal-name", - target_signal_to_name (stop_info)); - annotate_signal_name_end (); - ui_out_text (uiout, ", "); - annotate_signal_string (); - ui_out_field_string (uiout, "signal-meaning", - target_signal_to_string (stop_info)); - annotate_signal_string_end (); - } - ui_out_text (uiout, ".\n"); - break; - case NO_HISTORY: - /* Reverse execution: target ran out of history info. */ - ui_out_text (uiout, "\nNo more reverse-execution history.\n"); - break; - default: - internal_error (__FILE__, __LINE__, - _("print_stop_reason: unrecognized enum value")); - break; - } +static void +print_no_history_reason (void) +{ + ui_out_text (uiout, "\nNo more reverse-execution history.\n"); } - /* Here to return control to GDB when the inferior stops for real. Print appropriate messages, remove breakpoints, give terminal our modes. @@ -5253,12 +5497,13 @@ Further execution is probably impossible.\n")); stop_registers = regcache_dup (get_current_regcache ()); } - if (stop_stack_dummy) + if (stop_stack_dummy == STOP_STACK_DUMMY) { /* Pop the empty frame that contains the stack dummy. This also restores inferior state prior to the call (struct inferior_thread_state). */ struct frame_info *frame = get_current_frame (); + gdb_assert (get_frame_type (frame) == DUMMY_FRAME); frame_pop (frame); /* frame_pop() calls reinit_frame_cache as the last thing it does @@ -5346,6 +5591,7 @@ int signal_stop_update (int signo, int state) { int ret = signal_stop[signo]; + signal_stop[signo] = state; return ret; } @@ -5354,6 +5600,7 @@ int signal_print_update (int signo, int state) { int ret = signal_print[signo]; + signal_print[signo] = state; return ret; } @@ -5362,6 +5609,7 @@ int signal_pass_update (int signo, int state) { int ret = signal_program[signo]; + signal_program[signo] = state; return ret; } @@ -5645,6 +5893,7 @@ static void signals_info (char *signum_exp, int from_tty) { enum target_signal oursig; + sig_print_header (); if (signum_exp) @@ -5743,6 +5992,7 @@ siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var) && gdbarch_get_siginfo_type_p (gdbarch)) { struct type *type = gdbarch_get_siginfo_type (gdbarch); + return allocate_computed_value (type, &siginfo_value_funcs, NULL); } @@ -5831,7 +6081,7 @@ struct inferior_status { bpstat stop_bpstat; int stop_step; - int stop_stack_dummy; + enum stop_stack_kind stop_stack_dummy; int stopped_by_random_signal; int stepping_over_breakpoint; CORE_ADDR step_range_start; @@ -6112,6 +6362,25 @@ ptid_is_pid (ptid_t ptid) return (ptid_get_lwp (ptid) == 0 && ptid_get_tid (ptid) == 0); } +int +ptid_match (ptid_t ptid, ptid_t filter) +{ + /* Since both parameters have the same type, prevent easy mistakes + from happening. */ + gdb_assert (!ptid_equal (ptid, minus_one_ptid) + && !ptid_equal (ptid, null_ptid)); + + if (ptid_equal (filter, minus_one_ptid)) + return 1; + if (ptid_is_pid (filter) + && ptid_get_pid (ptid) == ptid_get_pid (filter)) + return 1; + else if (ptid_equal (ptid, filter)) + return 1; + + return 0; +} + /* restore_inferior_ptid() will be used by the cleanup machinery to restore the inferior_ptid value saved in a call to save_inferior_ptid(). */ @@ -6120,6 +6389,7 @@ static void restore_inferior_ptid (void *arg) { ptid_t *saved_ptid_ptr = arg; + inferior_ptid = *saved_ptid_ptr; xfree (arg); } @@ -6164,6 +6434,11 @@ set_exec_direction_func (char *args, int from_tty, else if (!strcmp (exec_direction, exec_reverse)) execution_direction = EXEC_REVERSE; } + else + { + exec_direction = exec_forward; + error (_("Target does not support this operation.")); + } } static void @@ -6189,7 +6464,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, @@ -6226,7 +6500,6 @@ _initialize_infrun (void) { int i; int numsigs; - struct cmd_list_element *c; add_info ("signals", signals_info, _("\ What debugger does when program gets various signals.\n\ @@ -6261,7 +6534,7 @@ from 1-15 are allowed for compatibility with old versions of GDB.\n\ Numeric ranges may be specified with the form LOW-HIGH (e.g. 1-5).\n\ The special arg \"all\" is recognized to mean all signals except those\n\ used by the debugger, typically SIGTRAP and SIGINT.\n\ -Recognized actions include \"s\" (toggles between stop and nostop), \n\ +Recognized actions include \"s\" (toggles between stop and nostop),\n\ \"r\" (toggles between print and noprint), \"i\" (toggles between pass and \ nopass), \"Q\" (noprint)\n\ Stop means reenter debugger if this signal happens (implies print).\n\ @@ -6395,7 +6668,7 @@ An exec call replaces the program image of a process.\n\ \n\ follow-exec-mode can be:\n\ \n\ - new - the debugger creates a new inferior and rebinds the process \n\ + new - the debugger creates a new inferior and rebinds the process\n\ to this new inferior. The program the process was running before\n\ the exec call can be restarted afterwards by restarting the original\n\ inferior.\n\ @@ -6481,15 +6754,28 @@ Tells gdb whether to detach the child of a fork."), minus_one_ptid = ptid_build (-1, 0, 0); inferior_ptid = null_ptid; target_last_wait_ptid = minus_one_ptid; - displaced_step_ptid = null_ptid; observer_attach_thread_ptid_changed (infrun_thread_ptid_changed); observer_attach_thread_stop_requested (infrun_thread_stop_requested); observer_attach_thread_exit (infrun_thread_thread_exit); + observer_attach_inferior_exit (infrun_inferior_exit); /* Explicitly create without lookup, since that tries to create a value with a void typed value, and when we get here, gdbarch 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); }