-/* Target independent code for starting (run) and stoping an inferior
- process.
-
- Copyright 1986, 1987, 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
+/* Target-struct-independent code to start (run) and stop an inferior process.
+ Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993
+ Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include <string.h>
+#include <ctype.h>
#include "symtab.h"
#include "frame.h"
#include "inferior.h"
#include "breakpoint.h"
#include "wait.h"
#include "gdbcore.h"
-#include "command.h"
+#include "gdbcmd.h"
#include "target.h"
#include <signal.h>
static void
resume_cleanups PARAMS ((int));
-extern struct target_ops child_ops; /* In inftarg.c */
-
-/* Sigtramp is a routine that the kernel calls (which then calls the
- signal handler). On most machines it is a library routine that
- is linked into the executable.
-
- This macro, given a program counter value and the name of the
- function in which that PC resides (which can be null if the
- name is not known), returns nonzero if the PC and name show
- that we are in sigtramp.
-
- On most machines just see if the name is sigtramp (and if we have
- no name, assume we are not in sigtramp). */
-#if !defined (IN_SIGTRAMP)
-#define IN_SIGTRAMP(pc, name) \
- (name && !strcmp ("_sigtramp", name))
-#endif
+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
#define IN_SOLIB_TRAMPOLINE(pc,name) 0
#endif
-/* Notify other parts of gdb that might care that signal handling may
- have changed for one or more signals. */
-#ifndef NOTICE_SIGNAL_HANDLING_CHANGE
-#define NOTICE_SIGNAL_HANDLING_CHANGE /* No actions */
+/* On some systems, the PC may be left pointing at an instruction that won't
+ actually be executed. This is usually indicated by a bit in the PSW. If
+ we find ourselves in such a state, then we step the target beyond the
+ nullified instruction before returning control to the user so as to avoid
+ confusion. */
+
+#ifndef INSTRUCTION_NULLIFIED
+#define INSTRUCTION_NULLIFIED 0
#endif
#ifdef TDESC
(flags)[signum] = 0; \
} while (0)
+
+/* Command list pointer for the "stop" placeholder. */
+
+static struct cmd_list_element *stop_command;
+
/* Nonzero if breakpoints are now inserted in the inferior. */
-/* Nonstatic for initialization during xxx_create_inferior. FIXME. */
-/*static*/ int breakpoints_inserted;
+static int breakpoints_inserted;
/* Function inferior was in as of last step command. */
oneproc = 1;
}
else
- {
- write_register (PC_REGNUM, addr);
-#ifdef NPC_REGNUM
- write_register (NPC_REGNUM, addr + 4);
-#ifdef NNPC_REGNUM
- write_register (NNPC_REGNUM, addr + 8);
-#endif
-#endif
- }
+ write_pc (addr);
if (trap_expected_after_continue)
{
int remove_breakpoints_on_following_step = 0;
int current_line;
int handling_longjmp = 0; /* FIXME */
+ struct symtab *symtab;
sal = find_pc_line(prev_pc, 0);
current_line = sal.line;
single_step (0); /* This actually cleans up the ss */
#endif /* NO_SINGLE_STEP */
+/* If PC is pointing at a nullified instruction, then step beyond it so that
+ the user won't be confused when GDB appears to be ready to execute it. */
+
+ if (INSTRUCTION_NULLIFIED)
+ {
+ resume (1, 0);
+ continue;
+ }
+
stop_pc = read_pc ();
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
read_pc ()));
stop_frame_address = FRAME_FP (get_current_frame ());
stop_sp = read_register (SP_REGNUM);
+/* XXX - FIXME. Need to figure out a better way to grab the stack seg reg. */
+#ifdef GDB_TARGET_IS_H8500
+ stop_sp |= read_register (SEG_T_REGNUM) << 16;
+#endif
stop_func_start = 0;
stop_func_name = 0;
/* Don't care about return value; stop_func_start and stop_func_name
if (DECR_PC_AFTER_BREAK)
{
stop_pc -= DECR_PC_AFTER_BREAK;
- write_register (PC_REGNUM, stop_pc);
- pc_changed = 0;
+ write_pc (stop_pc);
}
}
else
else if (printed)
target_terminal_inferior ();
+ /* Clear the signal if it should not be passed. */
+ if (signal_program[stop_signal] == 0)
+ stop_signal = 0;
+
/* Note that virtually all the code below does `if !random_signal'.
Perhaps this code should end with a goto or continue. At least
one (now fixed) bug was caused by this -- a !random_signal was
/* Handle cases caused by hitting a breakpoint. */
if (!random_signal)
- if (bpstat_explains_signal (stop_bpstat))
- {
- CORE_ADDR jmp_buf_pc;
+ {
+ CORE_ADDR jmp_buf_pc;
+ enum bpstat_what what = bpstat_what (stop_bpstat);
- switch (stop_bpstat->breakpoint_at->type) /* FIXME */
- {
- /* If we hit the breakpoint at longjmp, disable it for the
- duration of this command. Then, install a temporary
- breakpoint at the target of the jmp_buf. */
- case bp_longjmp:
- disable_longjmp_breakpoint();
- remove_breakpoints ();
- breakpoints_inserted = 0;
- if (!GET_LONGJMP_TARGET(&jmp_buf_pc)) goto keep_going;
+ switch (what)
+ {
+ case BPSTAT_WHAT_SET_LONGJMP_RESUME:
+ /* If we hit the breakpoint at longjmp, disable it for the
+ duration of this command. Then, install a temporary
+ breakpoint at the target of the jmp_buf. */
+ disable_longjmp_breakpoint();
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ if (!GET_LONGJMP_TARGET(&jmp_buf_pc)) goto keep_going;
- /* Need to blow away step-resume breakpoint, as it
- interferes with us */
- remove_step_breakpoint ();
- step_resume_break_address = 0;
- stop_step_resume_break = 0;
+ /* Need to blow away step-resume breakpoint, as it
+ interferes with us */
+ remove_step_breakpoint ();
+ step_resume_break_address = 0;
+ stop_step_resume_break = 0;
-#if 0 /* FIXME - Need to implement nested temporary breakpoints */
- if (step_over_calls > 0)
- set_longjmp_resume_breakpoint(jmp_buf_pc,
- get_current_frame());
- else
+#if 0
+ /* FIXME - Need to implement nested temporary breakpoints */
+ if (step_over_calls > 0)
+ set_longjmp_resume_breakpoint(jmp_buf_pc,
+ get_current_frame());
+ else
#endif /* 0 */
- set_longjmp_resume_breakpoint(jmp_buf_pc, NULL);
- handling_longjmp = 1; /* FIXME */
- goto keep_going;
+ set_longjmp_resume_breakpoint(jmp_buf_pc, NULL);
+ handling_longjmp = 1; /* FIXME */
+ goto keep_going;
- case bp_longjmp_resume:
- remove_breakpoints ();
- breakpoints_inserted = 0;
-#if 0 /* FIXME - Need to implement nested temporary breakpoints */
- if (step_over_calls
- && (stop_frame_address
- INNER_THAN step_frame_address))
- {
- another_trap = 1;
- goto keep_going;
- }
+ case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
+ case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE:
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+#if 0
+ /* FIXME - Need to implement nested temporary breakpoints */
+ if (step_over_calls
+ && (stop_frame_address
+ INNER_THAN step_frame_address))
+ {
+ another_trap = 1;
+ goto keep_going;
+ }
#endif /* 0 */
- disable_longjmp_breakpoint();
- handling_longjmp = 0; /* FIXME */
+ disable_longjmp_breakpoint();
+ handling_longjmp = 0; /* FIXME */
+ if (what == BPSTAT_WHAT_CLEAR_LONGJMP_RESUME)
break;
+ /* else fallthrough */
- default:
- fprintf(stderr, "Unknown breakpoint type %d\n",
- stop_bpstat->breakpoint_at->type);
- case bp_watchpoint:
- case bp_breakpoint:
- case bp_until:
- case bp_finish:
- /* Does a breakpoint want us to stop? */
- if (bpstat_stop (stop_bpstat))
- {
- stop_print_frame = bpstat_should_print (stop_bpstat);
- goto stop_stepping;
- }
- /* Otherwise, must remove breakpoints and single-step
- to get us past the one we hit. */
- else
- {
- remove_breakpoints ();
- remove_step_breakpoint ();
- breakpoints_inserted = 0;
- another_trap = 1;
- }
- break;
- }
- }
- else if (stop_step_resume_break)
+ case BPSTAT_WHAT_SINGLE:
+ if (breakpoints_inserted)
+ remove_breakpoints ();
+ remove_step_breakpoint ();
+ breakpoints_inserted = 0;
+ another_trap = 1;
+ /* Still need to check other stuff, at least the case
+ where we are stepping and step out of the right range. */
+ break;
+
+ case BPSTAT_WHAT_STOP_NOISY:
+ stop_print_frame = 1;
+ goto stop_stepping;
+
+ case BPSTAT_WHAT_STOP_SILENT:
+ stop_print_frame = 0;
+ goto stop_stepping;
+
+ case BPSTAT_WHAT_KEEP_CHECKING:
+ break;
+ }
+
+ if (stop_step_resume_break)
{
/* But if we have hit the step-resumption breakpoint,
remove it. It has done its job getting us here.
another_trap = 1;
}
}
+ }
/* We come here if we hit a breakpoint but should not
stop for it. Possibly we also were stepping
to a subroutine call that we should proceed to the end of. */
else if (!random_signal && step_range_end)
{
- if (stop_func_start)
- {
- prologue_pc = stop_func_start;
- SKIP_PROLOGUE (prologue_pc);
- }
-
/* Did we just take a signal? */
if (IN_SIGTRAMP (stop_pc, stop_func_name)
&& !IN_SIGTRAMP (prev_pc, prev_func_name))
goto save_pc;
}
+ if (stop_func_start)
+ {
+ /* Do this after the IN_SIGTRAMP check; it might give
+ an error. */
+ prologue_pc = stop_func_start;
+ SKIP_PROLOGUE (prologue_pc);
+ }
+
/* ==> See comments at top of file on this algorithm. <==*/
if ((stop_pc == stop_func_start
if (tmp != 0)
stop_func_start = tmp;
- if (find_pc_function (stop_func_start) != 0)
- goto step_into_function;
+ symtab = find_pc_symtab (stop_func_start);
+ if (symtab && LINETABLE (symtab))
+ goto step_into_function;
step_over_function:
/* A subroutine call has happened. */
target_terminal_ours ();
+ /* Look up the hook_stop and run it if it exists. */
+
+ if (stop_command->hook)
+ {
+ catch_errors (hook_stop_stub, (char *)stop_command->hook,
+ "Error while running hook_stop:\n");
+ }
+
if (!target_has_stack)
return;
select_frame (get_current_frame (), 0);
}
}
+
+static int
+hook_stop_stub (cmd)
+ char *cmd;
+{
+ execute_user_command ((struct cmd_list_element *)cmd, 0);
+ return (0);
+}
+
\f
static void
insert_step_breakpoint ()
argv++;
}
- NOTICE_SIGNAL_HANDLING_CHANGE;
+ target_notice_signals();
if (from_tty)
{
Ignore is a synonym for nopass and noignore is a synonym for pass.\n\
Pass and Stop may be combined.");
+ stop_command = add_cmd ("stop", class_obscure, not_just_help_class_command,
+ "There is no `stop' command, but you can set a hook on `stop'.\n\
+This allows you to set a list of commands to be run each time execution\n\
+of the inferior program stops.", &cmdlist);
+
numsigs = signo_max () + 1;
signal_stop = (unsigned char *)
xmalloc (sizeof (signal_stop[0]) * numsigs);