static void mi_on_normal_stop (struct bpstats *bs, int print_frame) { /* Since this can be called when CLI command is executing, using cli interpreter, be sure to use MI uiout for output, not the current one. */ struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); if (print_frame) { int core; if (current_uiout != mi_uiout) { /* The normal_stop function has printed frame information into CLI uiout, or some other non-MI uiout. There's no way we can extract proper fields from random uiout object, so we print the frame again. In practice, this can only happen when running a CLI command in MI. */ struct ui_out *saved_uiout = current_uiout; struct target_waitstatus last; ptid_t last_ptid; current_uiout = mi_uiout; get_last_target_status (&last_ptid, &last); bpstat_print (bs, last.kind); print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC, 1); current_uiout = saved_uiout; } ui_out_field_int (mi_uiout, "thread-id", pid_to_thread_id (inferior_ptid)); if (non_stop) { struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (mi_uiout, "stopped-threads"); ui_out_field_int (mi_uiout, NULL, pid_to_thread_id (inferior_ptid)); do_cleanups (back_to); } else ui_out_field_string (mi_uiout, "stopped-threads", "all"); core = target_core_of_thread (inferior_ptid); if (core != -1) ui_out_field_int (mi_uiout, "core", core); } fputs_unfiltered ("*stopped", raw_stdout); mi_out_put (mi_uiout, raw_stdout); mi_out_rewind (mi_uiout); mi_print_timing_maybe (); fputs_unfiltered ("\n", raw_stdout); gdb_flush (raw_stdout); }
/* Generic prepare_to_proceed(). This one should be suitable for most targets that support threads. */ int generic_prepare_to_proceed (int select_it) { ptid_t wait_ptid; struct target_waitstatus wait_status; /* Get the last target status returned by target_wait(). */ get_last_target_status (&wait_ptid, &wait_status); /* Make sure we were stopped either at a breakpoint, or because of a Ctrl-C. */ if (wait_status.kind != TARGET_WAITKIND_STOPPED || (wait_status.value.sig != TARGET_SIGNAL_TRAP && wait_status.value.sig != TARGET_SIGNAL_INT)) { return 0; } if (!ptid_equal (wait_ptid, minus_one_ptid) && !ptid_equal (inferior_ptid, wait_ptid)) { /* Switched over from WAIT_PID. */ CORE_ADDR wait_pc = read_pc_pid (wait_ptid); if (wait_pc != read_pc ()) { if (select_it) { /* Switch back to WAIT_PID thread. */ inferior_ptid = wait_ptid; /* FIXME: This stuff came from switch_to_thread() in thread.c (which should probably be a public function). */ flush_cached_frames (); registers_changed (); stop_pc = wait_pc; select_frame (get_current_frame ()); } /* We return 1 to indicate that there is a breakpoint here, so we need to step over it before continuing to avoid hitting it straight away. */ if (breakpoint_here_p (wait_pc)) { return 1; } } } return 0; }
static int inf_ptrace_follow_fork (struct target_ops *ops, int follow_child) { pid_t pid, fpid; ptrace_state_t pe; /* FIXME: kettenis/20050720: This stuff should really be passed as an argument by our caller. */ { ptid_t ptid; struct target_waitstatus status; get_last_target_status (&ptid, &status); gdb_assert (status.kind == TARGET_WAITKIND_FORKED); pid = ptid_get_pid (ptid); } if (ptrace (PT_GET_PROCESS_STATE, pid, (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1) perror_with_name (("ptrace")); gdb_assert (pe.pe_report_event == PTRACE_FORK); fpid = pe.pe_other_pid; if (follow_child) { inferior_ptid = pid_to_ptid (fpid); detach_breakpoints (pid); /* Reset breakpoints in the child as appropriate. */ follow_inferior_reset_breakpoints (); if (ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, 0) == -1) perror_with_name (("ptrace")); } else { inferior_ptid = pid_to_ptid (pid); detach_breakpoints (fpid); if (ptrace (PT_DETACH, fpid, (PTRACE_TYPE_ARG3)1, 0) == -1) perror_with_name (("ptrace")); } return 0; }
static enum print_stop_action signal_catchpoint_print_it (bpstat bs) { struct breakpoint *b = bs->breakpoint_at; ptid_t ptid; struct target_waitstatus last; const char *signal_name; get_last_target_status (&ptid, &last); signal_name = signal_to_name_or_int (last.value.sig); annotate_catchpoint (b->number); printf_filtered (_("\nCatchpoint %d (signal %s), "), b->number, signal_name); return PRINT_SRC_AND_LOC; }
static void mi_on_normal_stop (struct bpstats *bs, int print_frame) { /* Since this can be called when CLI command is executing, using cli interpreter, be sure to use MI uiout for output, not the current one. */ struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); if (print_frame) { int core; if (current_uiout != mi_uiout) { /* The normal_stop function has printed frame information into CLI uiout, or some other non-MI uiout. There's no way we can extract proper fields from random uiout object, so we print the frame again. In practice, this can only happen when running a CLI command in MI. */ struct ui_out *saved_uiout = current_uiout; struct target_waitstatus last; ptid_t last_ptid; current_uiout = mi_uiout; get_last_target_status (&last_ptid, &last); print_stop_event (&last); current_uiout = saved_uiout; } /* Otherwise, frame information has already been printed by normal_stop. */ else { /* Breakpoint hits should always be mirrored to the console. Deciding what to mirror to the console wrt to breakpoints and random stops gets messy real fast. E.g., say "s" trips on a breakpoint. We'd clearly want to mirror the event to the console in this case. But what about more complicated cases like "s&; thread n; s&", and one of those steps spawning a new thread, and that thread hitting a breakpoint? It's impossible in general to track whether the thread had any relation to the commands that had been executed. So we just simplify and always mirror breakpoints and random events to the console. Also, CLI execution commands (-interpreter-exec console "next", for example) in async mode have the opposite issue as described in the "then" branch above -- normal_stop has already printed frame information to MI uiout, but nothing has printed the same information to the CLI channel. We should print the source line to the console when stepping or other similar commands, iff the step was started by a console command (but not if it was started with -exec-step or similar). */ struct thread_info *tp = inferior_thread (); if ((!tp->control.stop_step && !tp->control.proceed_to_finish) || (tp->control.command_interp != NULL && tp->control.command_interp != top_level_interpreter ())) { struct mi_interp *mi = top_level_interpreter_data (); struct target_waitstatus last; ptid_t last_ptid; struct cleanup *old_chain; /* Set the current uiout to CLI uiout temporarily. */ old_chain = make_cleanup (restore_current_uiout_cleanup, current_uiout); current_uiout = mi->cli_uiout; get_last_target_status (&last_ptid, &last); print_stop_event (&last); do_cleanups (old_chain); } } ui_out_field_int (mi_uiout, "thread-id", pid_to_thread_id (inferior_ptid)); if (non_stop) { struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (mi_uiout, "stopped-threads"); ui_out_field_int (mi_uiout, NULL, pid_to_thread_id (inferior_ptid)); do_cleanups (back_to); } else ui_out_field_string (mi_uiout, "stopped-threads", "all"); core = target_core_of_thread (inferior_ptid); if (core != -1) ui_out_field_int (mi_uiout, "core", core); } fputs_unfiltered ("*stopped", raw_stdout); mi_out_put (mi_uiout, raw_stdout); mi_out_rewind (mi_uiout); mi_print_timing_maybe (); fputs_unfiltered ("\n", raw_stdout); gdb_flush (raw_stdout); }
int child_follow_fork (int follow_child) { ptid_t last_ptid; struct target_waitstatus last_status; int has_vforked; int parent_pid, child_pid; get_last_target_status (&last_ptid, &last_status); has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED); parent_pid = ptid_get_pid (last_ptid); child_pid = last_status.value.related_pid; /* At this point, if we are vforking, breakpoints were already detached from the child in child_wait; and the child has already called execve(). If we are forking, both the parent and child have breakpoints inserted. */ if (! follow_child) { if (! has_vforked) { detach_breakpoints (child_pid); #ifdef SOLIB_REMOVE_INFERIOR_HOOK SOLIB_REMOVE_INFERIOR_HOOK (child_pid); #endif } /* Detach from the child. */ printf_unfiltered ("Detaching after fork from %s\n", target_pid_to_str (pid_to_ptid (child_pid))); hppa_require_detach (child_pid, 0); /* The parent and child of a vfork share the same address space. Also, on some targets the order in which vfork and exec events are received for parent in child requires some delicate handling of the events. For instance, on ptrace-based HPUX we receive the child's vfork event first, at which time the parent has been suspended by the OS and is essentially untouchable until the child's exit or second exec event arrives. At that time, the parent's vfork event is delivered to us, and that's when we see and decide how to follow the vfork. But to get to that point, we must continue the child until it execs or exits. To do that smoothly, all breakpoints must be removed from the child, in case there are any set between the vfork() and exec() calls. But removing them from the child also removes them from the parent, due to the shared-address-space nature of a vfork'd parent and child. On HPUX, therefore, we must take care to restore the bp's to the parent before we continue it. Else, it's likely that we may not stop in the expected place. (The worst scenario is when the user tries to step over a vfork() call; the step-resume bp must be restored for the step to properly stop in the parent after the call completes!) Sequence of events, as reported to gdb from HPUX: Parent Child Action for gdb to take ------------------------------------------------------- 1 VFORK Continue child 2 EXEC 3 EXEC or EXIT 4 VFORK Now that the child has safely exec'd or exited, we must restore the parent's breakpoints before we continue it. Else, we may cause it run past expected stopping points. */ if (has_vforked) reattach_breakpoints (parent_pid); } else { /* Needed to keep the breakpoint lists in sync. */ if (! has_vforked) detach_breakpoints (child_pid); /* Before detaching from the parent, remove all breakpoints from it. */ remove_breakpoints (); /* Also reset the solib inferior hook from the parent. */ #ifdef SOLIB_REMOVE_INFERIOR_HOOK SOLIB_REMOVE_INFERIOR_HOOK (PIDGET (inferior_ptid)); #endif /* Detach from the parent. */ target_detach (NULL, 1); /* Attach to the child. */ printf_unfiltered ("Attaching after fork to %s\n", target_pid_to_str (pid_to_ptid (child_pid))); hppa_require_attach (child_pid); inferior_ptid = pid_to_ptid (child_pid); /* If we vforked, then we've also execed by now. The exec will be reported momentarily. follow_exec () will handle breakpoints, so we don't have to.. */ if (!has_vforked) follow_inferior_reset_breakpoints (); } if (has_vforked) { /* If we followed the parent, don't try to follow the child's exec. */ if (saved_vfork_state != STATE_GOT_PARENT && saved_vfork_state != STATE_FAKE_EXEC) fprintf_unfiltered (gdb_stdout, "hppa: post follow vfork: confused state\n"); if (! follow_child || saved_vfork_state == STATE_GOT_PARENT) saved_vfork_state = STATE_NONE; else return 1; } return 0; }