/* Prototypes for local functions */
-static void
-signals_info PARAMS ((char *, int));
+static void signals_info PARAMS ((char *, int));
-static void
-handle_command PARAMS ((char *, int));
+static void handle_command PARAMS ((char *, int));
static void sig_print_info PARAMS ((enum target_signal));
-static void
-sig_print_header PARAMS ((void));
+static void sig_print_header PARAMS ((void));
-static void
-resume_cleanups PARAMS ((int));
+static void resume_cleanups PARAMS ((int));
-static int
-hook_stop_stub PARAMS ((char *));
+static int hook_stop_stub PARAMS ((char *));
/* GET_LONGJMP_TARGET returns the PC at which longjmp() will resume the
program. It needs to examine the jmp_buf argument and extract the PC
from it. The return value is non-zero on success, zero otherwise. */
+
#ifndef GET_LONGJMP_TARGET
#define GET_LONGJMP_TARGET(PC_ADDR) 0
#endif
/* Some machines have trampoline code that sits between function callers
and the actual functions themselves. If this machine doesn't have
such things, disable their processing. */
+
#ifndef SKIP_TRAMPOLINE_CODE
#define SKIP_TRAMPOLINE_CODE(pc) 0
#endif
/* For SVR4 shared libraries, each call goes through a small piece of
- trampoline code in the ".plt" section. IN_SOLIB_TRAMPOLINE evaluates
+ trampoline code in the ".plt" section. IN_SOLIB_CALL_TRAMPOLINE evaluates
to nonzero if we are current stopped in one of these. */
-#ifndef IN_SOLIB_TRAMPOLINE
-#define IN_SOLIB_TRAMPOLINE(pc,name) 0
+
+#ifndef IN_SOLIB_CALL_TRAMPOLINE
+#define IN_SOLIB_CALL_TRAMPOLINE(pc,name) 0
+#endif
+
+/* In some shared library schemes, the return path from a shared library
+ call may need to go through a trampoline too. */
+
+#ifndef IN_SOLIB_RETURN_TRAMPOLINE
+#define IN_SOLIB_RETURN_TRAMPOLINE(pc,name) 0
#endif
/* On some systems, the PC may be left pointing at an instruction that won't
breakpoint to be hit again, but you can always continue, so it's not
a big deal.) */
- if (! step && PREPARE_TO_PROCEED && breakpoint_here_p (read_pc ()))
+ if (! step && PREPARE_TO_PROCEED (1) && breakpoint_here_p (read_pc ()))
oneproc = 1;
#endif /* PREPARE_TO_PROCEED */
to be preserved over calls to it and cleared when the inferior
is started. */
static CORE_ADDR prev_pc;
-static CORE_ADDR prev_sp;
static CORE_ADDR prev_func_start;
static char *prev_func_name;
-static CORE_ADDR prev_frame_address;
\f
/* Start remote-debugging of a machine over a serial link. */
void
start_remote ()
{
+ init_thread_list ();
init_wait_for_inferior ();
clear_proceed_status ();
stop_soon_quietly = 1;
{
/* These are meaningless until the first time through wait_for_inferior. */
prev_pc = 0;
- prev_sp = 0;
prev_func_start = 0;
prev_func_name = NULL;
- prev_frame_address = 0;
trap_expected_after_continue = 0;
breakpoints_inserted = 0;
struct target_waitstatus w;
int another_trap;
int random_signal;
- CORE_ADDR stop_sp = 0;
CORE_ADDR stop_func_start;
CORE_ADDR stop_func_end;
char *stop_func_name;
struct breakpoint *step_resume_breakpoint = NULL;
struct breakpoint *through_sigtramp_breakpoint = NULL;
int pid;
+ int update_step_sp = 0;
old_cleanups = make_cleanup (delete_breakpoint_current_contents,
&step_resume_breakpoint);
registers_changed ();
- pid = target_wait (-1, &w);
+ if (target_wait_hook)
+ pid = target_wait_hook (-1, &w);
+ else
+ pid = target_wait (-1, &w);
flush_cached_frames ();
{
fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid));
add_thread (pid);
+
+ /* We may want to consider not doing a resume here in order to give
+ the user a chance to play with the new thread. It might be good
+ to make that a user-settable option. */
+
+ /* At this point, all threads are stopped (happens automatically in
+ either the OS or the native code). Therefore we need to continue
+ all threads in order to make progress. */
+
+ target_resume (-1, 0, TARGET_SIGNAL_0);
+ continue;
}
switch (w.kind)
printf_filtered ("\nProgram exited with code 0%o.\n",
(unsigned int)w.value.integer);
else
- if (!batch_mode())
- printf_filtered ("\nProgram exited normally.\n");
+ printf_filtered ("\nProgram exited normally.\n");
gdb_flush (gdb_stdout);
target_mourn_inferior ();
#ifdef NO_SINGLE_STEP
stop_signal = w.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));
target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */
/* FIXME: What if a signal arrives instead of the single-step
happening? */
- target_wait (pid, &w);
+
+ if (target_wait_hook)
+ target_wait_hook (pid, &w);
+ else
+ target_wait (pid, &w);
insert_breakpoints ();
target_resume (pid, 0, TARGET_SIGNAL_0);
continue;
through_sigtramp_breakpoint = NULL;
}
prev_pc = 0;
- prev_sp = 0;
prev_func_name = NULL;
step_range_start = 0;
step_range_end = 0;
continue;
}
- set_current_frame (create_new_frame (read_fp (), stop_pc));
- select_frame (get_current_frame (), 0);
-
#ifdef HAVE_STEPPABLE_WATCHPOINT
/* It may not be necessary to disable the watchpoint to stop over
it. For example, the PA can (with some kernel cooperation)
STOPPED_BY_WATCHPOINT (w);
#endif
- stop_frame_address = FRAME_FP (get_current_frame ());
- stop_sp = read_sp ();
stop_func_start = 0;
stop_func_name = 0;
/* Don't care about return value; stop_func_start and stop_func_name
{
/* See if there is a breakpoint at the current PC. */
stop_bpstat = bpstat_stop_status
- (&stop_pc, stop_frame_address,
+ (&stop_pc,
#if DECR_PC_AFTER_BREAK
/* Notice the case of stepping through a jump
that lands just after a breakpoint.
= !(bpstat_explains_signal (stop_bpstat)
|| trap_expected
#ifndef CALL_DUMMY_BREAKPOINT_OFFSET
- || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+ || PC_IN_CALL_DUMMY (stop_pc, read_sp (),
+ FRAME_FP (get_current_frame ()))
#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */
|| (step_range_end && step_resume_breakpoint == NULL));
else
news) give another signal besides SIGTRAP,
so check here as well as above. */
#ifndef CALL_DUMMY_BREAKPOINT_OFFSET
- || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+ || PC_IN_CALL_DUMMY (stop_pc, read_sp (),
+ FRAME_FP (get_current_frame ()))
#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */
);
if (!random_signal)
#if 0
/* FIXME - Need to implement nested temporary breakpoints */
if (step_over_calls
- && (stop_frame_address
+ && (FRAME_FP (get_current_frame ())
INNER_THAN step_frame_address))
{
another_trap = 1;
break;
case BPSTAT_WHAT_THROUGH_SIGTRAMP:
- delete_breakpoint (through_sigtramp_breakpoint);
+ if (through_sigtramp_breakpoint)
+ delete_breakpoint (through_sigtramp_breakpoint);
through_sigtramp_breakpoint = NULL;
/* If were waiting for a trap, hitting the step_resume_break
just stop silently, unless the user was doing an si/ni, in which
case she'd better know what she's doing. */
- if (PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+ if (PC_IN_CALL_DUMMY (stop_pc, read_sp (), FRAME_FP (get_current_frame ()))
&& !step_range_end)
{
stop_print_frame = 0;
step range and either the stack or frame pointers
just changed, we've stepped outside */
&& !(stop_pc == step_range_start
- && stop_frame_address
- && (stop_sp INNER_THAN prev_sp
- || stop_frame_address != step_frame_address)))
+ && FRAME_FP (get_current_frame ())
+ && (read_sp () INNER_THAN step_sp
+ || FRAME_FP (get_current_frame ()) != step_frame_address)))
{
/* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal.
So definately need to check for sigtramp here. */
goto check_sigtramp2;
}
- /* We stepped out of the stepping range. See if that was due
- to a subroutine call that we should proceed to the end of. */
+ /* We stepped out of the stepping range. */
+
+ /* We can't update step_sp every time through the loop, because
+ reading the stack pointer would slow down stepping too much.
+ But we can update it every time we leave the step range. */
+ update_step_sp = 1;
/* Did we just take a signal? */
if (IN_SIGTRAMP (stop_pc, stop_func_name)
sr_sal.symtab = NULL;
sr_sal.line = 0;
/* We could probably be setting the frame to
- prev_frame_address; the reason we don't is that it didn't used
- to exist. */
+ step_frame_address; I don't think anyone thought to try it. */
step_resume_breakpoint =
set_momentary_breakpoint (sr_sal, NULL, bp_step_resume);
if (breakpoints_inserted)
}
#if 1
+ /* See if we left the step range due to a subroutine call that
+ we should proceed to the end of. */
+
if (stop_func_start)
{
struct symtab *s;
/* Might be a recursive call if either we have a prologue
or the call instruction itself saves the PC on the stack. */
|| prologue_pc != stop_func_start
- || stop_sp != prev_sp)
+ || read_sp () != step_sp)
&& (/* PC is completely out of bounds of any known objfiles. Treat
like a subroutine call. */
! stop_func_start
|| stop_pc < prologue_pc
+ /* ...and if it is a leaf function, the prologue might
+ consist of gp loading only, so the call transfers to
+ the first instruction after the prologue. */
+ || (stop_pc == prologue_pc
+
+ /* Distinguish this from the case where we jump back
+ to the first instruction after the prologue,
+ within a function. */
+ && stop_func_start != prev_func_start)
+
/* If we end up in certain places, it means we did a subroutine
call. I'm not completely sure this is necessary now that we
have the above checks with stop_func_start (and now that
find_pc_partial_function is pickier). */
- || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name)
+ || IN_SOLIB_CALL_TRAMPOLINE (stop_pc, stop_func_name)
/* If none of the above apply, it is a jump within a function,
or a return from a subroutine. The other case is longjmp,
step_resume_breakpoint =
set_momentary_breakpoint (sr_sal, get_current_frame (),
bp_step_resume);
- step_resume_breakpoint->frame = prev_frame_address;
+ step_resume_breakpoint->frame = step_frame_address;
if (breakpoints_inserted)
insert_breakpoints ();
}
break;
}
+ /* If we're in the return path from a shared library trampoline,
+ we want to proceed through the trampoline when stepping. */
+ if (IN_SOLIB_RETURN_TRAMPOLINE(stop_pc, stop_func_name))
+ {
+ CORE_ADDR tmp;
+
+ /* Determine where this trampoline returns. */
+ tmp = SKIP_TRAMPOLINE_CODE (stop_pc);
+
+ /* Only proceed through if we know where it's going. */
+ if (tmp)
+ {
+ /* And put the step-breakpoint there and go until there. */
+ struct symtab_and_line sr_sal;
+
+ sr_sal.pc = tmp;
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ /* 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. */
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, NULL, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+
+ /* Restart without fiddling with the step ranges or
+ other state. */
+ goto keep_going;
+ }
+ }
+
if (sal.line == 0)
{
/* We have no line number information. That means to stop
been at the start of a
function. */
prev_func_name = stop_func_name;
- prev_sp = stop_sp;
- prev_frame_address = stop_frame_address;
+
+ if (update_step_sp)
+ step_sp = read_sp ();
+ update_step_sp = 0;
/* If we did not do break;, it means we should keep
running the inferior and not return to debugger. */
prev_pc = read_pc ();
prev_func_start = stop_func_start;
prev_func_name = stop_func_name;
- prev_sp = stop_sp;
- prev_frame_address = stop_frame_address;
}
do_cleanups (old_cleanups);
}
if we have one. */
if (!stop_stack_dummy)
{
+ select_frame (get_current_frame (), 0);
+
if (stop_print_frame)
{
int source_only;
source_only = bpstat_print (stop_bpstat);
source_only = source_only ||
( stop_step
- && step_frame_address == stop_frame_address
+ && step_frame_address == FRAME_FP (get_current_frame ())
&& step_start_function == find_pc_function (stop_pc));
print_stack_frame (selected_frame, -1, source_only? -1: 1);
{
inf_status->stop_signal = stop_signal;
inf_status->stop_pc = stop_pc;
- inf_status->stop_frame_address = stop_frame_address;
inf_status->stop_step = stop_step;
inf_status->stop_stack_dummy = stop_stack_dummy;
inf_status->stopped_by_random_signal = stopped_by_random_signal;
}
struct restore_selected_frame_args {
- FRAME_ADDR frame_address;
+ CORE_ADDR frame_address;
int level;
};
restore_selected_frame_args * (declared as char * for catch_errors)
telling us what frame to restore. Returns 1 for success, or 0 for
failure. An error message will have been printed on error. */
+
static int
restore_selected_frame (args)
char *args;
{
struct restore_selected_frame_args *fr =
(struct restore_selected_frame_args *) args;
- FRAME fid;
+ struct frame_info *frame;
int level = fr->level;
- fid = find_relative_frame (get_current_frame (), &level);
+ frame = find_relative_frame (get_current_frame (), &level);
/* If inf_status->selected_frame_address is NULL, there was no
previously selected frame. */
- if (fid == 0 ||
- FRAME_FP (fid) != fr->frame_address ||
+ if (frame == NULL ||
+ FRAME_FP (frame) != fr->frame_address ||
level != 0)
{
warning ("Unable to restore previously selected frame.\n");
return 0;
}
- select_frame (fid, fr->level);
+ select_frame (frame, fr->level);
return(1);
}
{
stop_signal = inf_status->stop_signal;
stop_pc = inf_status->stop_pc;
- stop_frame_address = inf_status->stop_frame_address;
stop_step = inf_status->stop_step;
stop_stack_dummy = inf_status->stop_stack_dummy;
stopped_by_random_signal = inf_status->stopped_by_random_signal;