+/* finish_backward -- helper function for finish_command. */
+
+static void
+finish_backward (struct symbol *function)
+{
+ struct symtab_and_line sal;
+ struct thread_info *tp = inferior_thread ();
+ CORE_ADDR pc;
+ CORE_ADDR func_addr;
+
+ pc = get_frame_pc (get_current_frame ());
+
+ if (find_pc_partial_function (pc, NULL, &func_addr, NULL) == 0)
+ internal_error (__FILE__, __LINE__,
+ _("Finish: couldn't find function."));
+
+ sal = find_pc_line (func_addr, 0);
+
+ tp->control.proceed_to_finish = 1;
+ /* 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 != pc)
+ {
+ struct frame_info *frame = get_selected_frame (NULL);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct symtab_and_line sr_sal;
+
+ /* Set a step-resume at the function's entry point. Once that's
+ hit, we'll do one more step backwards. */
+ init_sal (&sr_sal);
+ sr_sal.pc = sal.pc;
+ sr_sal.pspace = get_frame_program_space (frame);
+ insert_step_resume_breakpoint_at_sal (gdbarch,
+ sr_sal, null_frame_id);
+
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ }
+ else
+ {
+ /* We're almost there -- we just need to back up by one more
+ single-step. */
+ tp->control.step_range_start = tp->control.step_range_end = 1;
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+ }
+}
+
+/* finish_forward -- helper function for finish_command. */
+
+static void
+finish_forward (struct symbol *function, struct frame_info *frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct symtab_and_line sal;
+ struct thread_info *tp = inferior_thread ();
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+ struct finish_command_continuation_args *cargs;
+ int thread = tp->num;
+
+ sal = find_pc_line (get_frame_pc (frame), 0);
+ sal.pc = get_frame_pc (frame);
+
+ breakpoint = set_momentary_breakpoint (gdbarch, sal,
+ get_stack_frame_id (frame),
+ bp_finish);
+
+ old_chain = make_cleanup_delete_breakpoint (breakpoint);
+
+ set_longjmp_breakpoint (tp, get_frame_id (frame));
+ make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
+
+ /* We want stop_registers, please... */
+ tp->control.proceed_to_finish = 1;
+ cargs = xmalloc (sizeof (*cargs));
+
+ cargs->breakpoint = breakpoint;
+ cargs->function = function;
+ add_continuation (tp, finish_command_continuation, cargs,
+ finish_command_continuation_free_arg);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+
+ discard_cleanups (old_chain);
+ if (!target_can_async_p ())
+ do_all_continuations ();
+}
+