X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=031544633e9e76b81508c2dde6ff9194c0d3f6b7;hb=8464be768129e057bc92e27de51317b99717da8f;hp=7379107020a3f5e87ac8549a5d7832edbb123d4c;hpb=fc1cf338c43f4f84624cd0f9026e1be8561b2c42;p=binutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 7379107020a..031544633e9 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -83,6 +83,16 @@ static void xdb_handle_command (char *args, int from_tty); static int prepare_to_proceed (int); +static void print_exited_reason (int exitstatus); + +static void print_signal_exited_reason (enum target_signal siggnal); + +static void print_no_history_reason (void); + +static void print_signal_received_reason (enum target_signal siggnal); + +static void print_end_stepping_range_reason (void); + void _initialize_infrun (void); void nullify_last_target_wait_ptid (void); @@ -119,7 +129,7 @@ show_debug_displaced (struct ui_file *file, int from_tty, fprintf_filtered (file, _("Displace stepping debugging is %s.\n"), value); } -static int debug_infrun = 0; +int debug_infrun = 0; static void show_debug_infrun (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -178,16 +188,85 @@ show_debug_infrun (struct ui_file *file, int from_tty, #define SOLIB_IN_DYNAMIC_LINKER(pid,pc) 0 #endif +/* "Observer mode" is somewhat like a more extreme version of + non-stop, in which all GDB operations that might affect the + target's execution have been disabled. */ -/* Convert the #defines into values. This is temporary until wfi control - flow is completely sorted out. */ +static int non_stop_1 = 0; -#ifndef CANNOT_STEP_HW_WATCHPOINTS -#define CANNOT_STEP_HW_WATCHPOINTS 0 -#else -#undef CANNOT_STEP_HW_WATCHPOINTS -#define CANNOT_STEP_HW_WATCHPOINTS 1 -#endif +int observer_mode = 0; +static int observer_mode_1 = 0; + +static void +set_observer_mode (char *args, int from_tty, + struct cmd_list_element *c) +{ + extern int pagination_enabled; + + if (target_has_execution) + { + observer_mode_1 = observer_mode; + error (_("Cannot change this setting while the inferior is running.")); + } + + observer_mode = observer_mode_1; + + may_write_registers = !observer_mode; + may_write_memory = !observer_mode; + may_insert_breakpoints = !observer_mode; + may_insert_tracepoints = !observer_mode; + /* We can insert fast tracepoints in or out of observer mode, + but enable them if we're going into this mode. */ + if (observer_mode) + may_insert_fast_tracepoints = 1; + may_stop = !observer_mode; + update_target_permissions (); + + /* Going *into* observer mode we must force non-stop, then + going out we leave it that way. */ + if (observer_mode) + { + target_async_permitted = 1; + pagination_enabled = 0; + non_stop = non_stop_1 = 1; + } + + if (from_tty) + printf_filtered (_("Observer mode is now %s.\n"), + (observer_mode ? "on" : "off")); +} + +static void +show_observer_mode (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Observer mode is %s.\n"), value); +} + +/* This updates the value of observer mode based on changes in + permissions. Note that we are deliberately ignoring the values of + may-write-registers and may-write-memory, since the user may have + reason to enable these during a session, for instance to turn on a + debugging-related global. */ + +void +update_observer_mode (void) +{ + int newval; + + newval = (!may_insert_breakpoints + && !may_insert_tracepoints + && may_insert_fast_tracepoints + && !may_stop + && non_stop); + + /* Let the user know if things change. */ + if (newval != observer_mode) + printf_filtered (_("Observer mode is now %s.\n"), + (newval ? "on" : "off")); + + observer_mode = observer_mode_1 = newval; +} /* Tables of how to react to signals; the user sets them. */ @@ -225,7 +304,7 @@ static struct symbol *step_start_function; /* Nonzero if we want to give control to the user when we're notified of shared library events by the dynamic linker. */ -static int stop_on_solib_events; +int stop_on_solib_events; static void show_stop_on_solib_events (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -660,7 +739,6 @@ show_follow_exec_mode_string (struct ui_file *file, int from_tty, static void follow_exec (ptid_t pid, char *execd_pathname) { - struct target_ops *tgt; struct thread_info *th = inferior_thread (); struct inferior *inf = current_inferior (); @@ -720,6 +798,7 @@ follow_exec (ptid_t pid, char *execd_pathname) char *name = alloca (strlen (gdb_sysroot) + strlen (execd_pathname) + 1); + strcpy (name, gdb_sysroot); strcat (name, execd_pathname); execd_pathname = name; @@ -736,7 +815,6 @@ follow_exec (ptid_t pid, char *execd_pathname) if (follow_exec_mode_string == follow_exec_mode_new) { struct program_space *pspace; - struct inferior *new_inf; /* The user wants to keep the old inferior and program spaces around. Create a new fresh one, and switch to it. */ @@ -1222,6 +1300,7 @@ static void write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr, const gdb_byte *myaddr, int len) { struct cleanup *ptid_cleanup = save_inferior_ptid (); + inferior_ptid = ptid; write_memory (memaddr, myaddr, len); do_cleanups (ptid_cleanup); @@ -1248,6 +1327,7 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal) /* Restore the contents of the copy area. */ { ULONGEST len = gdbarch_max_insn_length (displaced->step_gdbarch); + write_memory_ptid (displaced->step_ptid, displaced->step_copy, displaced->step_saved_copy, len); if (debug_displaced) @@ -1272,6 +1352,7 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal) relocate the PC. */ struct regcache *regcache = get_thread_regcache (event_ptid); CORE_ADDR pc = regcache_read_pc (regcache); + pc = displaced->step_original + (pc - displaced->step_copy); regcache_write_pc (regcache, pc); } @@ -1444,7 +1525,8 @@ maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc) { int hw_step = 1; - if (gdbarch_software_single_step_p (gdbarch) + if (execution_direction == EXEC_FORWARD + && gdbarch_software_single_step_p (gdbarch) && gdbarch_software_single_step (gdbarch, get_current_frame ())) { hw_step = 0; @@ -1484,18 +1566,6 @@ resume (int step, enum target_signal sig) "trap_expected=%d\n", step, sig, tp->trap_expected); - /* 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) - 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 @@ -2014,8 +2084,8 @@ void start_remote (int from_tty) { struct inferior *inferior; - init_wait_for_inferior (); + init_wait_for_inferior (); inferior = current_inferior (); inferior->stop_soon = STOP_QUIETLY_REMOTE; @@ -2079,22 +2149,6 @@ 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 -{ - /* Step, next, nexti, stepi finished. */ - END_STEPPING_RANGE, - /* Inferior terminated by signal. */ - SIGNAL_EXITED, - /* Inferior exited. */ - EXITED, - /* Inferior received signal, and user asked to be notified. */ - SIGNAL_RECEIVED, - /* Reverse execution -- target ran out of history info. */ - NO_HISTORY -}; - /* The PTID we'll do a target_wait on.*/ ptid_t waiton_ptid; @@ -2135,8 +2189,6 @@ static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR); 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); /* Callback for iterate over threads. If the thread is stopped, but the user/frontend doesn't know about that yet, go through @@ -2276,6 +2328,7 @@ delete_step_thread_step_resume_breakpoint (void) longjmp-resume breakpoint of the thread that just stopped stepping. */ struct thread_info *tp = inferior_thread (); + delete_step_resume_breakpoint (tp); } else @@ -2331,6 +2384,92 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid, ui_file_delete (tmp_stream); } +/* Prepare and stabilize the inferior for detaching it. E.g., + detaching while a thread is displaced stepping is a recipe for + crashing it, as nothing would readjust the PC out of the scratch + pad. */ + +void +prepare_for_detach (void) +{ + struct inferior *inf = current_inferior (); + ptid_t pid_ptid = pid_to_ptid (inf->pid); + struct cleanup *old_chain_1; + struct displaced_step_inferior_state *displaced; + + displaced = get_displaced_stepping_state (inf->pid); + + /* Is any thread of this process displaced stepping? If not, + there's nothing else to do. */ + if (displaced == NULL || ptid_equal (displaced->step_ptid, null_ptid)) + return; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "displaced-stepping in-process while detaching"); + + old_chain_1 = make_cleanup_restore_integer (&inf->detaching); + inf->detaching = 1; + + while (!ptid_equal (displaced->step_ptid, null_ptid)) + { + struct cleanup *old_chain_2; + struct execution_control_state ecss; + struct execution_control_state *ecs; + + ecs = &ecss; + memset (ecs, 0, sizeof (*ecs)); + + 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. */ + + registers_changed (); + + if (deprecated_target_wait_hook) + ecs->ptid = deprecated_target_wait_hook (pid_ptid, &ecs->ws, 0); + else + ecs->ptid = target_wait (pid_ptid, &ecs->ws, 0); + + if (debug_infrun) + print_target_wait_results (pid_ptid, ecs->ptid, &ecs->ws); + + /* If an error happens while handling the event, propagate GDB's + knowledge of the executing state to the frontend/user running + state. */ + old_chain_2 = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid); + + /* In non-stop mode, each thread is handled individually. + Switch early, so the global state is set correctly for this + thread. */ + if (non_stop + && ecs->ws.kind != TARGET_WAITKIND_EXITED + && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED) + context_switch (ecs->ptid); + + /* Now figure out what to do with the result of the result. */ + handle_inferior_event (ecs); + + /* No error, don't finish the state yet. */ + discard_cleanups (old_chain_2); + + /* Breakpoints and watchpoints are not installed on the target + at this point, and signals are passed directly to the + inferior, so this must mean the process is gone. */ + if (!ecs->wait_some_more) + { + discard_cleanups (old_chain_1); + error (_("Program exited while detaching")); + } + } + + discard_cleanups (old_chain_1); +} + /* Wait for control to return from inferior to debugger. If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals @@ -2662,6 +2801,7 @@ adjust_pc_after_break (struct execution_control_state *ecs) || (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc))) { struct cleanup *old_cleanups = NULL; + if (RECORD_IS_USED) old_cleanups = record_gdb_operation_disable_set (); @@ -2815,6 +2955,7 @@ handle_inferior_event (struct execution_control_state *ecs) && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED) { struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid)); + gdb_assert (inf); stop_soon = inf->stop_soon; } @@ -2826,7 +2967,7 @@ handle_inferior_event (struct execution_control_state *ecs) target_last_waitstatus = ecs->ws; /* Always clear state belonging to the previous time we stopped. */ - stop_stack_dummy = 0; + stop_stack_dummy = STOP_NONE; /* If it's a new process, add it to the thread database */ @@ -3008,7 +3149,7 @@ handle_inferior_event (struct execution_control_state *ecs) set_current_program_space (current_inferior ()->pspace); handle_vfork_child_exec_or_exit (0); target_terminal_ours (); /* Must do this before mourn anyway */ - print_stop_reason (EXITED, ecs->ws.value.integer); + print_exited_reason (ecs->ws.value.integer); /* Record the exit code in the convenience variable $_exitcode, so that the user can inspect this again later. */ @@ -3017,6 +3158,7 @@ handle_inferior_event (struct execution_control_state *ecs) gdb_flush (gdb_stdout); target_mourn_inferior (); singlestep_breakpoints_inserted_p = 0; + cancel_single_step_breakpoints (); stop_print_frame = 0; stop_stepping (ecs); return; @@ -3038,8 +3180,9 @@ handle_inferior_event (struct execution_control_state *ecs) may be needed. */ target_mourn_inferior (); - print_stop_reason (SIGNAL_EXITED, ecs->ws.value.sig); + print_signal_exited_reason (ecs->ws.value.sig); singlestep_breakpoints_inserted_p = 0; + cancel_single_step_breakpoints (); stop_stepping (ecs); return; @@ -3077,6 +3220,13 @@ handle_inferior_event (struct execution_control_state *ecs) detach_breakpoints (child_pid); } + if (singlestep_breakpoints_inserted_p) + { + /* Pull the single step breakpoints out of the target. */ + remove_single_step_breakpoints (); + singlestep_breakpoints_inserted_p = 0; + } + /* In case the event is caught by a catchpoint, remember that the event is to be followed at the next resume of the thread, and not immediately. */ @@ -3166,6 +3316,9 @@ handle_inferior_event (struct execution_control_state *ecs) reinit_frame_cache (); } + singlestep_breakpoints_inserted_p = 0; + cancel_single_step_breakpoints (); + stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); /* Do whatever is necessary to the parent branch of the vfork. */ @@ -3227,7 +3380,7 @@ handle_inferior_event (struct execution_control_state *ecs) case TARGET_WAITKIND_NO_HISTORY: /* Reverse execution: target ran out of history info. */ stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); - print_stop_reason (NO_HISTORY, 0); + print_no_history_reason (); stop_stepping (ecs); return; } @@ -3286,6 +3439,7 @@ targets should add new threads to the thread list themselves in non-stop mode.") if (target_stopped_by_watchpoint ()) { CORE_ADDR addr; + fprintf_unfiltered (gdb_stdlog, "infrun: stopped by watchpoint\n"); if (target_stopped_data_address (¤t_target, &addr)) @@ -3624,6 +3778,7 @@ targets should add new threads to the thread list themselves in non-stop mode.") the instruction and once for the delay slot. */ int step_through_delay = gdbarch_single_step_through_delay (gdbarch, frame); + if (debug_infrun && step_through_delay) fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n"); if (ecs->event_thread->step_range_end == 0 && step_through_delay) @@ -3787,6 +3942,7 @@ process_event_stop_test: { /* Signal not for debugging purposes. */ int printed = 0; + struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid)); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: random signal %d\n", @@ -3798,14 +3954,15 @@ process_event_stop_test: { printed = 1; target_terminal_ours_for_output (); - print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal); + print_signal_received_reason (ecs->event_thread->stop_signal); } /* Always stop on signals if we're either just gaining control of the program, or the user explicitly requested this thread to remain stopped. */ if (stop_soon != NO_STOP_QUIETLY || ecs->event_thread->stop_requested - || signal_stop_state (ecs->event_thread->stop_signal)) + || (!inf->detaching + && signal_stop_state (ecs->event_thread->stop_signal))) { stop_stepping (ecs); return; @@ -3890,9 +4047,15 @@ process_event_stop_test: if (what.call_dummy) { - stop_stack_dummy = 1; + stop_stack_dummy = what.call_dummy; } + /* If we hit an internal event that triggers symbol changes, the + current frame will be invalidated within bpstat_what (e.g., if + we hit an internal solib event). Re-fetch it. */ + frame = get_current_frame (); + gdbarch = get_frame_arch (frame); + switch (what.main_action) { case BPSTAT_WHAT_SET_LONGJMP_RESUME: @@ -3935,7 +4098,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); delete_step_resume_breakpoint (ecs->event_thread); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; @@ -3997,66 +4160,6 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); } break; - case BPSTAT_WHAT_CHECK_SHLIBS: - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_SHLIBS\n"); - - /* Check for any newly added shared libraries if we're - supposed to be adding them automatically. Switch - terminal for any messages produced by - breakpoint_re_set. */ - target_terminal_ours_for_output (); - /* NOTE: cagney/2003-11-25: Make certain that the target - stack's section table is kept up-to-date. Architectures, - (e.g., PPC64), use the section table to perform - operations such as address => section name and hence - require the table to contain all sections (including - those found in shared libraries). */ -#ifdef SOLIB_ADD - SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); -#else - solib_add (NULL, 0, ¤t_target, auto_solib_add); -#endif - target_terminal_inferior (); - - /* If requested, stop when the dynamic linker notifies - gdb of events. This allows the user to get control - and place breakpoints in initializer routines for - dynamically loaded objects (among other things). */ - if (stop_on_solib_events || stop_stack_dummy) - { - stop_stepping (ecs); - return; - } - else - { - /* We want to step over this breakpoint, then keep going. */ - ecs->event_thread->stepping_over_breakpoint = 1; - break; - } - } - break; - - case BPSTAT_WHAT_CHECK_JIT: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_JIT\n"); - - /* Switch terminal for any messages produced by breakpoint_re_set. */ - target_terminal_ours_for_output (); - - jit_event_handler (gdbarch); - - target_terminal_inferior (); - - /* We want to step over this breakpoint, then keep going. */ - ecs->event_thread->stepping_over_breakpoint = 1; - - break; - - case BPSTAT_WHAT_LAST: - /* Not a real code, but listed here to shut up gcc -Wall. */ - case BPSTAT_WHAT_KEEP_CHECKING: break; } @@ -4073,6 +4176,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); if (!non_stop) { struct thread_info *tp; + tp = iterate_over_threads (currently_stepping_or_nexting_callback, ecs->event_thread); if (tp) @@ -4192,6 +4296,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); the frame cache to be re-initialized, making our FRAME variable a dangling pointer. */ frame = get_current_frame (); + gdbarch = get_frame_arch (frame); /* If stepping through a line, keep going if still within it. @@ -4223,7 +4328,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); && execution_direction == EXEC_REVERSE) { ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); } else @@ -4261,6 +4366,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); /* 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; sr_sal.pspace = get_frame_program_space (frame); @@ -4332,7 +4438,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); well. FENN */ /* And this works the same backward as frontward. MVS */ ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4399,6 +4505,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc)) { struct symtab_and_line sr_sal; + init_sal (&sr_sal); sr_sal.pc = ecs->stop_func_start; sr_sal.pspace = get_frame_program_space (frame); @@ -4437,7 +4544,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); && step_stop_if_no_debug) { ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4447,6 +4554,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); /* Set a breakpoint at callee's start address. From there we can step once and be back in the caller. */ struct symtab_and_line sr_sal; + init_sal (&sr_sal); sr_sal.pc = ecs->stop_func_start; sr_sal.pspace = get_frame_program_space (frame); @@ -4485,6 +4593,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); Set a breakpoint at its start and continue, then one more step will take us out. */ struct symtab_and_line sr_sal; + init_sal (&sr_sal); sr_sal.pc = ecs->stop_func_start; sr_sal.pspace = get_frame_program_space (frame); @@ -4502,6 +4611,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); { /* Determine where this trampoline returns. */ CORE_ADDR real_stop_pc; + real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc); if (debug_infrun) @@ -4558,7 +4668,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); is set, we stop the step so that the user has a chance to switch in assembly mode. */ ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4579,7 +4689,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stepi/nexti\n"); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4593,7 +4703,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n"); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4626,7 +4736,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); step_into_inline_frame (ecs->ptid); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4641,7 +4751,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); else { ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); } return; @@ -4668,7 +4778,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); else { ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); } return; @@ -4685,7 +4795,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different line\n"); ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4786,7 +4896,7 @@ handle_step_into_function (struct gdbarch *gdbarch, { /* We are already there: stop now. */ ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); return; } @@ -4818,7 +4928,7 @@ handle_step_into_function_backward (struct gdbarch *gdbarch, struct execution_control_state *ecs) { struct symtab *s; - struct symtab_and_line stop_func_sal, sr_sal; + struct symtab_and_line stop_func_sal; s = find_pc_symtab (stop_pc); if (s && s->language != language_asm) @@ -4832,7 +4942,7 @@ handle_step_into_function_backward (struct gdbarch *gdbarch, { /* We're there already. Just stop stepping now. */ ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); + print_end_stepping_range_reason (); stop_stepping (ecs); } else @@ -5010,6 +5120,7 @@ keep_going (struct execution_control_state *ecs) if (ecs->event_thread->stepping_over_breakpoint) { struct regcache *thread_regcache = get_thread_regcache (ecs->ptid); + if (!use_displaced_stepping (get_regcache_arch (thread_regcache))) /* Since we can't do a displaced step, we have to remove the breakpoint while we step it. To keep things @@ -5019,6 +5130,7 @@ keep_going (struct execution_control_state *ecs) else { struct gdb_exception e; + /* Stop stepping when inserting breakpoints has failed. */ TRY_CATCH (e, RETURN_MASK_ERROR) @@ -5075,116 +5187,121 @@ prepare_to_wait (struct execution_control_state *ecs) 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.*/ +/* Several print_*_reason functions to 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 one of these + print_*_reason functions functions from handle_inferior_event each time + stop_stepping is called. */ + +/* Print why the inferior has stopped. + We are done with a step/next/si/ni command, print why the inferior has + stopped. For now print nothing. Print a message only if not in the middle + of doing a "step n" operation for n > 1. */ + +static void +print_end_stepping_range_reason (void) +{ + if ((!inferior_thread ()->step_multi || !inferior_thread ()->stop_step) + && ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE)); +} + +/* The inferior was terminated by a signal, print why it stopped. */ + +static void +print_signal_exited_reason (enum target_signal siggnal) +{ + annotate_signalled (); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", async_reason_lookup (EXEC_ASYNC_EXITED_SIGNALLED)); + ui_out_text (uiout, "\nProgram terminated with signal "); + annotate_signal_name (); + ui_out_field_string (uiout, "signal-name", + target_signal_to_name (siggnal)); + annotate_signal_name_end (); + ui_out_text (uiout, ", "); + annotate_signal_string (); + ui_out_field_string (uiout, "signal-meaning", + target_signal_to_string (siggnal)); + annotate_signal_string_end (); + ui_out_text (uiout, ".\n"); + ui_out_text (uiout, "The program no longer exists.\n"); +} + +/* The inferior program is finished, print why it stopped. */ + static void -print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info) +print_exited_reason (int exitstatus) { - switch (stop_reason) + annotate_exited (exitstatus); + if (exitstatus) + { + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_EXITED)); + ui_out_text (uiout, "\nProgram exited with code "); + ui_out_field_fmt (uiout, "exit-code", "0%o", (unsigned int) exitstatus); + ui_out_text (uiout, ".\n"); + } + else { - case END_STEPPING_RANGE: - /* We are done with a step/next/si/ni command. */ - /* For now print nothing. */ - /* Print a message only if not in the middle of doing a "step n" - operation for n > 1 */ - if (!inferior_thread ()->step_multi - || !inferior_thread ()->stop_step) - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE)); - break; - case SIGNAL_EXITED: - /* The inferior was terminated by a signal. */ - annotate_signalled (); if (ui_out_is_mi_like_p (uiout)) ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_EXITED_SIGNALLED)); - ui_out_text (uiout, "\nProgram terminated with signal "); + (uiout, "reason", async_reason_lookup (EXEC_ASYNC_EXITED_NORMALLY)); + ui_out_text (uiout, "\nProgram exited normally.\n"); + } + /* Support the --return-child-result option. */ + return_child_result_value = exitstatus; +} + +/* Signal received, print why the inferior has stopped. The signal table + tells us to print about it. */ + +static void +print_signal_received_reason (enum target_signal siggnal) +{ + annotate_signal (); + + if (siggnal == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout)) + { + struct thread_info *t = inferior_thread (); + + ui_out_text (uiout, "\n["); + ui_out_field_string (uiout, "thread-name", + target_pid_to_str (t->ptid)); + ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num); + ui_out_text (uiout, " stopped"); + } + else + { + ui_out_text (uiout, "\nProgram received signal "); annotate_signal_name (); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED)); ui_out_field_string (uiout, "signal-name", - target_signal_to_name (stop_info)); + target_signal_to_name (siggnal)); annotate_signal_name_end (); ui_out_text (uiout, ", "); annotate_signal_string (); ui_out_field_string (uiout, "signal-meaning", - target_signal_to_string (stop_info)); + target_signal_to_string (siggnal)); annotate_signal_string_end (); - ui_out_text (uiout, ".\n"); - ui_out_text (uiout, "The program no longer exists.\n"); - break; - case EXITED: - /* The inferior program is finished. */ - annotate_exited (stop_info); - if (stop_info) - { - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_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 (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_EXITED_NORMALLY)); - ui_out_text (uiout, "\nProgram exited normally.\n"); - } - /* Support the --return-child-result option. */ - return_child_result_value = stop_info; - break; - case SIGNAL_RECEIVED: - /* Signal received. The signal table tells us to print about - it. */ - annotate_signal (); + } + ui_out_text (uiout, ".\n"); +} - if (stop_info == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout)) - { - struct thread_info *t = inferior_thread (); +/* Reverse execution: target ran out of history info, print why the inferior + has stopped. */ - ui_out_text (uiout, "\n["); - ui_out_field_string (uiout, "thread-name", - target_pid_to_str (t->ptid)); - ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num); - ui_out_text (uiout, " stopped"); - } - else - { - ui_out_text (uiout, "\nProgram received signal "); - annotate_signal_name (); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED)); - 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"); - break; - case NO_HISTORY: - /* Reverse execution: target ran out of history info. */ - ui_out_text (uiout, "\nNo more reverse-execution history.\n"); - break; - default: - internal_error (__FILE__, __LINE__, - _("print_stop_reason: unrecognized enum value")); - break; - } +static void +print_no_history_reason (void) +{ + ui_out_text (uiout, "\nNo more reverse-execution history.\n"); } - /* Here to return control to GDB when the inferior stops for real. Print appropriate messages, remove breakpoints, give terminal our modes. @@ -5380,12 +5497,13 @@ Further execution is probably impossible.\n")); stop_registers = regcache_dup (get_current_regcache ()); } - if (stop_stack_dummy) + if (stop_stack_dummy == STOP_STACK_DUMMY) { /* Pop the empty frame that contains the stack dummy. This also restores inferior state prior to the call (struct inferior_thread_state). */ struct frame_info *frame = get_current_frame (); + gdb_assert (get_frame_type (frame) == DUMMY_FRAME); frame_pop (frame); /* frame_pop() calls reinit_frame_cache as the last thing it does @@ -5473,6 +5591,7 @@ int signal_stop_update (int signo, int state) { int ret = signal_stop[signo]; + signal_stop[signo] = state; return ret; } @@ -5481,6 +5600,7 @@ int signal_print_update (int signo, int state) { int ret = signal_print[signo]; + signal_print[signo] = state; return ret; } @@ -5489,6 +5609,7 @@ int signal_pass_update (int signo, int state) { int ret = signal_program[signo]; + signal_program[signo] = state; return ret; } @@ -5772,6 +5893,7 @@ static void signals_info (char *signum_exp, int from_tty) { enum target_signal oursig; + sig_print_header (); if (signum_exp) @@ -5870,6 +5992,7 @@ siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var) && gdbarch_get_siginfo_type_p (gdbarch)) { struct type *type = gdbarch_get_siginfo_type (gdbarch); + return allocate_computed_value (type, &siginfo_value_funcs, NULL); } @@ -5958,7 +6081,7 @@ struct inferior_status { bpstat stop_bpstat; int stop_step; - int stop_stack_dummy; + enum stop_stack_kind stop_stack_dummy; int stopped_by_random_signal; int stepping_over_breakpoint; CORE_ADDR step_range_start; @@ -6245,8 +6368,7 @@ ptid_match (ptid_t ptid, ptid_t filter) /* Since both parameters have the same type, prevent easy mistakes from happening. */ gdb_assert (!ptid_equal (ptid, minus_one_ptid) - && !ptid_equal (ptid, null_ptid) - && !ptid_is_pid (ptid)); + && !ptid_equal (ptid, null_ptid)); if (ptid_equal (filter, minus_one_ptid)) return 1; @@ -6267,6 +6389,7 @@ static void restore_inferior_ptid (void *arg) { ptid_t *saved_ptid_ptr = arg; + inferior_ptid = *saved_ptid_ptr; xfree (arg); } @@ -6311,6 +6434,11 @@ set_exec_direction_func (char *args, int from_tty, else if (!strcmp (exec_direction, exec_reverse)) execution_direction = EXEC_REVERSE; } + else + { + exec_direction = exec_forward; + error (_("Target does not support this operation.")); + } } static void @@ -6336,7 +6464,6 @@ show_exec_direction_func (struct ui_file *out, int from_tty, /* User interface for non-stop mode. */ int non_stop = 0; -static int non_stop_1 = 0; static void set_non_stop (char *args, int from_tty, @@ -6373,7 +6500,6 @@ _initialize_infrun (void) { int i; int numsigs; - struct cmd_list_element *c; add_info ("signals", signals_info, _("\ What debugger does when program gets various signals.\n\ @@ -6408,7 +6534,7 @@ from 1-15 are allowed for compatibility with old versions of GDB.\n\ Numeric ranges may be specified with the form LOW-HIGH (e.g. 1-5).\n\ The special arg \"all\" is recognized to mean all signals except those\n\ used by the debugger, typically SIGTRAP and SIGINT.\n\ -Recognized actions include \"s\" (toggles between stop and nostop), \n\ +Recognized actions include \"s\" (toggles between stop and nostop),\n\ \"r\" (toggles between print and noprint), \"i\" (toggles between pass and \ nopass), \"Q\" (noprint)\n\ Stop means reenter debugger if this signal happens (implies print).\n\ @@ -6542,7 +6668,7 @@ An exec call replaces the program image of a process.\n\ \n\ follow-exec-mode can be:\n\ \n\ - new - the debugger creates a new inferior and rebinds the process \n\ + new - the debugger creates a new inferior and rebinds the process\n\ to this new inferior. The program the process was running before\n\ the exec call can be restarted afterwards by restarting the original\n\ inferior.\n\ @@ -6639,4 +6765,17 @@ Tells gdb whether to detach the child of a fork."), isn't initialized yet. At this point, we're quite sure there isn't another convenience variable of the same name. */ create_internalvar_type_lazy ("_siginfo", siginfo_make_value); + + add_setshow_boolean_cmd ("observer", no_class, + &observer_mode_1, _("\ +Set whether gdb controls the inferior in observer mode."), _("\ +Show whether gdb controls the inferior in observer mode."), _("\ +In observer mode, GDB can get data from the inferior, but not\n\ +affect its execution. Registers and memory may not be changed,\n\ +breakpoints may not be set, and the program cannot be interrupted\n\ +or signalled."), + set_observer_mode, + show_observer_mode, + &setlist, + &showlist); }