⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 infrun.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Target-struct-independent code to start (run) and stop an inferior process.   Copyright 1986, 1987, 1988, 1989, 1991, 1992 Free Software Foundation, Inc.This file is part of GDB.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *//* Notes on the algorithm used in wait_for_inferior to determine if we   just did a subroutine call when stepping.  We have the following   information at that point:                  Current and previous (just before this step) pc.		  Current and previous sp.		  Current and previous start of current function.   If the starts of the functions don't match, then   	a) We did a subroutine call.   In this case, the pc will be at the beginning of a function.	b) We did a subroutine return.   Otherwise.	c) We did a longjmp.   If we did a longjump, we were doing "nexti", since a next would   have attempted to skip over the assembly language routine in which   the longjmp is coded and would have simply been the equivalent of a   continue.  I consider this ok behaivior.  We'd like one of two   things to happen if we are doing a nexti through the longjmp()   routine: 1) It behaves as a stepi, or 2) It acts like a continue as   above.  Given that this is a special case, and that anybody who   thinks that the concept of sub calls is meaningful in the context   of a longjmp, I'll take either one.  Let's see what happens.     Acts like a subroutine return.  I can handle that with no problem   at all.   -->So: If the current and previous beginnings of the current   function don't match, *and* the pc is at the start of a function,   we've done a subroutine call.  If the pc is not at the start of a   function, we *didn't* do a subroutine call.     -->If the beginnings of the current and previous function do match,   either:    	a) We just did a recursive call.	   In this case, we would be at the very beginning of a	   function and 1) it will have a prologue (don't jump to	   before prologue, or 2) (we assume here that it doesn't have	   a prologue) there will have been a change in the stack	   pointer over the last instruction.  (Ie. it's got to put	   the saved pc somewhere.  The stack is the usual place.  In	   a recursive call a register is only an option if there's a	   prologue to do something with it.  This is even true on	   register window machines; the prologue sets up the new	   window.  It might not be true on a register window machine	   where the call instruction moved the register window	   itself.  Hmmm.  One would hope that the stack pointer would	   also change.  If it doesn't, somebody send me a note, and	   I'll work out a more general theory.	   bug-gdb@prep.ai.mit.edu).  This is true (albeit slipperly	   so) on all machines I'm aware of:	      m68k:	Call changes stack pointer.  Regular jumps don't.	      sparc:	Recursive calls must have frames and therefor,	                prologues.	      vax:	All calls have frames and hence change the	                stack pointer.	b) We did a return from a recursive call.  I don't see that we	   have either the ability or the need to distinguish this	   from an ordinary jump.  The stack frame will be printed	   when and if the frame pointer changes; if we are in a	   function without a frame pointer, it's the users own	   lookout.	c) We did a jump within a function.  We assume that this is	   true if we didn't do a recursive call.	d) We are in no-man's land ("I see no symbols here").  We	   don't worry about this; it will make calls look like simple	   jumps (and the stack frames will be printed when the frame	   pointer moves), which is a reasonably non-violent response.*/#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 "gdbcmd.h"#include "target.h"#include <signal.h>/* unistd.h is needed to #define X_OK */#ifdef USG#include <unistd.h>#else#include <sys/file.h>#endif/* Prototypes for local functions */static voidsignals_info PARAMS ((char *, int));static voidhandle_command PARAMS ((char *, int));static voidsig_print_info PARAMS ((int));static voidsig_print_header PARAMS ((void));static voidremove_step_breakpoint PARAMS ((void));static voidinsert_step_breakpoint PARAMS ((void));static voidresume_cleanups PARAMS ((int));static inthook_stop_stub PARAMS ((char *));/* 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/* 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 ".init" section.  IN_SOLIB_TRAMPOLINE evaluates   to nonzero if we are current stopped in one of these. */#ifndef IN_SOLIB_TRAMPOLINE#define IN_SOLIB_TRAMPOLINE(pc,name)	0#endif#ifdef TDESC#include "tdesc.h"int safe_to_init_tdesc_context = 0;extern dc_dcontext_t current_context;#endif/* Tables of how to react to signals; the user sets them.  */static unsigned char *signal_stop;static unsigned char *signal_print;static unsigned char *signal_program;#define SET_SIGS(nsigs,sigs,flags) \  do { \    int signum = (nsigs); \    while (signum-- > 0) \      if ((sigs)[signum]) \	(flags)[signum] = 1; \  } while (0)#define UNSET_SIGS(nsigs,sigs,flags) \  do { \    int signum = (nsigs); \    while (signum-- > 0) \      if ((sigs)[signum]) \	(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.  */static int breakpoints_inserted;/* Function inferior was in as of last step command.  */static struct symbol *step_start_function;/* Nonzero => address for special breakpoint for resuming stepping.  */static CORE_ADDR step_resume_break_address;/* Pointer to orig contents of the byte where the special breakpoint is.  */static char step_resume_break_shadow[BREAKPOINT_MAX];/* Nonzero means the special breakpoint is a duplicate   so it has not itself been inserted.  */static int step_resume_break_duplicate;/* Nonzero if we are expecting a trace trap and should proceed from it.  */static int trap_expected;/* Nonzero if the next time we try to continue the inferior, it will   step one instruction and generate a spurious trace trap.   This is used to compensate for a bug in HP-UX.  */static int trap_expected_after_continue;/* Nonzero means expecting a trace trap   and should stop the inferior and return silently when it happens.  */int stop_after_trap;/* Nonzero means expecting a trap and caller will handle it themselves.   It is used after attach, due to attaching to a process;   when running in the shell before the child program has been exec'd;   and when running some kinds of remote stuff (FIXME?).  */int stop_soon_quietly;/* Nonzero if pc has been changed by the debugger   since the inferior stopped.  */int pc_changed;/* Nonzero if program stopped due to error trying to insert breakpoints.  */static int breakpoints_failed;/* Nonzero after stop if current stack frame should be printed.  */static int stop_print_frame;#ifdef NO_SINGLE_STEPextern int one_stepped;		/* From machine dependent code */extern void single_step ();	/* Same. */#endif /* NO_SINGLE_STEP *//* Things to clean up if we QUIT out of resume ().  *//* ARGSUSED */static voidresume_cleanups (arg)     int arg;{  normal_stop ();}/* 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   we get a SIGINT random_signal, but for remote debugging and perhaps   other targets, that's not true).   STEP nonzero if we should step (zero to continue instead).   SIG is the signal to give the inferior (zero for none).  */voidresume (step, sig)     int step;     int sig;{  struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);  QUIT;#ifdef NO_SINGLE_STEP  if (step) {    single_step(sig);	/* Do it the hard way, w/temp breakpoints */    step = 0;		/* ...and don't ask hardware to do it.  */  }#endif  /* Handle any optimized stores to the inferior NOW...  */#ifdef DO_DEFERRED_STORES  DO_DEFERRED_STORES;#endif  target_resume (step, sig);  discard_cleanups (old_cleanups);}/* Clear out all variables saying what to do when inferior is continued.   First do this, then set the ones you want, then call `proceed'.  */voidclear_proceed_status (){  trap_expected = 0;  step_range_start = 0;  step_range_end = 0;  step_frame_address = 0;  step_over_calls = -1;  step_resume_break_address = 0;  stop_after_trap = 0;  stop_soon_quietly = 0;  breakpoint_proceeded = 1;	/* We're about to proceed... */  /* Discard any remaining commands or status from previous stop.  */  bpstat_clear (&stop_bpstat);}/* Basic routine for continuing the program in various fashions.   ADDR is the address to resume at, or -1 for resume where stopped.   SIGGNAL is the signal to give it, or 0 for none,     or -1 for act according to how it stopped.   STEP is nonzero if should trap after one instruction.     -1 means return after that and print nothing.     You should probably set various step_... variables     before calling here, if you are stepping.   You should call clear_proceed_status before calling proceed.  */voidproceed (addr, siggnal, step)     CORE_ADDR addr;     int siggnal;     int step;{  int oneproc = 0;  if (step > 0)    step_start_function = find_pc_function (read_pc ());  if (step < 0)    stop_after_trap = 1;  if (addr == (CORE_ADDR)-1)    {      /* If there is a breakpoint at the address we will resume at,	 step one instruction before inserting breakpoints	 so that we do not stop right away.  */      if (!pc_changed && breakpoint_here_p (read_pc ()))	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    }  if (trap_expected_after_continue)    {      /* If (step == 0), a trap will be automatically generated after	 the first instruction is executed.  Force step one	 instruction to clear this condition.  This should not occur	 if step is nonzero, but it is harmless in that case.  */      oneproc = 1;      trap_expected_after_continue = 0;    }  if (oneproc)    /* We will get a trace trap after one instruction.       Continue it automatically and insert breakpoints then.  */    trap_expected = 1;  else    {      int temp = insert_breakpoints ();      if (temp)	{	  print_sys_errmsg ("ptrace", temp);	  error ("Cannot insert breakpoints.\n\The same program may be running in another process.");	}      breakpoints_inserted = 1;    }  /* Install inferior's terminal modes.  */  target_terminal_inferior ();  if (siggnal >= 0)    stop_signal = siggnal;  /* If this signal should not be seen by program,     give it zero.  Used for debugging signals.  */  else if (stop_signal < NSIG && !signal_program[stop_signal])    stop_signal= 0;  /* Resume inferior.  */  resume (oneproc || step || bpstat_should_step (), stop_signal);  /* Wait for it to stop (if not standalone)     and in any case decode why it stopped, and act accordingly.  */  wait_for_inferior ();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -