diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6feb42952f..d5404f8f8c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2006-06-15 Daniel Jacobowitz + + * infrun.c (insert_step_resume_breakpoint_at_caller): New function, + based on insert_step_resume_breakpoint_at_frame. + (handle_inferior_event): Update comments. Use + insert_step_resume_breakpoint_at_caller. + (insert_step_resume_breakpoint_at_frame): Revise comments. + 2006-06-14 Daniel Jacobowitz * dwarf2read.c (read_unspecified_type): New function. diff --git a/gdb/infrun.c b/gdb/infrun.c index bccca0d7dc..953983fd75 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -943,6 +943,7 @@ 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_at_frame (struct frame_info *step_frame); +static void insert_step_resume_breakpoint_at_caller (struct frame_info *); static void insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal, struct frame_id sr_id); static void stop_stepping (struct execution_control_state *ecs); @@ -2367,9 +2368,13 @@ process_event_stop_test: return; } + /* Check for subroutine calls. + + NOTE: frame_id_eq will never report two invalid frame IDs as + being equal, so to get into this block, both the current and + previous frame must have valid frame IDs. */ if (frame_id_eq (frame_unwind_id (get_current_frame ()), step_frame_id)) { - /* It's a subroutine call. */ CORE_ADDR real_stop_pc; if (debug_infrun) @@ -2396,7 +2401,7 @@ process_event_stop_test: /* 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 ())); + insert_step_resume_breakpoint_at_caller (get_current_frame ()); keep_going (ecs); return; } @@ -2459,7 +2464,7 @@ process_event_stop_test: /* 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 ())); + insert_step_resume_breakpoint_at_caller (get_current_frame ()); keep_going (ecs); return; } @@ -2513,8 +2518,11 @@ process_event_stop_test: and no line number 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) + function - unless the user has asked us not to (via + set step-mode) or we no longer know how to get back + to the call site. */ + if (step_stop_if_no_debug + || !frame_id_p (frame_unwind_id (get_current_frame ()))) { /* 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 @@ -2528,7 +2536,7 @@ process_event_stop_test: { /* 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 ())); + insert_step_resume_breakpoint_at_caller (get_current_frame ()); keep_going (ecs); return; } @@ -2735,20 +2743,13 @@ insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal, 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. + to skip a potential signal handler. - 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. */ + 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_at_frame (struct frame_info *return_frame) @@ -2763,6 +2764,38 @@ insert_step_resume_breakpoint_at_frame (struct frame_info *return_frame) insert_step_resume_breakpoint_at_sal (sr_sal, get_frame_id (return_frame)); } +/* Similar to insert_step_resume_breakpoint_at_frame, except + but a breakpoint at the previous frame's PC. This is used to + skip a function after stepping into it (for "next" or if the called + function has no debugging information). + + The current function has almost always been reached by single + stepping a call or return instruction. NEXT_FRAME belongs to the + current function, and the breakpoint will be set at the caller's + resume address. + + This is a separate function rather than reusing + insert_step_resume_breakpoint_at_frame in order to avoid + get_prev_frame, which may stop prematurely (see the implementation + of frame_unwind_id for an example). */ + +static void +insert_step_resume_breakpoint_at_caller (struct frame_info *next_frame) +{ + struct symtab_and_line sr_sal; + + /* We shouldn't have gotten here if we don't know where the call site + is. */ + gdb_assert (frame_id_p (frame_unwind_id (next_frame))); + + init_sal (&sr_sal); /* initialize to zeros */ + + sr_sal.pc = ADDR_BITS_REMOVE (frame_pc_unwind (next_frame)); + sr_sal.section = find_pc_overlay (sr_sal.pc); + + insert_step_resume_breakpoint_at_sal (sr_sal, frame_unwind_id (next_frame)); +} + static void stop_stepping (struct execution_control_state *ecs) {