X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;ds=sidebyside;f=gdb%2Finfrun.c;h=d68ab16dfc50a150f73267e73a53c3095ad6fca4;hb=60250e8b18a4dee75e82d49da715681d41561b3b;hp=bec87465bdfd0c5e8916b5209b24b76be7ba22f9;hpb=00d4360e1c3b690029405686bd10559da3e44796;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index bec87465bd..d68ab16dfc 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -28,6 +28,7 @@ #include "symtab.h" #include "frame.h" #include "inferior.h" +#include "exceptions.h" #include "breakpoint.h" #include "gdb_wait.h" #include "gdbcore.h" @@ -106,6 +107,8 @@ static ptid_t previous_inferior_ptid; static int may_follow_exec = MAY_FOLLOW_EXEC; +static int debug_infrun = 0; + /* If the program uses ELF-style shared libraries, then calls to functions in shared libraries go through stubs, which live in a table called the PLT (Procedure Linkage Table). The first time the @@ -161,24 +164,6 @@ static int may_follow_exec = MAY_FOLLOW_EXEC; #define SOLIB_IN_DYNAMIC_LINKER(pid,pc) 0 #endif -/* On MIPS16, a function that returns a floating point value may call - a library helper function to copy the return value to a floating point - register. The IGNORE_HELPER_CALL macro returns non-zero if we - should ignore (i.e. step over) this function call. */ -#ifndef IGNORE_HELPER_CALL -#define IGNORE_HELPER_CALL(pc) 0 -#endif - -/* On some systems, the PC may be left pointing at an instruction that won't - actually be executed. This is usually indicated by a bit in the PSW. If - we find ourselves in such a state, then we step the target beyond the - nullified instruction before returning control to the user so as to avoid - confusion. */ - -#ifndef INSTRUCTION_NULLIFIED -#define INSTRUCTION_NULLIFIED 0 -#endif - /* We can't step off a permanent breakpoint in the ordinary way, because we can't remove it. Instead, we have to advance the PC to the next instruction. This macro should expand to a pointer to a function that @@ -262,14 +247,6 @@ static int trap_expected; static int stop_on_solib_events; #endif -#ifdef HP_OS_BUG -/* Nonzero if the next time we try to continue the inferior, it will - step one instruction and generate a spurious trace trap. - This is used to compensate for a bug in HP-UX. */ - -static int trap_expected_after_continue; -#endif - /* Nonzero means expecting a trace trap and should stop the inferior and return silently when it happens. */ @@ -304,14 +281,6 @@ static int stop_print_frame; static struct breakpoint *step_resume_breakpoint = NULL; -/* On some platforms (e.g., HP-UX), hardware watchpoints have bad - interactions with an inferior that is running a kernel function - (aka, a system call or "syscall"). wait_for_inferior therefore - may have a need to know when the inferior is in a syscall. This - is a count of the number of inferior threads which are known to - currently be running in a syscall. */ -static int number_of_threads_in_syscalls; - /* This is a cached copy of the pid/waitstatus of the last event returned by target_wait()/deprecated_target_wait_hook(). This information is returned by get_last_target_status(). */ @@ -500,14 +469,15 @@ static const char *scheduler_enums[] = { static void set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c) { - /* NOTE: cagney/2002-03-17: The add_show_from_set() function clones - the set command passed as a parameter. The clone operation will - include (BUG?) any ``set'' command callback, if present. - Commands like ``info set'' call all the ``show'' command - callbacks. Unfortunately, for ``show'' commands cloned from - ``set'', this includes callbacks belonging to ``set'' commands. - Making this worse, this only occures if add_show_from_set() is - called after add_cmd_sfunc() (BUG?). */ + /* NOTE: cagney/2002-03-17: The deprecated_add_show_from_set() + function clones the set command passed as a parameter. The clone + operation will include (BUG?) any ``set'' command callback, if + present. Commands like ``info set'' call all the ``show'' + command callbacks. Unfortunately, for ``show'' commands cloned + from ``set'', this includes callbacks belonging to ``set'' + commands. Making this worse, this only occures if + deprecated_add_show_from_set() is called after add_cmd_sfunc() + (BUG?). */ if (cmd_type (c) == set_cmd) if (!target_can_lock_scheduler) { @@ -532,6 +502,9 @@ resume (int step, enum target_signal sig) struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); QUIT; + if (debug_infrun) + printf_unfiltered ("infrun: resume (step=%d, signal=%d)\n", step, sig); + /* FIXME: calling breakpoint_here_p (read_pc ()) three times! */ @@ -595,9 +568,9 @@ resume (int step, enum target_signal sig) resume_ptid = RESUME_ALL; /* Default */ - if ((step || singlestep_breakpoints_inserted_p) && - (stepping_past_singlestep_breakpoint - || (!breakpoints_inserted && breakpoint_here_p (read_pc ())))) + if ((step || singlestep_breakpoints_inserted_p) + && (stepping_past_singlestep_breakpoint + || (!breakpoints_inserted && breakpoint_here_p (read_pc ())))) { /* Stepping past a breakpoint without inserting breakpoints. Make sure only the current thread gets to step, so that @@ -607,9 +580,9 @@ resume (int step, enum target_signal sig) resume_ptid = inferior_ptid; } - if ((scheduler_mode == schedlock_on) || - (scheduler_mode == schedlock_step && - (step || singlestep_breakpoints_inserted_p))) + if ((scheduler_mode == schedlock_on) + || (scheduler_mode == schedlock_step + && (step || singlestep_breakpoints_inserted_p))) { /* User-settable 'scheduler' mode requires solo thread resume. */ resume_ptid = inferior_ptid; @@ -664,8 +637,8 @@ prepare_to_proceed (void) /* Make sure we were stopped either at a breakpoint, or because of a Ctrl-C. */ if (wait_status.kind != TARGET_WAITKIND_STOPPED - || (wait_status.value.sig != TARGET_SIGNAL_TRAP && - wait_status.value.sig != TARGET_SIGNAL_INT)) + || (wait_status.value.sig != TARGET_SIGNAL_TRAP + && wait_status.value.sig != TARGET_SIGNAL_INT)) { return 0; } @@ -689,15 +662,15 @@ prepare_to_proceed (void) select_frame (get_current_frame ()); } - /* We return 1 to indicate that there is a breakpoint here, - so we need to step over it before continuing to avoid - hitting it straight away. */ - if (breakpoint_here_p (wait_pc)) - return 1; + /* We return 1 to indicate that there is a breakpoint here, + so we need to step over it before continuing to avoid + hitting it straight away. */ + if (breakpoint_here_p (wait_pc)) + return 1; } return 0; - + } /* Record the pc of the program the last time it stopped. This is @@ -729,24 +702,17 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) if (addr == (CORE_ADDR) -1) { - /* If 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). */ - if (read_pc () == stop_pc && breakpoint_here_p (read_pc ())) + /* 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). */ oneproc = 1; - -#ifndef STEP_SKIPS_DELAY -#define STEP_SKIPS_DELAY(pc) (0) -#define STEP_SKIPS_DELAY_P (0) -#endif - /* Check breakpoint_here_p first, because breakpoint_here_p is fast - (it just checks internal GDB data structures) and STEP_SKIPS_DELAY - is slow (it needs to read memory from the target). */ - if (STEP_SKIPS_DELAY_P - && breakpoint_here_p (read_pc () + 4) - && STEP_SKIPS_DELAY (read_pc ())) + else if (gdbarch_single_step_through_delay_p (current_gdbarch) + && gdbarch_single_step_through_delay (current_gdbarch, + get_current_frame ())) + /* We stepped onto an instruction that needs to be stepped + again before re-inserting the breakpoint, do so. */ oneproc = 1; } else @@ -754,6 +720,10 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) write_pc (addr); } + if (debug_infrun) + printf_unfiltered ("infrun: proceed (addr=0x%s, signal=%d, step=%d)\n", + paddr_nz (addr), siggnal, step); + /* In a multi-threaded task we may select another thread and then continue or step. @@ -768,18 +738,6 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) if (prepare_to_proceed () && breakpoint_here_p (read_pc ())) oneproc = 1; -#ifdef HP_OS_BUG - if (trap_expected_after_continue) - { - /* If (step == 0), a trap will be automatically generated after - the first instruction is executed. Force step one - instruction to clear this condition. This should not occur - if step is nonzero, but it is harmless in that case. */ - oneproc = 1; - trap_expected_after_continue = 0; - } -#endif /* HP_OS_BUG */ - if (oneproc) /* We will get a trace trap after one instruction. Continue it automatically and insert breakpoints then. */ @@ -788,7 +746,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) { insert_breakpoints (); /* If we get here there was no call to error() in - insert breakpoints -- so they were inserted. */ + insert breakpoints -- so they were inserted. */ breakpoints_inserted = 1; } @@ -826,7 +784,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) cannot be read unless the inferior is stopped. At that point, we are not guaranteed the inferior is stopped and so the read_pc () call can fail. Setting the prev_pc value here ensures the value is - updated correctly when the inferior is stopped. */ + updated correctly when the inferior is stopped. */ prev_pc = read_pc (); /* Resume inferior. */ @@ -836,7 +794,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) and in any case decode why it stopped, and act accordingly. */ /* Do this only if we are not using the event loop, or if the target does not support asynchronous execution. */ - if (!event_loop_p || !target_can_async_p ()) + if (!target_can_async_p ()) { wait_for_inferior (); normal_stop (); @@ -880,9 +838,6 @@ init_wait_for_inferior (void) /* These are meaningless until the first time through wait_for_inferior. */ prev_pc = 0; -#ifdef HP_OS_BUG - trap_expected_after_continue = 0; -#endif breakpoints_inserted = 0; breakpoint_init_inferior (inf_starting); @@ -892,9 +847,6 @@ init_wait_for_inferior (void) /* The first resume is not following a fork/vfork/exec. */ pending_follow.kind = TARGET_WAITKIND_SPURIOUS; /* I.e., none. */ - /* See wait_for_inferior's handling of SYSCALL_ENTRY/RETURN events. */ - number_of_threads_in_syscalls = 0; - clear_proceed_status (); stepping_past_singlestep_breakpoint = 0; @@ -908,7 +860,6 @@ enum infwait_states { infwait_normal_state, infwait_thread_hop_state, - infwait_nullified_state, infwait_nonstep_watch_state }; @@ -944,16 +895,14 @@ struct execution_control_state CORE_ADDR stop_func_end; char *stop_func_name; struct symtab_and_line sal; - int remove_breakpoints_on_following_step; int current_line; struct symtab *current_symtab; int handling_longjmp; /* FIXME */ ptid_t ptid; ptid_t saved_inferior_ptid; + int step_after_step_resume_breakpoint; int stepping_through_solib_after_catch; bpstat stepping_through_solib_catchpoints; - int enable_hw_watchpoints_after_wait; - int stepping_through_sigtramp; int new_thread_event; struct target_waitstatus tmpstatus; enum infwait_states infwait_state; @@ -963,12 +912,12 @@ struct execution_control_state void init_execution_control_state (struct execution_control_state *ecs); -static void handle_step_into_function (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 insert_step_resume_breakpoint (struct frame_info *step_frame, - 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_sal (struct symtab_and_line sr_sal, + struct frame_id sr_id); 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); @@ -988,6 +937,9 @@ wait_for_inferior (void) struct execution_control_state ecss; struct execution_control_state *ecs; + if (debug_infrun) + printf_unfiltered ("infrun: wait_for_inferior\n"); + old_cleanups = make_cleanup (delete_step_resume_breakpoint, &step_resume_breakpoint); @@ -1099,12 +1051,10 @@ init_execution_control_state (struct execution_control_state *ecs) { /* ecs->another_trap? */ ecs->random_signal = 0; - ecs->remove_breakpoints_on_following_step = 0; + ecs->step_after_step_resume_breakpoint = 0; ecs->handling_longjmp = 0; /* FIXME */ ecs->stepping_through_solib_after_catch = 0; ecs->stepping_through_solib_catchpoints = NULL; - ecs->enable_hw_watchpoints_after_wait = 0; - ecs->stepping_through_sigtramp = 0; ecs->sal = find_pc_line (prev_pc, 0); ecs->current_line = ecs->sal.line; ecs->current_symtab = ecs->sal.symtab; @@ -1113,18 +1063,6 @@ init_execution_control_state (struct execution_control_state *ecs) ecs->wp = &(ecs->ws); } -/* Call this function before setting step_resume_breakpoint, as a - sanity check. There should never be more than one step-resume - breakpoint per thread, so we should never be setting a new - step_resume_breakpoint when one is already active. */ -static void -check_for_old_step_resume_breakpoint (void) -{ - if (step_resume_breakpoint) - warning - ("GDB bug: infrun.c (wait_for_inferior): dropping old step_resume breakpoint"); -} - /* Return the cached copy of the last pid/waitstatus returned by target_wait()/deprecated_target_wait_hook(). The data is actually cached by handle_inferior_event(), which gets called immediately @@ -1158,7 +1096,6 @@ context_switch (struct execution_control_state *ecs) ecs->handling_longjmp, ecs->another_trap, ecs->stepping_through_solib_after_catch, ecs->stepping_through_solib_catchpoints, - ecs->stepping_through_sigtramp, ecs->current_line, ecs->current_symtab); /* Load infrun state for the new thread. */ @@ -1169,92 +1106,11 @@ context_switch (struct execution_control_state *ecs) &ecs->handling_longjmp, &ecs->another_trap, &ecs->stepping_through_solib_after_catch, &ecs->stepping_through_solib_catchpoints, - &ecs->stepping_through_sigtramp, &ecs->current_line, &ecs->current_symtab); } inferior_ptid = ecs->ptid; } -/* Handle the inferior event in the cases when we just stepped - into a function. */ - -static void -handle_step_into_function (struct execution_control_state *ecs) -{ - CORE_ADDR real_stop_pc; - - if ((step_over_calls == STEP_OVER_NONE) - || ((step_range_end == 1) - && in_prologue (prev_pc, ecs->stop_func_start))) - { - /* I presume that step_over_calls is only 0 when we're - supposed to be stepping at the assembly language level - ("stepi"). Just stop. */ - /* Also, maybe we just did a "nexti" inside a prolog, - so we thought it was a subroutine call but it was not. - Stop as well. FENN */ - stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); - stop_stepping (ecs); - return; - } - - if (step_over_calls == STEP_OVER_ALL || IGNORE_HELPER_CALL (stop_pc)) - { - /* 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 (get_prev_frame (get_current_frame ()), - ecs); - keep_going (ecs); - return; - } - - /* If we are in a function call trampoline (a stub between - the calling routine and the real function), locate the real - function. That's what tells us (a) whether we want to step - into it at all, and (b) what prologue we want to run to - the end of, if we do step into it. */ - real_stop_pc = skip_language_trampoline (stop_pc); - if (real_stop_pc == 0) - real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc); - if (real_stop_pc != 0) - ecs->stop_func_start = real_stop_pc; - - /* If we have line number information for the function we - are thinking of stepping into, step into it. - - If there are several symtabs at that PC (e.g. with include - files), just want to know whether *any* of them have line - numbers. find_pc_line handles this. */ - { - struct symtab_and_line tmp_sal; - - tmp_sal = find_pc_line (ecs->stop_func_start, 0); - if (tmp_sal.line != 0) - { - step_into_function (ecs); - return; - } - } - - /* If we have no line number and the step-stop-if-no-debug - is set, we stop the step so that the user has a chance to - switch in assembly mode. */ - if (step_over_calls == STEP_OVER_UNDEBUGGABLE && step_stop_if_no_debug) - { - stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); - stop_stepping (ecs); - return; - } - - /* Set a breakpoint at callee's return address (the address at which - the caller will resume). */ - insert_step_resume_breakpoint (get_prev_frame (get_current_frame ()), ecs); - keep_going (ecs); - return; -} - static void adjust_pc_after_break (struct execution_control_state *ecs) { @@ -1272,14 +1128,14 @@ adjust_pc_after_break (struct execution_control_state *ecs) affected by DECR_PC_AFTER_BREAK. Other waitkinds which are implemented by software breakpoints should be handled through the normal breakpoint layer. - + NOTE drow/2004-01-31: On some targets, breakpoints may generate different signals (SIGILL or SIGEMT for instance), but it is less clear where the PC is pointing afterwards. It may not match DECR_PC_AFTER_BREAK. I don't know any specific target that generates these signals at breakpoints (the code has been in GDB since at least 1992) so I can not guess how to handle them here. - + In earlier versions of GDB, a target with HAVE_NONSTEPPABLE_WATCHPOINTS would have the PC after hitting a watchpoint affected by DECR_PC_AFTER_BREAK. I haven't found any target with both of these set @@ -1299,8 +1155,8 @@ adjust_pc_after_break (struct execution_control_state *ecs) if (SOFTWARE_SINGLE_STEP_P ()) { /* When using software single-step, a SIGTRAP can only indicate - an inserted breakpoint. This actually makes things - easier. */ + an inserted breakpoint. This actually makes things + easier. */ if (singlestep_breakpoints_inserted_p) /* When software single stepping, the instruction at [prev_pc] is never a breakpoint, but the instruction following @@ -1316,9 +1172,9 @@ adjust_pc_after_break (struct execution_control_state *ecs) else { /* When using hardware single-step, a SIGTRAP is reported for - both a completed single-step and a software breakpoint. Need - to differentiate between the two as the latter needs - adjusting but the former does not. */ + both a completed single-step and a software breakpoint. Need + to differentiate between the two as the latter needs + adjusting but the former does not. */ if (currently_stepping (ecs)) { if (prev_pc == breakpoint_pc @@ -1356,7 +1212,7 @@ handle_inferior_event (struct execution_control_state *ecs) defined in the file "config/pa/nm-hppah.h", accesses the variable indirectly. Mutter something rude about the HP merge. */ int sw_single_step_trap_p = 0; - int stopped_by_watchpoint = 0; + int stopped_by_watchpoint = -1; /* Mark as unknown. */ /* Cache the last pid/waitstatus. */ target_last_wait_ptid = ecs->ptid; @@ -1367,34 +1223,21 @@ handle_inferior_event (struct execution_control_state *ecs) switch (ecs->infwait_state) { case infwait_thread_hop_state: + if (debug_infrun) + printf_unfiltered ("infrun: infwait_thread_hop_state\n"); /* Cancel the waiton_ptid. */ ecs->waiton_ptid = pid_to_ptid (-1); - /* See comments where a TARGET_WAITKIND_SYSCALL_RETURN event - is serviced in this loop, below. */ - if (ecs->enable_hw_watchpoints_after_wait) - { - TARGET_ENABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid)); - ecs->enable_hw_watchpoints_after_wait = 0; - } - stepped_after_stopped_by_watchpoint = 0; break; case infwait_normal_state: - /* See comments where a TARGET_WAITKIND_SYSCALL_RETURN event - is serviced in this loop, below. */ - if (ecs->enable_hw_watchpoints_after_wait) - { - TARGET_ENABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid)); - ecs->enable_hw_watchpoints_after_wait = 0; - } - stepped_after_stopped_by_watchpoint = 0; - break; - - case infwait_nullified_state: + if (debug_infrun) + printf_unfiltered ("infrun: infwait_normal_state\n"); stepped_after_stopped_by_watchpoint = 0; break; case infwait_nonstep_watch_state: + if (debug_infrun) + printf_unfiltered ("infrun: infwait_nonstep_watch_state\n"); insert_breakpoints (); /* FIXME-maybe: is this cleaner than setting a flag? Does it @@ -1413,6 +1256,7 @@ handle_inferior_event (struct execution_control_state *ecs) /* If it's a new process, add it to the thread database */ ecs->new_thread_event = (!ptid_equal (ecs->ptid, inferior_ptid) + && !ptid_equal (ecs->ptid, minus_one_ptid) && !in_thread_list (ecs->ptid)); if (ecs->ws.kind != TARGET_WAITKIND_EXITED @@ -1423,36 +1267,13 @@ handle_inferior_event (struct execution_control_state *ecs) ui_out_text (uiout, "[New "); ui_out_text (uiout, target_pid_or_tid_to_str (ecs->ptid)); ui_out_text (uiout, "]\n"); - -#if 0 - /* NOTE: This block is ONLY meant to be invoked in case of a - "thread creation event"! If it is invoked for any other - sort of event (such as a new thread landing on a breakpoint), - the event will be discarded, which is almost certainly - a bad thing! - - To avoid this, the low-level module (eg. target_wait) - should call in_thread_list and add_thread, so that the - new thread is known by the time we get here. */ - - /* We may want to consider not doing a resume here in order - to give the user a chance to play with the new thread. - It might be good to make that a user-settable option. */ - - /* At this point, all threads are stopped (happens - automatically in either the OS or the native code). - Therefore we need to continue all threads in order to - make progress. */ - - target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0); - prepare_to_wait (ecs); - return; -#endif } switch (ecs->ws.kind) { case TARGET_WAITKIND_LOADED: + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_LOADED\n"); /* Ignore gracefully during startup of the inferior, as it might be the shell which has just loaded some objects, otherwise add the symbols for the newly loaded objects. */ @@ -1470,20 +1291,20 @@ handle_inferior_event (struct execution_control_state *ecs) 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). */ + 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). */ /* NOTE: cagney/2003-11-25: Pass current_target and not - exec_ops to SOLIB_ADD. This is because current GDB is - only tooled to propagate section_table changes out from - the "current_target" (see target_resize_to_sections), and - not up from the exec stratum. This, of course, isn't - right. "infrun.c" should only interact with the - exec/process stratum, instead relying on the target stack - to propagate relevant changes (stop, section table - changed, ...) up to other layers. */ + exec_ops to SOLIB_ADD. This is because current GDB is + only tooled to propagate section_table changes out from + the "current_target" (see target_resize_to_sections), and + not up from the exec stratum. This, of course, isn't + right. "infrun.c" should only interact with the + exec/process stratum, instead relying on the target stack + to propagate relevant changes (stop, section table + changed, ...) up to other layers. */ SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); target_terminal_inferior (); @@ -1497,11 +1318,15 @@ handle_inferior_event (struct execution_control_state *ecs) return; case TARGET_WAITKIND_SPURIOUS: + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_SPURIOUS\n"); resume (0, TARGET_SIGNAL_0); prepare_to_wait (ecs); return; case TARGET_WAITKIND_EXITED: + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_EXITED\n"); target_terminal_ours (); /* Must do this before mourn anyway */ print_stop_reason (EXITED, ecs->ws.value.integer); @@ -1518,6 +1343,8 @@ handle_inferior_event (struct execution_control_state *ecs) return; case TARGET_WAITKIND_SIGNALLED: + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_SIGNALLED\n"); stop_print_frame = 0; stop_signal = ecs->ws.value.sig; target_terminal_ours (); /* Must do this before mourn anyway */ @@ -1538,6 +1365,8 @@ handle_inferior_event (struct execution_control_state *ecs) the above cases end in a continue or goto. */ case TARGET_WAITKIND_FORKED: case TARGET_WAITKIND_VFORKED: + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_FORKED\n"); stop_signal = TARGET_SIGNAL_TRAP; pending_follow.kind = ecs->ws.kind; @@ -1560,11 +1389,13 @@ handle_inferior_event (struct execution_control_state *ecs) goto process_event_stop_test; case TARGET_WAITKIND_EXECD: + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_EXECED\n"); stop_signal = TARGET_SIGNAL_TRAP; /* NOTE drow/2002-12-05: This code should be pushed down into the - target_wait function. Until then following vfork on HP/UX 10.20 - is probably broken by this. Of course, it's broken anyway. */ + target_wait function. Until then following vfork on HP/UX 10.20 + is probably broken by this. Of course, it's broken anyway. */ /* Is this a target which reports multiple exec events per actual call to exec()? (HP-UX using ptrace does, for example.) If so, ignore all but the last one. Just resume the exec'r, and wait @@ -1609,29 +1440,11 @@ handle_inferior_event (struct execution_control_state *ecs) } goto process_event_stop_test; - /* These syscall events are returned on HP-UX, as part of its - implementation of page-protection-based "hardware" watchpoints. - HP-UX has unfortunate interactions between page-protections and - some system calls. Our solution is to disable hardware watches - when a system call is entered, and reenable them when the syscall - completes. The downside of this is that we may miss the precise - point at which a watched piece of memory is modified. "Oh well." - - Note that we may have multiple threads running, which may each - enter syscalls at roughly the same time. Since we don't have a - good notion currently of whether a watched piece of memory is - thread-private, we'd best not have any page-protections active - when any thread is in a syscall. Thus, we only want to reenable - hardware watches when no threads are in a syscall. - - Also, be careful not to try to gather much state about a thread - that's in a syscall. It's frequently a losing proposition. */ + /* Be careful not to try to gather much state about a thread + that's in a syscall. It's frequently a losing proposition. */ case TARGET_WAITKIND_SYSCALL_ENTRY: - number_of_threads_in_syscalls++; - if (number_of_threads_in_syscalls == 1) - { - TARGET_DISABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid)); - } + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n"); resume (0, TARGET_SIGNAL_0); prepare_to_wait (ecs); return; @@ -1640,42 +1453,32 @@ handle_inferior_event (struct execution_control_state *ecs) get it entirely out of the syscall. (We get notice of the event when the thread is just on the verge of exiting a syscall. Stepping one instruction seems to get it back - into user code.) - - Note that although the logical place to reenable h/w watches - is here, we cannot. We cannot reenable them before stepping - the thread (this causes the next wait on the thread to hang). - - Nor can we enable them after stepping until we've done a wait. - Thus, we simply set the flag ecs->enable_hw_watchpoints_after_wait - here, which will be serviced immediately after the target - is waited on. */ + into user code.) */ case TARGET_WAITKIND_SYSCALL_RETURN: + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_SYSCALL_RETURN\n"); target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); - - if (number_of_threads_in_syscalls > 0) - { - number_of_threads_in_syscalls--; - ecs->enable_hw_watchpoints_after_wait = - (number_of_threads_in_syscalls == 0); - } prepare_to_wait (ecs); return; case TARGET_WAITKIND_STOPPED: + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_STOPPED\n"); stop_signal = ecs->ws.value.sig; break; /* 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. - - One of the possible circumstances for this is when the - inferior produces output for the console. The inferior has - not stopped, and we are ignoring the event. Another possible - circumstance is any event which the lower level knows will be - reported multiple times without an intervening resume. */ + + One of the possible circumstances for this is when the + inferior produces output for the console. The inferior has + not stopped, and we are ignoring the event. Another possible + circumstance is any event which the lower level knows will be + reported multiple times without an intervening resume. */ case TARGET_WAITKIND_IGNORE: + if (debug_infrun) + printf_unfiltered ("infrun: TARGET_WAITKIND_IGNORE\n"); prepare_to_wait (ecs); return; } @@ -1696,19 +1499,25 @@ handle_inferior_event (struct execution_control_state *ecs) stop_pc = read_pc_pid (ecs->ptid); + if (debug_infrun) + printf_unfiltered ("infrun: stop_pc = 0x%s\n", paddr_nz (stop_pc)); + if (stepping_past_singlestep_breakpoint) { - gdb_assert (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p); + gdb_assert (SOFTWARE_SINGLE_STEP_P () + && singlestep_breakpoints_inserted_p); gdb_assert (ptid_equal (singlestep_ptid, ecs->ptid)); gdb_assert (!ptid_equal (singlestep_ptid, saved_singlestep_ptid)); stepping_past_singlestep_breakpoint = 0; /* We've either finished single-stepping past the single-step - breakpoint, or stopped for some other reason. It would be nice if - we could tell, but we can't reliably. */ + breakpoint, or stopped for some other reason. It would be nice if + we could tell, but we can't reliably. */ if (stop_signal == TARGET_SIGNAL_TRAP) - { + { + if (debug_infrun) + printf_unfiltered ("infrun: stepping_past_singlestep_breakpoint\n"); /* Pull the single step breakpoints out of the target. */ SOFTWARE_SINGLE_STEP (0, 0); singlestep_breakpoints_inserted_p = 0; @@ -1762,66 +1571,69 @@ handle_inferior_event (struct execution_control_state *ecs) } if (thread_hop_needed) - { - int remove_status; + { + int remove_status; - /* Saw a breakpoint, but it was hit by the wrong thread. - Just continue. */ + if (debug_infrun) + printf_unfiltered ("infrun: thread_hop_needed\n"); - if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p) - { - /* Pull the single step breakpoints out of the target. */ - SOFTWARE_SINGLE_STEP (0, 0); - singlestep_breakpoints_inserted_p = 0; - } + /* Saw a breakpoint, but it was hit by the wrong thread. + Just continue. */ - remove_status = remove_breakpoints (); - /* Did we fail to remove breakpoints? If so, try - to set the PC past the bp. (There's at least - one situation in which we can fail to remove - the bp's: On HP-UX's that use ttrace, we can't - change the address space of a vforking child - process until the child exits (well, okay, not - then either :-) or execs. */ - if (remove_status != 0) - { - /* FIXME! This is obviously non-portable! */ - write_pc_pid (stop_pc + 4, ecs->ptid); - /* We need to restart all the threads now, - * unles we're running in scheduler-locked mode. - * Use currently_stepping to determine whether to - * step or continue. - */ - /* FIXME MVS: is there any reason not to call resume()? */ - if (scheduler_mode == schedlock_on) - target_resume (ecs->ptid, - currently_stepping (ecs), TARGET_SIGNAL_0); - else - target_resume (RESUME_ALL, - currently_stepping (ecs), TARGET_SIGNAL_0); - prepare_to_wait (ecs); - return; - } + if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p) + { + /* Pull the single step breakpoints out of the target. */ + SOFTWARE_SINGLE_STEP (0, 0); + singlestep_breakpoints_inserted_p = 0; + } + + remove_status = remove_breakpoints (); + /* Did we fail to remove breakpoints? If so, try + to set the PC past the bp. (There's at least + one situation in which we can fail to remove + the bp's: On HP-UX's that use ttrace, we can't + change the address space of a vforking child + process until the child exits (well, okay, not + then either :-) or execs. */ + if (remove_status != 0) + { + /* FIXME! This is obviously non-portable! */ + write_pc_pid (stop_pc + 4, ecs->ptid); + /* We need to restart all the threads now, + * unles we're running in scheduler-locked mode. + * Use currently_stepping to determine whether to + * step or continue. + */ + /* FIXME MVS: is there any reason not to call resume()? */ + if (scheduler_mode == schedlock_on) + target_resume (ecs->ptid, + currently_stepping (ecs), TARGET_SIGNAL_0); else - { /* Single step */ - breakpoints_inserted = 0; - if (!ptid_equal (inferior_ptid, ecs->ptid)) - context_switch (ecs); - ecs->waiton_ptid = ecs->ptid; - ecs->wp = &(ecs->ws); - ecs->another_trap = 1; - - ecs->infwait_state = infwait_thread_hop_state; - keep_going (ecs); - registers_changed (); - return; - } + target_resume (RESUME_ALL, + currently_stepping (ecs), TARGET_SIGNAL_0); + prepare_to_wait (ecs); + return; + } + else + { /* Single step */ + breakpoints_inserted = 0; + if (!ptid_equal (inferior_ptid, ecs->ptid)) + context_switch (ecs); + ecs->waiton_ptid = ecs->ptid; + ecs->wp = &(ecs->ws); + ecs->another_trap = 1; + + ecs->infwait_state = infwait_thread_hop_state; + keep_going (ecs); + registers_changed (); + return; + } } else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p) - { - sw_single_step_trap_p = 1; - ecs->random_signal = 0; - } + { + sw_single_step_trap_p = 1; + ecs->random_signal = 0; + } } else ecs->random_signal = 1; @@ -1830,6 +1642,9 @@ handle_inferior_event (struct execution_control_state *ecs) so, then switch to that thread. */ if (!ptid_equal (ecs->ptid, inferior_ptid)) { + if (debug_infrun) + printf_unfiltered ("infrun: context switch\n"); + context_switch (ecs); if (deprecated_context_hook) @@ -1845,32 +1660,13 @@ handle_inferior_event (struct execution_control_state *ecs) singlestep_breakpoints_inserted_p = 0; } - /* If PC is pointing at a nullified instruction, then step beyond - it so that the user won't be confused when GDB appears to be ready - to execute it. */ - - /* if (INSTRUCTION_NULLIFIED && currently_stepping (ecs)) */ - if (INSTRUCTION_NULLIFIED) - { - registers_changed (); - target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); - - /* We may have received a signal that we want to pass to - the inferior; therefore, we must not clobber the waitstatus - in WS. */ - - ecs->infwait_state = infwait_nullified_state; - ecs->waiton_ptid = ecs->ptid; - ecs->wp = &(ecs->tmpstatus); - prepare_to_wait (ecs); - return; - } - /* It may not be necessary to disable the watchpoint to stop over it. For example, the PA can (with some kernel cooperation) single step over a watchpoint without disabling the watchpoint. */ if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws)) { + if (debug_infrun) + printf_unfiltered ("infrun: STOPPED_BY_WATCHPOINT\n"); resume (1, 0); prepare_to_wait (ecs); return; @@ -1898,6 +1694,8 @@ handle_inferior_event (struct execution_control_state *ecs) includes evaluating watchpoints, things will come to a stop in the correct manner. */ + if (debug_infrun) + printf_unfiltered ("infrun: STOPPED_BY_WATCHPOINT\n"); remove_breakpoints (); registers_changed (); target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */ @@ -1920,7 +1718,7 @@ handle_inferior_event (struct execution_control_state *ecs) will both be 0 if it doesn't work. */ find_pc_partial_function (stop_pc, &ecs->stop_func_name, &ecs->stop_func_start, &ecs->stop_func_end); - ecs->stop_func_start += FUNCTION_START_OFFSET; + ecs->stop_func_start += DEPRECATED_FUNCTION_START_OFFSET; ecs->another_trap = 0; bpstat_clear (&stop_bpstat); stop_step = 0; @@ -1930,6 +1728,41 @@ handle_inferior_event (struct execution_control_state *ecs) stopped_by_random_signal = 0; breakpoints_failed = 0; + if (stop_signal == TARGET_SIGNAL_TRAP + && trap_expected + && gdbarch_single_step_through_delay_p (current_gdbarch) + && currently_stepping (ecs)) + { + /* We're trying to step of a breakpoint. Turns out that we're + also on an instruction that needs to be stepped multiple + times before it's been fully executing. E.g., architectures + with a delay slot. It needs to be stepped twice, once for + the instruction and once for the delay slot. */ + int step_through_delay + = gdbarch_single_step_through_delay (current_gdbarch, + get_current_frame ()); + if (debug_infrun && step_through_delay) + printf_unfiltered ("infrun: step through delay\n"); + if (step_range_end == 0 && step_through_delay) + { + /* The user issued a continue when stopped at a breakpoint. + Set up for another trap and get out of here. */ + ecs->another_trap = 1; + keep_going (ecs); + return; + } + else if (step_through_delay) + { + /* The user issued a step when stopped at a breakpoint. + Maybe we should stop, maybe we should not - the delay + slot *might* correspond to a line of source. In any + case, don't decide that here, just set ecs->another_trap, + making sure we single-step again before breakpoints are + re-inserted. */ + ecs->another_trap = 1; + } + } + /* Look at the cause of the stop, and decide what to do. The alternatives are: 1) break; to really stop and return to the debugger, @@ -1950,15 +1783,16 @@ handle_inferior_event (struct execution_control_state *ecs) stack. */ if (stop_signal == TARGET_SIGNAL_TRAP - || (breakpoints_inserted && - (stop_signal == TARGET_SIGNAL_ILL - || stop_signal == TARGET_SIGNAL_SEGV - || stop_signal == TARGET_SIGNAL_EMT)) - || stop_soon == STOP_QUIETLY - || stop_soon == STOP_QUIETLY_NO_SIGSTOP) + || (breakpoints_inserted + && (stop_signal == TARGET_SIGNAL_ILL + || stop_signal == TARGET_SIGNAL_SEGV + || stop_signal == TARGET_SIGNAL_EMT)) + || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP) { if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap) { + if (debug_infrun) + printf_unfiltered ("infrun: stopped\n"); stop_print_frame = 0; stop_stepping (ecs); return; @@ -1968,6 +1802,8 @@ handle_inferior_event (struct execution_control_state *ecs) shared libraries hook functions. */ if (stop_soon == STOP_QUIETLY) { + if (debug_infrun) + printf_unfiltered ("infrun: quietly stopped\n"); stop_stepping (ecs); return; } @@ -1987,11 +1823,15 @@ handle_inferior_event (struct execution_control_state *ecs) /* Don't even think about breakpoints if just proceeded over a breakpoint. */ if (stop_signal == TARGET_SIGNAL_TRAP && trap_expected) - bpstat_clear (&stop_bpstat); + { + if (debug_infrun) + printf_unfiltered ("infrun: trap expected\n"); + bpstat_clear (&stop_bpstat); + } else { /* See if there is a breakpoint at the current PC. */ - stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, stopped_by_watchpoint); /* Following in case break condition called a @@ -2000,13 +1840,13 @@ handle_inferior_event (struct execution_control_state *ecs) } /* NOTE: cagney/2003-03-29: These two checks for a random signal - at one stage in the past included checks for an inferior - function call's call dummy's return breakpoint. The original - comment, that went with the test, read: + at one stage in the past included checks for an inferior + function call's call dummy's return breakpoint. The original + comment, that went with the test, read: - ``End of a stack dummy. Some systems (e.g. Sony news) give - another signal besides SIGTRAP, so check here as well as - above.'' + ``End of a stack dummy. Some systems (e.g. Sony news) give + another signal besides SIGTRAP, so check here as well as + above.'' If someone ever tries to get get call dummys on a non-executable stack to work (where the target would stop @@ -2015,9 +1855,9 @@ handle_inferior_event (struct execution_control_state *ecs) enabled when momentary breakpoints were not being used, I suspect that it won't be the case. - NOTE: kettenis/2004-02-05: Indeed such checks don't seem to - be necessary for call dummies on a non-executable stack on - SPARC. */ + NOTE: kettenis/2004-02-05: Indeed such checks don't seem to + be necessary for call dummies on a non-executable stack on + SPARC. */ if (stop_signal == TARGET_SIGNAL_TRAP) ecs->random_signal @@ -2048,6 +1888,9 @@ process_event_stop_test: /* Signal not for debugging purposes. */ int printed = 0; + if (debug_infrun) + printf_unfiltered ("infrun: random signal %d\n", stop_signal); + stopped_by_random_signal = 1; if (signal_print[stop_signal]) @@ -2070,10 +1913,29 @@ process_event_stop_test: if (signal_program[stop_signal] == 0) stop_signal = TARGET_SIGNAL_0; - if (step_range_end != 0 - && stop_signal != TARGET_SIGNAL_0 - && stop_pc >= step_range_start && stop_pc < step_range_end - && frame_id_eq (get_frame_id (get_current_frame ()), step_frame_id)) + if (prev_pc == read_pc () + && !breakpoints_inserted + && breakpoint_here_p (read_pc ()) + && step_resume_breakpoint == NULL) + { + /* We were just starting a new sequence, attempting to + single-step off of a breakpoint and expecting a SIGTRAP. + Intead this signal arrives. This signal will take us out + of the stepping range so GDB needs to remember to, when + the signal handler returns, resume stepping off that + breakpoint. */ + /* To simplify things, "continue" is forced to use the same + code paths as single-step - set a breakpoint at the + signal return address and then, once hit, step off that + breakpoint. */ + insert_step_resume_breakpoint_at_frame (get_current_frame ()); + ecs->step_after_step_resume_breakpoint = 1; + } + else if (step_range_end != 0 + && stop_signal != TARGET_SIGNAL_0 + && stop_pc >= step_range_start && stop_pc < step_range_end + && frame_id_eq (get_frame_id (get_current_frame ()), + step_frame_id)) { /* The inferior is about to take a signal that will take it out of the single step range. Set a breakpoint at the @@ -2084,7 +1946,7 @@ process_event_stop_test: Note that this is only needed for a signal delivered while in the single-step range. Nested signals aren't a problem as they eventually all return. */ - insert_step_resume_breakpoint (get_current_frame (), ecs); + insert_step_resume_breakpoint_at_frame (get_current_frame ()); } keep_going (ecs); return; @@ -2100,9 +1962,6 @@ process_event_stop_test: if (what.call_dummy) { stop_stack_dummy = 1; -#ifdef HP_OS_BUG - trap_expected_after_continue = 1; -#endif } switch (what.main_action) @@ -2111,6 +1970,8 @@ process_event_stop_test: /* If we hit the breakpoint at longjmp, disable it for the duration of this command. Then, install a temporary breakpoint at the target of the jmp_buf. */ + if (debug_infrun) + printf_unfiltered ("infrun: BPSTATE_WHAT_SET_LONGJMP_RESUME\n"); disable_longjmp_breakpoint (); remove_breakpoints (); breakpoints_inserted = 0; @@ -2127,32 +1988,17 @@ process_event_stop_test: delete_step_resume_breakpoint (&step_resume_breakpoint); } -#if 0 - /* FIXME - Need to implement nested temporary breakpoints */ - if (step_over_calls > 0) - set_longjmp_resume_breakpoint (jmp_buf_pc, get_current_frame ()); - else -#endif /* 0 */ - set_longjmp_resume_breakpoint (jmp_buf_pc, null_frame_id); + set_longjmp_resume_breakpoint (jmp_buf_pc, null_frame_id); ecs->handling_longjmp = 1; /* FIXME */ keep_going (ecs); return; case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME: case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE: + if (debug_infrun) + printf_unfiltered ("infrun: BPSTATE_WHAT_CLEAR_LONGJMP_RESUME\n"); remove_breakpoints (); breakpoints_inserted = 0; -#if 0 - /* FIXME - Need to implement nested temporary breakpoints */ - if (step_over_calls - && (frame_id_inner (get_frame_id (get_current_frame ()), - step_frame_id))) - { - ecs->another_trap = 1; - keep_going (ecs); - return; - } -#endif /* 0 */ disable_longjmp_breakpoint (); ecs->handling_longjmp = 0; /* FIXME */ if (what.main_action == BPSTAT_WHAT_CLEAR_LONGJMP_RESUME) @@ -2160,6 +2006,8 @@ process_event_stop_test: /* else fallthrough */ case BPSTAT_WHAT_SINGLE: + if (debug_infrun) + printf_unfiltered ("infrun: BPSTATE_WHAT_SINGLE\n"); if (breakpoints_inserted) { remove_breakpoints (); @@ -2171,6 +2019,8 @@ process_event_stop_test: break; case BPSTAT_WHAT_STOP_NOISY: + if (debug_infrun) + printf_unfiltered ("infrun: BPSTATE_WHAT_STOP_NOISY\n"); stop_print_frame = 1; /* We are about to nuke the step_resume_breakpointt via the @@ -2180,6 +2030,8 @@ process_event_stop_test: return; case BPSTAT_WHAT_STOP_SILENT: + if (debug_infrun) + printf_unfiltered ("infrun: BPSTATE_WHAT_STOP_SILENT\n"); stop_print_frame = 0; /* We are about to nuke the step_resume_breakpoin via the @@ -2206,15 +2058,32 @@ process_event_stop_test: step-resume bp, but it makes no effort to ensure that the one deleted is the one currently stopped at. MVS */ + if (debug_infrun) + printf_unfiltered ("infrun: BPSTATE_WHAT_STEP_RESUME\n"); + if (step_resume_breakpoint == NULL) { step_resume_breakpoint = bpstat_find_step_resume_breakpoint (stop_bpstat); } delete_step_resume_breakpoint (&step_resume_breakpoint); + if (ecs->step_after_step_resume_breakpoint) + { + /* Back when the step-resume breakpoint was inserted, we + were trying to single-step off a breakpoint. Go back + to doing that. */ + ecs->step_after_step_resume_breakpoint = 0; + remove_breakpoints (); + breakpoints_inserted = 0; + ecs->another_trap = 1; + keep_going (ecs); + return; + } break; case BPSTAT_WHAT_THROUGH_SIGTRAMP: + if (debug_infrun) + printf_unfiltered ("infrun: BPSTATE_WHAT_THROUGH_SIGTRAMP\n"); /* If were waiting for a trap, hitting the step_resume_break doesn't count as getting it. */ if (trap_expected) @@ -2225,6 +2094,8 @@ process_event_stop_test: case BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK: #ifdef SOLIB_ADD { + if (debug_infrun) + printf_unfiltered ("infrun: BPSTATE_WHAT_CHECK_SHLIBS\n"); /* Remove breakpoints, we eventually want to step over the shlib event breakpoint, and SOLIB_ADD might adjust breakpoint addresses via breakpoint_re_set. */ @@ -2238,20 +2109,20 @@ process_event_stop_test: 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). */ + 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). */ /* NOTE: cagney/2003-11-25: Pass current_target and not - exec_ops to SOLIB_ADD. This is because current GDB is - only tooled to propagate section_table changes out from - the "current_target" (see target_resize_to_sections), and - not up from the exec stratum. This, of course, isn't - right. "infrun.c" should only interact with the - exec/process stratum, instead relying on the target stack - to propagate relevant changes (stop, section table - changed, ...) up to other layers. */ + exec_ops to SOLIB_ADD. This is because current GDB is + only tooled to propagate section_table changes out from + the "current_target" (see target_resize_to_sections), and + not up from the exec stratum. This, of course, isn't + right. "infrun.c" should only interact with the + exec/process stratum, instead relying on the target stack + to propagate relevant changes (stop, section table + changed, ...) up to other layers. */ SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); target_terminal_inferior (); @@ -2279,8 +2150,8 @@ process_event_stop_test: 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) + 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 @@ -2337,11 +2208,15 @@ process_event_stop_test: /* Have we reached our destination? If not, keep going. */ if (SOLIB_IN_DYNAMIC_LINKER (PIDGET (ecs->ptid), stop_pc)) { + if (debug_infrun) + printf_unfiltered ("infrun: stepping in dynamic linker\n"); ecs->another_trap = 1; keep_going (ecs); return; } #endif + if (debug_infrun) + printf_unfiltered ("infrun: step past dynamic linker\n"); /* Else, stop and report the catchpoint(s) whose triggering caused us to begin stepping. */ ecs->stepping_through_solib_after_catch = 0; @@ -2355,6 +2230,9 @@ process_event_stop_test: if (step_resume_breakpoint) { + if (debug_infrun) + printf_unfiltered ("infrun: step-resume breakpoint\n"); + /* Having a step-resume breakpoint overrides anything else having to do with stepping commands until that breakpoint is reached. */ @@ -2364,6 +2242,8 @@ process_event_stop_test: if (step_range_end == 0) { + if (debug_infrun) + printf_unfiltered ("infrun: no stepping, continue\n"); /* Likewise if we aren't even stepping. */ keep_going (ecs); return; @@ -2376,6 +2256,10 @@ process_event_stop_test: within it! */ if (stop_pc >= step_range_start && stop_pc < step_range_end) { + if (debug_infrun) + printf_unfiltered ("infrun: stepping inside range [0x%s-0x%s]\n", + paddr_nz (step_range_start), + paddr_nz (step_range_end)); keep_going (ecs); return; } @@ -2392,6 +2276,9 @@ process_event_stop_test: CORE_ADDR pc_after_resolver = gdbarch_skip_solib_resolver (current_gdbarch, stop_pc); + if (debug_infrun) + printf_unfiltered ("infrun: stepped into dynsym resolve code\n"); + if (pc_after_resolver) { /* Set up a step-resume breakpoint at the address @@ -2400,62 +2287,117 @@ process_event_stop_test: init_sal (&sr_sal); sr_sal.pc = pc_after_resolver; - check_for_old_step_resume_breakpoint (); - step_resume_breakpoint = - set_momentary_breakpoint (sr_sal, null_frame_id, bp_step_resume); - if (breakpoints_inserted) - insert_breakpoints (); + insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id); } keep_going (ecs); return; } - if (step_over_calls == STEP_OVER_UNDEBUGGABLE - && ecs->stop_func_name == NULL) - { - /* There is no symbol, not even a minimal symbol, corresponding - to the address where we just stopped. So we just stepped - inside undebuggable code. Since we want to step over this - kind of code, we keep going until the inferior returns from - the current function. */ - handle_step_into_function (ecs); - return; - } - if (step_range_end != 1 && (step_over_calls == STEP_OVER_UNDEBUGGABLE || step_over_calls == STEP_OVER_ALL) && get_frame_type (get_current_frame ()) == SIGTRAMP_FRAME) { + if (debug_infrun) + printf_unfiltered ("infrun: stepped into signal trampoline\n"); /* The inferior, while doing a "step" or "next", has ended up in - a signal trampoline (either by a signal being delivered or by - the signal handler returning). Just single-step until the - inferior leaves the trampoline (either by calling the handler - or returning). */ + a signal trampoline (either by a signal being delivered or by + the signal handler returning). Just single-step until the + inferior leaves the trampoline (either by calling the handler + or returning). */ keep_going (ecs); return; } - if (frame_id_eq (get_frame_id (get_prev_frame (get_current_frame ())), - step_frame_id)) + if (frame_id_eq (frame_unwind_id (get_current_frame ()), step_frame_id)) { /* It's a subroutine call. */ - handle_step_into_function (ecs); - return; - } + CORE_ADDR real_stop_pc; - /* We've wandered out of the step range. */ + if (debug_infrun) + printf_unfiltered ("infrun: stepped into subroutine\n"); - ecs->sal = find_pc_line (stop_pc, 0); + if ((step_over_calls == STEP_OVER_NONE) + || ((step_range_end == 1) + && in_prologue (prev_pc, ecs->stop_func_start))) + { + /* I presume that step_over_calls is only 0 when we're + supposed to be stepping at the assembly language level + ("stepi"). Just stop. */ + /* Also, maybe we just did a "nexti" inside a prolog, so we + thought it was a subroutine call but it was not. Stop as + well. FENN */ + stop_step = 1; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; + } - if (step_range_end == 1) - { - /* It is stepi or nexti. We always want to stop stepping after - one instruction. */ - stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); - stop_stepping (ecs); + if (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_frame (get_prev_frame (get_current_frame ())); + keep_going (ecs); + return; + } + + /* If we are in a function call trampoline (a stub between the + calling routine and the real function), locate the real + function. That's what tells us (a) whether we want to step + into it at all, and (b) what prologue we want to run to the + end of, if we do step into it. */ + real_stop_pc = skip_language_trampoline (stop_pc); + if (real_stop_pc == 0) + real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc); + if (real_stop_pc != 0) + ecs->stop_func_start = real_stop_pc; + + if (IN_SOLIB_DYNSYM_RESOLVE_CODE (ecs->stop_func_start)) + { + 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); + keep_going (ecs); + return; + } + + /* If we have line number information for the function we are + thinking of stepping into, step into it. + + If there are several symtabs at that PC (e.g. with include + files), just want to know whether *any* of them have line + numbers. find_pc_line handles this. */ + { + struct symtab_and_line tmp_sal; + + tmp_sal = find_pc_line (ecs->stop_func_start, 0); + if (tmp_sal.line != 0) + { + step_into_function (ecs); + return; + } + } + + /* If we have no line number and the step-stop-if-no-debug is + set, we stop the step so that the user has a chance to switch + in assembly mode. */ + if (step_over_calls == STEP_OVER_UNDEBUGGABLE && step_stop_if_no_debug) + { + stop_step = 1; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; + } + + /* Set a breakpoint at callee's return address (the address at + which the caller will resume). */ + insert_step_resume_breakpoint_at_frame (get_prev_frame (get_current_frame ())); + keep_going (ecs); return; } @@ -2466,6 +2408,9 @@ process_event_stop_test: /* Determine where this trampoline returns. */ CORE_ADDR real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc); + if (debug_infrun) + printf_unfiltered ("infrun: stepped into solib return tramp\n"); + /* Only proceed through if we know where it's going. */ if (real_stop_pc) { @@ -2475,14 +2420,11 @@ process_event_stop_test: init_sal (&sr_sal); /* initialize to zeroes */ sr_sal.pc = real_stop_pc; sr_sal.section = find_pc_overlay (sr_sal.pc); - /* Do not specify what the fp should be when we stop - since on some machines the prologue - is where the new fp value is established. */ - check_for_old_step_resume_breakpoint (); - step_resume_breakpoint = - set_momentary_breakpoint (sr_sal, null_frame_id, bp_step_resume); - if (breakpoints_inserted) - insert_breakpoints (); + + /* Do not specify what the fp should be when we stop since + on some machines the prologue is where the new fp value + is established. */ + insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id); /* Restart without fiddling with the step ranges or other state. */ @@ -2491,12 +2433,63 @@ process_event_stop_test: } } + /* NOTE: tausq/2004-05-24: This if block used to be done before all + the trampoline processing logic, however, there are some trampolines + that have no names, so we should do trampoline handling first. */ + if (step_over_calls == STEP_OVER_UNDEBUGGABLE + && ecs->stop_func_name == NULL) + { + if (debug_infrun) + printf_unfiltered ("infrun: stepped into undebuggable function\n"); + + /* The inferior just stepped into, or returned to, an + undebuggable function (where there is no symbol, not even a + minimal symbol, corresponding to the address where the + inferior stopped). Since we want to skip this kind of code, + we keep going until the inferior returns from this + function. */ + if (step_stop_if_no_debug) + { + /* If we have no line number and the step-stop-if-no-debug + is set, we stop the step so that the user has a chance to + switch in assembly mode. */ + stop_step = 1; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; + } + else + { + /* Set a breakpoint at callee's return address (the address + at which the caller will resume). */ + insert_step_resume_breakpoint_at_frame (get_prev_frame (get_current_frame ())); + keep_going (ecs); + return; + } + } + + if (step_range_end == 1) + { + /* It is stepi or nexti. We always want to stop stepping after + one instruction. */ + if (debug_infrun) + printf_unfiltered ("infrun: stepi/nexti\n"); + stop_step = 1; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; + } + + ecs->sal = find_pc_line (stop_pc, 0); + if (ecs->sal.line == 0) { /* We have no line number information. That means to stop stepping (does this always happen right after one instruction, when we do "s" in a function with no line numbers, or can this happen as a result of a return or longjmp?). */ + if (debug_infrun) + printf_unfiltered ("infrun: no line number info\n"); stop_step = 1; print_stop_reason (END_STEPPING_RANGE, 0); stop_stepping (ecs); @@ -2511,6 +2504,8 @@ process_event_stop_test: we don't stop if we step into the middle of a different line. That is said to make things like for (;;) statements work better. */ + if (debug_infrun) + printf_unfiltered ("infrun: stepped to a different line\n"); stop_step = 1; print_stop_reason (END_STEPPING_RANGE, 0); stop_stepping (ecs); @@ -2531,6 +2526,8 @@ process_event_stop_test: This is particularly necessary for a one-line function, in which after skipping the prologue we better stop even though we will be in mid-line. */ + if (debug_infrun) + printf_unfiltered ("infrun: stepped to a different function\n"); stop_step = 1; print_stop_reason (END_STEPPING_RANGE, 0); stop_stepping (ecs); @@ -2551,15 +2548,15 @@ process_event_stop_test: stackless leaf function. I think the logic should instead look at the unwound frame ID has that should give a more robust indication of what happened. */ - if (step-ID == current-ID) - still stepping in same function; - else if (step-ID == unwind (current-ID)) - stepped into a function; - else - stepped out of a function; - /* Of course this assumes that the frame ID unwind code is robust - and we're willing to introduce frame unwind logic into this - function. Fortunately, those days are nearly upon us. */ + if (step - ID == current - ID) + still stepping in same function; + else if (step - ID == unwind (current - ID)) + stepped into a function; + else + stepped out of a function; + /* Of course this assumes that the frame ID unwind code is robust + and we're willing to introduce frame unwind logic into this + function. Fortunately, those days are nearly upon us. */ #endif { struct frame_id current_frame = get_frame_id (get_current_frame ()); @@ -2567,6 +2564,8 @@ process_event_stop_test: step_frame_id = current_frame; } + if (debug_infrun) + printf_unfiltered ("infrun: keep going\n"); keep_going (ecs); } @@ -2612,7 +2611,7 @@ step_into_function (struct execution_control_state *ecs) ``ecs->stop_func_start == stop_pc'' will never succeed. Adjust ecs->stop_func_start to an address at which a breakpoint may be legitimately placed. - + Note: kevinb/2004-01-19: On FR-V, if this adjustment is not made, GDB will enter an infinite loop when stepping through optimized code consisting of VLIW instructions which contain @@ -2622,12 +2621,12 @@ step_into_function (struct execution_control_state *ecs) set, GDB will adjust the breakpoint address to the beginning of the VLIW instruction. Thus, we need to make the corresponding adjustment here when computing the stop address. */ - + if (gdbarch_adjust_breakpoint_address_p (current_gdbarch)) { ecs->stop_func_start = gdbarch_adjust_breakpoint_address (current_gdbarch, - ecs->stop_func_start); + ecs->stop_func_start); } if (ecs->stop_func_start == stop_pc) @@ -2644,14 +2643,11 @@ step_into_function (struct execution_control_state *ecs) init_sal (&sr_sal); /* initialize to zeroes */ sr_sal.pc = ecs->stop_func_start; sr_sal.section = find_pc_overlay (ecs->stop_func_start); + /* Do not specify what the fp should be when we stop since on some machines the prologue is where the new fp value is established. */ - check_for_old_step_resume_breakpoint (); - step_resume_breakpoint = - set_momentary_breakpoint (sr_sal, null_frame_id, bp_step_resume); - if (breakpoints_inserted) - insert_breakpoints (); + insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id); /* And make sure stepping stops right away then. */ step_range_end = step_range_start; @@ -2659,45 +2655,56 @@ step_into_function (struct execution_control_state *ecs) keep_going (ecs); } -/* The inferior, as a result of a function call (has left) or signal - (about to leave) the single-step range. Set a momentary breakpoint - within the step range where the inferior is expected to later - 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. */ + +static void +insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal, + struct frame_id sr_id) +{ + /* There should never be more than one step-resume breakpoint per + thread, so we should never be setting a new + step_resume_breakpoint when one is already active. */ + gdb_assert (step_resume_breakpoint == NULL); + step_resume_breakpoint = set_momentary_breakpoint (sr_sal, sr_id, + bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); +} + +/* Insert a "step resume breakpoint" at RETURN_FRAME.pc. This is used + to skip a function (next, skip-no-debug) or signal. It's assumed + that the function/signal handler being skipped eventually returns + to the breakpoint inserted at RETURN_FRAME.pc. + + For the skip-function case, the function may have been reached by + either single stepping a call / return / signal-return instruction, + or by hitting a breakpoint. In all cases, the RETURN_FRAME belongs + to the skip-function's caller. + + For the signals case, this is called with the interrupted + function's frame. The signal handler, when it returns, will resume + the interrupted function at RETURN_FRAME.pc. */ static void -insert_step_resume_breakpoint (struct frame_info *step_frame, - struct execution_control_state *ecs) +insert_step_resume_breakpoint_at_frame (struct frame_info *return_frame) { struct symtab_and_line sr_sal; - /* This is only used within the step-resume range/frame. */ - gdb_assert (frame_id_eq (step_frame_id, get_frame_id (step_frame))); - gdb_assert (step_range_end != 0); - /* Remember, if the call instruction is the last in the step range, - the breakpoint will land just beyond that. Hence ``<= - step_range_end''. Also, ignore check when "nexti". */ - gdb_assert (step_range_start == step_range_end - || (get_frame_pc (step_frame) >= step_range_start - && get_frame_pc (step_frame) <= step_range_end)); - init_sal (&sr_sal); /* initialize to zeros */ - sr_sal.pc = ADDR_BITS_REMOVE (get_frame_pc (step_frame)); + sr_sal.pc = ADDR_BITS_REMOVE (get_frame_pc (return_frame)); sr_sal.section = find_pc_overlay (sr_sal.pc); - check_for_old_step_resume_breakpoint (); - - step_resume_breakpoint - = set_momentary_breakpoint (sr_sal, get_frame_id (step_frame), - bp_step_resume); - - if (breakpoints_inserted) - insert_breakpoints (); + insert_step_resume_breakpoint_at_sal (sr_sal, get_frame_id (return_frame)); } static void stop_stepping (struct execution_control_state *ecs) { + if (debug_infrun) + printf_unfiltered ("infrun: stop_stepping\n"); + /* Let callers know we don't want to wait for the inferior anymore. */ ecs->wait_some_more = 0; } @@ -2731,20 +2738,9 @@ keep_going (struct execution_control_state *ecs) The signal was SIGTRAP, e.g. it was our signal, but we decided we should resume from it. - We're going to run this baby now! + We're going to run this baby now! */ - Insert breakpoints now, unless we are trying to one-proceed - past a breakpoint. */ - /* If we've just finished a special step resume and we don't - want to hit a breakpoint, pull em out. */ - if (step_resume_breakpoint == NULL - && ecs->remove_breakpoints_on_following_step) - { - ecs->remove_breakpoints_on_following_step = 0; - remove_breakpoints (); - breakpoints_inserted = 0; - } - else if (!breakpoints_inserted && !ecs->another_trap) + if (!breakpoints_inserted && !ecs->another_trap) { breakpoints_failed = insert_breakpoints (); if (breakpoints_failed) @@ -2786,6 +2782,8 @@ keep_going (struct execution_control_state *ecs) static void prepare_to_wait (struct execution_control_state *ecs) { + if (debug_infrun) + printf_unfiltered ("infrun: prepare_to_wait\n"); if (ecs->infwait_state == infwait_normal_state) { overlay_cache_invalid = 1; @@ -3010,8 +3008,8 @@ normal_stop (void) { case PRINT_UNKNOWN: /* FIXME: cagney/2002-12-01: Given that a frame ID does - (or should) carry around the function and does (or - should) use that when doing a frame comparison. */ + (or should) carry around the function and does (or + should) use that when doing a frame comparison. */ if (stop_step && frame_id_eq (step_frame_id, get_frame_id (get_current_frame ())) @@ -3047,7 +3045,7 @@ normal_stop (void) LOCATION: Print only location SRC_AND_LOC: Print location and source line */ if (do_frame_printing) - print_stack_frame (get_selected_frame (), 0, source_flag); + print_stack_frame (get_selected_frame (NULL), 0, source_flag); /* Display the auto-display expressions. */ do_displays (); @@ -3477,7 +3475,7 @@ void write_inferior_status_register (struct inferior_status *inf_status, int regno, LONGEST val) { - int size = DEPRECATED_REGISTER_RAW_SIZE (regno); + 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); @@ -3823,6 +3821,10 @@ Pass and Stop may be combined.", NULL)); This allows you to set a list of commands to be run each time execution\n\ of the program stops.", &cmdlist); + add_set_cmd ("infrun", class_maintenance, var_zinteger, + &debug_infrun, "Set inferior debugging.\n\ +When non-zero, inferior specific debugging is enabled.", &setdebuglist); + numsigs = (int) TARGET_SIGNAL_LAST; signal_stop = (unsigned char *) xmalloc (sizeof (signal_stop[0]) * numsigs); signal_print = (unsigned char *) @@ -3871,7 +3873,7 @@ of the program stops.", &cmdlist); signal_print[TARGET_SIGNAL_CANCEL] = 0; #ifdef SOLIB_ADD - add_show_from_set + deprecated_add_show_from_set (add_set_cmd ("stop-on-solib-events", class_support, var_zinteger, (char *) &stop_on_solib_events, "Set stopping for shared library events.\n\ @@ -3890,7 +3892,7 @@ A fork or vfork creates a new process. follow-fork-mode can be:\n\ child - the new process is debugged after a fork\n\ The unfollowed process will continue to run.\n\ By default, the debugger will follow the parent process.", &setlist); - add_show_from_set (c, &showlist); + deprecated_add_show_from_set (c, &showlist); c = add_set_enum_cmd ("scheduler-locking", class_run, scheduler_enums, /* array of string names */ &scheduler_mode, /* current mode */ @@ -3902,7 +3904,7 @@ step == scheduler locked during every single-step operation.\n\ Other threads may run while stepping over a function call ('next').", &setlist); set_cmd_sfunc (c, set_schedlock_func); /* traps on target vector */ - add_show_from_set (c, &showlist); + deprecated_add_show_from_set (c, &showlist); c = add_set_cmd ("step-mode", class_run, var_boolean, (char *) &step_stop_if_no_debug, @@ -3910,7 +3912,7 @@ step == scheduler locked during every single-step operation.\n\ function without debug line information will stop at the first\n\ instruction of that function. Otherwise, the function is skipped and\n\ the step command stops at a different source line.", &setlist); - add_show_from_set (c, &showlist); + deprecated_add_show_from_set (c, &showlist); /* ptid initializations */ null_ptid = ptid_build (0, 0, 0);