X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=4e270fc9f625d1c5e5199a6e70e6d991a8eba0a9;hb=d729566a19c83c452f3a962182d1c6d349562159;hp=93487e3e7c4756dca2631ba28210b2a71c76ffa9;hpb=d6b48e9c8beee5d3ab78ac1979f6af0d6de9ae30;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 93487e3e7c..4e270fc9f6 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -3,7 +3,7 @@ Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - 2008 Free Software Foundation, Inc. + 2008, 2009 Free Software Foundation, Inc. This file is part of GDB. @@ -45,7 +45,6 @@ #include "language.h" #include "solib.h" #include "main.h" - #include "gdb_assert.h" #include "mi/mi-common.h" #include "event-top.h" @@ -75,6 +74,8 @@ static void set_schedlock_func (char *args, int from_tty, static int currently_stepping (struct thread_info *tp); +static int currently_stepping_callback (struct thread_info *tp, void *data); + static void xdb_handle_command (char *args, int from_tty); static int prepare_to_proceed (int); @@ -230,8 +231,8 @@ show_stop_on_solib_events (struct ui_file *file, int from_tty, int stop_after_trap; -/* Save register contents here when about to pop a stack dummy frame, - if-and-only-if proceed_to_finish is set. +/* Save register contents here when executing a "finish" command or are + about to pop a stack dummy frame, if-and-only-if proceed_to_finish is set. Thus this contains the return value from the called function (assuming values are returned in a register). */ @@ -331,7 +332,6 @@ follow_inferior_reset_breakpoints (void) static void follow_exec (ptid_t pid, char *execd_pathname) { - ptid_t saved_pid = pid; struct target_ops *tgt; struct thread_info *th = inferior_thread (); @@ -370,9 +370,8 @@ follow_exec (ptid_t pid, char *execd_pathname) inferior has essentially been killed & reborn. */ gdb_flush (gdb_stdout); - generic_mourn_inferior (); - /* Because mourn_inferior resets inferior_ptid. */ - inferior_ptid = saved_pid; + + breakpoint_init_inferior (inf_execd); if (gdb_sysroot && *gdb_sysroot) { @@ -555,26 +554,55 @@ static CORE_ADDR displaced_step_original, displaced_step_copy; /* Saved contents of copy area. */ static gdb_byte *displaced_step_saved_copy; -/* When this is non-zero, we are allowed to use displaced stepping, if - the architecture supports it. When this is zero, we use - traditional the hold-and-step approach. */ -int can_use_displaced_stepping = 1; +/* Enum strings for "set|show displaced-stepping". */ + +static const char can_use_displaced_stepping_auto[] = "auto"; +static const char can_use_displaced_stepping_on[] = "on"; +static const char can_use_displaced_stepping_off[] = "off"; +static const char *can_use_displaced_stepping_enum[] = +{ + can_use_displaced_stepping_auto, + can_use_displaced_stepping_on, + can_use_displaced_stepping_off, + NULL, +}; + +/* If ON, and the architecture supports it, GDB will use displaced + stepping to step over breakpoints. If OFF, or if the architecture + doesn't support it, GDB will instead use the traditional + hold-and-step approach. If AUTO (which is the default), GDB will + decide which technique to use to step over breakpoints depending on + which of all-stop or non-stop mode is active --- displaced stepping + in non-stop mode; hold-and-step in all-stop mode. */ + +static const char *can_use_displaced_stepping = + can_use_displaced_stepping_auto; + static void show_can_use_displaced_stepping (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("\ -Debugger's willingness to use displaced stepping to step over " -"breakpoints is %s.\n"), value); + if (can_use_displaced_stepping == can_use_displaced_stepping_auto) + fprintf_filtered (file, _("\ +Debugger's willingness to use displaced stepping to step over \ +breakpoints is %s (currently %s).\n"), + value, non_stop ? "on" : "off"); + else + fprintf_filtered (file, _("\ +Debugger's willingness to use displaced stepping to step over \ +breakpoints is %s.\n"), value); } -/* Return non-zero if displaced stepping is enabled, and can be used - with GDBARCH. */ +/* Return non-zero if displaced stepping can/should be used to step + over breakpoints. */ + static int use_displaced_stepping (struct gdbarch *gdbarch) { - return (can_use_displaced_stepping + return (((can_use_displaced_stepping == can_use_displaced_stepping_auto + && non_stop) + || can_use_displaced_stepping == can_use_displaced_stepping_on) && gdbarch_displaced_step_copy_insn_p (gdbarch)); } @@ -631,7 +659,7 @@ displaced_step_dump_bytes (struct ui_file *file, static int displaced_step_prepare (ptid_t ptid) { - struct cleanup *old_cleanups; + struct cleanup *old_cleanups, *ignore_cleanups; struct regcache *regcache = get_thread_regcache (ptid); struct gdbarch *gdbarch = get_regcache_arch (regcache); CORE_ADDR original, copy; @@ -683,6 +711,9 @@ displaced_step_prepare (ptid_t ptid) displaced_step_clear (); + old_cleanups = save_inferior_ptid (); + inferior_ptid = ptid; + original = regcache_read_pc (regcache); copy = gdbarch_displaced_step_location (gdbarch); @@ -690,8 +721,8 @@ displaced_step_prepare (ptid_t ptid) /* Save the original contents of the copy area. */ displaced_step_saved_copy = xmalloc (len); - old_cleanups = make_cleanup (free_current_contents, - &displaced_step_saved_copy); + ignore_cleanups = make_cleanup (free_current_contents, + &displaced_step_saved_copy); read_memory (copy, displaced_step_saved_copy, len); if (debug_displaced) { @@ -701,7 +732,7 @@ displaced_step_prepare (ptid_t ptid) }; closure = gdbarch_displaced_step_copy_insn (gdbarch, - original, copy, regcache); + original, copy, regcache); /* We don't support the fully-simulated case at present. */ gdb_assert (closure); @@ -711,11 +742,13 @@ displaced_step_prepare (ptid_t ptid) /* Resume execution at the copy. */ regcache_write_pc (regcache, copy); - discard_cleanups (old_cleanups); + discard_cleanups (ignore_cleanups); + + do_cleanups (old_cleanups); if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: displaced pc to 0x%s\n", - paddr_nz (copy)); + paddr_nz (copy)); /* Save the information we need to fix things up if the step succeeds. */ @@ -786,27 +819,71 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal) do_cleanups (old_cleanups); + displaced_step_ptid = null_ptid; + /* Are there any pending displaced stepping requests? If so, run one now. */ - if (displaced_step_request_queue) + while (displaced_step_request_queue) { struct displaced_step_request *head; ptid_t ptid; + CORE_ADDR actual_pc; head = displaced_step_request_queue; ptid = head->ptid; displaced_step_request_queue = head->next; xfree (head); - if (debug_displaced) - fprintf_unfiltered (gdb_stdlog, - "displaced: stepping queued %s now\n", - target_pid_to_str (ptid)); + context_switch (ptid); + actual_pc = read_pc (); - displaced_step_ptid = null_ptid; - displaced_step_prepare (ptid); - target_resume (ptid, 1, TARGET_SIGNAL_0); + if (breakpoint_here_p (actual_pc)) + { + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, + "displaced: stepping queued %s now\n", + target_pid_to_str (ptid)); + + displaced_step_prepare (ptid); + + if (debug_displaced) + { + gdb_byte buf[4]; + + fprintf_unfiltered (gdb_stdlog, "displaced: run 0x%s: ", + paddr_nz (actual_pc)); + read_memory (actual_pc, buf, sizeof (buf)); + displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf)); + } + + target_resume (ptid, 1, TARGET_SIGNAL_0); + + /* Done, we're stepping a thread. */ + break; + } + else + { + int step; + struct thread_info *tp = inferior_thread (); + + /* The breakpoint we were sitting under has since been + removed. */ + tp->trap_expected = 0; + + /* Go back to what we were trying to do. */ + step = currently_stepping (tp); + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "breakpoint is gone %s: step(%d)\n", + target_pid_to_str (tp->ptid), step); + + target_resume (ptid, step, TARGET_SIGNAL_0); + tp->stop_signal = TARGET_SIGNAL_0; + + /* This request was discarded. See if there's any other + thread waiting for its turn. */ + } } } @@ -887,10 +964,13 @@ resume (int step, enum target_signal sig) { int should_resume = 1; struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); + + /* Note that these must be reset if we follow a fork below. */ struct regcache *regcache = get_current_regcache (); struct gdbarch *gdbarch = get_regcache_arch (regcache); struct thread_info *tp = inferior_thread (); CORE_ADDR pc = regcache_read_pc (regcache); + QUIT; if (debug_infrun) @@ -975,6 +1055,13 @@ a command like `return' or `jump' to continue execution.")); pending_follow.kind = TARGET_WAITKIND_SPURIOUS; if (follow_fork ()) should_resume = 0; + + /* Following a child fork will change our notion of current + thread. */ + tp = inferior_thread (); + regcache = get_current_regcache (); + gdbarch = get_regcache_arch (regcache); + pc = regcache_read_pc (regcache); break; case TARGET_WAITKIND_EXECD: @@ -1070,11 +1157,11 @@ a command like `return' or `jump' to continue execution.")); displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf)); } - target_resume (resume_ptid, step, sig); - /* Avoid confusing the next resume, if the next stop/resume happens to apply to another thread. */ tp->stop_signal = TARGET_SIGNAL_0; + + target_resume (resume_ptid, step, sig); } discard_cleanups (old_cleanups); @@ -1085,36 +1172,66 @@ a command like `return' or `jump' to continue execution.")); /* Clear out all variables saying what to do when inferior is continued. First do this, then set the ones you want, then call `proceed'. */ -void -clear_proceed_status (void) +static void +clear_proceed_status_thread (struct thread_info *tp) { - if (!ptid_equal (inferior_ptid, null_ptid)) - { - struct thread_info *tp; - struct inferior *inferior; + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: clear_proceed_status_thread (%s)\n", + target_pid_to_str (tp->ptid)); - tp = inferior_thread (); + tp->trap_expected = 0; + tp->step_range_start = 0; + tp->step_range_end = 0; + tp->step_frame_id = null_frame_id; + tp->step_over_calls = STEP_OVER_UNDEBUGGABLE; + tp->stop_requested = 0; + + tp->stop_step = 0; - tp->trap_expected = 0; - tp->step_range_start = 0; - tp->step_range_end = 0; - tp->step_frame_id = null_frame_id; - tp->step_over_calls = STEP_OVER_UNDEBUGGABLE; + tp->proceed_to_finish = 0; - tp->stop_step = 0; + /* Discard any remaining commands or status from previous stop. */ + bpstat_clear (&tp->stop_bpstat); +} - tp->proceed_to_finish = 0; +static int +clear_proceed_status_callback (struct thread_info *tp, void *data) +{ + if (is_exited (tp->ptid)) + return 0; - /* Discard any remaining commands or status from previous - stop. */ - bpstat_clear (&tp->stop_bpstat); + clear_proceed_status_thread (tp); + return 0; +} + +void +clear_proceed_status (void) +{ + if (!ptid_equal (inferior_ptid, null_ptid)) + { + struct inferior *inferior; + if (non_stop) + { + /* If in non-stop mode, only delete the per-thread status + of the current thread. */ + clear_proceed_status_thread (inferior_thread ()); + } + else + { + /* In all-stop mode, delete the per-thread status of + *all* threads. */ + iterate_over_threads (clear_proceed_status_callback, NULL); + } + inferior = current_inferior (); inferior->stop_soon = NO_STOP_QUIETLY; } stop_after_trap = 0; - breakpoint_proceeded = 1; /* We're about to proceed... */ + + observer_notify_about_to_proceed (); if (stop_registers) { @@ -1186,7 +1303,6 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) struct thread_info *tp; CORE_ADDR pc = regcache_read_pc (regcache); int oneproc = 0; - enum target_signal stop_signal; if (step > 0) step_start_function = find_pc_function (pc); @@ -1195,11 +1311,17 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) if (addr == (CORE_ADDR) -1) { - if (pc == stop_pc && breakpoint_here_p (pc)) + if (pc == stop_pc && breakpoint_here_p (pc) + && execution_direction != EXEC_REVERSE) /* There is a breakpoint at the address we will resume at, step one instruction before inserting breakpoints so that we do not stop right away (and report a second hit at this - breakpoint). */ + breakpoint). + + Note, we don't do this in reverse, because we won't + actually be executing the breakpoint insn anyway. + We'll be (un-)executing the previous instruction. */ + oneproc = 1; else if (gdbarch_single_step_through_delay_p (gdbarch) && gdbarch_single_step_through_delay (gdbarch, @@ -1428,7 +1550,9 @@ enum inferior_stop_reason /* Inferior exited. */ EXITED, /* Inferior received signal, and user asked to be notified. */ - SIGNAL_RECEIVED + SIGNAL_RECEIVED, + /* Reverse execution -- target ran out of history info. */ + NO_HISTORY }; /* The PTID we'll do a target_wait on.*/ @@ -1459,7 +1583,8 @@ void init_execution_control_state (struct execution_control_state *ecs); void handle_inferior_event (struct execution_control_state *ecs); -static void step_into_function (struct execution_control_state *ecs); +static void handle_step_into_function (struct execution_control_state *ecs); +static void handle_step_into_function_backward (struct execution_control_state *ecs); static void insert_step_resume_breakpoint_at_frame (struct frame_info *step_frame); static void insert_step_resume_breakpoint_at_caller (struct frame_info *); static void insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal, @@ -1472,6 +1597,100 @@ 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 + normal_stop, as if the thread had just stopped now. ARG points at + a ptid. If PTID is MINUS_ONE_PTID, applies to all threads. If + ptid_is_pid(PTID) is true, applies to all threads of the process + pointed at by PTID. Otherwise, apply only to the thread pointed by + PTID. */ + +static int +infrun_thread_stop_requested_callback (struct thread_info *info, void *arg) +{ + ptid_t ptid = * (ptid_t *) arg; + + if ((ptid_equal (info->ptid, ptid) + || ptid_equal (minus_one_ptid, ptid) + || (ptid_is_pid (ptid) + && ptid_get_pid (ptid) == ptid_get_pid (info->ptid))) + && is_running (info->ptid) + && !is_executing (info->ptid)) + { + struct cleanup *old_chain; + struct execution_control_state ecss; + struct execution_control_state *ecs = &ecss; + + memset (ecs, 0, sizeof (*ecs)); + + old_chain = make_cleanup_restore_current_thread (); + + switch_to_thread (info->ptid); + + /* Go through handle_inferior_event/normal_stop, so we always + have consistent output as if the stop event had been + reported. */ + ecs->ptid = info->ptid; + ecs->event_thread = find_thread_pid (info->ptid); + ecs->ws.kind = TARGET_WAITKIND_STOPPED; + ecs->ws.value.sig = TARGET_SIGNAL_0; + + handle_inferior_event (ecs); + + if (!ecs->wait_some_more) + { + struct thread_info *tp; + + normal_stop (); + + /* Finish off the continuations. The continations + themselves are responsible for realising the thread + didn't finish what it was supposed to do. */ + tp = inferior_thread (); + do_all_intermediate_continuations_thread (tp); + do_all_continuations_thread (tp); + } + + do_cleanups (old_chain); + } + + return 0; +} + +/* This function is attached as a "thread_stop_requested" observer. + Cleanup local state that assumed the PTID was to be resumed, and + report the stop to the frontend. */ + +static void +infrun_thread_stop_requested (ptid_t ptid) +{ + struct displaced_step_request *it, *next, *prev = NULL; + + /* 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) + { + next = it->next; + + 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))) + { + if (displaced_step_request_queue == it) + displaced_step_request_queue = it->next; + else + prev->next = it->next; + + xfree (it); + } + else + prev = it; + } + + iterate_over_threads (infrun_thread_stop_requested_callback, &ptid); +} + /* Callback for iterate_over_threads. */ static int @@ -1519,6 +1738,46 @@ delete_step_thread_step_resume_breakpoint_cleanup (void *arg) delete_step_thread_step_resume_breakpoint (); } +/* Pretty print the results of target_wait, for debugging purposes. */ + +static void +print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid, + const struct target_waitstatus *ws) +{ + char *status_string = target_waitstatus_to_string (ws); + struct ui_file *tmp_stream = mem_fileopen (); + char *text; + long len; + + /* The text is split over several lines because it was getting too long. + Call fprintf_unfiltered (gdb_stdlog) once so that the text is still + output as a unit; we want only one timestamp printed if debug_timestamp + is set. */ + + fprintf_unfiltered (tmp_stream, + "infrun: target_wait (%d", PIDGET (waiton_ptid)); + if (PIDGET (waiton_ptid) != -1) + fprintf_unfiltered (tmp_stream, + " [%s]", target_pid_to_str (waiton_ptid)); + fprintf_unfiltered (tmp_stream, ", status) =\n"); + fprintf_unfiltered (tmp_stream, + "infrun: %d [%s],\n", + PIDGET (result_ptid), target_pid_to_str (result_ptid)); + fprintf_unfiltered (tmp_stream, + "infrun: %s\n", + status_string); + + text = ui_file_xstrdup (tmp_stream, &len); + + /* This uses %s in part to handle %'s in the text, but also to avoid + a gcc error: the format attribute requires a string literal. */ + fprintf_unfiltered (gdb_stdlog, "%s", text); + + xfree (status_string); + xfree (text); + ui_file_delete (tmp_stream); +} + /* Wait for control to return from inferior to debugger. If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals @@ -1564,11 +1823,16 @@ wait_for_inferior (int treat_exec_as_sigtrap) while (1) { + struct cleanup *old_chain; + if (deprecated_target_wait_hook) ecs->ptid = deprecated_target_wait_hook (waiton_ptid, &ecs->ws); else ecs->ptid = target_wait (waiton_ptid, &ecs->ws); + if (debug_infrun) + print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws); + if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD) { xfree (ecs->ws.value.execd_pathname); @@ -1576,9 +1840,17 @@ wait_for_inferior (int treat_exec_as_sigtrap) ecs->ws.value.sig = TARGET_SIGNAL_TRAP; } + /* If an error happens while handling the event, propagate GDB's + knowledge of the executing state to the frontend/user running + state. */ + old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_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); + if (!ecs->wait_some_more) break; } @@ -1601,6 +1873,7 @@ fetch_inferior_event (void *client_data) struct execution_control_state ecss; struct execution_control_state *ecs = &ecss; struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); + struct cleanup *ts_old_chain; int was_sync = sync_execution; memset (ecs, 0, sizeof (*ecs)); @@ -1635,6 +1908,9 @@ fetch_inferior_event (void *client_data) else ecs->ptid = target_wait (waiton_ptid, &ecs->ws); + if (debug_infrun) + print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws); + if (non_stop && ecs->ws.kind != TARGET_WAITKIND_IGNORE && ecs->ws.kind != TARGET_WAITKIND_EXITED @@ -1644,6 +1920,14 @@ fetch_inferior_event (void *client_data) thread. */ context_switch (ecs->ptid); + /* If an error happens while handling the event, propagate GDB's + knowledge of the executing state to the frontend/user running + state. */ + if (!non_stop) + ts_old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid); + else + ts_old_chain = make_cleanup (finish_thread_state_cleanup, &ecs->ptid); + /* Now figure out what to do with the result of the result. */ handle_inferior_event (ecs); @@ -1667,6 +1951,9 @@ fetch_inferior_event (void *client_data) inferior_event_handler (INF_EXEC_COMPLETE, NULL); } + /* No error, don't finish the thread states yet. */ + discard_cleanups (ts_old_chain); + /* Revert thread and frame. */ do_cleanups (old_chain); @@ -1770,6 +2057,35 @@ adjust_pc_after_break (struct execution_control_state *ecs) if (ecs->ws.value.sig != TARGET_SIGNAL_TRAP) return; + /* In reverse execution, when a breakpoint is hit, the instruction + under it has already been de-executed. The reported PC always + points at the breakpoint address, so adjusting it further would + be wrong. E.g., consider this case on a decr_pc_after_break == 1 + architecture: + + B1 0x08000000 : INSN1 + B2 0x08000001 : INSN2 + 0x08000002 : INSN3 + PC -> 0x08000003 : INSN4 + + Say you're stopped at 0x08000003 as above. Reverse continuing + from that point should hit B2 as below. Reading the PC when the + SIGTRAP is reported should read 0x08000001 and INSN2 should have + been de-executed already. + + B1 0x08000000 : INSN1 + B2 PC -> 0x08000001 : INSN2 + 0x08000002 : INSN3 + 0x08000003 : INSN4 + + We can't apply the same logic as for forward execution, because + we would wrongly adjust the PC to 0x08000000, since there's a + breakpoint at PC - 1. We'd then report a hit on B1, although + INSN1 hadn't been de-executed yet. Doing nothing is the correct + behaviour. */ + if (execution_direction == EXEC_REVERSE) + return; + /* If this target does not decrement the PC after breakpoints, then we have nothing to do. */ regcache = get_thread_regcache (ecs->ptid); @@ -1782,9 +2098,16 @@ adjust_pc_after_break (struct execution_control_state *ecs) breakpoint_pc = regcache_read_pc (regcache) - gdbarch_decr_pc_after_break (gdbarch); - /* Check whether there actually is a software breakpoint inserted - at that location. */ - if (software_breakpoint_inserted_here_p (breakpoint_pc)) + /* Check whether there actually is a software breakpoint inserted at + that location. + + If in non-stop mode, a race condition is possible where we've + removed a breakpoint, but stop events for that breakpoint were + already queued and arrive later. To suppress those spurious + SIGTRAPs, we keep a list of such breakpoint locations for a bit, + and retire them after a number of stop events are reported. */ + if (software_breakpoint_inserted_here_p (breakpoint_pc) + || (non_stop && moribund_breakpoint_here_p (breakpoint_pc))) { /* When using hardware single-step, a SIGTRAP is reported for both a completed single-step and a software breakpoint. Need to @@ -1857,8 +2180,6 @@ handle_inferior_event (struct execution_control_state *ecs) else stop_soon = NO_STOP_QUIETLY; - breakpoint_retire_moribund (); - /* Cache the last pid/waitstatus. */ target_last_wait_ptid = ecs->ptid; target_last_waitstatus = ecs->ws; @@ -1886,13 +2207,19 @@ handle_inferior_event (struct execution_control_state *ecs) if (ecs->ws.kind != TARGET_WAITKIND_IGNORE) { - /* Mark the non-executing threads accordingly. */ - if (!non_stop - || ecs->ws.kind == TARGET_WAITKIND_EXITED - || ecs->ws.kind == TARGET_WAITKIND_SIGNALLED) - set_executing (pid_to_ptid (-1), 0); - else - set_executing (ecs->ptid, 0); + breakpoint_retire_moribund (); + + /* 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 + we're handling a process exit in non-stop mode, there's + nothing to do, as threads of the dead process are gone, and + threads of any other process were left running. */ + if (!non_stop) + set_executing (minus_one_ptid, 0); + else if (ecs->ws.kind != TARGET_WAITKIND_SIGNALLED + && ecs->ws.kind != TARGET_WAITKIND_EXITED) + set_executing (inferior_ptid, 0); } switch (infwait_state) @@ -2016,6 +2343,7 @@ handle_inferior_event (struct execution_control_state *ecs) case TARGET_WAITKIND_EXITED: if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n"); + inferior_ptid = ecs->ptid; target_terminal_ours (); /* Must do this before mourn anyway */ print_stop_reason (EXITED, ecs->ws.value.integer); @@ -2034,6 +2362,7 @@ handle_inferior_event (struct execution_control_state *ecs) case TARGET_WAITKIND_SIGNALLED: if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SIGNALLED\n"); + inferior_ptid = ecs->ptid; stop_print_frame = 0; target_terminal_ours (); /* Must do this before mourn anyway */ @@ -2089,32 +2418,23 @@ handle_inferior_event (struct execution_control_state *ecs) savestring (ecs->ws.value.execd_pathname, strlen (ecs->ws.value.execd_pathname)); - /* This causes the eventpoints and symbol table to be reset. Must - do this now, before trying to determine whether to stop. */ - follow_exec (inferior_ptid, pending_follow.execd_pathname); - xfree (pending_follow.execd_pathname); - - stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); - - { - /* The breakpoints module may need to touch the inferior's - memory. Switch to the (stopped) event ptid - momentarily. */ - ptid_t saved_inferior_ptid = inferior_ptid; - inferior_ptid = ecs->ptid; - - ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); - - ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat); - inferior_ptid = saved_inferior_ptid; - } - if (!ptid_equal (ecs->ptid, inferior_ptid)) { context_switch (ecs->ptid); reinit_frame_cache (); } + stop_pc = read_pc (); + + /* This causes the eventpoints and symbol table to be reset. + Must do this now, before trying to determine whether to + stop. */ + follow_exec (inferior_ptid, pending_follow.execd_pathname); + xfree (pending_follow.execd_pathname); + + ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); + ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat); + /* If no catchpoint triggered for this, then keep going. */ if (ecs->random_signal) { @@ -2152,6 +2472,13 @@ handle_inferior_event (struct execution_control_state *ecs) ecs->event_thread->stop_signal = ecs->ws.value.sig; break; + case TARGET_WAITKIND_NO_HISTORY: + /* Reverse execution: target ran out of history info. */ + stop_pc = read_pc (); + print_stop_reason (NO_HISTORY, 0); + stop_stepping (ecs); + return; + /* We had an event in the inferior, but we are not interested in handling it at this level. The lower layers have already done what needs to be done, if anything. @@ -2189,11 +2516,21 @@ targets should add new threads to the thread list themselves in non-stop mode.") return; } - /* Do we need to clean up the state of a thread that has completed a - displaced single-step? (Doing so usually affects the PC, so do - it here, before we set stop_pc.) */ if (ecs->ws.kind == TARGET_WAITKIND_STOPPED) - displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal); + { + /* Do we need to clean up the state of a thread that has + completed a displaced single-step? (Doing so usually affects + the PC, so do it here, before we set stop_pc.) */ + displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal); + + /* If we either finished a single-step or hit a breakpoint, but + the user wanted this thread to be stopped, pretend we got a + SIG0 (generic unsignaled stop). */ + + if (ecs->event_thread->stop_requested + && ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP) + ecs->event_thread->stop_signal = TARGET_SIGNAL_0; + } stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); @@ -2247,8 +2584,6 @@ targets should add new threads to the thread list themselves in non-stop mode.") } } - stepping_past_singlestep_breakpoint = 0; - if (!ptid_equal (deferred_step_ptid, null_ptid)) { /* In non-stop mode, there's never a deferred_step_ptid set. */ @@ -2258,8 +2593,6 @@ targets should add new threads to the thread list themselves in non-stop mode.") the fact that we were supposed to switch back. */ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP) { - struct thread_info *tp; - if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: handling deferred step\n"); @@ -2610,10 +2943,19 @@ targets should add new threads to the thread list themselves in non-stop mode.") SIGTRAP. Some systems (e.g. Windows), and stubs supporting target extended-remote report it instead of a SIGSTOP (e.g. gdbserver). We already rely on SIGTRAP being our - signal, so this is no exception. */ + signal, so this is no exception. + + Also consider that the attach is complete when we see a + TARGET_SIGNAL_0. In non-stop mode, GDB will explicitly tell + the target to stop all threads of the inferior, in case the + low level attach operation doesn't stop them implicitly. If + they weren't stopped implicitly, then the stub will report a + TARGET_SIGNAL_0, meaning: stopped for no particular reason + other than GDB's request. */ if (stop_soon == STOP_QUIETLY_NO_SIGSTOP && (ecs->event_thread->stop_signal == TARGET_SIGNAL_STOP - || ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)) + || ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP + || ecs->event_thread->stop_signal == TARGET_SIGNAL_0)) { stop_stepping (ecs); ecs->event_thread->stop_signal = TARGET_SIGNAL_0; @@ -2636,7 +2978,7 @@ targets should add new threads to the thread list themselves in non-stop mode.") another signal besides SIGTRAP, so check here as well as above.'' - If someone ever tries to get get call dummys on a + If someone ever tries to get call dummys on a non-executable stack to work (where the target would stop with something like a SIGSEGV), then those tests might need to be re-instated. Given, however, that the tests were only @@ -2689,9 +3031,11 @@ process_event_stop_test: target_terminal_ours_for_output (); print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal); } - /* Always stop on signals if we're just gaining control of the - program. */ + /* 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)) { stop_stepping (ecs); @@ -2872,10 +3216,20 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); keep_going (ecs); return; } + if (stop_pc == ecs->stop_func_start + && execution_direction == EXEC_REVERSE) + { + /* We are stepping over a function call in reverse, and + just hit the step-resume breakpoint at the start + address of the function. Go back to single-stepping, + which should take us back to the function call. */ + ecs->event_thread->stepping_over_breakpoint = 1; + keep_going (ecs); + return; + } break; case BPSTAT_WHAT_CHECK_SHLIBS: - case BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK: { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_SHLIBS\n"); @@ -2916,43 +3270,6 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); stop_stepping (ecs); return; } - - /* If we stopped due to an explicit catchpoint, then the - (see above) call to SOLIB_ADD pulled in any symbols - from a newly-loaded library, if appropriate. - - We do want the inferior to stop, but not where it is - now, which is in the dynamic linker callback. Rather, - we would like it stop in the user's program, just after - the call that caused this catchpoint to trigger. That - gives the user a more useful vantage from which to - examine their program's state. */ - else if (what.main_action - == BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK) - { - /* ??rehrauer: If I could figure out how to get the - right return PC from here, we could just set a temp - breakpoint and resume. I'm not sure we can without - cracking open the dld's shared libraries and sniffing - their unwind tables and text/data ranges, and that's - not a terribly portable notion. - - Until that time, we must step the inferior out of the - dld callback, and also out of the dld itself (and any - code or stubs in libdld.sl, such as "shl_load" and - friends) until we reach non-dld code. At that point, - we can stop stepping. */ - bpstat_get_triggered_catchpoints (ecs->event_thread->stop_bpstat, - &ecs-> - event_thread-> - stepping_through_solib_catchpoints); - ecs->event_thread->stepping_through_solib_after_catch = 1; - - /* Be sure to lift all breakpoints, so the inferior does - actually step past this point... */ - ecs->event_thread->stepping_over_breakpoint = 1; - break; - } else { /* We want to step over this breakpoint, then keep going. */ @@ -2976,6 +3293,43 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); test for stepping. But, if not stepping, do not stop. */ + /* In all-stop mode, if we're currently stepping but have stopped in + some other thread, we need to switch back to the stepped thread. */ + if (!non_stop) + { + struct thread_info *tp; + tp = iterate_over_threads (currently_stepping_callback, + ecs->event_thread); + if (tp) + { + /* However, if the current thread is blocked on some internal + breakpoint, and we simply need to step over that breakpoint + to get it going again, do that first. */ + if ((ecs->event_thread->trap_expected + && ecs->event_thread->stop_signal != TARGET_SIGNAL_TRAP) + || ecs->event_thread->stepping_over_breakpoint) + { + keep_going (ecs); + return; + } + + /* Otherwise, we no longer expect a trap in the current thread. + Clear the trap_expected flag before switching back -- this is + what keep_going would do as well, if we called it. */ + ecs->event_thread->trap_expected = 0; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: switching back to stepped thread\n"); + + ecs->event_thread = tp; + ecs->ptid = tp->ptid; + context_switch (ecs->ptid); + keep_going (ecs); + return; + } + } + /* Are we stepping to get the inferior out of the dynamic linker's hook (and possibly the dld itself) after catching a shlib event? */ @@ -3037,10 +3391,24 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); && stop_pc < ecs->event_thread->step_range_end) { if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: stepping inside range [0x%s-0x%s]\n", + fprintf_unfiltered (gdb_stdlog, "infrun: stepping inside range [0x%s-0x%s]\n", paddr_nz (ecs->event_thread->step_range_start), paddr_nz (ecs->event_thread->step_range_end)); - keep_going (ecs); + + /* When stepping backward, stop at beginning of line range + (unless it's the function entry point, in which case + keep going back to the call point). */ + if (stop_pc == ecs->event_thread->step_range_start + && stop_pc != ecs->stop_func_start + && execution_direction == EXEC_REVERSE) + { + ecs->event_thread->stop_step = 1; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + } + else + keep_going (ecs); + return; } @@ -3100,8 +3468,9 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); previous frame must have valid frame IDs. */ if (!frame_id_eq (get_frame_id (get_current_frame ()), ecs->event_thread->step_frame_id) - && frame_id_eq (frame_unwind_id (get_current_frame ()), - ecs->event_thread->step_frame_id)) + && (frame_id_eq (frame_unwind_id (get_current_frame ()), + ecs->event_thread->step_frame_id) + || execution_direction == EXEC_REVERSE)) { CORE_ADDR real_stop_pc; @@ -3127,10 +3496,43 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); if (ecs->event_thread->step_over_calls == STEP_OVER_ALL) { - /* We're doing a "next", set a breakpoint at callee's return - address (the address at which the caller will - resume). */ - insert_step_resume_breakpoint_at_caller (get_current_frame ()); + /* We're doing a "next". + + Normal (forward) execution: set a breakpoint at the + callee's return address (the address at which the caller + will resume). + + Reverse (backward) execution. set the step-resume + breakpoint at the start of the function that we just + stepped into (backwards), and continue to there. When we + get there, we'll need to single-step back to the caller. */ + + if (execution_direction == EXEC_REVERSE) + { + struct symtab_and_line sr_sal; + + if (ecs->stop_func_start == 0 + && in_solib_dynsym_resolve_code (stop_pc)) + { + /* Stepped into runtime loader dynamic symbol + resolution code. Since we're in reverse, + we have already backed up through the runtime + loader and the dynamic function. This is just + the trampoline (jump table). + + Just keep stepping, we'll soon be home. + */ + keep_going (ecs); + return; + } + /* Normal (staticly linked) function call return. */ + init_sal (&sr_sal); + sr_sal.pc = ecs->stop_func_start; + insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id); + } + else + insert_step_resume_breakpoint_at_caller (get_current_frame ()); + keep_going (ecs); return; } @@ -3147,7 +3549,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); if (real_stop_pc != 0) ecs->stop_func_start = real_stop_pc; - if (in_solib_dynsym_resolve_code (ecs->stop_func_start)) + if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc)) { struct symtab_and_line sr_sal; init_sal (&sr_sal); @@ -3170,7 +3572,10 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); tmp_sal = find_pc_line (ecs->stop_func_start, 0); if (tmp_sal.line != 0) { - step_into_function (ecs); + if (execution_direction == EXEC_REVERSE) + handle_step_into_function_backward (ecs); + else + handle_step_into_function (ecs); return; } } @@ -3187,9 +3592,20 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); return; } - /* Set a breakpoint at callee's return address (the address at - which the caller will resume). */ - insert_step_resume_breakpoint_at_caller (get_current_frame ()); + if (execution_direction == EXEC_REVERSE) + { + /* 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; + insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id); + } + else + /* Set a breakpoint at callee's return address (the address + at which the caller will resume). */ + insert_step_resume_breakpoint_at_caller (get_current_frame ()); + keep_going (ecs); return; } @@ -3332,28 +3748,42 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); /* Are we in the middle of stepping? */ +static int +currently_stepping_thread (struct thread_info *tp) +{ + return (tp->step_range_end && tp->step_resume_breakpoint == NULL) + || tp->trap_expected + || tp->stepping_through_solib_after_catch; +} + +static int +currently_stepping_callback (struct thread_info *tp, void *data) +{ + /* Return true if any thread *but* the one passed in "data" is + in the middle of stepping. */ + return tp != data && currently_stepping_thread (tp); +} + static int currently_stepping (struct thread_info *tp) { - return (((tp->step_range_end && tp->step_resume_breakpoint == NULL) - || tp->trap_expected) - || tp->stepping_through_solib_after_catch - || bpstat_should_step ()); + return currently_stepping_thread (tp) || bpstat_should_step (); } -/* Subroutine call with source code we should not step over. Do step - to the first line of code in it. */ +/* Inferior has stepped into a subroutine call with source code that + we should not step over. Do step to the first line of code in + it. */ static void -step_into_function (struct execution_control_state *ecs) +handle_step_into_function (struct execution_control_state *ecs) { struct symtab *s; struct symtab_and_line stop_func_sal, sr_sal; s = find_pc_symtab (stop_pc); if (s && s->language != language_asm) - ecs->stop_func_start = gdbarch_skip_prologue - (current_gdbarch, ecs->stop_func_start); + ecs->stop_func_start = gdbarch_skip_prologue (current_gdbarch, + ecs->stop_func_start); stop_func_sal = find_pc_line (ecs->stop_func_start, 0); /* Use the step_resume_break to step until the end of the prologue, @@ -3416,6 +3846,43 @@ step_into_function (struct execution_control_state *ecs) keep_going (ecs); } +/* Inferior has stepped backward into a subroutine call with source + code that we should not step over. Do step to the beginning of the + last line of code in it. */ + +static void +handle_step_into_function_backward (struct execution_control_state *ecs) +{ + struct symtab *s; + struct symtab_and_line stop_func_sal, sr_sal; + + s = find_pc_symtab (stop_pc); + if (s && s->language != language_asm) + ecs->stop_func_start = gdbarch_skip_prologue (current_gdbarch, + ecs->stop_func_start); + + stop_func_sal = find_pc_line (stop_pc, 0); + + /* OK, we're just going to keep stepping here. */ + if (stop_func_sal.pc == stop_pc) + { + /* We're there already. Just stop stepping now. */ + ecs->event_thread->stop_step = 1; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + } + else + { + /* Else just reset the step range and keep going. + No step-resume breakpoint, they don't work for + epilogues, which can have multiple entry paths. */ + ecs->event_thread->step_range_start = stop_func_sal.pc; + ecs->event_thread->step_range_end = stop_func_sal.end; + keep_going (ecs); + } + return; +} + /* Insert a "step-resume breakpoint" at SR_SAL with frame ID SR_ID. This is used to both functions and to skip over code. */ @@ -3705,24 +4172,42 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info) return_child_result_value = stop_info; break; case SIGNAL_RECEIVED: - /* Signal received. The signal table tells us to print about - it. */ + /* Signal received. The signal table tells us to print about + it. */ annotate_signal (); - 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 (); + + if (stop_info == 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)); + 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")); @@ -3744,9 +4229,23 @@ normal_stop (void) { struct target_waitstatus last; ptid_t last_ptid; + struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); get_last_target_status (&last_ptid, &last); + /* If an exception is thrown from this point on, make sure to + propagate GDB's knowledge of the executing state to the + frontend/user running state. A QUIT is an easy exception to see + here, so do this before any filtered output. */ + if (target_has_execution) + { + if (!non_stop) + make_cleanup (finish_thread_state_cleanup, &minus_one_ptid); + else if (last.kind != TARGET_WAITKIND_SIGNALLED + && last.kind != TARGET_WAITKIND_EXITED) + make_cleanup (finish_thread_state_cleanup, &inferior_ptid); + } + /* In non-stop mode, we don't want GDB to switch threads behind the user's back, to avoid races where the user is typing a command to apply to thread x, but GDB switches to thread y before the user @@ -3772,17 +4271,6 @@ normal_stop (void) previous_inferior_ptid = inferior_ptid; } - /* NOTE drow/2004-01-17: Is this still necessary? */ - /* Make sure that the current_frame's pc is correct. This - is a correction for setting up the frame info before doing - gdbarch_decr_pc_after_break */ - if (target_has_execution) - /* FIXME: cagney/2002-12-06: Has the PC changed? Thanks to - gdbarch_decr_pc_after_break, the program counter can change. Ask the - frame code to check for this and sort out any resultant mess. - gdbarch_decr_pc_after_break needs to just go away. */ - deprecated_update_frame_pc_hack (get_current_frame (), read_pc ()); - if (!breakpoints_always_inserted_mode () && target_has_execution) { if (remove_breakpoints ()) @@ -3790,7 +4278,6 @@ normal_stop (void) target_terminal_ours_for_output (); printf_filtered (_("\ Cannot remove breakpoints because program is no longer writable.\n\ -It might be running in another process.\n\ Further execution is probably impossible.\n")); } } @@ -3815,10 +4302,19 @@ Further execution is probably impossible.\n")); /* Set the current source location. This will also happen if we display the frame below, but the current SAL will be incorrect during a user hook-stop function. */ - if (target_has_stack && !stop_stack_dummy) + if (has_stack_frames () && !stop_stack_dummy) set_current_sal_from_frame (get_current_frame (), 1); - if (!target_has_stack) + /* Let the user/frontend see the threads as stopped. */ + do_cleanups (old_chain); + + /* Look up the hook_stop and run it (CLI internally handles problem + of stop_command's pre-hook not existing). */ + if (stop_command) + catch_errors (hook_stop_stub, stop_command, + "Error while running hook_stop:\n", RETURN_MASK_ALL); + + if (!has_stack_frames ()) goto done; if (last.kind == TARGET_WAITKIND_SIGNALLED @@ -3891,22 +4387,6 @@ Further execution is probably impossible.\n")); internal_error (__FILE__, __LINE__, _("Unknown value.")); } - if (ui_out_is_mi_like_p (uiout)) - { - - ui_out_field_int (uiout, "thread-id", - pid_to_thread_id (inferior_ptid)); - if (non_stop) - { - struct cleanup *back_to = make_cleanup_ui_out_list_begin_end - (uiout, "stopped-threads"); - ui_out_field_int (uiout, NULL, - pid_to_thread_id (inferior_ptid)); - do_cleanups (back_to); - } - else - ui_out_field_string (uiout, "stopped-threads", "all"); - } /* The behavior of this routine with respect to the source flag is: SRC_LINE: Print only source line @@ -3935,50 +4415,61 @@ Further execution is probably impossible.\n")); if (stop_stack_dummy) { - /* Pop the empty frame that contains the stack dummy. POP_FRAME - ends with a setting of the current frame, so we can use that - next. */ - frame_pop (get_current_frame ()); - /* Set stop_pc to what it was before we called the function. - Can't rely on restore_inferior_status because that only gets - called if we don't stop in the called function. */ - stop_pc = read_pc (); + /* 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 + which means there's currently no selected frame. We don't need + to re-establish a selected frame if the dummy call returns normally, + that will be done by restore_inferior_status. However, we do have + to handle the case where the dummy call is returning after being + stopped (e.g. the dummy call previously hit a breakpoint). We + can't know which case we have so just always re-establish a + selected frame here. */ select_frame (get_current_frame ()); } done: annotate_stopped (); - if (!suppress_stop_observer - && !(target_has_execution - && last.kind != TARGET_WAITKIND_SIGNALLED - && last.kind != TARGET_WAITKIND_EXITED - && inferior_thread ()->step_multi)) + + /* Suppress the stop observer if we're in the middle of: + + - a step n (n > 1), as there still more steps to be done. + + - a "finish" command, as the observer will be called in + finish_command_continuation, so it can include the inferior + function's return value. + + - calling an inferior function, as we pretend we inferior didn't + run at all. The return value of the call is handled by the + expression evaluator, through call_function_by_hand. */ + + if (!target_has_execution + || last.kind == TARGET_WAITKIND_SIGNALLED + || last.kind == TARGET_WAITKIND_EXITED + || (!inferior_thread ()->step_multi + && !(inferior_thread ()->stop_bpstat + && inferior_thread ()->proceed_to_finish) + && !inferior_thread ()->in_infcall)) { if (!ptid_equal (inferior_ptid, null_ptid)) - observer_notify_normal_stop (inferior_thread ()->stop_bpstat); + observer_notify_normal_stop (inferior_thread ()->stop_bpstat, + stop_print_frame); else - observer_notify_normal_stop (NULL); + observer_notify_normal_stop (NULL, stop_print_frame); } - if (target_has_execution - && last.kind != TARGET_WAITKIND_SIGNALLED - && last.kind != TARGET_WAITKIND_EXITED) - { - /* Delete the breakpoint we stopped at, if it wants to be deleted. - Delete any breakpoint that is to be deleted at the next stop. */ - breakpoint_auto_delete (inferior_thread ()->stop_bpstat); - if (!non_stop) - set_running (pid_to_ptid (-1), 0); - else - set_running (inferior_ptid, 0); + if (target_has_execution) + { + if (last.kind != TARGET_WAITKIND_SIGNALLED + && last.kind != TARGET_WAITKIND_EXITED) + /* Delete the breakpoint we stopped at, if it wants to be deleted. + Delete any breakpoint that is to be deleted at the next stop. */ + breakpoint_auto_delete (inferior_thread ()->stop_bpstat); } - - /* Look up the hook_stop and run it (CLI internally handles problem - of stop_command's pre-hook not existing). */ - if (stop_command) - catch_errors (hook_stop_stub, stop_command, - "Error while running hook_stop:\n", RETURN_MASK_ALL); - } static int @@ -4040,7 +4531,7 @@ Signal Stop\tPrint\tPass to program\tDescription\n")); static void sig_print_info (enum target_signal oursig) { - char *name = target_signal_to_name (oursig); + const char *name = target_signal_to_name (oursig); int name_padding = 13 - strlen (name); if (name_padding <= 0) @@ -4081,11 +4572,7 @@ handle_command (char *args, int from_tty) /* Break the command line up into args. */ - argv = buildargv (args); - if (argv == NULL) - { - nomem (0); - } + argv = gdb_buildargv (args); old_chain = make_cleanup_freeargv (argv); /* Walk through the args, looking for signal oursigs, signal names, and @@ -4192,8 +4679,8 @@ handle_command (char *args, int from_tty) case TARGET_SIGNAL_INT: if (!allsigs && !sigs[signum]) { - if (query ("%s is used by the debugger.\n\ -Are you sure you want to change it? ", target_signal_to_name ((enum target_signal) signum))) + if (query (_("%s is used by the debugger.\n\ +Are you sure you want to change it? "), target_signal_to_name ((enum target_signal) signum))) { sigs[signum] = 1; } @@ -4218,20 +4705,22 @@ Are you sure you want to change it? ", target_signal_to_name ((enum target_signa argv++; } - target_notice_signals (inferior_ptid); + for (signum = 0; signum < nsigs; signum++) + if (sigs[signum]) + { + target_notice_signals (inferior_ptid); - if (from_tty) - { - /* Show the results. */ - sig_print_header (); - for (signum = 0; signum < nsigs; signum++) - { - if (sigs[signum]) - { - sig_print_info (signum); - } - } - } + if (from_tty) + { + /* Show the results. */ + sig_print_header (); + for (; signum < nsigs; signum++) + if (sigs[signum]) + sig_print_info (signum); + } + + break; + } do_cleanups (old_chain); } @@ -4242,13 +4731,12 @@ xdb_handle_command (char *args, int from_tty) char **argv; struct cleanup *old_chain; + if (args == NULL) + error_no_arg (_("xdb command")); + /* Break the command line up into args. */ - argv = buildargv (args); - if (argv == NULL) - { - nomem (0); - } + argv = gdb_buildargv (args); old_chain = make_cleanup_freeargv (argv); if (argv[1] != (char *) NULL) { @@ -4343,11 +4831,167 @@ signals_info (char *signum_exp, int from_tty) printf_filtered (_("\nUse the \"handle\" command to change these tables.\n")); } + +/* The $_siginfo convenience variable is a bit special. We don't know + for sure the type of the value until we actually have a chance to + fetch the data. The type can change depending on gdbarch, so it it + also dependent on which thread you have selected. + + 1. making $_siginfo be an internalvar that creates a new value on + access. + + 2. making the value of $_siginfo be an lval_computed value. */ + +/* This function implements the lval_computed support for reading a + $_siginfo value. */ + +static void +siginfo_value_read (struct value *v) +{ + LONGEST transferred; + + transferred = + target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, + NULL, + value_contents_all_raw (v), + value_offset (v), + TYPE_LENGTH (value_type (v))); + + if (transferred != TYPE_LENGTH (value_type (v))) + error (_("Unable to read siginfo")); +} + +/* This function implements the lval_computed support for writing a + $_siginfo value. */ + +static void +siginfo_value_write (struct value *v, struct value *fromval) +{ + LONGEST transferred; + + transferred = target_write (¤t_target, + TARGET_OBJECT_SIGNAL_INFO, + NULL, + value_contents_all_raw (fromval), + value_offset (v), + TYPE_LENGTH (value_type (fromval))); + + if (transferred != TYPE_LENGTH (value_type (fromval))) + error (_("Unable to write siginfo")); +} + +static struct lval_funcs siginfo_value_funcs = + { + siginfo_value_read, + siginfo_value_write + }; + +/* Return a new value with the correct type for the siginfo object of + the current thread. Return a void value if there's no object + available. */ + +static struct value * +siginfo_make_value (struct internalvar *var) +{ + struct type *type; + struct gdbarch *gdbarch; + + if (target_has_stack + && !ptid_equal (inferior_ptid, null_ptid)) + { + gdbarch = get_frame_arch (get_current_frame ()); + + if (gdbarch_get_siginfo_type_p (gdbarch)) + { + type = gdbarch_get_siginfo_type (gdbarch); + + return allocate_computed_value (type, &siginfo_value_funcs, NULL); + } + } + + return allocate_value (builtin_type_void); +} + -struct inferior_status +/* Inferior thread state. + These are details related to the inferior itself, and don't include + things like what frame the user had selected or what gdb was doing + with the target at the time. + For inferior function calls these are things we want to restore + regardless of whether the function call successfully completes + or the dummy frame has to be manually popped. */ + +struct inferior_thread_state { enum target_signal stop_signal; CORE_ADDR stop_pc; + struct regcache *registers; +}; + +struct inferior_thread_state * +save_inferior_thread_state (void) +{ + struct inferior_thread_state *inf_state = XMALLOC (struct inferior_thread_state); + struct thread_info *tp = inferior_thread (); + + inf_state->stop_signal = tp->stop_signal; + inf_state->stop_pc = stop_pc; + + inf_state->registers = regcache_dup (get_current_regcache ()); + + return inf_state; +} + +/* Restore inferior session state to INF_STATE. */ + +void +restore_inferior_thread_state (struct inferior_thread_state *inf_state) +{ + struct thread_info *tp = inferior_thread (); + + tp->stop_signal = inf_state->stop_signal; + stop_pc = inf_state->stop_pc; + + /* The inferior can be gone if the user types "print exit(0)" + (and perhaps other times). */ + if (target_has_execution) + /* NB: The register write goes through to the target. */ + regcache_cpy (get_current_regcache (), inf_state->registers); + regcache_xfree (inf_state->registers); + xfree (inf_state); +} + +static void +do_restore_inferior_thread_state_cleanup (void *state) +{ + restore_inferior_thread_state (state); +} + +struct cleanup * +make_cleanup_restore_inferior_thread_state (struct inferior_thread_state *inf_state) +{ + return make_cleanup (do_restore_inferior_thread_state_cleanup, inf_state); +} + +void +discard_inferior_thread_state (struct inferior_thread_state *inf_state) +{ + regcache_xfree (inf_state->registers); + xfree (inf_state); +} + +struct regcache * +get_inferior_thread_state_regcache (struct inferior_thread_state *inf_state) +{ + return inf_state->registers; +} + +/* Session related state for inferior function calls. + These are the additional bits of state that need to be restored + when an inferior function call successfully completes. */ + +struct inferior_status +{ bpstat stop_bpstat; int stop_step; int stop_stack_dummy; @@ -4361,42 +5005,23 @@ struct inferior_status int stop_after_trap; int stop_soon; - /* These are here because if call_function_by_hand has written some - registers and then decides to call error(), we better not have changed - any registers. */ - struct regcache *registers; - - /* A frame unique identifier. */ + /* ID if the selected frame when the inferior function call was made. */ struct frame_id selected_frame_id; - int breakpoint_proceeded; - int restore_stack_info; int proceed_to_finish; + int in_infcall; }; -void -write_inferior_status_register (struct inferior_status *inf_status, int regno, - LONGEST val) -{ - int size = register_size (current_gdbarch, regno); - void *buf = alloca (size); - store_signed_integer (buf, size, val); - regcache_raw_write (inf_status->registers, regno, buf); -} - /* Save all of the information associated with the inferior<==>gdb - connection. INF_STATUS is a pointer to a "struct inferior_status" - (defined in inferior.h). */ + connection. */ struct inferior_status * -save_inferior_status (int restore_stack_info) +save_inferior_status (void) { struct inferior_status *inf_status = XMALLOC (struct inferior_status); struct thread_info *tp = inferior_thread (); struct inferior *inf = current_inferior (); - inf_status->stop_signal = tp->stop_signal; - inf_status->stop_pc = stop_pc; inf_status->stop_step = tp->stop_step; inf_status->stop_stack_dummy = stop_stack_dummy; inf_status->stopped_by_random_signal = stopped_by_random_signal; @@ -4413,13 +5038,11 @@ save_inferior_status (int restore_stack_info) called. */ inf_status->stop_bpstat = tp->stop_bpstat; tp->stop_bpstat = bpstat_copy (tp->stop_bpstat); - inf_status->breakpoint_proceeded = breakpoint_proceeded; - inf_status->restore_stack_info = restore_stack_info; inf_status->proceed_to_finish = tp->proceed_to_finish; - - inf_status->registers = regcache_dup (get_current_regcache ()); + inf_status->in_infcall = tp->in_infcall; inf_status->selected_frame_id = get_frame_id (get_selected_frame (NULL)); + return inf_status; } @@ -4444,14 +5067,14 @@ restore_selected_frame (void *args) return (1); } +/* Restore inferior session state to INF_STATUS. */ + void restore_inferior_status (struct inferior_status *inf_status) { struct thread_info *tp = inferior_thread (); struct inferior *inf = current_inferior (); - tp->stop_signal = inf_status->stop_signal; - stop_pc = inf_status->stop_pc; tp->stop_step = inf_status->stop_step; stop_stack_dummy = inf_status->stop_stack_dummy; stopped_by_random_signal = inf_status->stopped_by_random_signal; @@ -4464,24 +5087,11 @@ restore_inferior_status (struct inferior_status *inf_status) inf->stop_soon = inf_status->stop_soon; bpstat_clear (&tp->stop_bpstat); tp->stop_bpstat = inf_status->stop_bpstat; - breakpoint_proceeded = inf_status->breakpoint_proceeded; + inf_status->stop_bpstat = NULL; tp->proceed_to_finish = inf_status->proceed_to_finish; + tp->in_infcall = inf_status->in_infcall; - /* The inferior can be gone if the user types "print exit(0)" - (and perhaps other times). */ - if (target_has_execution) - /* NB: The register write goes through to the target. */ - regcache_cpy (get_current_regcache (), inf_status->registers); - regcache_xfree (inf_status->registers); - - /* FIXME: If we are being called after stopping in a function which - is called from gdb, we should not be trying to restore the - selected frame; it just prints a spurious error message (The - message is useful, however, in detecting bugs in gdb (like if gdb - clobbers the stack)). In fact, should we be restoring the - inferior status at all in that case? . */ - - if (target_has_stack && inf_status->restore_stack_info) + if (target_has_stack) { /* The point of catch_errors is that if the stack is clobbered, walking the stack might encounter a garbage pointer and @@ -4493,7 +5103,6 @@ restore_inferior_status (struct inferior_status *inf_status) /* Error in restoring the selected frame. Select the innermost frame. */ select_frame (get_current_frame ()); - } xfree (inf_status); @@ -4516,10 +5125,9 @@ discard_inferior_status (struct inferior_status *inf_status) { /* See save_inferior_status for info on stop_bpstat. */ bpstat_clear (&inf_status->stop_bpstat); - regcache_xfree (inf_status->registers); xfree (inf_status); } - + int inferior_has_forked (ptid_t pid, ptid_t *child_pid) { @@ -4632,6 +5240,19 @@ ptid_equal (ptid_t ptid1, ptid_t ptid2) && ptid1.tid == ptid2.tid); } +/* Returns true if PTID represents a process. */ + +int +ptid_is_pid (ptid_t ptid) +{ + if (ptid_equal (minus_one_ptid, ptid)) + return 0; + if (ptid_equal (null_ptid, ptid)) + return 0; + + return (ptid_get_lwp (ptid) == 0 && ptid_get_tid (ptid) == 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(). */ @@ -4659,6 +5280,55 @@ save_inferior_ptid (void) } +/* User interface for reverse debugging: + Set exec-direction / show exec-direction commands + (returns error unless target implements to_set_exec_direction method). */ + +enum exec_direction_kind execution_direction = EXEC_FORWARD; +static const char exec_forward[] = "forward"; +static const char exec_reverse[] = "reverse"; +static const char *exec_direction = exec_forward; +static const char *exec_direction_names[] = { + exec_forward, + exec_reverse, + NULL +}; + +static void +set_exec_direction_func (char *args, int from_tty, + struct cmd_list_element *cmd) +{ + if (target_can_execute_reverse) + { + if (!strcmp (exec_direction, exec_forward)) + execution_direction = EXEC_FORWARD; + else if (!strcmp (exec_direction, exec_reverse)) + execution_direction = EXEC_REVERSE; + } +} + +static void +show_exec_direction_func (struct ui_file *out, int from_tty, + struct cmd_list_element *cmd, const char *value) +{ + switch (execution_direction) { + case EXEC_FORWARD: + fprintf_filtered (out, _("Forward.\n")); + break; + case EXEC_REVERSE: + fprintf_filtered (out, _("Reverse.\n")); + break; + case EXEC_ERROR: + default: + fprintf_filtered (out, + _("Forward (target `%s' does not support exec-direction).\n"), + target_shortname); + break; + } +} + +/* User interface for non-stop mode. */ + int non_stop = 0; static int non_stop_1 = 0; @@ -4873,16 +5543,28 @@ function is skipped and the step command stops at a different source line."), show_step_stop_if_no_debug, &setlist, &showlist); - add_setshow_boolean_cmd ("can-use-displaced-stepping", class_maintenance, - &can_use_displaced_stepping, _("\ + add_setshow_enum_cmd ("displaced-stepping", class_run, + can_use_displaced_stepping_enum, + &can_use_displaced_stepping, _("\ Set debugger's willingness to use displaced stepping."), _("\ Show debugger's willingness to use displaced stepping."), _("\ -If zero, gdb will not use displaced stepping to step over\n\ -breakpoints, even if such is supported by the target."), - NULL, - show_can_use_displaced_stepping, - &maintenance_set_cmdlist, - &maintenance_show_cmdlist); +If on, gdb will use displaced stepping to step over breakpoints if it is\n\ +supported by the target architecture. If off, gdb will not use displaced\n\ +stepping to step over breakpoints, even if such is supported by the target\n\ +architecture. If auto (which is the default), gdb will use displaced stepping\n\ +if the target architecture supports it and non-stop mode is active, but will not\n\ +use it in all-stop mode (see help set non-stop)."), + NULL, + show_can_use_displaced_stepping, + &setlist, &showlist); + + add_setshow_enum_cmd ("exec-direction", class_run, exec_direction_names, + &exec_direction, _("Set direction of execution.\n\ +Options are 'forward' or 'reverse'."), + _("Show direction of execution (forward/reverse)."), + _("Tells gdb whether to execute forward or backward."), + set_exec_direction_func, show_exec_direction_func, + &setlist, &showlist); /* ptid initializations */ null_ptid = ptid_build (0, 0, 0); @@ -4892,4 +5574,11 @@ breakpoints, even if such is supported by the target."), displaced_step_ptid = null_ptid; observer_attach_thread_ptid_changed (infrun_thread_ptid_changed); + observer_attach_thread_stop_requested (infrun_thread_stop_requested); + + /* 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); }