+ /* We suppress normal call of normal_stop observer and do it here so
+ that the *stopped notification includes the return value. */
+ if (bs != NULL && tp->control.proceed_to_finish)
+ observer_notify_normal_stop (bs, 1 /* print frame */);
+ delete_breakpoint (a->breakpoint);
+ delete_longjmp_breakpoint (inferior_thread ()->num);
+}
+
+static void
+finish_command_continuation_free_arg (void *arg)
+{
+ xfree (arg);
+}
+
+/* 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 ();
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+ CORE_ADDR pc;
+ CORE_ADDR func_addr;
+ int back_up;
+
+ 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);
+
+ /* We don't need a return value. */
+ tp->control.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 != pc)
+ {
+ struct frame_info *frame = get_selected_frame (NULL);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+
+ /* Set breakpoint and continue. */
+ breakpoint =
+ set_momentary_breakpoint (gdbarch, sal,
+ get_stack_frame_id (frame),
+ bp_breakpoint);
+ /* Tell the breakpoint to keep quiet. We won't be done
+ until we've done another reverse single-step. */
+ make_breakpoint_silent (breakpoint);
+ old_chain = make_cleanup_delete_breakpoint (breakpoint);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ /* We will be stopped when proceed returns. */
+ back_up = (bpstat_find_breakpoint (tp->control.stop_bpstat, breakpoint)
+ != NULL);
+ do_cleanups (old_chain);
+ }
+ else
+ back_up = 1;
+ if (back_up)
+ {
+ /* If in fact we hit the step-resume breakpoint (and not
+ some other breakpoint), then 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);
+ }
+ return;
+}
+
+/* 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 ();