X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=09cf494142d78992a9eca9d4899b5929b30228b3;hb=8601f500c85902a5ea5134cd9de8adf8bcd27c6b;hp=0ddb8f2613f6a1037db0cb199f285a32f64b54d5;hpb=7be570e7ce77920e2e628a03bdfe2d295fc2568f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 0ddb8f2613..09cf494142 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1,5 +1,6 @@ /* Target-struct-independent code to start (run) and stop an inferior process. - Copyright 1986-1989, 1991-1999 Free Software Foundation, Inc. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, + 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GDB. @@ -25,16 +26,17 @@ #include "frame.h" #include "inferior.h" #include "breakpoint.h" -#include "wait.h" +#include "gdb_wait.h" #include "gdbcore.h" #include "gdbcmd.h" #include "target.h" #include "gdbthread.h" #include "annotate.h" -#include "symfile.h" /* for overlay functions */ +#include "symfile.h" #include "top.h" #include -#include "event-loop.h" +#include "inf-loop.h" +#include "regcache.h" /* Prototypes for local functions */ @@ -46,7 +48,7 @@ static void sig_print_info (enum target_signal); static void sig_print_header (void); -static void resume_cleanups (int); +static void resume_cleanups (void *); static int hook_stop_stub (void *); @@ -55,8 +57,6 @@ static void delete_breakpoint_current_contents (void *); static void set_follow_fork_mode_command (char *arg, int from_tty, struct cmd_list_element * c); -static void complete_execution (void); - static struct inferior_status *xmalloc_inferior_status (void); static void free_inferior_status (struct inferior_status *); @@ -75,10 +75,6 @@ static void follow_vfork (int parent_pid, int child_pid); static void set_schedlock_func (char *args, int from_tty, struct cmd_list_element * c); -static int is_internal_shlib_eventpoint (struct breakpoint * ep); - -static int stopped_for_internal_shlib_event (bpstat bs); - struct execution_control_state; static int currently_stepping (struct execution_control_state *ecs); @@ -90,6 +86,11 @@ void _initialize_infrun (void); int inferior_ignoring_startup_exec_events = 0; int inferior_ignoring_leading_exec_events = 0; +/* When set, stop the 'step' command if we enter a function which has + no line number information. The normal behavior is that we step + over such function. */ +int step_stop_if_no_debug = 0; + /* In asynchronous mode, but simulating synchronous execution. */ int sync_execution = 0; @@ -98,17 +99,7 @@ int sync_execution = 0; when the inferior stopped in a different thread than it had been running in. */ -static int switched_from_inferior_pid; - -/* This will be true for configurations that may actually report an - inferior pid different from the original. At present this is only - true for HP-UX native. */ - -#ifndef MAY_SWITCH_FROM_INFERIOR_PID -#define MAY_SWITCH_FROM_INFERIOR_PID (0) -#endif - -static int may_switch_from_inferior_pid = MAY_SWITCH_FROM_INFERIOR_PID; +static ptid_t previous_inferior_ptid; /* This is true for configurations that may follow through execl() and similar functions. At present this is only true for HP-UX native. */ @@ -176,15 +167,53 @@ static int use_thread_step_needed = USE_THREAD_STEP_NEEDED; #define DYNAMIC_TRAMPOLINE_NEXTPC(pc) 0 #endif -/* On SVR4 based systems, determining the callee's address is exceedingly - difficult and depends on the implementation of the run time loader. - If we are stepping at the source level, we single step until we exit - the run time loader code and reach the callee's address. */ +/* If the program uses ELF-style shared libraries, then calls to + functions in shared libraries go through stubs, which live in a + table called the PLT (Procedure Linkage Table). The first time the + function is called, the stub sends control to the dynamic linker, + which looks up the function's real address, patches the stub so + that future calls will go directly to the function, and then passes + control to the function. + + If we are stepping at the source level, we don't want to see any of + this --- we just want to skip over the stub and the dynamic linker. + The simple approach is to single-step until control leaves the + dynamic linker. + + However, on some systems (e.g., Red Hat Linux 5.2) the dynamic + linker calls functions in the shared C library, so you can't tell + from the PC alone whether the dynamic linker is still running. In + this case, we use a step-resume breakpoint to get us past the + dynamic linker, as if we were using "next" to step over a function + call. + + IN_SOLIB_DYNSYM_RESOLVE_CODE says whether we're in the dynamic + linker code or not. Normally, this means we single-step. However, + if SKIP_SOLIB_RESOLVER then returns non-zero, then its value is an + address where we can place a step-resume breakpoint to get past the + linker's symbol resolution function. + + IN_SOLIB_DYNSYM_RESOLVE_CODE can generally be implemented in a + pretty portable way, by comparing the PC against the address ranges + of the dynamic linker's sections. + + SKIP_SOLIB_RESOLVER is generally going to be system-specific, since + it depends on internal details of the dynamic linker. It's usually + not too hard to figure out where to put a breakpoint, but it + certainly isn't portable. SKIP_SOLIB_RESOLVER should do plenty of + sanity checking. If it can't figure things out, returning zero and + getting the (possibly confusing) stepping behavior is better than + signalling an error, which will obscure the change in the + inferior's state. */ #ifndef IN_SOLIB_DYNSYM_RESOLVE_CODE #define IN_SOLIB_DYNSYM_RESOLVE_CODE(pc) 0 #endif +#ifndef SKIP_SOLIB_RESOLVER +#define SKIP_SOLIB_RESOLVER(pc) 0 +#endif + /* For SVR4 shared libraries, each call goes through a small piece of trampoline code in the ".plt" section. IN_SOLIB_CALL_TRAMPOLINE evaluates to nonzero if we are current stopped in one of these. */ @@ -230,6 +259,26 @@ static int use_thread_step_needed = USE_THREAD_STEP_NEEDED; #define INSTRUCTION_NULLIFIED 0 #endif +/* We can't step off a permanent breakpoint in the ordinary way, because we + can't remove it. Instead, we have to advance the PC to the next + instruction. This macro should expand to a pointer to a function that + does that, or zero if we have no such function. If we don't have a + definition for it, we have to report an error. */ +#ifndef SKIP_PERMANENT_BREAKPOINT +#define SKIP_PERMANENT_BREAKPOINT (default_skip_permanent_breakpoint) +static void +default_skip_permanent_breakpoint (void) +{ + error_begin (); + fprintf_filtered (gdb_stderr, "\ +The program is stopped at a permanent breakpoint, but GDB does not know\n\ +how to step past a permanent breakpoint on this architecture. Try using\n\ +a command like `return' or `jump' to continue execution.\n"); + return_to_top_level (RETURN_ERROR); +} +#endif + + /* Convert the #defines into values. This is temporary until wfi control flow is completely sorted out. */ @@ -254,6 +303,13 @@ static int use_thread_step_needed = USE_THREAD_STEP_NEEDED; #define HAVE_CONTINUABLE_WATCHPOINT 1 #endif +#ifndef CANNOT_STEP_HW_WATCHPOINTS +#define CANNOT_STEP_HW_WATCHPOINTS 0 +#else +#undef CANNOT_STEP_HW_WATCHPOINTS +#define CANNOT_STEP_HW_WATCHPOINTS 1 +#endif + /* Tables of how to react to signals; the user sets them. */ static unsigned char *signal_stop; @@ -276,6 +332,9 @@ static unsigned char *signal_program; (flags)[signum] = 0; \ } while (0) +/* Value to pass to target_resume() to cause all threads to resume */ + +#define RESUME_ALL (pid_to_ptid (-1)) /* Command list pointer for the "stop" placeholder. */ @@ -350,6 +409,12 @@ static struct breakpoint *through_sigtramp_breakpoint = NULL; currently be running in a syscall. */ static int number_of_threads_in_syscalls; +/* This is a cached copy of the pid/waitstatus of the last event + returned by target_wait()/target_wait_hook(). This information is + returned by get_last_target_status(). */ +static ptid_t target_last_wait_ptid; +static struct target_waitstatus target_last_waitstatus; + /* This is used to remember when a fork, vfork or exec event was caught by a catchpoint, and thus the event is to be followed at the next resume of the inferior, and not @@ -379,23 +444,31 @@ pending_follow; set to 1, a vfork event has been seen, but cannot be followed until the exec is seen. - (In the latter case, inferior_pid is still the parent of the + (In the latter case, inferior_ptid is still the parent of the vfork, and pending_follow.fork_event.child_pid is the child. The appropriate process is followed, according to the setting of follow-fork-mode.) */ static int follow_vfork_when_exec; -static char *follow_fork_mode_kind_names[] = +static const char follow_fork_mode_ask[] = "ask"; +static const char follow_fork_mode_both[] = "both"; +static const char follow_fork_mode_child[] = "child"; +static const char follow_fork_mode_parent[] = "parent"; + +static const char *follow_fork_mode_kind_names[] = { -/* ??rehrauer: The "both" option is broken, by what may be a 10.20 - kernel problem. It's also not terribly useful without a GUI to - help the user drive two debuggers. So for now, I'm disabling - the "both" option. - "parent", "child", "both", "ask" }; - */ - "parent", "child", "ask"}; + follow_fork_mode_ask, + /* ??rehrauer: The "both" option is broken, by what may be a 10.20 + kernel problem. It's also not terribly useful without a GUI to + help the user drive two debuggers. So for now, I'm disabling the + "both" option. */ + /* follow_fork_mode_both, */ + follow_fork_mode_child, + follow_fork_mode_parent, + NULL +}; -static char *follow_fork_mode_string = NULL; +static const char *follow_fork_mode_string = follow_fork_mode_parent; static void @@ -406,23 +479,20 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked, int followed_child = 0; /* Which process did the user want us to follow? */ - char *follow_mode = - savestring (follow_fork_mode_string, strlen (follow_fork_mode_string)); + const char *follow_mode = follow_fork_mode_string; /* Or, did the user not know, and want us to ask? */ - if (STREQ (follow_fork_mode_string, "ask")) + if (follow_fork_mode_string == follow_fork_mode_ask) { - char requested_mode[100]; - - free (follow_mode); - error ("\"ask\" mode NYI"); - follow_mode = savestring (requested_mode, strlen (requested_mode)); + internal_error (__FILE__, __LINE__, + "follow_inferior_fork: \"ask\" mode not implemented"); + /* follow_mode = follow_fork_mode_...; */ } /* If we're to be following the parent, then detach from child_pid. We're already following the parent, so need do nothing explicit for it. */ - if (STREQ (follow_mode, "parent")) + if (follow_mode == follow_fork_mode_parent) { followed_parent = 1; @@ -446,8 +516,8 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked, } /* If we're to be following the child, then attach to it, detach - from inferior_pid, and set inferior_pid to child_pid. */ - else if (STREQ (follow_mode, "child")) + from inferior_ptid, and set inferior_ptid to child_pid. */ + else if (follow_mode == follow_fork_mode_child) { char child_pid_spelling[100]; /* Arbitrary length. */ @@ -469,7 +539,7 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked, /* Also reset the solib inferior hook from the parent. */ #ifdef SOLIB_REMOVE_INFERIOR_HOOK - SOLIB_REMOVE_INFERIOR_HOOK (inferior_pid); + SOLIB_REMOVE_INFERIOR_HOOK (PIDGET (inferior_ptid)); #endif /* Detach from the parent. */ @@ -477,7 +547,7 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked, target_detach (NULL, 1); /* Attach to the child. */ - inferior_pid = child_pid; + inferior_ptid = pid_to_ptid (child_pid); sprintf (child_pid_spelling, "%d", child_pid); dont_repeat (); @@ -509,7 +579,7 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked, /* If we're to be following both parent and child, then fork ourselves, and attach the debugger clone to the child. */ - else if (STREQ (follow_mode, "both")) + else if (follow_mode == follow_fork_mode_both) { char pid_suffix[100]; /* Arbitrary length. */ @@ -521,7 +591,7 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked, /* We continue to follow the parent. To help distinguish the two debuggers, though, both we and our clone will reset our prompts. */ - sprintf (pid_suffix, "[%d] ", inferior_pid); + sprintf (pid_suffix, "[%d] ", PIDGET (inferior_ptid)); set_prompt (strcat (get_prompt (), pid_suffix)); } @@ -565,8 +635,6 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked, pending_follow.fork_event.saw_parent_fork = 0; pending_follow.fork_event.saw_child_fork = 0; - - free (follow_mode); } static void @@ -585,15 +653,18 @@ follow_vfork (int parent_pid, int child_pid) follow_inferior_fork (parent_pid, child_pid, 0, 1); /* Did we follow the child? Had it exec'd before we saw the parent vfork? */ - if (pending_follow.fork_event.saw_child_exec && (inferior_pid == child_pid)) + if (pending_follow.fork_event.saw_child_exec + && (PIDGET (inferior_ptid) == child_pid)) { pending_follow.fork_event.saw_child_exec = 0; pending_follow.kind = TARGET_WAITKIND_SPURIOUS; - follow_exec (inferior_pid, pending_follow.execd_pathname); - free (pending_follow.execd_pathname); + follow_exec (PIDGET (inferior_ptid), pending_follow.execd_pathname); + xfree (pending_follow.execd_pathname); } } +/* EXECD_PATHNAME is assumed to be non-NULL. */ + static void follow_exec (int pid, char *execd_pathname) { @@ -609,13 +680,14 @@ follow_exec (int pid, char *execd_pathname) (pending_follow.kind == TARGET_WAITKIND_VFORKED)) { pending_follow.kind = TARGET_WAITKIND_SPURIOUS; - follow_vfork (inferior_pid, pending_follow.fork_event.child_pid); + follow_vfork (PIDGET (inferior_ptid), + pending_follow.fork_event.child_pid); follow_vfork_when_exec = 0; - saved_pid = inferior_pid; + saved_pid = PIDGET (inferior_ptid); /* Did we follow the parent? If so, we're done. If we followed the child then we must also follow its exec(). */ - if (inferior_pid == pending_follow.fork_event.parent_pid) + if (PIDGET (inferior_ptid) == pending_follow.fork_event.parent_pid) return; } @@ -664,14 +736,15 @@ follow_exec (int pid, char *execd_pathname) gdb_flush (gdb_stdout); target_mourn_inferior (); - inferior_pid = saved_pid; /* Because mourn_inferior resets inferior_pid. */ + inferior_ptid = pid_to_ptid (saved_pid); + /* Because mourn_inferior resets inferior_ptid. */ push_target (tgt); /* That a.out is now the one to use. */ exec_file_attach (execd_pathname, 0); /* And also is where symbols can be found. */ - symbol_file_command (execd_pathname, 0); + symbol_file_add_main (execd_pathname, 0); /* Reset the shared library package. This ensures that we get a shlib event when the child reaches "_start", at which point @@ -680,7 +753,7 @@ follow_exec (int pid, char *execd_pathname) SOLIB_RESTART (); #endif #ifdef SOLIB_CREATE_INFERIOR_HOOK - SOLIB_CREATE_INFERIOR_HOOK (inferior_pid); + SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid)); #endif /* Reinsert all breakpoints. (Those which were symbolic have @@ -703,17 +776,22 @@ static int singlestep_breakpoints_inserted_p = 0; /* Things to clean up if we QUIT out of resume (). */ /* ARGSUSED */ static void -resume_cleanups (int arg) +resume_cleanups (void *ignore) { normal_stop (); } -static char schedlock_off[] = "off"; -static char schedlock_on[] = "on"; -static char schedlock_step[] = "step"; -static char *scheduler_mode = schedlock_off; -static char *scheduler_enums[] = -{schedlock_off, schedlock_on, schedlock_step}; +static const char schedlock_off[] = "off"; +static const char schedlock_on[] = "on"; +static const char schedlock_step[] = "step"; +static const char *scheduler_mode = schedlock_off; +static const char *scheduler_enums[] = +{ + schedlock_off, + schedlock_on, + schedlock_step, + NULL +}; static void set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c) @@ -728,6 +806,8 @@ set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c) } + + /* Resume the inferior, but allow a QUIT. This is useful if the user wants to interrupt some lengthy single-stepping operation (for child processes, the SIGINT goes to the inferior, and so @@ -740,8 +820,7 @@ void resume (int step, enum target_signal sig) { int should_resume = 1; - struct cleanup *old_cleanups = make_cleanup ((make_cleanup_func) - resume_cleanups, 0); + struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); QUIT; #ifdef CANNOT_STEP_BREAKPOINT @@ -752,7 +831,26 @@ resume (int step, enum target_signal sig) step = 0; #endif - if (SOFTWARE_SINGLE_STEP_P && step) + /* Some targets (e.g. Solaris x86) have a kernel bug when stepping + over an instruction that causes a page fault without triggering + a hardware watchpoint. The kernel properly notices that it shouldn't + stop, because the hardware watchpoint is not triggered, but it forgets + the step request and continues the program normally. + Work around the problem by removing hardware watchpoints if a step is + requested, GDB will check for a hardware watchpoint trigger after the + step anyway. */ + if (CANNOT_STEP_HW_WATCHPOINTS && step && breakpoints_inserted) + remove_hw_watchpoints (); + + + /* Normally, by the time we reach `resume', the breakpoints are either + removed or inserted, as appropriate. The exception is if we're sitting + at a permanent breakpoint; we need to step over it, but permanent + breakpoints can't be removed. So we have to test for it here. */ + if (breakpoint_here_p (read_pc ()) == permanent_breakpoint_here) + SKIP_PERMANENT_BREAKPOINT (); + + if (SOFTWARE_SINGLE_STEP_P () && step) { /* Do it the hard way, w/temp breakpoints */ SOFTWARE_SINGLE_STEP (sig, 1 /*insert-breakpoints */ ); @@ -774,7 +872,8 @@ resume (int step, enum target_signal sig) { case (TARGET_WAITKIND_FORKED): pending_follow.kind = TARGET_WAITKIND_SPURIOUS; - follow_fork (inferior_pid, pending_follow.fork_event.child_pid); + follow_fork (PIDGET (inferior_ptid), + pending_follow.fork_event.child_pid); break; case (TARGET_WAITKIND_VFORKED): @@ -782,14 +881,15 @@ resume (int step, enum target_signal sig) int saw_child_exec = pending_follow.fork_event.saw_child_exec; pending_follow.kind = TARGET_WAITKIND_SPURIOUS; - follow_vfork (inferior_pid, pending_follow.fork_event.child_pid); + follow_vfork (PIDGET (inferior_ptid), + pending_follow.fork_event.child_pid); /* Did we follow the child, but not yet see the child's exec event? If so, then it actually ought to be waiting for us; we respond to parent vfork events. We don't actually want to resume the child in this situation; we want to just get its exec event. */ if (!saw_child_exec && - (inferior_pid == pending_follow.fork_event.child_pid)) + (PIDGET (inferior_ptid) == pending_follow.fork_event.child_pid)) should_resume = 0; } break; @@ -810,6 +910,8 @@ resume (int step, enum target_signal sig) if (should_resume) { + ptid_t resume_ptid; + if (use_thread_step_needed && thread_step_needed) { /* We stopped on a BPT instruction; @@ -821,7 +923,7 @@ resume (int step, enum target_signal sig) { /* Breakpoint deleted: ok to do regular resume where all the threads either step or continue. */ - target_resume (-1, step, sig); + resume_ptid = RESUME_ALL; } else { @@ -833,20 +935,19 @@ resume (int step, enum target_signal sig) trap_expected = 1; step = 1; } - - target_resume (inferior_pid, step, sig); + resume_ptid = inferior_ptid; } } else { /* Vanilla resume. */ - if ((scheduler_mode == schedlock_on) || (scheduler_mode == schedlock_step && step != 0)) - target_resume (inferior_pid, step, sig); + resume_ptid = inferior_ptid; else - target_resume (-1, step, sig); + resume_ptid = RESUME_ALL; } + target_resume (resume_ptid, step, sig); } discard_cleanups (old_cleanups); @@ -863,7 +964,7 @@ clear_proceed_status (void) step_range_start = 0; step_range_end = 0; step_frame_address = 0; - step_over_calls = -1; + step_over_calls = STEP_OVER_UNDEBUGGABLE; stop_after_trap = 0; stop_soon_quietly = 0; proceed_to_finish = 0; @@ -895,7 +996,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) if (step < 0) stop_after_trap = 1; - if (addr == (CORE_ADDR) - 1) + if (addr == (CORE_ADDR) -1) { /* If there is a breakpoint at the address we will resume at, step one instruction before inserting breakpoints @@ -973,9 +1074,11 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) int temp = insert_breakpoints (); if (temp) { - print_sys_errmsg ("ptrace", temp); + print_sys_errmsg ("insert_breakpoints", temp); error ("Cannot insert breakpoints.\n\ -The same program may be running in another process."); +The same program may be running in another process,\n\ +or you may have requested too many hardware\n\ +breakpoints and/or watchpoints.\n"); } breakpoints_inserted = 1; @@ -1001,7 +1104,7 @@ The same program may be running in another process."); and in any case decode why it stopped, and act accordingly. */ /* Do this only if we are not using the event loop, or if the target does not support asynchronous execution. */ - if (!async_p || !target_has_async) + if (!event_loop_p || !target_can_async_p ()) { wait_for_inferior (); normal_stop (); @@ -1027,23 +1130,22 @@ start_remote (void) stop_soon_quietly = 1; trap_expected = 0; - /* Go on waiting only in case gdb is not started in async mode, or - in case the target doesn't support async execution. */ - if (!async_p || !target_has_async) - { - wait_for_inferior (); - normal_stop (); - } - else - { - /* The 'tar rem' command should always look synchronous, - i.e. display the prompt only once it has connected and - started the target. */ - sync_execution = 1; - push_prompt ("", "", ""); - delete_file_handler (input_fd); - target_executing = 1; - } + /* Always go on waiting for the target, regardless of the mode. */ + /* FIXME: cagney/1999-09-23: At present it isn't possible to + indicate to wait_for_inferior that a target should timeout if + nothing is returned (instead of just blocking). Because of this, + targets expecting an immediate response need to, internally, set + things up so that the target_wait() is forced to eventually + timeout. */ + /* FIXME: cagney/1999-09-24: It isn't possible for target_open() to + differentiate to its caller what the state of the target is after + the initial open has been performed. Here we're assuming that + the target has stopped. It should be possible to eventually have + target_open() return to the caller an indication that the target + is currently running and GDB state should be set to the same as + for an async run. */ + wait_for_inferior (); + normal_stop (); } /* Initialize static vars when a new inferior begins. */ @@ -1100,6 +1202,24 @@ enum infwait_states infwait_nonstep_watch_state }; +/* Why did the inferior stop? Used to print the appropriate messages + to the interface from within handle_inferior_event(). */ +enum inferior_stop_reason +{ + /* We don't know why. */ + STOP_UNKNOWN, + /* Step, next, nexti, stepi finished. */ + END_STEPPING_RANGE, + /* Found breakpoint. */ + BREAKPOINT_HIT, + /* Inferior terminated by signal. */ + SIGNAL_EXITED, + /* Inferior exited. */ + EXITED, + /* Inferior received signal, and user asked to be notified. */ + SIGNAL_RECEIVED +}; + /* This structure contains what used to be local variables in wait_for_inferior. Probably many of them can return to being locals in handle_inferior_event. */ @@ -1118,8 +1238,8 @@ struct execution_control_state int current_line; struct symtab *current_symtab; int handling_longjmp; /* FIXME */ - int pid; - int saved_inferior_pid; + ptid_t ptid; + ptid_t saved_inferior_ptid; int update_step_sp; int stepping_through_solib_after_catch; bpstat stepping_through_solib_catchpoints; @@ -1128,7 +1248,7 @@ struct execution_control_state int new_thread_event; struct target_waitstatus tmpstatus; enum infwait_states infwait_state; - int waiton_pid; + ptid_t waiton_ptid; int wait_some_more; }; @@ -1136,6 +1256,14 @@ void init_execution_control_state (struct execution_control_state * ecs); void handle_inferior_event (struct execution_control_state * ecs); +static void check_sigtramp2 (struct execution_control_state *ecs); +static void step_into_function (struct execution_control_state *ecs); +static void step_over_function (struct execution_control_state *ecs); +static void stop_stepping (struct execution_control_state *ecs); +static void prepare_to_wait (struct execution_control_state *ecs); +static void keep_going (struct execution_control_state *ecs); +static void print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info); + /* Wait for control to return from inferior to debugger. If inferior gets a signal, we may decide to start it up again instead of returning. That is why there is a loop in this function. @@ -1149,7 +1277,7 @@ wait_for_inferior (void) struct execution_control_state ecss; struct execution_control_state *ecs; - old_cleanups = make_cleanup (delete_breakpoint_current_contents, + old_cleanups = make_cleanup (delete_step_resume_breakpoint, &step_resume_breakpoint); make_cleanup (delete_breakpoint_current_contents, &through_sigtramp_breakpoint); @@ -1164,8 +1292,7 @@ wait_for_inferior (void) thread_step_needed = 0; /* We'll update this if & when we switch to a new thread. */ - if (may_switch_from_inferior_pid) - switched_from_inferior_pid = inferior_pid; + previous_inferior_ptid = inferior_ptid; overlay_cache_invalid = 1; @@ -1180,9 +1307,9 @@ wait_for_inferior (void) while (1) { if (target_wait_hook) - ecs->pid = target_wait_hook (ecs->waiton_pid, ecs->wp); + ecs->ptid = target_wait_hook (ecs->waiton_ptid, ecs->wp); else - ecs->pid = target_wait (ecs->waiton_pid, ecs->wp); + ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp); /* Now figure out what to do with the result of the result. */ handle_inferior_event (ecs); @@ -1206,7 +1333,7 @@ struct execution_control_state async_ecss; struct execution_control_state *async_ecs; void -fetch_inferior_event (void) +fetch_inferior_event (void *client_data) { static struct cleanup *old_cleanups; @@ -1214,7 +1341,7 @@ fetch_inferior_event (void) if (!async_ecs->wait_some_more) { - old_cleanups = make_exec_cleanup (delete_breakpoint_current_contents, + old_cleanups = make_exec_cleanup (delete_step_resume_breakpoint, &step_resume_breakpoint); make_exec_cleanup (delete_breakpoint_current_contents, &through_sigtramp_breakpoint); @@ -1225,8 +1352,7 @@ fetch_inferior_event (void) thread_step_needed = 0; /* We'll update this if & when we switch to a new thread. */ - if (may_switch_from_inferior_pid) - switched_from_inferior_pid = inferior_pid; + previous_inferior_ptid = inferior_ptid; overlay_cache_invalid = 1; @@ -1240,9 +1366,9 @@ fetch_inferior_event (void) } if (target_wait_hook) - async_ecs->pid = target_wait_hook (async_ecs->waiton_pid, async_ecs->wp); + async_ecs->ptid = target_wait_hook (async_ecs->waiton_ptid, async_ecs->wp); else - async_ecs->pid = target_wait (async_ecs->waiton_pid, async_ecs->wp); + async_ecs->ptid = target_wait (async_ecs->waiton_ptid, async_ecs->wp); /* Now figure out what to do with the result of the result. */ handle_inferior_event (async_ecs); @@ -1254,11 +1380,10 @@ fetch_inferior_event (void) if there are any. */ do_exec_cleanups (old_cleanups); normal_stop (); - /* Is there anything left to do for the command issued to - complete? */ - do_all_continuations (); - /* Reset things after target has stopped for the async commands. */ - complete_execution (); + if (step_multi && stop_step) + inferior_event_handler (INF_EXEC_CONTINUE, NULL); + else + inferior_event_handler (INF_EXEC_COMPLETE, NULL); } } @@ -1268,6 +1393,7 @@ fetch_inferior_event (void) void init_execution_control_state (struct execution_control_state *ecs) { + /* ecs->another_trap? */ ecs->random_signal = 0; ecs->remove_breakpoints_on_following_step = 0; ecs->handling_longjmp = 0; /* FIXME */ @@ -1280,13 +1406,14 @@ init_execution_control_state (struct execution_control_state *ecs) ecs->current_line = ecs->sal.line; ecs->current_symtab = ecs->sal.symtab; ecs->infwait_state = infwait_normal_state; - ecs->waiton_pid = -1; + ecs->waiton_ptid = pid_to_ptid (-1); ecs->wp = &(ecs->ws); } /* Call this function before setting step_resume_breakpoint, as a - sanity check. We should never be setting a new - step_resume_breakpoint when we have an old one active. */ + sanity check. There should never be more than one step-resume + breakpoint per thread, so we should never be setting a new + step_resume_breakpoint when one is already active. */ static void check_for_old_step_resume_breakpoint (void) { @@ -1294,6 +1421,18 @@ check_for_old_step_resume_breakpoint (void) warning ("GDB bug: infrun.c (wait_for_inferior): dropping old step_resume breakpoint"); } +/* Return the cached copy of the last pid/waitstatus returned by + target_wait()/target_wait_hook(). The data is actually cached by + handle_inferior_event(), which gets called immediately after + target_wait()/target_wait_hook(). */ + +void +get_last_target_status(ptid_t *ptidp, struct target_waitstatus *status) +{ + *ptidp = target_last_wait_ptid; + *status = target_last_waitstatus; +} + /* Given an execution control state that has been freshly filled in by an event from the inferior, figure out what it means and take appropriate action. */ @@ -1304,6 +1443,10 @@ handle_inferior_event (struct execution_control_state *ecs) CORE_ADDR tmp; int stepped_after_stopped_by_watchpoint; + /* Cache the last pid/waitstatus. */ + target_last_wait_ptid = ecs->ptid; + target_last_waitstatus = *ecs->wp; + /* Keep this extra brace for now, minimizes diffs. */ { switch (ecs->infwait_state) @@ -1318,7 +1461,7 @@ handle_inferior_event (struct execution_control_state *ecs) is serviced in this loop, below. */ if (ecs->enable_hw_watchpoints_after_wait) { - TARGET_ENABLE_HW_WATCHPOINTS (inferior_pid); + TARGET_ENABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid)); ecs->enable_hw_watchpoints_after_wait = 0; } stepped_after_stopped_by_watchpoint = 0; @@ -1328,15 +1471,20 @@ handle_inferior_event (struct execution_control_state *ecs) insert_breakpoints (); /* We need to restart all the threads now, - * unles we're running in scheduler-locked mode. - * FIXME: shouldn't we look at currently_stepping ()? + * unless we're running in scheduler-locked mode. + * Use currently_stepping to determine whether to + * step or continue. */ + if (scheduler_mode == schedlock_on) - target_resume (ecs->pid, 0, TARGET_SIGNAL_0); + target_resume (ecs->ptid, + currently_stepping (ecs), TARGET_SIGNAL_0); else - target_resume (-1, 0, TARGET_SIGNAL_0); + target_resume (RESUME_ALL, + currently_stepping (ecs), TARGET_SIGNAL_0); ecs->infwait_state = infwait_normal_state; - goto wfi_continue; + prepare_to_wait (ecs); + return; case infwait_nullified_state: break; @@ -1356,15 +1504,22 @@ handle_inferior_event (struct execution_control_state *ecs) /* If it's a new process, add it to the thread database */ - ecs->new_thread_event = ((ecs->pid != inferior_pid) && !in_thread_list (ecs->pid)); + ecs->new_thread_event = (! ptid_equal (ecs->ptid, inferior_ptid) + && ! in_thread_list (ecs->ptid)); if (ecs->ws.kind != TARGET_WAITKIND_EXITED && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event) { - add_thread (ecs->pid); + add_thread (ecs->ptid); - printf_filtered ("[New %s]\n", target_pid_or_tid_to_str (ecs->pid)); +#ifdef UI_OUT + ui_out_text (uiout, "[New "); + ui_out_text (uiout, target_pid_or_tid_to_str (ecs->ptid)); + ui_out_text (uiout, "]\n"); +#else + printf_filtered ("[New %s]\n", target_pid_or_tid_to_str (ecs->ptid)); +#endif #if 0 /* NOTE: This block is ONLY meant to be invoked in case of a @@ -1386,8 +1541,9 @@ handle_inferior_event (struct execution_control_state *ecs) Therefore we need to continue all threads in order to make progress. */ - target_resume (-1, 0, TARGET_SIGNAL_0); - goto wfi_continue; + target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0); + prepare_to_wait (ecs); + return; #endif } @@ -1422,20 +1578,17 @@ handle_inferior_event (struct execution_control_state *ecs) } #endif resume (0, TARGET_SIGNAL_0); - goto wfi_continue; + prepare_to_wait (ecs); + return; case TARGET_WAITKIND_SPURIOUS: resume (0, TARGET_SIGNAL_0); - goto wfi_continue; + prepare_to_wait (ecs); + return; case TARGET_WAITKIND_EXITED: target_terminal_ours (); /* Must do this before mourn anyway */ - annotate_exited (ecs->ws.value.integer); - if (ecs->ws.value.integer) - printf_filtered ("\nProgram exited with code 0%o.\n", - (unsigned int) ecs->ws.value.integer); - else - printf_filtered ("\nProgram exited normally.\n"); + print_stop_reason (EXITED, ecs->ws.value.integer); /* Record the exit code in the convenience variable $_exitcode, so that the user can inspect this again later. */ @@ -1444,37 +1597,27 @@ handle_inferior_event (struct execution_control_state *ecs) (LONGEST) ecs->ws.value.integer)); gdb_flush (gdb_stdout); target_mourn_inferior (); - singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P */ + singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P() */ stop_print_frame = 0; - goto stop_stepping; + stop_stepping (ecs); + return; case TARGET_WAITKIND_SIGNALLED: stop_print_frame = 0; stop_signal = ecs->ws.value.sig; target_terminal_ours (); /* Must do this before mourn anyway */ - annotate_signalled (); - - /* This looks pretty bogus to me. Doesn't TARGET_WAITKIND_SIGNALLED - mean it is already dead? This has been here since GDB 2.8, so - perhaps it means rms didn't understand unix waitstatuses? - For the moment I'm just kludging around this in remote.c - rather than trying to change it here --kingdon, 5 Dec 1994. */ - target_kill (); /* kill mourns as well */ - - printf_filtered ("\nProgram terminated with signal "); - annotate_signal_name (); - printf_filtered ("%s", target_signal_to_name (stop_signal)); - annotate_signal_name_end (); - printf_filtered (", "); - annotate_signal_string (); - printf_filtered ("%s", target_signal_to_string (stop_signal)); - annotate_signal_string_end (); - printf_filtered (".\n"); - - printf_filtered ("The program no longer exists.\n"); - gdb_flush (gdb_stdout); - singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P */ - goto stop_stepping; + + /* Note: By definition of TARGET_WAITKIND_SIGNALLED, we shouldn't + reach here unless the inferior is dead. However, for years + target_kill() was called here, which hints that fatal signals aren't + really fatal on some systems. If that's true, then some changes + may be needed. */ + target_mourn_inferior (); + + print_stop_reason (SIGNAL_EXITED, stop_signal); + singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P() */ + stop_stepping (ecs); + return; /* The following are the only cases in which we keep going; the above cases end in a continue or goto. */ @@ -1486,32 +1629,27 @@ handle_inferior_event (struct execution_control_state *ecs) interested in reacting to forks of the child. Note that we expect the child's fork event to be available if we waited for it now. */ - if (inferior_pid == ecs->pid) + if (ptid_equal (inferior_ptid, ecs->ptid)) { pending_follow.fork_event.saw_parent_fork = 1; - pending_follow.fork_event.parent_pid = ecs->pid; + pending_follow.fork_event.parent_pid = PIDGET (ecs->ptid); pending_follow.fork_event.child_pid = ecs->ws.value.related_pid; - goto wfi_continue; + prepare_to_wait (ecs); + return; } else { pending_follow.fork_event.saw_child_fork = 1; - pending_follow.fork_event.child_pid = ecs->pid; + pending_follow.fork_event.child_pid = PIDGET (ecs->ptid); pending_follow.fork_event.parent_pid = ecs->ws.value.related_pid; } - stop_pc = read_pc_pid (ecs->pid); - ecs->saved_inferior_pid = inferior_pid; - inferior_pid = ecs->pid; - stop_bpstat = bpstat_stop_status - (&stop_pc, - (DECR_PC_AFTER_BREAK ? - (prev_pc != stop_pc - DECR_PC_AFTER_BREAK - && currently_stepping (ecs)) - : 0) - ); + stop_pc = read_pc_pid (ecs->ptid); + ecs->saved_inferior_ptid = inferior_ptid; + inferior_ptid = ecs->ptid; + stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs)); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); - inferior_pid = ecs->saved_inferior_pid; + inferior_ptid = ecs->saved_inferior_ptid; goto process_event_stop_test; /* If this a platform which doesn't allow a debugger to touch a @@ -1531,10 +1669,10 @@ handle_inferior_event (struct execution_control_state *ecs) it execs, and the child has not yet exec'd. We probably should warn the user to that effect when the catchpoint triggers...) */ - if (ecs->pid == inferior_pid) + if (ptid_equal (ecs->ptid, inferior_ptid)) { pending_follow.fork_event.saw_parent_fork = 1; - pending_follow.fork_event.parent_pid = ecs->pid; + pending_follow.fork_event.parent_pid = PIDGET (ecs->ptid); pending_follow.fork_event.child_pid = ecs->ws.value.related_pid; } @@ -1544,25 +1682,21 @@ handle_inferior_event (struct execution_control_state *ecs) else { pending_follow.fork_event.saw_child_fork = 1; - pending_follow.fork_event.child_pid = ecs->pid; + pending_follow.fork_event.child_pid = PIDGET (ecs->ptid); pending_follow.fork_event.parent_pid = ecs->ws.value.related_pid; - target_post_startup_inferior (pending_follow.fork_event.child_pid); + target_post_startup_inferior ( + pid_to_ptid (pending_follow.fork_event.child_pid)); follow_vfork_when_exec = !target_can_follow_vfork_prior_to_exec (); if (follow_vfork_when_exec) { - target_resume (ecs->pid, 0, TARGET_SIGNAL_0); - goto wfi_continue; + target_resume (ecs->ptid, 0, TARGET_SIGNAL_0); + prepare_to_wait (ecs); + return; } } stop_pc = read_pc (); - stop_bpstat = bpstat_stop_status - (&stop_pc, - (DECR_PC_AFTER_BREAK ? - (prev_pc != stop_pc - DECR_PC_AFTER_BREAK - && currently_stepping (ecs)) - : 0) - ); + stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs)); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); goto process_event_stop_test; @@ -1578,8 +1712,9 @@ handle_inferior_event (struct execution_control_state *ecs) inferior_ignoring_leading_exec_events--; if (pending_follow.kind == TARGET_WAITKIND_VFORKED) ENSURE_VFORKING_PARENT_REMAINS_STOPPED (pending_follow.fork_event.parent_pid); - target_resume (ecs->pid, 0, TARGET_SIGNAL_0); - goto wfi_continue; + target_resume (ecs->ptid, 0, TARGET_SIGNAL_0); + prepare_to_wait (ecs); + return; } inferior_ignoring_leading_exec_events = target_reported_exec_events_per_exec_call () - 1; @@ -1588,7 +1723,7 @@ handle_inferior_event (struct execution_control_state *ecs) savestring (ecs->ws.value.execd_pathname, strlen (ecs->ws.value.execd_pathname)); - /* Did inferior_pid exec, or did a (possibly not-yet-followed) + /* Did inferior_ptid exec, or did a (possibly not-yet-followed) child of a vfork exec? ??rehrauer: This is unabashedly an HP-UX specific thing. On @@ -1612,28 +1747,23 @@ handle_inferior_event (struct execution_control_state *ecs) the parent vfork event is delivered. A single-step suffices. */ if (RESUME_EXECD_VFORKING_CHILD_TO_GET_PARENT_VFORK ()) - target_resume (ecs->pid, 1, TARGET_SIGNAL_0); + target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* We expect the parent vfork event to be available now. */ - goto wfi_continue; + prepare_to_wait (ecs); + return; } /* This causes the eventpoints and symbol table to be reset. Must do this now, before trying to determine whether to stop. */ - follow_exec (inferior_pid, pending_follow.execd_pathname); - free (pending_follow.execd_pathname); - - stop_pc = read_pc_pid (ecs->pid); - ecs->saved_inferior_pid = inferior_pid; - inferior_pid = ecs->pid; - stop_bpstat = bpstat_stop_status - (&stop_pc, - (DECR_PC_AFTER_BREAK ? - (prev_pc != stop_pc - DECR_PC_AFTER_BREAK - && currently_stepping (ecs)) - : 0) - ); + follow_exec (PIDGET (inferior_ptid), pending_follow.execd_pathname); + xfree (pending_follow.execd_pathname); + + stop_pc = read_pc_pid (ecs->ptid); + ecs->saved_inferior_ptid = inferior_ptid; + inferior_ptid = ecs->ptid; + stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs)); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); - inferior_pid = ecs->saved_inferior_pid; + inferior_ptid = ecs->saved_inferior_ptid; goto process_event_stop_test; /* These syscall events are returned on HP-UX, as part of its @@ -1657,10 +1787,11 @@ handle_inferior_event (struct execution_control_state *ecs) number_of_threads_in_syscalls++; if (number_of_threads_in_syscalls == 1) { - TARGET_DISABLE_HW_WATCHPOINTS (inferior_pid); + TARGET_DISABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid)); } resume (0, TARGET_SIGNAL_0); - goto wfi_continue; + prepare_to_wait (ecs); + return; /* Before examining the threads further, step this thread to get it entirely out of the syscall. (We get notice of the @@ -1677,7 +1808,7 @@ handle_inferior_event (struct execution_control_state *ecs) here, which will be serviced immediately after the target is waited on. */ case TARGET_WAITKIND_SYSCALL_RETURN: - target_resume (ecs->pid, 1, TARGET_SIGNAL_0); + target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); if (number_of_threads_in_syscalls > 0) { @@ -1685,11 +1816,23 @@ handle_inferior_event (struct execution_control_state *ecs) ecs->enable_hw_watchpoints_after_wait = (number_of_threads_in_syscalls == 0); } - goto wfi_continue; + prepare_to_wait (ecs); + return; case TARGET_WAITKIND_STOPPED: stop_signal = ecs->ws.value.sig; break; + + /* We had an event in the inferior, but we are not interested + in handling it at this level. The lower layers have already + done what needs to be done, if anything. This case can + occur only when the target is async or extended-async. One + of the circumstamces for this to happen is when the + inferior produces output for the console. The inferior has + not stopped, and we are ignoring the event. */ + case TARGET_WAITKIND_IGNORE: + ecs->wait_some_more = 1; + return; } /* We may want to consider not doing a resume here in order to give @@ -1701,11 +1844,12 @@ handle_inferior_event (struct execution_control_state *ecs) all threads in order to make progress. */ if (ecs->new_thread_event) { - target_resume (-1, 0, TARGET_SIGNAL_0); - goto wfi_continue; + target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0); + prepare_to_wait (ecs); + return; } - stop_pc = read_pc_pid (ecs->pid); + stop_pc = read_pc_pid (ecs->ptid); /* See if a thread hit a thread-specific breakpoint that was meant for another thread. If so, then step that thread past the breakpoint, @@ -1713,20 +1857,20 @@ handle_inferior_event (struct execution_control_state *ecs) if (stop_signal == TARGET_SIGNAL_TRAP) { - if (SOFTWARE_SINGLE_STEP_P && singlestep_breakpoints_inserted_p) + if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p) ecs->random_signal = 0; else if (breakpoints_inserted && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK)) { ecs->random_signal = 0; if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, - ecs->pid)) + ecs->ptid)) { int remove_status; /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */ - write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, ecs->pid); + write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, ecs->ptid); remove_status = remove_breakpoints (); /* Did we fail to remove breakpoints? If so, try @@ -1738,29 +1882,35 @@ handle_inferior_event (struct execution_control_state *ecs) then either :-) or execs. */ if (remove_status != 0) { - write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK + 4, ecs->pid); + write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK + 4, ecs->ptid); + /* We need to restart all the threads now, + * unles we're running in scheduler-locked mode. + * Use currently_stepping to determine whether to + * step or continue. + */ + if (scheduler_mode == schedlock_on) + target_resume (ecs->ptid, + currently_stepping (ecs), + TARGET_SIGNAL_0); + else + target_resume (RESUME_ALL, + currently_stepping (ecs), + TARGET_SIGNAL_0); + prepare_to_wait (ecs); + return; } else { /* Single step */ - target_resume (ecs->pid, 1, TARGET_SIGNAL_0); + target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* FIXME: What if a signal arrives instead of the single-step happening? */ - ecs->waiton_pid = ecs->pid; + ecs->waiton_ptid = ecs->ptid; ecs->wp = &(ecs->ws); ecs->infwait_state = infwait_thread_hop_state; - goto wfi_continue; + prepare_to_wait (ecs); + return; } - - /* We need to restart all the threads now, - * unles we're running in scheduler-locked mode. - * FIXME: shouldn't we look at currently_stepping ()? - */ - if (scheduler_mode == schedlock_on) - target_resume (ecs->pid, 0, TARGET_SIGNAL_0); - else - target_resume (-1, 0, TARGET_SIGNAL_0); - goto wfi_continue; } else { @@ -1782,7 +1932,7 @@ handle_inferior_event (struct execution_control_state *ecs) Note that if there's any kind of pending follow (i.e., of a fork, vfork or exec), we don't want to do this now. Rather, we'll let the next resume handle it. */ - if ((ecs->pid != inferior_pid) && + if (! ptid_equal (ecs->ptid, inferior_ptid) && (pending_follow.kind == TARGET_WAITKIND_SPURIOUS)) { int printed = 0; @@ -1825,50 +1975,56 @@ handle_inferior_event (struct execution_control_state *ecs) if (signal_program[stop_signal] == 0) stop_signal = TARGET_SIGNAL_0; - target_resume (ecs->pid, 0, stop_signal); - goto wfi_continue; + target_resume (ecs->ptid, 0, stop_signal); + prepare_to_wait (ecs); + return; } /* It's a SIGTRAP or a signal we're interested in. Switch threads, and fall into the rest of wait_for_inferior(). */ - /* Save infrun state for the old thread. */ - save_infrun_state (inferior_pid, prev_pc, - prev_func_start, prev_func_name, - trap_expected, step_resume_breakpoint, - through_sigtramp_breakpoint, - step_range_start, step_range_end, - step_frame_address, ecs->handling_longjmp, - ecs->another_trap, - ecs->stepping_through_solib_after_catch, - ecs->stepping_through_solib_catchpoints, - ecs->stepping_through_sigtramp); - - if (may_switch_from_inferior_pid) - switched_from_inferior_pid = inferior_pid; - - inferior_pid = ecs->pid; - - /* Load infrun state for the new thread. */ - load_infrun_state (inferior_pid, &prev_pc, - &prev_func_start, &prev_func_name, - &trap_expected, &step_resume_breakpoint, - &through_sigtramp_breakpoint, - &step_range_start, &step_range_end, - &step_frame_address, &ecs->handling_longjmp, - &ecs->another_trap, - &ecs->stepping_through_solib_after_catch, - &ecs->stepping_through_solib_catchpoints, - &ecs->stepping_through_sigtramp); + /* Caution: it may happen that the new thread (or the old one!) + is not in the thread list. In this case we must not attempt + to "switch context", or we run the risk that our context may + be lost. This may happen as a result of the target module + mishandling thread creation. */ + + if (in_thread_list (inferior_ptid) && in_thread_list (ecs->ptid)) + { /* Perform infrun state context switch: */ + /* Save infrun state for the old thread. */ + save_infrun_state (inferior_ptid, prev_pc, + prev_func_start, prev_func_name, + trap_expected, step_resume_breakpoint, + through_sigtramp_breakpoint, + step_range_start, step_range_end, + step_frame_address, ecs->handling_longjmp, + ecs->another_trap, + ecs->stepping_through_solib_after_catch, + ecs->stepping_through_solib_catchpoints, + ecs->stepping_through_sigtramp); + + /* Load infrun state for the new thread. */ + load_infrun_state (ecs->ptid, &prev_pc, + &prev_func_start, &prev_func_name, + &trap_expected, &step_resume_breakpoint, + &through_sigtramp_breakpoint, + &step_range_start, &step_range_end, + &step_frame_address, &ecs->handling_longjmp, + &ecs->another_trap, + &ecs->stepping_through_solib_after_catch, + &ecs->stepping_through_solib_catchpoints, + &ecs->stepping_through_sigtramp); + } + + inferior_ptid = ecs->ptid; if (context_hook) - context_hook (pid_to_thread_id (ecs->pid)); + context_hook (pid_to_thread_id (ecs->ptid)); - printf_filtered ("[Switching to %s]\n", target_pid_to_str (ecs->pid)); flush_cached_frames (); } - if (SOFTWARE_SINGLE_STEP_P && singlestep_breakpoints_inserted_p) + if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p) { /* Pull the single step breakpoints out of the target. */ SOFTWARE_SINGLE_STEP (0, 0); @@ -1883,16 +2039,17 @@ handle_inferior_event (struct execution_control_state *ecs) if (INSTRUCTION_NULLIFIED) { registers_changed (); - target_resume (ecs->pid, 1, TARGET_SIGNAL_0); + target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* We may have received a signal that we want to pass to the inferior; therefore, we must not clobber the waitstatus in WS. */ ecs->infwait_state = infwait_nullified_state; - ecs->waiton_pid = ecs->pid; + ecs->waiton_ptid = ecs->ptid; ecs->wp = &(ecs->tmpstatus); - goto wfi_continue; + prepare_to_wait (ecs); + return; } /* It may not be necessary to disable the watchpoint to stop over @@ -1901,7 +2058,8 @@ handle_inferior_event (struct execution_control_state *ecs) if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws)) { resume (1, 0); - goto wfi_continue; + prepare_to_wait (ecs); + return; } /* It is far more common to need to disable a watchpoint to step @@ -1930,12 +2088,13 @@ handle_inferior_event (struct execution_control_state *ecs) remove_breakpoints (); registers_changed (); - target_resume (ecs->pid, 1, TARGET_SIGNAL_0); /* Single step */ + target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */ - ecs->waiton_pid = ecs->pid; + ecs->waiton_ptid = ecs->ptid; ecs->wp = &(ecs->ws); ecs->infwait_state = infwait_nonstep_watch_state; - goto wfi_continue; + prepare_to_wait (ecs); + return; } /* It may be possible to simply continue after a watchpoint. */ @@ -1984,10 +2143,14 @@ handle_inferior_event (struct execution_control_state *ecs) if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap) { stop_print_frame = 0; - goto wfi_break; + stop_stepping (ecs); + return; } if (stop_soon_quietly) - goto wfi_break; + { + stop_stepping (ecs); + return; + } /* Don't even think about breakpoints if just proceeded over a breakpoint. @@ -2004,22 +2167,15 @@ handle_inferior_event (struct execution_control_state *ecs) /* See if there is a breakpoint at the current PC. */ stop_bpstat = bpstat_stop_status (&stop_pc, - (DECR_PC_AFTER_BREAK ? - /* Notice the case of stepping through a jump - that lands just after a breakpoint. - Don't confuse that with hitting the breakpoint. - What we check for is that 1) stepping is going on - and 2) the pc before the last insn does not match - the address of the breakpoint before the current pc - and 3) we didn't hit a breakpoint in a signal handler - without an intervening stop in sigtramp, which is - detected by a new stack pointer value below - any usual function calling stack adjustments. */ + /* Pass TRUE if our reason for stopping is something other + than hitting a breakpoint. We do this by checking that + 1) stepping is going on and 2) we didn't hit a breakpoint + in a signal handler without an intervening stop in + sigtramp, which is detected by a new stack pointer value + below any usual function calling stack adjustments. */ (currently_stepping (ecs) - && prev_pc != stop_pc - DECR_PC_AFTER_BREAK && !(step_range_end - && INNER_THAN (read_sp (), (step_sp - 16)))) : - 0) + && INNER_THAN (read_sp (), (step_sp - 16)))) ); /* Following in case break condition called a function. */ @@ -2080,15 +2236,17 @@ handle_inferior_event (struct execution_control_state *ecs) { trap_expected = 1; stop_signal = TARGET_SIGNAL_0; - goto keep_going; + keep_going (ecs); + return; } } else if (ecs->ws.kind == TARGET_WAITKIND_VFORKED) { if (ecs->random_signal) /* I.e., no catchpoint triggered for this. */ { - stop_signal = TARGET_SIGNAL_0; - goto keep_going; + stop_signal = TARGET_SIGNAL_0; + keep_going (ecs); + return; } } else if (ecs->ws.kind == TARGET_WAITKIND_EXECD) @@ -2098,7 +2256,8 @@ handle_inferior_event (struct execution_control_state *ecs) { trap_expected = 1; stop_signal = TARGET_SIGNAL_0; - goto keep_going; + keep_going (ecs); + return; } } @@ -2116,20 +2275,13 @@ handle_inferior_event (struct execution_control_state *ecs) { printed = 1; target_terminal_ours_for_output (); - annotate_signal (); - printf_filtered ("\nProgram received signal "); - annotate_signal_name (); - printf_filtered ("%s", target_signal_to_name (stop_signal)); - annotate_signal_name_end (); - printf_filtered (", "); - annotate_signal_string (); - printf_filtered ("%s", target_signal_to_string (stop_signal)); - annotate_signal_string_end (); - printf_filtered (".\n"); - gdb_flush (gdb_stdout); + print_stop_reason (SIGNAL_RECEIVED, stop_signal); } if (signal_stop[stop_signal]) - goto wfi_break; + { + stop_stepping (ecs); + return; + } /* If not going to stop, give terminal back if we took it away. */ else if (printed) @@ -2151,7 +2303,7 @@ handle_inferior_event (struct execution_control_state *ecs) that case, when we reach this point, there is already a step-resume breakpoint established, right where it should be: immediately after the function call the user is "next"-ing - over. If we jump to step_over_function now, two bad things + over. If we call step_over_function now, two bad things happen: - we'll create a new breakpoint, at wherever the current @@ -2171,7 +2323,9 @@ handle_inferior_event (struct execution_control_state *ecs) this probably breaks that. As with anything else, it's up to the HP-UX maintainer to furnish a fix that doesn't break other platforms. --JimB, 20 May 1999 */ - goto check_sigtramp2; + check_sigtramp2 (ecs); + keep_going (ecs); + return; } /* Handle cases caused by hitting a breakpoint. */ @@ -2199,14 +2353,16 @@ handle_inferior_event (struct execution_control_state *ecs) remove_breakpoints (); breakpoints_inserted = 0; if (!GET_LONGJMP_TARGET (&jmp_buf_pc)) - goto keep_going; + { + keep_going (ecs); + return; + } /* Need to blow away step-resume breakpoint, as it interferes with us */ if (step_resume_breakpoint != NULL) { - delete_breakpoint (step_resume_breakpoint); - step_resume_breakpoint = NULL; + delete_step_resume_breakpoint (&step_resume_breakpoint); } /* Not sure whether we need to blow this away too, but probably it is like the step-resume breakpoint. */ @@ -2225,7 +2381,8 @@ handle_inferior_event (struct execution_control_state *ecs) #endif /* 0 */ set_longjmp_resume_breakpoint (jmp_buf_pc, NULL); ecs->handling_longjmp = 1; /* FIXME */ - goto keep_going; + keep_going (ecs); + return; case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME: case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE: @@ -2238,7 +2395,8 @@ handle_inferior_event (struct execution_control_state *ecs) step_frame_address))) { ecs->another_trap = 1; - goto keep_going; + keep_going (ecs); + return; } #endif /* 0 */ disable_longjmp_breakpoint (); @@ -2266,7 +2424,8 @@ handle_inferior_event (struct execution_control_state *ecs) through_sigtramp_breakpoint via the cleanup chain, so no need to worry about it here. */ - goto stop_stepping; + stop_stepping (ecs); + return; case BPSTAT_WHAT_STOP_SILENT: stop_print_frame = 0; @@ -2275,7 +2434,8 @@ handle_inferior_event (struct execution_control_state *ecs) through_sigtramp_breakpoint via the cleanup chain, so no need to worry about it here. */ - goto stop_stepping; + stop_stepping (ecs); + return; case BPSTAT_WHAT_STEP_RESUME: /* This proably demands a more elegant solution, but, yeah @@ -2289,14 +2449,18 @@ handle_inferior_event (struct execution_control_state *ecs) If we reach here and step_resume_breakpoint is already NULL, then apparently we have multiple active step-resume bp's. We'll just delete the breakpoint we - stopped at, and carry on. */ + stopped at, and carry on. + + Correction: what the code currently does is delete a + step-resume bp, but it makes no effort to ensure that + the one deleted is the one currently stopped at. MVS */ + if (step_resume_breakpoint == NULL) { step_resume_breakpoint = bpstat_find_step_resume_breakpoint (stop_bpstat); } - delete_breakpoint (step_resume_breakpoint); - step_resume_breakpoint = NULL; + delete_step_resume_breakpoint (&step_resume_breakpoint); break; case BPSTAT_WHAT_THROUGH_SIGTRAMP: @@ -2342,8 +2506,8 @@ handle_inferior_event (struct execution_control_state *ecs) dynamically loaded objects (among other things). */ if (stop_on_solib_events) { - stop_print_frame = 0; - goto stop_stepping; + stop_stepping (ecs); + return; } /* If we stopped due to an explicit catchpoint, then the @@ -2410,10 +2574,11 @@ handle_inferior_event (struct execution_control_state *ecs) { #if defined(SOLIB_ADD) /* Have we reached our destination? If not, keep going. */ - if (SOLIB_IN_DYNAMIC_LINKER (ecs->pid, stop_pc)) + if (SOLIB_IN_DYNAMIC_LINKER (PIDGET (ecs->ptid), stop_pc)) { ecs->another_trap = 1; - goto keep_going; + keep_going (ecs); + return; } #endif /* Else, stop and report the catchpoint(s) whose triggering @@ -2423,7 +2588,8 @@ handle_inferior_event (struct execution_control_state *ecs) stop_bpstat = bpstat_copy (ecs->stepping_through_solib_catchpoints); bpstat_clear (&ecs->stepping_through_solib_catchpoints); stop_print_frame = 1; - goto stop_stepping; + stop_stepping (ecs); + return; } if (!CALL_DUMMY_BREAKPOINT_OFFSET_P) @@ -2446,23 +2612,32 @@ handle_inferior_event (struct execution_control_state *ecs) #ifdef HP_OS_BUG trap_expected_after_continue = 1; #endif - goto wfi_break; + stop_stepping (ecs); + return; } } if (step_resume_breakpoint) - /* Having a step-resume breakpoint overrides anything - else having to do with stepping commands until - that breakpoint is reached. */ - /* I'm not sure whether this needs to be check_sigtramp2 or - whether it could/should be keep_going. */ - goto check_sigtramp2; - + { + /* Having a step-resume breakpoint overrides anything + else having to do with stepping commands until + that breakpoint is reached. */ + /* I'm not sure whether this needs to be check_sigtramp2 or + whether it could/should be keep_going. */ + check_sigtramp2 (ecs); + keep_going (ecs); + return; + } + if (step_range_end == 0) - /* Likewise if we aren't even stepping. */ - /* I'm not sure whether this needs to be check_sigtramp2 or - whether it could/should be keep_going. */ - goto check_sigtramp2; + { + /* Likewise if we aren't even stepping. */ + /* I'm not sure whether this needs to be check_sigtramp2 or + whether it could/should be keep_going. */ + check_sigtramp2 (ecs); + keep_going (ecs); + return; + } /* If stepping through a line, keep going if still within it. @@ -2474,7 +2649,9 @@ handle_inferior_event (struct execution_control_state *ecs) { /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal. So definately need to check for sigtramp here. */ - goto check_sigtramp2; + check_sigtramp2 (ecs); + keep_going (ecs); + return; } /* We stepped out of the stepping range. */ @@ -2483,8 +2660,28 @@ handle_inferior_event (struct execution_control_state *ecs) loader dynamic symbol resolution code, we keep on single stepping until we exit the run time loader code and reach the callee's address. */ - if (step_over_calls < 0 && IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc)) - goto keep_going; + if (step_over_calls == STEP_OVER_UNDEBUGGABLE && IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc)) + { + CORE_ADDR pc_after_resolver = SKIP_SOLIB_RESOLVER (stop_pc); + + if (pc_after_resolver) + { + /* Set up a step-resume breakpoint at the address + indicated by SKIP_SOLIB_RESOLVER. */ + struct symtab_and_line sr_sal; + INIT_SAL (&sr_sal); + sr_sal.pc = pc_after_resolver; + + check_for_old_step_resume_breakpoint (); + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); + } + + keep_going (ecs); + return; + } /* We can't update step_sp every time through the loop, because reading the stack pointer would slow down stepping too much. @@ -2543,7 +2740,7 @@ handle_inferior_event (struct execution_control_state *ecs) /* We just stepped out of a signal handler and into its calling trampoline. - Normally, we'd jump to step_over_function from + Normally, we'd call step_over_function from here, but for some reason GDB can't unwind the stack correctly to find the real PC for the point user code where the signal trampoline will return @@ -2572,7 +2769,8 @@ handle_inferior_event (struct execution_control_state *ecs) step_range_end = (step_range_start = prev_pc) + 1; ecs->remove_breakpoints_on_following_step = 1; - goto keep_going; + keep_going (ecs); + return; } if (stop_pc == ecs->stop_func_start /* Quick test */ @@ -2583,18 +2781,38 @@ handle_inferior_event (struct execution_control_state *ecs) { /* It's a subroutine call. */ - if (step_over_calls == 0) + if (step_over_calls == STEP_OVER_NONE) { /* I presume that step_over_calls is only 0 when we're supposed to be stepping at the assembly language level ("stepi"). Just stop. */ stop_step = 1; - goto wfi_break; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; } - if (step_over_calls > 0 || IGNORE_HELPER_CALL (stop_pc)) - /* We're doing a "next". */ - goto step_over_function; + if (step_over_calls == STEP_OVER_ALL || IGNORE_HELPER_CALL (stop_pc)) + { + /* We're doing a "next". */ + + if (IN_SIGTRAMP (stop_pc, ecs->stop_func_name) + && INNER_THAN (step_frame_address, read_sp())) + /* We stepped out of a signal handler, and into its + calling trampoline. This is misdetected as a + subroutine call, but stepping over the signal + trampoline isn't such a bad idea. In order to do + that, we have to ignore the value in + step_frame_address, since that doesn't represent the + frame that'll reach when we return from the signal + trampoline. Otherwise we'll probably continue to the + end of the program. */ + step_frame_address = 0; + + step_over_function (ecs); + keep_going (ecs); + return; + } /* If we are in a function call trampoline (a stub between the calling routine and the real function), locate the real @@ -2619,7 +2837,8 @@ handle_inferior_event (struct execution_control_state *ecs) step_resume_breakpoint = set_momentary_breakpoint (xxx, NULL, bp_step_resume); insert_breakpoints (); - goto keep_going; + keep_going (ecs); + return; } } @@ -2634,95 +2853,27 @@ handle_inferior_event (struct execution_control_state *ecs) tmp_sal = find_pc_line (ecs->stop_func_start, 0); if (tmp_sal.line != 0) - goto step_into_function; - } - - step_over_function: - /* A subroutine call has happened. */ - { - /* We've just entered a callee, and we wish to resume until it - returns to the caller. Setting a step_resume breakpoint on - the return address will catch a return from the callee. - - However, if the callee is recursing, we want to be careful - not to catch returns of those recursive calls, but only of - THIS instance of the call. - - To do this, we set the step_resume bp's frame to our current - caller's frame (step_frame_address, which is set by the "next" - or "until" command, before execution begins). */ - struct symtab_and_line sr_sal; - - INIT_SAL (&sr_sal); /* initialize to zeros */ - sr_sal.pc = - ADDR_BITS_REMOVE (SAVED_PC_AFTER_CALL (get_current_frame ())); - sr_sal.section = find_pc_overlay (sr_sal.pc); - - check_for_old_step_resume_breakpoint (); - step_resume_breakpoint = - set_momentary_breakpoint (sr_sal, get_current_frame (), - bp_step_resume); - - if (!IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc)) - step_resume_breakpoint->frame = step_frame_address; - - if (breakpoints_inserted) - insert_breakpoints (); - } - goto keep_going; - - step_into_function: - /* Subroutine call with source code we should not step over. - Do step to the first line of code in it. */ - { - struct symtab *s; - - s = find_pc_symtab (stop_pc); - if (s && s->language != language_asm) - ecs->stop_func_start = SKIP_PROLOGUE (ecs->stop_func_start); + { + step_into_function (ecs); + return; + } } - ecs->sal = find_pc_line (ecs->stop_func_start, 0); - /* Use the step_resume_break to step until - the end of the prologue, even if that involves jumps - (as it seems to on the vax under 4.2). */ - /* If the prologue ends in the middle of a source line, - continue to the end of that source line (if it is still - within the function). Otherwise, just go to end of prologue. */ -#ifdef PROLOGUE_FIRSTLINE_OVERLAP - /* no, don't either. It skips any code that's - legitimately on the first line. */ -#else - if (ecs->sal.end && ecs->sal.pc != ecs->stop_func_start && ecs->sal.end < ecs->stop_func_end) - ecs->stop_func_start = ecs->sal.end; -#endif - if (ecs->stop_func_start == stop_pc) + /* 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 + switch in assembly mode. */ + if (step_over_calls == STEP_OVER_UNDEBUGGABLE && step_stop_if_no_debug) { - /* We are already there: stop now. */ stop_step = 1; - goto wfi_break; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; } - else - /* Put the step-breakpoint there and go until there. */ - { - struct symtab_and_line sr_sal; - INIT_SAL (&sr_sal); /* initialize to zeroes */ - sr_sal.pc = ecs->stop_func_start; - sr_sal.section = find_pc_overlay (ecs->stop_func_start); - /* Do not specify what the fp should be when we stop - since on some machines the prologue - is where the new fp value is established. */ - check_for_old_step_resume_breakpoint (); - step_resume_breakpoint = - set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); - if (breakpoints_inserted) - insert_breakpoints (); + step_over_function (ecs); + keep_going (ecs); + return; - /* And make sure stepping stops right away then. */ - step_range_end = step_range_start; - } - goto keep_going; } /* We've wandered out of the step range. */ @@ -2734,7 +2885,9 @@ handle_inferior_event (struct execution_control_state *ecs) /* It is stepi or nexti. We always want to stop stepping after one instruction. */ stop_step = 1; - goto wfi_break; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; } /* If we're in the return path from a shared library trampoline, @@ -2766,7 +2919,8 @@ handle_inferior_event (struct execution_control_state *ecs) /* Restart without fiddling with the step ranges or other state. */ - goto keep_going; + keep_going (ecs); + return; } } @@ -2777,7 +2931,9 @@ handle_inferior_event (struct execution_control_state *ecs) when we do "s" in a function with no line numbers, or can this happen as a result of a return or longjmp?). */ stop_step = 1; - goto wfi_break; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; } if ((stop_pc == ecs->sal.pc) @@ -2788,7 +2944,9 @@ handle_inferior_event (struct execution_control_state *ecs) That is said to make things like for (;;) statements work better. */ stop_step = 1; - goto wfi_break; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; } /* We aren't done stepping. @@ -2806,7 +2964,9 @@ handle_inferior_event (struct execution_control_state *ecs) in which after skipping the prologue we better stop even though we will be in mid-line. */ stop_step = 1; - goto wfi_break; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; } step_range_start = ecs->sal.pc; step_range_end = ecs->sal.end; @@ -2823,199 +2983,178 @@ handle_inferior_event (struct execution_control_state *ecs) step_frame_address = current_frame; } + keep_going (ecs); - goto keep_going; - - check_sigtramp2: - if (trap_expected - && IN_SIGTRAMP (stop_pc, ecs->stop_func_name) - && !IN_SIGTRAMP (prev_pc, prev_func_name) - && INNER_THAN (read_sp (), step_sp)) - { - /* What has happened here is that we have just stepped the inferior - with a signal (because it is a signal which shouldn't make - us stop), thus stepping into sigtramp. - - So we need to set a step_resume_break_address breakpoint - and continue until we hit it, and then step. FIXME: This should - be more enduring than a step_resume breakpoint; we should know - that we will later need to keep going rather than re-hitting - the breakpoint here (see testsuite/gdb.t06/signals.exp where - it says "exceedingly difficult"). */ - struct symtab_and_line sr_sal; - - INIT_SAL (&sr_sal); /* initialize to zeroes */ - sr_sal.pc = prev_pc; - sr_sal.section = find_pc_overlay (sr_sal.pc); - /* We perhaps could set the frame if we kept track of what - the frame corresponding to prev_pc was. But we don't, - so don't. */ - through_sigtramp_breakpoint = - set_momentary_breakpoint (sr_sal, NULL, bp_through_sigtramp); - if (breakpoints_inserted) - insert_breakpoints (); + } /* extra brace, to preserve old indentation */ +} - ecs->remove_breakpoints_on_following_step = 1; - ecs->another_trap = 1; - } +/* Are we in the middle of stepping? */ - keep_going: - /* Come to this label when you need to resume the inferior. - It's really much cleaner to do a goto than a maze of if-else - conditions. */ - - /* ??rehrauer: ttrace on HP-UX theoretically allows one to debug - a vforked child beetween its creation and subsequent exit or - call to exec(). However, I had big problems in this rather - creaky exec engine, getting that to work. The fundamental - problem is that I'm trying to debug two processes via an - engine that only understands a single process with possibly - multiple threads. - - Hence, this spot is known to have problems when - target_can_follow_vfork_prior_to_exec returns 1. */ - - /* Save the pc before execution, to compare with pc after stop. */ - prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */ - prev_func_start = ecs->stop_func_start; /* Ok, since if DECR_PC_AFTER - BREAK is defined, the - original pc would not have - been at the start of a - function. */ - prev_func_name = ecs->stop_func_name; +static int +currently_stepping (struct execution_control_state *ecs) +{ + return ((through_sigtramp_breakpoint == NULL + && !ecs->handling_longjmp + && ((step_range_end && step_resume_breakpoint == NULL) + || trap_expected)) + || ecs->stepping_through_solib_after_catch + || bpstat_should_step ()); +} - if (ecs->update_step_sp) - step_sp = read_sp (); - ecs->update_step_sp = 0; +static void +check_sigtramp2 (struct execution_control_state *ecs) +{ + if (trap_expected + && IN_SIGTRAMP (stop_pc, ecs->stop_func_name) + && !IN_SIGTRAMP (prev_pc, prev_func_name) + && INNER_THAN (read_sp (), step_sp)) + { + /* What has happened here is that we have just stepped the + inferior with a signal (because it is a signal which + shouldn't make us stop), thus stepping into sigtramp. + + So we need to set a step_resume_break_address breakpoint and + continue until we hit it, and then step. FIXME: This should + be more enduring than a step_resume breakpoint; we should + know that we will later need to keep going rather than + re-hitting the breakpoint here (see the testsuite, + gdb.base/signals.exp where it says "exceedingly difficult"). */ + + struct symtab_and_line sr_sal; + + INIT_SAL (&sr_sal); /* initialize to zeroes */ + sr_sal.pc = prev_pc; + sr_sal.section = find_pc_overlay (sr_sal.pc); + /* We perhaps could set the frame if we kept track of what the + frame corresponding to prev_pc was. But we don't, so don't. */ + through_sigtramp_breakpoint = + set_momentary_breakpoint (sr_sal, NULL, bp_through_sigtramp); + if (breakpoints_inserted) + insert_breakpoints (); - /* If we did not do break;, it means we should keep - running the inferior and not return to debugger. */ + ecs->remove_breakpoints_on_following_step = 1; + ecs->another_trap = 1; + } +} - if (trap_expected && stop_signal != TARGET_SIGNAL_TRAP) - { - /* We took a signal (which we are supposed to pass through to - the inferior, else we'd have done a break above) and we - haven't yet gotten our trap. Simply continue. */ - resume (currently_stepping (ecs), stop_signal); - } - else - { - /* Either the trap was not expected, but we are continuing - anyway (the user asked that this signal be passed to the - child) - -- or -- - The signal was SIGTRAP, e.g. it was our signal, but we - decided we should resume from it. - - We're going to run this baby now! - - Insert breakpoints now, unless we are trying - to one-proceed past a breakpoint. */ - /* If we've just finished a special step resume and we don't - want to hit a breakpoint, pull em out. */ - if (step_resume_breakpoint == NULL - && through_sigtramp_breakpoint == NULL - && ecs->remove_breakpoints_on_following_step) - { - ecs->remove_breakpoints_on_following_step = 0; - remove_breakpoints (); - breakpoints_inserted = 0; - } - else if (!breakpoints_inserted && - (through_sigtramp_breakpoint != NULL || !ecs->another_trap)) - { - breakpoints_failed = insert_breakpoints (); - if (breakpoints_failed) - goto wfi_break; - breakpoints_inserted = 1; - } +/* Subroutine call with source code we should not step over. Do step + to the first line of code in it. */ - trap_expected = ecs->another_trap; +static void +step_into_function (struct execution_control_state *ecs) +{ + struct symtab *s; + struct symtab_and_line sr_sal; + + s = find_pc_symtab (stop_pc); + if (s && s->language != language_asm) + ecs->stop_func_start = SKIP_PROLOGUE (ecs->stop_func_start); + + ecs->sal = find_pc_line (ecs->stop_func_start, 0); + /* Use the step_resume_break to step until the end of the prologue, + even if that involves jumps (as it seems to on the vax under + 4.2). */ + /* If the prologue ends in the middle of a source line, continue to + the end of that source line (if it is still within the function). + Otherwise, just go to end of prologue. */ +#ifdef PROLOGUE_FIRSTLINE_OVERLAP + /* no, don't either. It skips any code that's legitimately on the + first line. */ +#else + if (ecs->sal.end + && ecs->sal.pc != ecs->stop_func_start + && ecs->sal.end < ecs->stop_func_end) + ecs->stop_func_start = ecs->sal.end; +#endif - /* Do not deliver SIGNAL_TRAP (except when the user - explicitly specifies that such a signal should be - delivered to the target program). + if (ecs->stop_func_start == stop_pc) + { + /* We are already there: stop now. */ + stop_step = 1; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; + } + else + { + /* Put the step-breakpoint there and go until there. */ + INIT_SAL (&sr_sal); /* initialize to zeroes */ + sr_sal.pc = ecs->stop_func_start; + sr_sal.section = find_pc_overlay (ecs->stop_func_start); + /* Do not specify what the fp should be when we stop since on + some machines the prologue is where the new fp value is + established. */ + check_for_old_step_resume_breakpoint (); + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); - Typically, this would occure when a user is debugging a - target monitor on a simulator: the target monitor sets a - breakpoint; the simulator encounters this break-point and - halts the simulation handing control to GDB; GDB, noteing - that the break-point isn't valid, returns control back to - the simulator; the simulator then delivers the hardware - equivalent of a SIGNAL_TRAP to the program being - debugged. */ + /* And make sure stepping stops right away then. */ + step_range_end = step_range_start; + } + keep_going (ecs); +} - if (stop_signal == TARGET_SIGNAL_TRAP - && !signal_program[stop_signal]) - stop_signal = TARGET_SIGNAL_0; +/* We've just entered a callee, and we wish to resume until it returns + to the caller. Setting a step_resume breakpoint on the return + address will catch a return from the callee. + + However, if the callee is recursing, we want to be careful not to + catch returns of those recursive calls, but only of THIS instance + of the call. -#ifdef SHIFT_INST_REGS - /* I'm not sure when this following segment applies. I do know, - now, that we shouldn't rewrite the regs when we were stopped - by a random signal from the inferior process. */ - /* FIXME: Shouldn't this be based on the valid bit of the SXIP? - (this is only used on the 88k). */ - - if (!bpstat_explains_signal (stop_bpstat) - && (stop_signal != TARGET_SIGNAL_CHLD) - && !stopped_by_random_signal) - SHIFT_INST_REGS (); -#endif /* SHIFT_INST_REGS */ + To do this, we set the step_resume bp's frame to our current + caller's frame (step_frame_address, which is set by the "next" or + "until" command, before execution begins). */ - resume (currently_stepping (ecs), stop_signal); - } +static void +step_over_function (struct execution_control_state *ecs) +{ + struct symtab_and_line sr_sal; - /* Former continues in the main loop goto here. */ - wfi_continue: - /* This used to be at the top of the loop. */ - if (ecs->infwait_state == infwait_normal_state) - { - overlay_cache_invalid = 1; + INIT_SAL (&sr_sal); /* initialize to zeros */ + sr_sal.pc = ADDR_BITS_REMOVE (SAVED_PC_AFTER_CALL (get_current_frame ())); + sr_sal.section = find_pc_overlay (sr_sal.pc); - /* We have to invalidate the registers BEFORE calling - target_wait because they can be loaded from the target - while in target_wait. This makes remote debugging a bit - more efficient for those targets that provide critical - registers as part of their normal status mechanism. */ + check_for_old_step_resume_breakpoint (); + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, get_current_frame (), bp_step_resume); - registers_changed (); - ecs->waiton_pid = -1; - ecs->wp = &(ecs->ws); - } - /* This is the old end of the while loop. Let everybody know - we want to wait for the inferior some more and get called - again soon. */ - ecs->wait_some_more = 1; - return; - } + if (step_frame_address && !IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc)) + step_resume_breakpoint->frame = step_frame_address; - /* Former breaks in the main loop goto here. */ -wfi_break: + if (breakpoints_inserted) + insert_breakpoints (); +} -stop_stepping: +static void +stop_stepping (struct execution_control_state *ecs) +{ if (target_has_execution) { /* Are we stopping for a vfork event? We only stop when we see the child's event. However, we may not yet have seen the - parent's event. And, inferior_pid is still set to the parent's - pid, until we resume again and follow either the parent or child. + parent's event. And, inferior_ptid is still set to the + parent's pid, until we resume again and follow either the + parent or child. - To ensure that we can really touch inferior_pid (aka, the + To ensure that we can really touch inferior_ptid (aka, the parent process) -- which calls to functions like read_pc implicitly do -- wait on the parent if necessary. */ if ((pending_follow.kind == TARGET_WAITKIND_VFORKED) && !pending_follow.fork_event.saw_parent_fork) { - int parent_pid; + ptid_t parent_ptid; do { if (target_wait_hook) - parent_pid = target_wait_hook (-1, &(ecs->ws)); + parent_ptid = target_wait_hook (pid_to_ptid (-1), &(ecs->ws)); else - parent_pid = target_wait (-1, &(ecs->ws)); + parent_ptid = target_wait (pid_to_ptid (-1), &(ecs->ws)); } - while (parent_pid != inferior_pid); + while (! ptid_equal (parent_ptid, inferior_ptid)); } /* Assuming the inferior still exists, set these up for next @@ -3025,76 +3164,273 @@ stop_stepping: prev_func_start = ecs->stop_func_start; prev_func_name = ecs->stop_func_name; } + /* Let callers know we don't want to wait for the inferior anymore. */ ecs->wait_some_more = 0; } -/* Are we in the middle of stepping? */ +/* This function handles various cases where we need to continue + waiting for the inferior. */ +/* (Used to be the keep_going: label in the old wait_for_inferior) */ -static int -currently_stepping (struct execution_control_state *ecs) +static void +keep_going (struct execution_control_state *ecs) { - return ((through_sigtramp_breakpoint == NULL - && !ecs->handling_longjmp - && ((step_range_end && step_resume_breakpoint == NULL) - || trap_expected)) - || ecs->stepping_through_solib_after_catch - || bpstat_should_step ()); -} + /* ??rehrauer: ttrace on HP-UX theoretically allows one to debug a + vforked child between its creation and subsequent exit or call to + exec(). However, I had big problems in this rather creaky exec + engine, getting that to work. The fundamental problem is that + I'm trying to debug two processes via an engine that only + understands a single process with possibly multiple threads. + + Hence, this spot is known to have problems when + target_can_follow_vfork_prior_to_exec returns 1. */ + + /* Save the pc before execution, to compare with pc after stop. */ + prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */ + prev_func_start = ecs->stop_func_start; /* Ok, since if DECR_PC_AFTER + BREAK is defined, the + original pc would not have + been at the start of a + function. */ + prev_func_name = ecs->stop_func_name; -/* This function returns TRUE if ep is an internal breakpoint - set to catch generic shared library (aka dynamically-linked - library) events. (This is *NOT* the same as a catchpoint for a - shlib event. The latter is something a user can set; this is - something gdb sets for its own use, and isn't ever shown to a - user.) */ -static int -is_internal_shlib_eventpoint (struct breakpoint *ep) -{ - return - (ep->type == bp_shlib_event) - ; -} + if (ecs->update_step_sp) + step_sp = read_sp (); + ecs->update_step_sp = 0; -/* This function returns TRUE if bs indicates that the inferior - stopped due to a shared library (aka dynamically-linked library) - event. */ + /* If we did not do break;, it means we should keep running the + inferior and not return to debugger. */ -static int -stopped_for_internal_shlib_event (bpstat bs) -{ - /* Note that multiple eventpoints may've caused the stop. Any - that are associated with shlib events will be accepted. */ - for (; bs != NULL; bs = bs->next) + if (trap_expected && stop_signal != TARGET_SIGNAL_TRAP) { - if ((bs->breakpoint_at != NULL) - && is_internal_shlib_eventpoint (bs->breakpoint_at)) - return 1; + /* We took a signal (which we are supposed to pass through to + the inferior, else we'd have done a break above) and we + haven't yet gotten our trap. Simply continue. */ + resume (currently_stepping (ecs), stop_signal); + } + else + { + /* Either the trap was not expected, but we are continuing + anyway (the user asked that this signal be passed to the + child) + -- or -- + The signal was SIGTRAP, e.g. it was our signal, but we + decided we should resume from it. + + We're going to run this baby now! + + Insert breakpoints now, unless we are trying to one-proceed + past a breakpoint. */ + /* If we've just finished a special step resume and we don't + want to hit a breakpoint, pull em out. */ + if (step_resume_breakpoint == NULL + && through_sigtramp_breakpoint == NULL + && ecs->remove_breakpoints_on_following_step) + { + ecs->remove_breakpoints_on_following_step = 0; + remove_breakpoints (); + breakpoints_inserted = 0; + } + else if (!breakpoints_inserted && + (through_sigtramp_breakpoint != NULL || !ecs->another_trap)) + { + breakpoints_failed = insert_breakpoints (); + if (breakpoints_failed) + { + stop_stepping (ecs); + return; + } + breakpoints_inserted = 1; + } + + trap_expected = ecs->another_trap; + + /* Do not deliver SIGNAL_TRAP (except when the user explicitly + specifies that such a signal should be delivered to the + target program). + + Typically, this would occure when a user is debugging a + target monitor on a simulator: the target monitor sets a + breakpoint; the simulator encounters this break-point and + halts the simulation handing control to GDB; GDB, noteing + that the break-point isn't valid, returns control back to the + simulator; the simulator then delivers the hardware + equivalent of a SIGNAL_TRAP to the program being debugged. */ + + if (stop_signal == TARGET_SIGNAL_TRAP + && !signal_program[stop_signal]) + stop_signal = TARGET_SIGNAL_0; + +#ifdef SHIFT_INST_REGS + /* I'm not sure when this following segment applies. I do know, + now, that we shouldn't rewrite the regs when we were stopped + by a random signal from the inferior process. */ + /* FIXME: Shouldn't this be based on the valid bit of the SXIP? + (this is only used on the 88k). */ + + if (!bpstat_explains_signal (stop_bpstat) + && (stop_signal != TARGET_SIGNAL_CHLD) + && !stopped_by_random_signal) + SHIFT_INST_REGS (); +#endif /* SHIFT_INST_REGS */ + + resume (currently_stepping (ecs), stop_signal); } - /* If we get here, then no candidate was found. */ - return 0; + prepare_to_wait (ecs); } - -/* Reset proper settings after an asynchronous command has finished. - If the execution command was in synchronous mode, register stdin - with the event loop, and reset the prompt. */ + +/* This function normally comes after a resume, before + handle_inferior_event exits. It takes care of any last bits of + housekeeping, and sets the all-important wait_some_more flag. */ static void -complete_execution (void) +prepare_to_wait (struct execution_control_state *ecs) { - extern int cleanup_sigint_signal_handler (void); + if (ecs->infwait_state == infwait_normal_state) + { + overlay_cache_invalid = 1; + + /* We have to invalidate the registers BEFORE calling + target_wait because they can be loaded from the target while + in target_wait. This makes remote debugging a bit more + efficient for those targets that provide critical registers + as part of their normal status mechanism. */ - target_executing = 0; - if (sync_execution) + registers_changed (); + ecs->waiton_ptid = pid_to_ptid (-1); + ecs->wp = &(ecs->ws); + } + /* This is the old end of the while loop. Let everybody know we + want to wait for the inferior some more and get called again + soon. */ + ecs->wait_some_more = 1; +} + +/* Print why the inferior has stopped. We always print something when + the inferior exits, or receives a signal. The rest of the cases are + dealt with later on in normal_stop() and print_it_typical(). Ideally + there should be a call to this function from handle_inferior_event() + each time stop_stepping() is called.*/ +static void +print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info) +{ + switch (stop_reason) { - add_file_handler (input_fd, call_readline, 0); - pop_prompt (); - sync_execution = 0; - cleanup_sigint_signal_handler (); - display_gdb_prompt (0); + case STOP_UNKNOWN: + /* We don't deal with these cases from handle_inferior_event() + yet. */ + break; + case END_STEPPING_RANGE: + /* We are done with a step/next/si/ni command. */ + /* For now print nothing. */ +#ifdef UI_OUT + /* Print a message only if not in the middle of doing a "step n" + operation for n > 1 */ + if (!step_multi || !stop_step) + if (interpreter_p && strcmp (interpreter_p, "mi") == 0) + ui_out_field_string (uiout, "reason", "end-stepping-range"); +#endif + break; + case BREAKPOINT_HIT: + /* We found a breakpoint. */ + /* For now print nothing. */ + break; + case SIGNAL_EXITED: + /* The inferior was terminated by a signal. */ +#ifdef UI_OUT + annotate_signalled (); + if (interpreter_p && strcmp (interpreter_p, "mi") == 0) + ui_out_field_string (uiout, "reason", "exited-signalled"); + ui_out_text (uiout, "\nProgram terminated with signal "); + annotate_signal_name (); + ui_out_field_string (uiout, "signal-name", target_signal_to_name (stop_info)); + annotate_signal_name_end (); + ui_out_text (uiout, ", "); + annotate_signal_string (); + ui_out_field_string (uiout, "signal-meaning", target_signal_to_string (stop_info)); + annotate_signal_string_end (); + ui_out_text (uiout, ".\n"); + ui_out_text (uiout, "The program no longer exists.\n"); +#else + annotate_signalled (); + printf_filtered ("\nProgram terminated with signal "); + annotate_signal_name (); + printf_filtered ("%s", target_signal_to_name (stop_info)); + annotate_signal_name_end (); + printf_filtered (", "); + annotate_signal_string (); + printf_filtered ("%s", target_signal_to_string (stop_info)); + annotate_signal_string_end (); + printf_filtered (".\n"); + + printf_filtered ("The program no longer exists.\n"); + gdb_flush (gdb_stdout); +#endif + break; + case EXITED: + /* The inferior program is finished. */ +#ifdef UI_OUT + annotate_exited (stop_info); + if (stop_info) + { + if (interpreter_p && strcmp (interpreter_p, "mi") == 0) + ui_out_field_string (uiout, "reason", "exited"); + ui_out_text (uiout, "\nProgram exited with code "); + ui_out_field_fmt (uiout, "exit-code", "0%o", (unsigned int) stop_info); + ui_out_text (uiout, ".\n"); + } + else + { + if (interpreter_p && strcmp (interpreter_p, "mi") == 0) + ui_out_field_string (uiout, "reason", "exited-normally"); + ui_out_text (uiout, "\nProgram exited normally.\n"); + } +#else + annotate_exited (stop_info); + if (stop_info) + printf_filtered ("\nProgram exited with code 0%o.\n", + (unsigned int) stop_info); + else + printf_filtered ("\nProgram exited normally.\n"); +#endif + break; + case SIGNAL_RECEIVED: + /* Signal received. The signal table tells us to print about + it. */ +#ifdef UI_OUT + annotate_signal (); + ui_out_text (uiout, "\nProgram received signal "); + annotate_signal_name (); + ui_out_field_string (uiout, "signal-name", target_signal_to_name (stop_info)); + annotate_signal_name_end (); + ui_out_text (uiout, ", "); + annotate_signal_string (); + ui_out_field_string (uiout, "signal-meaning", target_signal_to_string (stop_info)); + annotate_signal_string_end (); + ui_out_text (uiout, ".\n"); +#else + annotate_signal (); + printf_filtered ("\nProgram received signal "); + annotate_signal_name (); + printf_filtered ("%s", target_signal_to_name (stop_info)); + annotate_signal_name_end (); + printf_filtered (", "); + annotate_signal_string (); + printf_filtered ("%s", target_signal_to_string (stop_info)); + annotate_signal_string_end (); + printf_filtered (".\n"); + gdb_flush (gdb_stdout); +#endif + break; + default: + internal_error (__FILE__, __LINE__, + "print_stop_reason: unrecognized enum value"); + break; } } + /* Here to return control to GDB when the inferior stops for real. Print appropriate messages, remove breakpoints, give terminal our modes. @@ -3113,14 +3449,13 @@ normal_stop (void) (Note that there's no point in saying anything if the inferior has exited!) */ - if (may_switch_from_inferior_pid - && (switched_from_inferior_pid != inferior_pid) + if (! ptid_equal (previous_inferior_ptid, inferior_ptid) && target_has_execution) { target_terminal_ours_for_output (); - printf_filtered ("[Switched to %s]\n", - target_pid_or_tid_to_str (inferior_pid)); - switched_from_inferior_pid = inferior_pid; + printf_filtered ("[Switching to %s]\n", + target_pid_or_tid_to_str (inferior_ptid)); + previous_inferior_ptid = inferior_ptid; } /* Make sure that the current_frame's pc is correct. This @@ -3132,9 +3467,11 @@ normal_stop (void) if (breakpoints_failed) { target_terminal_ours_for_output (); - print_sys_errmsg ("ptrace", breakpoints_failed); + print_sys_errmsg ("While inserting breakpoints", breakpoints_failed); printf_filtered ("Stopped; cannot insert breakpoints.\n\ -The same program may be running in another process.\n"); +The same program may be running in another process,\n\ +or you may have requested too many hardware breakpoints\n\ +and/or watchpoints.\n"); } if (target_has_execution && breakpoints_inserted) @@ -3168,19 +3505,11 @@ The same program may be running in another process.\n"); target_terminal_ours (); - /* Did we stop because the user set the stop_on_solib_events - variable? (If so, we report this as a generic, "Stopped due - to shlib event" message.) */ - if (stopped_for_internal_shlib_event (stop_bpstat)) - { - printf_filtered ("Stopped due to shared library event\n"); - } - /* Look up the hook_stop and run it if it exists. */ - if (stop_command && stop_command->hook) + if (stop_command && stop_command->hook_pre) { - catch_errors (hook_stop_stub, stop_command->hook, + catch_errors (hook_stop_stub, stop_command->hook_pre, "Error while running hook_stop:\n", RETURN_MASK_ALL); } @@ -3205,36 +3534,57 @@ The same program may be running in another process.\n"); bpstat_print() contains the logic deciding in detail what to print, based on the event(s) that just occurred. */ - if (stop_print_frame) + if (stop_print_frame + && selected_frame) { int bpstat_ret; int source_flag; + int do_frame_printing = 1; bpstat_ret = bpstat_print (stop_bpstat); - /* bpstat_print() returned one of: - -1: Didn't print anything - 0: Printed preliminary "Breakpoint n, " message, desires - location tacked on - 1: Printed something, don't tack on location */ - - if (bpstat_ret == -1) - if (stop_step - && step_frame_address == FRAME_FP (get_current_frame ()) - && step_start_function == find_pc_function (stop_pc)) - source_flag = -1; /* finished step, just print source line */ - else - source_flag = 1; /* print location and source line */ - else if (bpstat_ret == 0) /* hit bpt, desire location */ - source_flag = 1; /* print location and source line */ - else /* bpstat_ret == 1, hit bpt, do not desire location */ - source_flag = -1; /* just print source line */ + switch (bpstat_ret) + { + case PRINT_UNKNOWN: + if (stop_step + && step_frame_address == FRAME_FP (get_current_frame ()) + && step_start_function == find_pc_function (stop_pc)) + source_flag = SRC_LINE; /* finished step, just print source line */ + else + source_flag = SRC_AND_LOC; /* print location and source line */ + break; + case PRINT_SRC_AND_LOC: + source_flag = SRC_AND_LOC; /* print location and source line */ + break; + case PRINT_SRC_ONLY: + source_flag = SRC_LINE; + break; + case PRINT_NOTHING: + source_flag = SRC_LINE; /* something bogus */ + do_frame_printing = 0; + break; + default: + internal_error (__FILE__, __LINE__, + "Unknown value."); + } +#ifdef UI_OUT + /* For mi, have the same behavior every time we stop: + print everything but the source line. */ + if (interpreter_p && strcmp (interpreter_p, "mi") == 0) + source_flag = LOC_AND_ADDRESS; +#endif +#ifdef UI_OUT + if (interpreter_p && strcmp (interpreter_p, "mi") == 0) + ui_out_field_int (uiout, "thread-id", + pid_to_thread_id (inferior_ptid)); +#endif /* The behavior of this routine with respect to the source flag is: - -1: Print only source line - 0: Print only location - 1: Print location and source line */ - show_and_print_stack_frame (selected_frame, -1, source_flag); + SRC_LINE: Print only source line + LOCATION: Print only location + SRC_AND_LOC: Print location and source line */ + if (do_frame_printing) + show_and_print_stack_frame (selected_frame, -1, source_flag); /* Display the auto-display expressions. */ do_displays (); @@ -3291,6 +3641,33 @@ signal_pass_state (int signo) return signal_program[signo]; } +int signal_stop_update (signo, state) + int signo; + int state; +{ + int ret = signal_stop[signo]; + signal_stop[signo] = state; + return ret; +} + +int signal_print_update (signo, state) + int signo; + int state; +{ + int ret = signal_print[signo]; + signal_print[signo] = state; + return ret; +} + +int signal_pass_update (signo, state) + int signo; + int state; +{ + int ret = signal_program[signo]; + signal_program[signo] = state; + return ret; +} + static void sig_print_header (void) { @@ -3482,7 +3859,7 @@ Are you sure you want to change it? ", argv++; } - target_notice_signals (inferior_pid); + target_notice_signals (inferior_ptid); if (from_tty) { @@ -3561,7 +3938,7 @@ xdb_handle_command (char *args, int from_tty) else printf_filtered ("Invalid signal handling flag.\n"); if (argBuf) - free (argBuf); + xfree (argBuf); } } do_cleanups (old_chain); @@ -3586,7 +3963,7 @@ signals_info (char *signum_exp, int from_tty) { /* No, try numeric. */ oursig = - target_signal_from_command (parse_and_eval_address (signum_exp)); + target_signal_from_command (parse_and_eval_long (signum_exp)); } sig_print_info (oursig); return; @@ -3621,7 +3998,7 @@ struct inferior_status CORE_ADDR step_range_start; CORE_ADDR step_range_end; CORE_ADDR step_frame_address; - int step_over_calls; + enum step_over_calls_kind step_over_calls; CORE_ADDR step_resume_break_address; int stop_after_trap; int stop_soon_quietly; @@ -3652,9 +4029,9 @@ xmalloc_inferior_status (void) static void free_inferior_status (struct inferior_status *inf_status) { - free (inf_status->registers); - free (inf_status->stop_registers); - free (inf_status); + xfree (inf_status->registers); + xfree (inf_status->stop_registers); + xfree (inf_status); } void @@ -3801,6 +4178,18 @@ restore_inferior_status (struct inferior_status *inf_status) free_inferior_status (inf_status); } +static void +do_restore_inferior_status_cleanup (void *sts) +{ + restore_inferior_status (sts); +} + +struct cleanup * +make_cleanup_restore_inferior_status (struct inferior_status *inf_status) +{ + return make_cleanup (do_restore_inferior_status_cleanup, inf_status); +} + void discard_inferior_status (struct inferior_status *inf_status) { @@ -3809,20 +4198,90 @@ discard_inferior_status (struct inferior_status *inf_status) free_inferior_status (inf_status); } +/* Oft used ptids */ +ptid_t null_ptid; +ptid_t minus_one_ptid; + +/* Create a ptid given the necessary PID, LWP, and TID components. */ + +ptid_t +ptid_build (int pid, long lwp, long tid) +{ + ptid_t ptid; + + ptid.pid = pid; + ptid.lwp = lwp; + ptid.tid = tid; + return ptid; +} + +/* Create a ptid from just a pid. */ + +ptid_t +pid_to_ptid (int pid) +{ + return ptid_build (pid, 0, 0); +} + +/* Fetch the pid (process id) component from a ptid. */ + +int +ptid_get_pid (ptid_t ptid) +{ + return ptid.pid; +} + +/* Fetch the lwp (lightweight process) component from a ptid. */ + +long +ptid_get_lwp (ptid_t ptid) +{ + return ptid.lwp; +} + +/* Fetch the tid (thread id) component from a ptid. */ + +long +ptid_get_tid (ptid_t ptid) +{ + return ptid.tid; +} + +/* ptid_equal() is used to test equality of two ptids. */ + +int +ptid_equal (ptid_t ptid1, ptid_t ptid2) +{ + return (ptid1.pid == ptid2.pid && ptid1.lwp == ptid2.lwp + && ptid1.tid == ptid2.tid); +} + +/* restore_inferior_ptid() will be used by the cleanup machinery + to restore the inferior_ptid value saved in a call to + save_inferior_ptid(). */ + static void -set_follow_fork_mode_command (char *arg, int from_tty, - struct cmd_list_element *c) -{ - if (!STREQ (arg, "parent") && - !STREQ (arg, "child") && - !STREQ (arg, "both") && - !STREQ (arg, "ask")) - error ("follow-fork-mode must be one of \"parent\", \"child\", \"both\" or \"ask\"."); - - if (follow_fork_mode_string != NULL) - free (follow_fork_mode_string); - follow_fork_mode_string = savestring (arg, strlen (arg)); +restore_inferior_ptid (void *arg) +{ + ptid_t *saved_ptid_ptr = arg; + inferior_ptid = *saved_ptid_ptr; + xfree (arg); } + +/* Save the value of inferior_ptid so that it may be restored by a + later call to do_cleanups(). Returns the struct cleanup pointer + needed for later doing the cleanup. */ + +struct cleanup * +save_inferior_ptid (void) +{ + ptid_t *saved_ptid_ptr; + + saved_ptid_ptr = xmalloc (sizeof (ptid_t)); + *saved_ptid_ptr = inferior_ptid; + return make_cleanup (restore_inferior_ptid, saved_ptid_ptr); +} + static void build_infrun (void) @@ -3954,7 +4413,7 @@ to the user would be loading/unloading of a new library.\n", c = add_set_enum_cmd ("follow-fork-mode", class_run, follow_fork_mode_kind_names, - (char *) &follow_fork_mode_string, + &follow_fork_mode_string, /* ??rehrauer: The "both" option is broken, by what may be a 10.20 kernel problem. It's also not terribly useful without a GUI to help the user drive two debuggers. So for now, I'm disabling @@ -3985,11 +4444,9 @@ By default, the debugger will follow the parent process.", /* c->function.sfunc = ; */ add_show_from_set (c, &showlist); - set_follow_fork_mode_command ("parent", 0, NULL); - c = add_set_enum_cmd ("scheduler-locking", class_run, scheduler_enums, /* array of string names */ - (char *) &scheduler_mode, /* current mode */ + &scheduler_mode, /* current mode */ "Set mode for locking scheduler during execution.\n\ off == no locking (threads may preempt at any time)\n\ on == full locking (no thread except the current thread may run)\n\ @@ -4000,4 +4457,19 @@ step == scheduler locked during every single-step operation.\n\ c->function.sfunc = set_schedlock_func; /* traps on target vector */ add_show_from_set (c, &showlist); + + c = add_set_cmd ("step-mode", class_run, + var_boolean, (char*) &step_stop_if_no_debug, +"Set mode of the step operation. When set, doing a step over a\n\ +function without debug line information will stop at the first\n\ +instruction of that function. Otherwise, the function is skipped and\n\ +the step command stops at a different source line.", + &setlist); + add_show_from_set (c, &showlist); + + /* ptid initializations */ + null_ptid = ptid_build (0, 0, 0); + minus_one_ptid = ptid_build (-1, 0, 0); + inferior_ptid = null_ptid; + target_last_wait_ptid = minus_one_ptid; }