Index: infcmd.c =================================================================== RCS file: /cvs/src/src/gdb/infcmd.c,v retrieving revision 1.123 diff -p -r1.123 infcmd.c *** infcmd.c 13 Sep 2004 18:26:28 -0000 1.123 --- infcmd.c 4 Sep 2005 23:08:10 -0000 *************** finish_command_continuation (struct cont *** 1181,1186 **** --- 1181,1188 ---- /* "finish": Set a temporary breakpoint at the place the selected frame will return to, then continue. */ + static void finish_backwards (struct symbol *); + static void finish_command (char *arg, int from_tty) { *************** finish_command (char *arg, int from_tty) *** 1223,1238 **** clear_proceed_status (); - sal = find_pc_line (get_frame_pc (frame), 0); - sal.pc = get_frame_pc (frame); - - breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish); - - if (!target_can_async_p ()) - old_chain = make_cleanup_delete_breakpoint (breakpoint); - else - old_chain = make_exec_cleanup_delete_breakpoint (breakpoint); - /* Find the function we will return from. */ function = find_pc_function (get_frame_pc (deprecated_selected_frame)); --- 1225,1230 ---- *************** finish_command (char *arg, int from_tty) *** 1241,1250 **** source. */ if (from_tty) { ! printf_filtered ("Run till exit from "); print_stack_frame (get_selected_frame (), 1, LOCATION); } /* If running asynchronously and the target support asynchronous execution, set things up for the rest of the finish command to be completed later on, when gdb has detected that the target has --- 1233,1263 ---- source. */ if (from_tty) { ! if (get_exec_direction () == EXEC_REVERSE) ! printf_filtered ("Run back to call of "); ! else ! printf_filtered ("Run till exit from "); ! print_stack_frame (get_selected_frame (), 1, LOCATION); } + if (get_exec_direction () == EXEC_REVERSE) + { + /* Split off at this point. */ + finish_backwards (function); + return; + } + + sal = find_pc_line (get_frame_pc (frame), 0); + sal.pc = get_frame_pc (frame); + + breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish); + + if (!target_can_async_p ()) + old_chain = make_cleanup_delete_breakpoint (breakpoint); + else + old_chain = make_exec_cleanup_delete_breakpoint (breakpoint); + /* If running asynchronously and the target support asynchronous execution, set things up for the rest of the finish command to be completed later on, when gdb has detected that the target has *************** finish_command (char *arg, int from_tty) *** 1301,1306 **** --- 1314,1375 ---- do_cleanups (old_chain); } } + + static void + finish_backwards (struct symbol *function) + { + struct symtab_and_line sal; + struct breakpoint *breakpoint; + struct cleanup *old_chain; + CORE_ADDR func_addr; + + if (find_pc_partial_function (get_frame_pc (get_current_frame ()), + NULL, &func_addr, NULL) == 0) + internal_error (__FILE__, __LINE__, + "Finish: couldn't find function."); + + sal = find_pc_line (func_addr, 0); + + /* Let's cheat and not worry about async until later. */ + + /* We don't need a return value. */ + proceed_to_finish = 0; + /* Special case: if we're sitting at the function entry point, + then all we need to do is take a reverse singlestep. We + don't need to set a breakpoint, and indeed it would do us + no good to do so. + + Note that this can only happen at frame #0, since there's + no way that a function up the stack can have a return address + that's equal to its entry point. */ + + if (sal.pc != read_pc ()) + { + /* Set breakpoint and continue. */ + breakpoint = + set_momentary_breakpoint (sal, + get_frame_id (get_selected_frame ()), + bp_breakpoint); + /* Tell the breakpoint to keep quiet. */ + breakpoint_muzzle (breakpoint); + old_chain = make_cleanup_delete_breakpoint (breakpoint); + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); + /* We will be stopped when proceed returns. */ + if (bpstat_find_breakpoint (stop_bpstat, breakpoint) == NULL) + { + /* Didn't hit our breakpoint. */ + internal_error (__FILE__, __LINE__, + "Finish backwards missed its breakpoint."); + } + do_cleanups (old_chain); + } + /* We're almost there; just back up one step. */ + /* (Kludgy way of letting wait_for_inferior know...) */ + step_range_start = step_range_end = 1; + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); + return; + } + static void