X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=aaf6ac85d50db5464adc1df1edaa51684246b14b;hb=f561f0263002fbd950e66676a666ee5f46483841;hp=0b85cc691c1643b9acb12d10c1bfc32ace434654;hpb=603942cc64cda6899670f0ab1f0560bbdb515965;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 0b85cc691c..aaf6ac85d5 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -2,8 +2,8 @@ process. Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, - 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software - Foundation, Inc. + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free + Software Foundation, Inc. This file is part of GDB. @@ -44,7 +44,7 @@ #include "value.h" #include "observer.h" #include "language.h" -#include "exec.h" +#include "gdb_assert.h" /* Prototypes for local functions */ @@ -62,9 +62,6 @@ static int hook_stop_stub (void *); static void delete_breakpoint_current_contents (void *); -static void set_follow_fork_mode_command (char *arg, int from_tty, - struct cmd_list_element *c); - static int restore_selected_frame (void *); static void build_infrun (void); @@ -341,12 +338,10 @@ static struct } pending_follow; -static const char follow_fork_mode_ask[] = "ask"; static const char follow_fork_mode_child[] = "child"; static const char follow_fork_mode_parent[] = "parent"; static const char *follow_fork_mode_kind_names[] = { - follow_fork_mode_ask, follow_fork_mode_child, follow_fork_mode_parent, NULL @@ -358,16 +353,7 @@ static const char *follow_fork_mode_string = follow_fork_mode_parent; static int follow_fork (void) { - const char *follow_mode = follow_fork_mode_string; - int follow_child = (follow_mode == follow_fork_mode_child); - - /* Or, did the user not know, and want us to ask? */ - if (follow_fork_mode_string == follow_fork_mode_ask) - { - internal_error (__FILE__, __LINE__, - "follow_inferior_fork: \"ask\" mode not implemented"); - /* follow_mode = follow_fork_mode_...; */ - } + int follow_child = (follow_fork_mode_string == follow_fork_mode_child); return target_follow_fork (follow_child); } @@ -489,6 +475,14 @@ follow_exec (int pid, char *execd_pathname) because we cannot remove the breakpoints in the inferior process until after the `wait' in `wait_for_inferior'. */ static int singlestep_breakpoints_inserted_p = 0; + +/* The thread we inserted single-step breakpoints for. */ +static ptid_t singlestep_ptid; + +/* If another thread hit the singlestep breakpoint, we save the original + thread here so that we can resume single-stepping it later. */ +static ptid_t saved_singlestep_ptid; +static int stepping_past_singlestep_breakpoint; /* Things to clean up if we QUIT out of resume (). */ @@ -575,6 +569,7 @@ resume (int step, enum target_signal sig) /* and do not pull these breakpoints until after a `wait' in `wait_for_inferior' */ singlestep_breakpoints_inserted_p = 1; + singlestep_ptid = inferior_ptid; } /* Handle any optimized stores to the inferior NOW... */ @@ -612,7 +607,8 @@ resume (int step, enum target_signal sig) resume_ptid = RESUME_ALL; /* Default */ if ((step || singlestep_breakpoints_inserted_p) && - !breakpoints_inserted && breakpoint_here_p (read_pc ())) + (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 @@ -911,6 +907,8 @@ init_wait_for_inferior (void) number_of_threads_in_syscalls = 0; clear_proceed_status (); + + stepping_past_singlestep_breakpoint = 0; } static void @@ -988,6 +986,7 @@ 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 check_sigtramp2 (struct execution_control_state *ecs); @@ -1204,8 +1203,8 @@ context_switch (struct execution_control_state *ecs) inferior_ptid = ecs->ptid; } -/* Wrapper for PC_IN_SIGTRAMP that takes care of the need to find the - function's name. +/* Wrapper for DEPRECATED_PC_IN_SIGTRAMP that takes care of the need + to find the function's name. In a classic example of "left hand VS right hand", "infrun.c" was trying to improve GDB's performance by caching the result of calls @@ -1234,9 +1233,176 @@ pc_in_sigtramp (CORE_ADDR pc) { char *name; find_pc_partial_function (pc, &name, NULL, NULL); - return PC_IN_SIGTRAMP (pc, name); + return DEPRECATED_PC_IN_SIGTRAMP (pc, name); +} + +/* 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". */ + + if (legacy_frame_p (current_gdbarch) + && pc_in_sigtramp (stop_pc) + && frame_id_inner (step_frame_id, + frame_id_build (read_sp (), 0))) + /* NOTE: cagney/2004-03-15: This is only needed for legacy + systems. On non-legacy systems step_over_function doesn't + use STEP_FRAME_ID and hence the below update "hack" isn't + needed. */ + /* We stepped out of a signal handler, and into its calling + trampoline. This is misdetected as a subroutine call, but + stepping over the signal trampoline isn't such a bad idea. + In order to do that, we have to ignore the value in + step_frame_id, since that doesn't represent the frame + that'll reach when we return from the signal trampoline. + Otherwise we'll probably continue to the end of the + program. */ + step_frame_id = null_frame_id; + + step_over_function (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; + } + + step_over_function (ecs); + keep_going (ecs); + return; } +static void +adjust_pc_after_break (struct execution_control_state *ecs) +{ + CORE_ADDR stop_pc; + + /* If this target does not decrement the PC after breakpoints, then + we have nothing to do. */ + if (DECR_PC_AFTER_BREAK == 0) + return; + + /* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If + we aren't, just return. + + We assume that waitkinds other than TARGET_WAITKIND_STOPPED are not + 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 + in GDB history, and it seems unlikely to be correct, so + HAVE_NONSTEPPABLE_WATCHPOINTS is not checked here. */ + + if (ecs->ws.kind != TARGET_WAITKIND_STOPPED) + return; + + if (ecs->ws.value.sig != TARGET_SIGNAL_TRAP) + return; + + /* Find the location where (if we've hit a breakpoint) the breakpoint would + be. */ + stop_pc = read_pc_pid (ecs->ptid) - DECR_PC_AFTER_BREAK; + + /* If we're software-single-stepping, then assume this is a breakpoint. + NOTE drow/2004-01-17: This doesn't check that the PC matches, or that + we're even in the right thread. The software-single-step code needs + some modernization. + + If we're not software-single-stepping, then we first check that there + is an enabled software breakpoint at this address. If there is, and + we weren't using hardware-single-step, then we've hit the breakpoint. + + If we were using hardware-single-step, we check prev_pc; if we just + stepped over an inserted software breakpoint, then we should decrement + the PC and eventually report hitting the breakpoint. The prev_pc check + prevents us from decrementing the PC if we just stepped over a jump + instruction and landed on the instruction after a breakpoint. + + The last bit checks that we didn't hit a breakpoint in a signal handler + without an intervening stop in sigtramp, which is detected by a new + stack pointer value below any usual function calling stack adjustments. + + NOTE drow/2004-01-17: I'm not sure that this is necessary. The check + predates checking for software single step at the same time. Also, + if we've moved into a signal handler we should have seen the + signal. */ + + if ((SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p) + || (software_breakpoint_inserted_here_p (stop_pc) + && !(currently_stepping (ecs) + && prev_pc != stop_pc + && !(step_range_end && INNER_THAN (read_sp (), (step_sp - 16)))))) + write_pc_pid (stop_pc, ecs->ptid); +} /* Given an execution control state that has been freshly filled in by an event from the inferior, figure out what it means and take @@ -1245,7 +1411,6 @@ pc_in_sigtramp (CORE_ADDR pc) void handle_inferior_event (struct execution_control_state *ecs) { - CORE_ADDR real_stop_pc; /* NOTE: cagney/2003-03-28: If you're looking at this code and thinking that the variable stepped_after_stopped_by_watchpoint isn't used, then you're wrong! The macro STOPPED_BY_WATCHPOINT, @@ -1258,6 +1423,8 @@ handle_inferior_event (struct execution_control_state *ecs) target_last_wait_ptid = ecs->ptid; target_last_waitstatus = *ecs->wp; + adjust_pc_after_break (ecs); + switch (ecs->infwait_state) { case infwait_thread_hop_state: @@ -1363,7 +1530,22 @@ handle_inferior_event (struct execution_control_state *ecs) terminal for any messages produced by breakpoint_re_set. */ target_terminal_ours_for_output (); - SOLIB_ADD (NULL, 0, &exec_ops, auto_solib_add); + /* 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). */ + /* 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. */ + SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); target_terminal_inferior (); /* Reinsert breakpoints and continue. */ @@ -1425,13 +1607,7 @@ handle_inferior_event (struct execution_control_state *ecs) stop_pc = read_pc (); - /* Assume that catchpoints are not really software breakpoints. If - some future target implements them using software breakpoints then - that target is responsible for fudging DECR_PC_AFTER_BREAK. Thus - we pass 1 for the NOT_A_SW_BREAKPOINT argument, so that - bpstat_stop_status will not decrement the PC. */ - - stop_bpstat = bpstat_stop_status (&stop_pc, 1); + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); @@ -1480,13 +1656,7 @@ handle_inferior_event (struct execution_control_state *ecs) ecs->saved_inferior_ptid = inferior_ptid; inferior_ptid = ecs->ptid; - /* Assume that catchpoints are not really software breakpoints. If - some future target implements them using software breakpoints then - that target is responsible for fudging DECR_PC_AFTER_BREAK. Thus - we pass 1 for the NOT_A_SW_BREAKPOINT argument, so that - bpstat_stop_status will not decrement the PC. */ - - stop_bpstat = bpstat_stop_status (&stop_pc, 1); + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); inferior_ptid = ecs->saved_inferior_ptid; @@ -1587,28 +1757,84 @@ handle_inferior_event (struct execution_control_state *ecs) stop_pc = read_pc_pid (ecs->ptid); + if (stepping_past_singlestep_breakpoint) + { + 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. */ + if (stop_signal == TARGET_SIGNAL_TRAP) + { + /* Pull the single step breakpoints out of the target. */ + SOFTWARE_SINGLE_STEP (0, 0); + singlestep_breakpoints_inserted_p = 0; + + ecs->random_signal = 0; + + ecs->ptid = saved_singlestep_ptid; + context_switch (ecs); + if (context_hook) + context_hook (pid_to_thread_id (ecs->ptid)); + + resume (1, TARGET_SIGNAL_0); + prepare_to_wait (ecs); + return; + } + } + + stepping_past_singlestep_breakpoint = 0; + /* See if a thread hit a thread-specific breakpoint that was meant for another thread. If so, then step that thread past the breakpoint, and continue it. */ if (stop_signal == TARGET_SIGNAL_TRAP) { + int thread_hop_needed = 0; + /* Check if a regular breakpoint has been hit before checking for a potential single step breakpoint. Otherwise, GDB will not see this breakpoint hit when stepping onto breakpoints. */ - if (breakpoints_inserted - && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK)) + if (breakpoints_inserted && breakpoint_here_p (stop_pc)) { ecs->random_signal = 0; - if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, - ecs->ptid)) + if (!breakpoint_thread_match (stop_pc, ecs->ptid)) + thread_hop_needed = 1; + } + else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p) + { + ecs->random_signal = 0; + /* The call to in_thread_list is necessary because PTIDs sometimes + change when we go from single-threaded to multi-threaded. If + the singlestep_ptid is still in the list, assume that it is + really different from ecs->ptid. */ + if (!ptid_equal (singlestep_ptid, ecs->ptid) + && in_thread_list (singlestep_ptid)) + { + thread_hop_needed = 1; + stepping_past_singlestep_breakpoint = 1; + saved_singlestep_ptid = singlestep_ptid; + } + } + + if (thread_hop_needed) { int remove_status; /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */ - if (DECR_PC_AFTER_BREAK) - write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, ecs->ptid); + + 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 @@ -1621,7 +1847,7 @@ handle_inferior_event (struct execution_control_state *ecs) if (remove_status != 0) { /* FIXME! This is obviously non-portable! */ - write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK + 4, ecs->ptid); + 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 @@ -1651,21 +1877,9 @@ handle_inferior_event (struct execution_control_state *ecs) registers_changed (); return; } - } } else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p) { - /* Readjust the stop_pc as it is off by DECR_PC_AFTER_BREAK - compared to the value it would have if the system stepping - capability was used. This allows the rest of the code in - this function to use this address without having to worry - whether software single step is in use or not. */ - if (DECR_PC_AFTER_BREAK) - { - stop_pc -= DECR_PC_AFTER_BREAK; - write_pc_pid (stop_pc, ecs->ptid); - } - sw_single_step_trap_p = 1; ecs->random_signal = 0; } @@ -1674,61 +1888,9 @@ handle_inferior_event (struct execution_control_state *ecs) ecs->random_signal = 1; /* See if something interesting happened to the non-current thread. If - so, then switch to that thread, and eventually give control back to - the user. - - Note that if there's any kind of pending follow (i.e., of a fork, - vfork or exec), we don't want to do this now. Rather, we'll let - the next resume handle it. */ - if (!ptid_equal (ecs->ptid, inferior_ptid) && - (pending_follow.kind == TARGET_WAITKIND_SPURIOUS)) + so, then switch to that thread. */ + if (!ptid_equal (ecs->ptid, inferior_ptid)) { - int printed = 0; - - /* If it's a random signal for a non-current thread, notify user - if he's expressed an interest. */ - if (ecs->random_signal && signal_print[stop_signal]) - { -/* ??rehrauer: I don't understand the rationale for this code. If the - inferior will stop as a result of this signal, then the act of handling - the stop ought to print a message that's couches the stoppage in user - terms, e.g., "Stopped for breakpoint/watchpoint". If the inferior - won't stop as a result of the signal -- i.e., if the signal is merely - a side-effect of something GDB's doing "under the covers" for the - user, such as stepping threads over a breakpoint they shouldn't stop - for -- then the message seems to be a serious annoyance at best. - - For now, remove the message altogether. */ -#if 0 - printed = 1; - target_terminal_ours_for_output (); - printf_filtered ("\nProgram received signal %s, %s.\n", - target_signal_to_name (stop_signal), - target_signal_to_string (stop_signal)); - gdb_flush (gdb_stdout); -#endif - } - - /* If it's not SIGTRAP and not a signal we want to stop for, then - continue the thread. */ - - if (stop_signal != TARGET_SIGNAL_TRAP && !signal_stop[stop_signal]) - { - if (printed) - target_terminal_inferior (); - - /* Clear the signal if it should not be passed. */ - if (signal_program[stop_signal] == 0) - stop_signal = TARGET_SIGNAL_0; - - target_resume (ecs->ptid, 0, stop_signal); - prepare_to_wait (ecs); - return; - } - - /* It's a SIGTRAP or a signal we're interested in. Switch threads, - and fall into the rest of wait_for_inferior(). */ - context_switch (ecs); if (context_hook) @@ -1797,9 +1959,6 @@ handle_inferior_event (struct execution_control_state *ecs) includes evaluating watchpoints, things will come to a stop in the correct manner. */ - if (DECR_PC_AFTER_BREAK) - write_pc (stop_pc - DECR_PC_AFTER_BREAK); - remove_breakpoints (); registers_changed (); target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */ @@ -1841,15 +2000,20 @@ handle_inferior_event (struct execution_control_state *ecs) will be made according to the signal handling tables. */ /* First, distinguish signals caused by the debugger from signals - that have to do with the program's own actions. - Note that breakpoint insns may cause SIGTRAP or SIGILL - or SIGEMT, depending on the operating system version. - Here we detect when a SIGILL or SIGEMT is really a breakpoint - and change it to SIGTRAP. */ + that have to do with the program's own actions. Note that + breakpoint insns may cause SIGTRAP or SIGILL or SIGEMT, depending + on the operating system version. Here we detect when a SIGILL or + SIGEMT is really a breakpoint and change it to SIGTRAP. We do + something similar for SIGSEGV, since a SIGSEGV will be generated + when we're trying to execute a breakpoint instruction on a + non-executable stack. This happens for call dummy breakpoints + for architectures like SPARC that place call dummies on the + stack. */ if (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) @@ -1894,29 +2058,8 @@ handle_inferior_event (struct execution_control_state *ecs) else { /* See if there is a breakpoint at the current PC. */ + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); - /* The second argument of bpstat_stop_status is meant to help - distinguish between a breakpoint trap and a singlestep trap. - This is only important on targets where DECR_PC_AFTER_BREAK - is non-zero. The prev_pc test is meant to distinguish between - singlestepping a trap instruction, and singlestepping thru a - jump to the instruction following a trap instruction. - - Therefore, pass TRUE if our reason for stopping is - something other than hitting a breakpoint. We do this by - checking that either: we detected earlier a software single - step trap or, 1) stepping is going on and 2) we didn't hit - a breakpoint in a signal handler without an intervening stop - in sigtramp, which is detected by a new stack pointer value - below any usual function calling stack adjustments. */ - stop_bpstat = - bpstat_stop_status - (&stop_pc, - sw_single_step_trap_p - || (currently_stepping (ecs) - && prev_pc != stop_pc - DECR_PC_AFTER_BREAK - && !(step_range_end - && INNER_THAN (read_sp (), (step_sp - 16))))); /* Following in case break condition called a function. */ stop_print_frame = 1; @@ -1933,10 +2076,14 @@ handle_inferior_event (struct execution_control_state *ecs) If someone ever tries to get get call dummys on a non-executable stack to work (where the target would stop - with something like a SIGSEG), then those tests might need to - be re-instated. Given, however, that the tests were only + with something like a SIGSEGV), then those tests might need + to be re-instated. Given, however, that the tests were only enabled when momentary breakpoints were not being used, I - suspect that it won't be the case. */ + 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. */ if (stop_signal == TARGET_SIGNAL_TRAP) ecs->random_signal @@ -2186,7 +2333,22 @@ process_event_stop_test: terminal for any messages produced by breakpoint_re_set. */ target_terminal_ours_for_output (); - SOLIB_ADD (NULL, 0, &exec_ops, auto_solib_add); + /* 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). */ + /* 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. */ + SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); target_terminal_inferior (); /* Try to reenable shared library breakpoints, additional @@ -2197,7 +2359,7 @@ process_event_stop_test: gdb of events. This allows the user to get control and place breakpoints in initializer routines for dynamically loaded objects (among other things). */ - if (stop_on_solib_events) + if (stop_on_solib_events || stop_stack_dummy) { stop_stepping (ecs); return; @@ -2359,22 +2521,19 @@ process_event_stop_test: But we can update it every time we leave the step range. */ ecs->update_step_sp = 1; - /* Did we just take a signal? */ - if (pc_in_sigtramp (stop_pc) - && !pc_in_sigtramp (prev_pc) - && INNER_THAN (read_sp (), step_sp)) + /* Did we just step into a singal trampoline (either by stepping out + of a handler, or by taking a signal)? */ + /* NOTE: cagney/2004-03-16: Replaced (except for legacy) a check for + "pc_in_sigtramp(stop_pc) != pc_in_sigtramp(step_pc)" with + frame_type == SIGTRAMP && !frame_id_eq. The latter is far more + robust as it will correctly handle nested signal trampolines. */ + if (legacy_frame_p (current_gdbarch) + ? (pc_in_sigtramp (stop_pc) + && !pc_in_sigtramp (prev_pc) + && INNER_THAN (read_sp (), step_sp)) + : (get_frame_type (get_current_frame ()) == SIGTRAMP_FRAME + && !frame_id_eq (get_frame_id (get_current_frame ()), step_frame_id))) { - /* We've just taken a signal; go until we are back to - the point where we took it and one more. */ - - /* Note: The test above succeeds not only when we stepped - into a signal handler, but also when we step past the last - statement of a signal handler and end up in the return stub - of the signal handler trampoline. To distinguish between - these two cases, check that the frame is INNER_THAN the - previous one below. pai/1997-09-11 */ - - { struct frame_id current_frame = get_frame_id (get_current_frame ()); @@ -2450,88 +2609,8 @@ process_event_stop_test: || ecs->stop_func_name == 0) { /* It's a subroutine call. */ - - 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". */ - - if (pc_in_sigtramp (stop_pc) - && frame_id_inner (step_frame_id, - frame_id_build (read_sp (), 0))) - /* We stepped out of a signal handler, and into its - calling trampoline. This is misdetected as a - subroutine call, but stepping over the signal - trampoline isn't such a bad idea. In order to do that, - we have to ignore the value in step_frame_id, since - that doesn't represent the frame that'll reach when we - return from the signal trampoline. Otherwise we'll - probably continue to the end of the program. */ - step_frame_id = null_frame_id; - - step_over_function (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; - } - - step_over_function (ecs); - keep_going (ecs); + handle_step_into_function (ecs); return; - } /* We've wandered out of the step range. */ @@ -2553,7 +2632,7 @@ process_event_stop_test: if (IN_SOLIB_RETURN_TRAMPOLINE (stop_pc, ecs->stop_func_name)) { /* Determine where this trampoline returns. */ - real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc); + CORE_ADDR real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc); /* Only proceed through if we know where it's going. */ if (real_stop_pc) @@ -2733,6 +2812,29 @@ step_into_function (struct execution_control_state *ecs) && ecs->sal.end < ecs->stop_func_end) ecs->stop_func_start = ecs->sal.end; + /* Architectures which require breakpoint adjustment might not be able + to place a breakpoint at the computed address. If so, the test + ``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 + subinstructions corresponding to different source lines. On + FR-V, it's not permitted to place a breakpoint on any but the + first subinstruction of a VLIW instruction. When a breakpoint is + 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); + } + if (ecs->stop_func_start == stop_pc) { /* We are already there: stop now. */ @@ -2768,16 +2870,16 @@ step_into_function (struct execution_control_state *ecs) However, if the callee is recursing, we want to be careful not to catch returns of those recursive calls, but only of THIS instance - of the call. + of the caller. To do this, we set the step_resume bp's frame to our current - caller's frame (step_frame_id, which is set by the "next" or - "until" command, before execution begins). */ + caller's frame (obtained by doing a frame ID unwind). */ static void step_over_function (struct execution_control_state *ecs) { struct symtab_and_line sr_sal; + struct frame_id sr_id; init_sal (&sr_sal); /* initialize to zeros */ @@ -2821,13 +2923,45 @@ step_over_function (struct execution_control_state *ecs) 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 (get_current_frame ()), - bp_step_resume); - if (frame_id_p (step_frame_id) - && !IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc)) - step_resume_breakpoint->frame_id = step_frame_id; + /* NOTE: cagney/2004-03-15: Code using the current value of + "step_frame_id", instead of unwinding that frame ID, removed (at + least for non-legacy platforms). On s390 GNU/Linux, after taking + a signal, the program is directly resumed at the signal handler + and, consequently, the PC would point at at the first instruction + of that signal handler but STEP_FRAME_ID would [incorrectly] at + the interrupted code when it should point at the signal + trampoline. By always and locally doing a frame ID unwind, it's + possible to assert that the code is always using the correct + ID. */ + if (legacy_frame_p (current_gdbarch)) + { + if (frame_id_p (step_frame_id) + && !IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc)) + /* NOTE: cagney/2004-02-27: Use the global state's idea of the + stepping frame ID. I suspect this is done as it is lighter + weight than a call to get_prev_frame. */ + /* NOTE: cagney/2004-03-15: See comment above about how this + is also broken. */ + sr_id = step_frame_id; + else + /* NOTE: cagney/2004-03-15: This is the way it was 'cos this + is the way it always was. It should be using the unwound + (or caller's) ID, and not this (or the callee's) ID. It + appeared to work because: legacy architectures used the + wrong end of the frame for the ID.stack (inner-most rather + than outer-most) so that the callee's id.stack (un + adjusted) matched the caller's id.stack giving the + "correct" id; more often than not + !IN_SOLIB_DYNSYM_RESOLVE_CODE and hence the code above (it + was originally later in the function) fixed the ID by using + global state. */ + sr_id = get_frame_id (get_current_frame ()); + } + else + sr_id = get_frame_id (get_prev_frame (get_current_frame ())); + + step_resume_breakpoint = set_momentary_breakpoint (sr_sal, sr_id, bp_step_resume); if (breakpoints_inserted) insert_breakpoints (); @@ -2916,17 +3050,6 @@ keep_going (struct execution_control_state *ecs) if (stop_signal == TARGET_SIGNAL_TRAP && !signal_program[stop_signal]) stop_signal = TARGET_SIGNAL_0; -#ifdef SHIFT_INST_REGS - /* I'm not sure when this following segment applies. I do know, - now, that we shouldn't rewrite the regs when we were stopped - by a random signal from the inferior process. */ - /* FIXME: Shouldn't this be based on the valid bit of the SXIP? - (this is only used on the 88k). */ - - if (!bpstat_explains_signal (stop_bpstat) - && (stop_signal != TARGET_SIGNAL_CHLD) && !stopped_by_random_signal) - SHIFT_INST_REGS (); -#endif /* SHIFT_INST_REGS */ resume (currently_stepping (ecs), stop_signal); } @@ -3085,6 +3208,7 @@ 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 DECR_PC_AFTER_BREAK */ @@ -3927,8 +4051,8 @@ _initialize_infrun (void) int numsigs; struct cmd_list_element *c; - register_gdbarch_swap (&stop_registers, sizeof (stop_registers), NULL); - register_gdbarch_swap (NULL, 0, build_infrun); + DEPRECATED_REGISTER_GDBARCH_SWAP (stop_registers); + deprecated_register_gdbarch_swap (NULL, 0, build_infrun); add_info ("signals", signals_info, "What debugger does when program gets various signals.\n\ @@ -4037,31 +4161,12 @@ to the user would be loading/unloading of a new library.\n", &setlist), &showlis c = add_set_enum_cmd ("follow-fork-mode", class_run, follow_fork_mode_kind_names, &follow_fork_mode_string, -/* ??rehrauer: The "both" option is broken, by what may be a 10.20 - kernel problem. It's also not terribly useful without a GUI to - help the user drive two debuggers. So for now, I'm disabling - the "both" option. */ -/* "Set debugger response to a program call of fork \ - or vfork.\n\ - A fork or vfork creates a new process. follow-fork-mode can be:\n\ - parent - the original process is debugged after a fork\n\ - child - the new process is debugged after a fork\n\ - both - both the parent and child are debugged after a fork\n\ - ask - the debugger will ask for one of the above choices\n\ - For \"both\", another copy of the debugger will be started to follow\n\ - the new child process. The original debugger will continue to follow\n\ - the original parent process. To distinguish their prompts, the\n\ - debugger copy's prompt will be changed.\n\ - For \"parent\" or \"child\", the unfollowed process will run free.\n\ - By default, the debugger will follow the parent process.", - */ "Set debugger response to a program call of fork \ or vfork.\n\ A fork or vfork creates a new process. follow-fork-mode can be:\n\ parent - the original process is debugged after a fork\n\ child - the new process is debugged after a fork\n\ - ask - the debugger will ask for one of the above choices\n\ -For \"parent\" or \"child\", the unfollowed process will run free.\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);