static void xdb_handle_command (char *args, int from_tty);
+static int prepare_to_proceed (void);
+
void _initialize_infrun (void);
int inferior_ignoring_startup_exec_events = 0;
#define IN_SOLIB_DYNSYM_RESOLVE_CODE(pc) 0
#endif
-#ifndef SKIP_SOLIB_RESOLVER
-#define SKIP_SOLIB_RESOLVER(pc) 0
-#endif
-
/* This function returns TRUE if pc is the address of an instruction
that lies within the dynamic linker (such as the event hook, or the
dld itself).
\f
/* Things to clean up if we QUIT out of resume (). */
-/* ARGSUSED */
static void
resume_cleanups (void *ignore)
{
the set command passed as a parameter. The clone operation will
include (BUG?) any ``set'' command callback, if present.
Commands like ``info set'' call all the ``show'' command
- callbacks. Unfortunatly, for ``show'' commands cloned from
+ callbacks. Unfortunately, for ``show'' commands cloned from
``set'', this includes callbacks belonging to ``set'' commands.
Making this worse, this only occures if add_show_from_set() is
called after add_cmd_sfunc() (BUG?). */
bpstat_clear (&stop_bpstat);
}
+/* This should be suitable for any targets that support threads. */
+
+static int
+prepare_to_proceed (void)
+{
+ ptid_t wait_ptid;
+ struct target_waitstatus wait_status;
+
+ /* Get the last target status returned by target_wait(). */
+ get_last_target_status (&wait_ptid, &wait_status);
+
+ /* Make sure we were stopped either at a breakpoint, or because
+ of a Ctrl-C. */
+ if (wait_status.kind != TARGET_WAITKIND_STOPPED
+ || (wait_status.value.sig != TARGET_SIGNAL_TRAP &&
+ wait_status.value.sig != TARGET_SIGNAL_INT))
+ {
+ return 0;
+ }
+
+ if (!ptid_equal (wait_ptid, minus_one_ptid)
+ && !ptid_equal (inferior_ptid, wait_ptid))
+ {
+ /* Switched over from WAIT_PID. */
+ CORE_ADDR wait_pc = read_pc_pid (wait_ptid);
+
+ if (wait_pc != read_pc ())
+ {
+ /* Switch back to WAIT_PID thread. */
+ inferior_ptid = wait_ptid;
+
+ /* FIXME: This stuff came from switch_to_thread() in
+ thread.c (which should probably be a public function). */
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = wait_pc;
+ select_frame (get_current_frame ());
+ }
+
+ /* We return 1 to indicate that there is a breakpoint here,
+ so we need to step over it before continuing to avoid
+ hitting it straight away. */
+ if (breakpoint_here_p (wait_pc))
+ return 1;
+ }
+
+ return 0;
+
+}
+
+/* Record the pc of the program the last time it stopped. This is
+ just used internally by wait_for_inferior, but need to be preserved
+ over calls to it and cleared when the inferior is started. */
+static CORE_ADDR prev_pc;
+
/* Basic routine for continuing the program in various fashions.
ADDR is the address to resume at, or -1 for resume where stopped.
write_pc (addr);
}
-#ifdef PREPARE_TO_PROCEED
/* In a multi-threaded task we may select another thread
and then continue or step.
any execution (i.e. it will report a breakpoint hit
incorrectly). So we must step over it first.
- PREPARE_TO_PROCEED checks the current thread against the thread
+ prepare_to_proceed checks the current thread against the thread
that reported the most recent event. If a step-over is required
it returns TRUE and sets the current thread to the old thread. */
- if (PREPARE_TO_PROCEED (1) && breakpoint_here_p (read_pc ()))
- {
- oneproc = 1;
- }
-
-#endif /* PREPARE_TO_PROCEED */
+ if (prepare_to_proceed () && breakpoint_here_p (read_pc ()))
+ oneproc = 1;
#ifdef HP_OS_BUG
if (trap_expected_after_continue)
inferior. */
gdb_flush (gdb_stdout);
+ /* Refresh prev_pc value just prior to resuming. This used to be
+ done in stop_stepping, however, setting prev_pc there did not handle
+ scenarios such as inferior function calls or returning from
+ a function via the return command. In those cases, the prev_pc
+ value was not set properly for subsequent commands. The prev_pc value
+ is used to initialize the starting line number in the ecs. With an
+ invalid value, the gdb next command ends up stopping at the position
+ represented by the next line table entry past our start position.
+ On platforms that generate one line table entry per line, this
+ is not a problem. However, on the ia64, the compiler generates
+ extraneous line table entries that do not increase the line number.
+ When we issue the gdb next command on the ia64 after an inferior call
+ or a return command, we often end up a few instructions forward, still
+ within the original line we started.
+
+ An attempt was made to have init_execution_control_state () refresh
+ the prev_pc value before calculating the line number. This approach
+ did not work because on platforms that use ptrace, the pc register
+ cannot be read unless the inferior is stopped. At that point, we
+ are not guaranteed the inferior is stopped and so the read_pc ()
+ call can fail. Setting the prev_pc value here ensures the value is
+ updated correctly when the inferior is stopped. */
+ prev_pc = read_pc ();
+
/* Resume inferior. */
resume (oneproc || step || bpstat_should_step (), stop_signal);
normal_stop ();
}
}
-
-/* Record the pc and sp of the program the last time it stopped.
- These are just used internally by wait_for_inferior, but need
- to be preserved over calls to it and cleared when the inferior
- is started. */
-static CORE_ADDR prev_pc;
-static char *prev_func_name;
\f
/* Start remote-debugging of a machine over a serial link. */
{
/* These are meaningless until the first time through wait_for_inferior. */
prev_pc = 0;
- prev_func_name = NULL;
#ifdef HP_OS_BUG
trap_expected_after_continue = 0;
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_name,
+ save_infrun_state (inferior_ptid, prev_pc,
trap_expected, step_resume_breakpoint,
through_sigtramp_breakpoint, step_range_start,
step_range_end, &step_frame_id,
ecs->current_line, ecs->current_symtab, step_sp);
/* Load infrun state for the new thread. */
- load_infrun_state (ecs->ptid, &prev_pc, &prev_func_name,
+ load_infrun_state (ecs->ptid, &prev_pc,
&trap_expected, &step_resume_breakpoint,
&through_sigtramp_breakpoint, &step_range_start,
&step_range_end, &step_frame_id,
inferior_ptid = ecs->ptid;
}
+/* Wrapper for PC_IN_SIGTRAMP that takes care of the need to find the
+ function's name.
+
+ In a classic example of "left hand VS right hand", "infrun.c" was
+ trying to improve GDB's performance by caching the result of calls
+ to calls to find_pc_partial_funtion, while at the same time
+ find_pc_partial_function was also trying to ramp up performance by
+ caching its most recent return value. The below makes the the
+ function find_pc_partial_function solely responsibile for
+ performance issues (the local cache that relied on a global
+ variable - arrrggg - deleted).
+
+ Using the testsuite and gcov, it was found that dropping the local
+ "infrun.c" cache and instead relying on find_pc_partial_function
+ increased the number of calls to 12000 (from 10000), but the number
+ of times find_pc_partial_function's cache missed (this is what
+ matters) was only increased by only 4 (to 3569). (A quick back of
+ envelope caculation suggests that the extra 2000 function calls
+ @1000 extra instructions per call make the 1 MIP VAX testsuite run
+ take two extra seconds, oops :-)
+
+ Long term, this function can be eliminated, replaced by the code:
+ get_frame_type(current_frame()) == SIGTRAMP_FRAME (for new
+ architectures this is very cheap). */
+
+static int
+pc_in_sigtramp (CORE_ADDR pc)
+{
+ char *name;
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ return PC_IN_SIGTRAMP (pc, name);
+}
+
/* Given an execution control state that has been freshly filled in
by an event from the inferior, figure out what it means and take
if (step_over_calls == STEP_OVER_UNDEBUGGABLE
&& IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc))
{
- CORE_ADDR pc_after_resolver = SKIP_SOLIB_RESOLVER (stop_pc);
+ CORE_ADDR pc_after_resolver =
+ gdbarch_skip_solib_resolver (current_gdbarch, stop_pc);
if (pc_after_resolver)
{
ecs->update_step_sp = 1;
/* Did we just take a signal? */
- if (PC_IN_SIGTRAMP (stop_pc, ecs->stop_func_name)
- && !PC_IN_SIGTRAMP (prev_pc, prev_func_name)
+ if (pc_in_sigtramp (stop_pc)
+ && !pc_in_sigtramp (prev_pc)
&& INNER_THAN (read_sp (), step_sp))
{
/* We've just taken a signal; go until we are back to
return;
}
- if (stop_pc == ecs->stop_func_start /* Quick test */
- || (in_prologue (stop_pc, ecs->stop_func_start) &&
- !IN_SOLIB_RETURN_TRAMPOLINE (stop_pc, ecs->stop_func_name))
+ if (((stop_pc == ecs->stop_func_start /* Quick test */
+ || in_prologue (stop_pc, ecs->stop_func_start))
+ && !IN_SOLIB_RETURN_TRAMPOLINE (stop_pc, ecs->stop_func_name))
|| IN_SOLIB_CALL_TRAMPOLINE (stop_pc, ecs->stop_func_name)
|| ecs->stop_func_name == 0)
{
{
/* We're doing a "next". */
- if (PC_IN_SIGTRAMP (stop_pc, ecs->stop_func_name)
+ if (pc_in_sigtramp (stop_pc)
&& frame_id_inner (step_frame_id,
frame_id_build (read_sp (), 0)))
/* We stepped out of a signal handler, and into its
/* In the case where we just stepped out of a function into the
middle of a line of the caller, continue stepping, but
step_frame_id must be modified to current frame */
+#if 0
+ /* NOTE: cagney/2003-10-16: I think this frame ID inner test is too
+ generous. It will trigger on things like a step into a frameless
+ stackless leaf function. I think the logic should instead look
+ at the unwound frame ID has that should give a more robust
+ indication of what happened. */
+ if (step-ID == current-ID)
+ still stepping in same function;
+ else if (step-ID == unwind (current-ID))
+ stepped into a function;
+ else
+ stepped out of a function;
+ /* Of course this assumes that the frame ID unwind code is robust
+ and we're willing to introduce frame unwind logic into this
+ function. Fortunately, those days are nearly upon us. */
+#endif
{
struct frame_id current_frame = get_frame_id (get_current_frame ());
if (!(frame_id_inner (current_frame, step_frame_id)))
check_sigtramp2 (struct execution_control_state *ecs)
{
if (trap_expected
- && PC_IN_SIGTRAMP (stop_pc, ecs->stop_func_name)
- && !PC_IN_SIGTRAMP (prev_pc, prev_func_name)
+ && pc_in_sigtramp (stop_pc)
+ && !pc_in_sigtramp (prev_pc)
&& INNER_THAN (read_sp (), step_sp))
{
/* What has happened here is that we have just stepped the
- avoid handling the case where the PC hasn't been saved in the
prologue analyzer
- Unfortunatly, not five lines further down, is a call to
+ Unfortunately, not five lines further down, is a call to
get_frame_id() and that is guarenteed to trigger the prologue
analyzer.
static void
stop_stepping (struct execution_control_state *ecs)
{
- if (target_has_execution)
- {
- /* Assuming the inferior still exists, set these up for next
- time, just like we did above if we didn't break out of the
- loop. */
- prev_pc = read_pc ();
- 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;
}
{
/* Save the pc before execution, to compare with pc after stop. */
prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
- prev_func_name = ecs->stop_func_name;
if (ecs->update_step_sp)
step_sp = read_sp ();
void
normal_stop (void)
{
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+
+ get_last_target_status (&last_ptid, &last);
+
/* As with the notification of thread events, we want to delay
notifying the user that we've switched thread context until
the inferior actually stops.
- (Note that there's no point in saying anything if the inferior
- has exited!) */
+ There's no point in saying anything if the inferior has exited.
+ Note that SIGNALLED here means "exited with a signal", not
+ "received a signal". */
if (!ptid_equal (previous_inferior_ptid, inferior_ptid)
- && target_has_execution)
+ && target_has_execution
+ && last.kind != TARGET_WAITKIND_SIGNALLED
+ && last.kind != TARGET_WAITKIND_EXITED)
{
target_terminal_ours_for_output ();
printf_filtered ("[Switching to %s]\n",
write_inferior_status_register (struct inferior_status *inf_status, int regno,
LONGEST val)
{
- int size = REGISTER_RAW_SIZE (regno);
+ int size = DEPRECATED_REGISTER_RAW_SIZE (regno);
void *buf = alloca (size);
store_signed_integer (buf, size, val);
regcache_raw_write (inf_status->registers, regno, buf);
void
_initialize_infrun (void)
{
- register int i;
- register int numsigs;
+ int i;
+ int numsigs;
struct cmd_list_element *c;
register_gdbarch_swap (&stop_registers, sizeof (stop_registers), NULL);