📄 process.c
字号:
/* * Copyright (c) 1983 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)process.c 5.6 (Berkeley) 6/1/90";#endif /* not lint *//* * Process management. * * This module contains the routines to manage the execution and * tracing of the debuggee process. */#include "defs.h"#include "process.h"#include "machine.h"#include "events.h"#include "tree.h"#include "eval.h"#include "operators.h"#include "source.h"#include "object.h"#include "mappings.h"#include "main.h"#include "coredump.h"#include <signal.h>#include <errno.h>#include <sys/stat.h>#ifndef publictypedef struct Process *Process;Process process;#define DEFSIG -1#include "machine.h"#endif#define NOTSTARTED 1#define STOPPED 0177#define FINISHED 0/* * A cache of the instruction segment is kept to reduce the number * of system calls. Might be better just to read the entire * code space into memory. */#define CACHESIZE 1003typedef struct { Word addr; Word val;} CacheWord;/* * This structure holds the information we need from the user structure. */struct Process { int pid; /* process being traced */ int mask; /* process status word */ Word reg[NREG]; /* process' registers */ Word oreg[NREG]; /* registers when process last stopped */ short status; /* either STOPPED or FINISHED */ short signo; /* signal that stopped process */ short sigcode; /* extra signal information */ int exitval; /* return value from exit() */ long sigset; /* bit array of traced signals */ CacheWord word[CACHESIZE]; /* text segment cache */ Ttyinfo ttyinfo; /* process' terminal characteristics */ Address sigstatus; /* process' handler for current signal */};/* * These definitions are for the arguments to "pio". */typedef enum { PREAD, PWRITE } PioOp;typedef enum { TEXTSEG, DATASEG } PioSeg;private struct Process pbuf;#define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */extern int errno;private Boolean just_started;private int argc;private String argv[MAXNCMDARGS];private String infile, outfile;/* * Initialize process information. */public process_init(){ register integer i; char buf[10]; process = &pbuf; process->status = (coredump) ? STOPPED : NOTSTARTED; setsigtrace();# if vax || tahoe for (i = 0; i < NREG; i++) { sprintf(buf, "$r%d", i); defregname(identname(buf, false), i); }# ifdef vax defregname(identname("$ap", true), ARGP);# endif# else# ifdef mc68000 for (i = 0; i < 8; i++) { sprintf(buf, "$d%d", i); defregname(identname(buf, false), i); sprintf(buf, "$a%d", i); defregname(identname(buf, false), i + 8); }# endif# endif defregname(identname("$fp", true), FRP); defregname(identname("$sp", true), STKP); defregname(identname("$pc", true), PROGCTR); if (coredump) { coredump_readin(process->mask, process->reg, process->signo); pc = process->reg[PROGCTR]; } arginit();}/* * Routines to get at process information from outside this module. */public Word reg(n)Integer n;{ register Word w; if (n == NREG) { w = process->mask; } else { w = process->reg[n]; } return w;}public setreg(n, w)Integer n;Word w;{ process->reg[n] = w;}/* * Begin execution. * * We set a breakpoint at the end of the code so that the * process data doesn't disappear after the program terminates. */private Boolean remade();public start(argv, infile, outfile)String argv[];String infile, outfile;{ String pargv[4]; Node cond; if (coredump) { coredump = false; fclose(corefile); coredump_close(); } if (argv == nil) { argv = pargv; pargv[0] = objname; pargv[1] = nil; } else { argv[argc] = nil; } pstart(process, argv, infile, outfile); if (remade(objname)) { reinit(argv, infile, outfile); } if (process->status == STOPPED) { pc = CODESTART; setcurfunc(program); if (objsize != 0) { cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); event_once(cond, buildcmdlist(build(O_ENDX))); } }}/* * Check to see if the object file has changed since the symbolic * information last was read. */private time_t modtime;private Boolean remade(filename)String filename;{ struct stat s; Boolean b; stat(filename, &s); b = (Boolean) (modtime != 0 and modtime < s.st_mtime); modtime = s.st_mtime; return b;}/* * Set up what signals we want to trace. */private setsigtrace(){ register Integer i; register Process p; p = process; for (i = 1; i <= NSIG; i++) { psigtrace(p, i, true); } psigtrace(p, SIGHUP, false); psigtrace(p, SIGKILL, false); psigtrace(p, SIGALRM, false);# ifdef SIGTSTP psigtrace(p, SIGTSTP, false); psigtrace(p, SIGCONT, false);# endif psigtrace(p, SIGCHLD, false); psigtrace(p, SIGWINCH, false);}/* * Initialize the argument list. */public arginit(){ infile = nil; outfile = nil; argv[0] = objname; argc = 1;}/* * Add an argument to the list for the debuggee. */public newarg(arg)String arg;{ if (argc >= MAXNCMDARGS) { error("too many arguments"); } argv[argc++] = arg;}/* * Set the standard input for the debuggee. */public inarg(filename)String filename;{ if (infile != nil) { error("multiple input redirects"); } infile = filename;}/* * Set the standard output for the debuggee. * Probably should check to avoid overwriting an existing file. */public outarg(filename)String filename;{ if (outfile != nil) { error("multiple output redirect"); } outfile = filename;}/* * Start debuggee executing. */public run(){ process->status = STOPPED; fixbps(); curline = 0; start(argv, infile, outfile); just_started = true; isstopped = false; cont(0);}/* * Continue execution wherever we left off. * * Note that this routine never returns. Eventually bpact() will fail * and we'll call printstatus or step will call it. */typedef int Intfunc();private sig_t dbintr;private void intr();public cont(signo)integer signo;{ integer s; dbintr = signal(SIGINT, intr); if (just_started) { just_started = false; } else { if (not isstopped) { error("can't continue execution"); } isstopped = false; stepover(); } s = signo; for (;;) { if (single_stepping) { printnews(); } else { setallbps(); resume(s); unsetallbps(); s = DEFSIG; if (not isbperr() or not bpact()) { printstatus(); } } stepover(); } /* NOTREACHED */}/* * This routine is called if we get an interrupt while "running" * but actually in the debugger. Could happen, for example, while * processing breakpoints. * * We basically just want to keep going; the assumption is * that when the process resumes it will get the interrupt, * which will then be handled. */private void intr(){ signal(SIGINT, intr);}public fixintr(){ signal(SIGINT, dbintr);}/* * Resume execution. */public resume(signo)int signo;{ register Process p; p = process; pcont(p, signo); pc = process->reg[PROGCTR]; if (p->status != STOPPED) { if (p->signo != 0) { error("program terminated by signal %d", p->signo); } else if (not runfirst) { if (p->exitval == 0) { error("program exited"); } else { error("program exited with code %d", p->exitval); } } }}/* * Continue execution up to the next source line. * * There are two ways to define the next source line depending on what * is desired when a procedure or function call is encountered. Step * stops at the beginning of the procedure or call; next skips over it. *//* * Stepc is what is called when the step command is given. * It has to play with the "isstopped" information. */public stepc(){ if (not isstopped) { error("can't continue execution"); } isstopped = false; dostep(false); isstopped = true;}public next(){ Address oldfrp, newfrp; if (not isstopped) { error("can't continue execution"); } isstopped = false; oldfrp = reg(FRP); do { dostep(true); pc = reg(PROGCTR); newfrp = reg(FRP); } while (newfrp < oldfrp and newfrp != 0); isstopped = true;}/* * Continue execution until the current function returns, or, * if the given argument is non-nil, until execution returns to * somewhere within the given function. */public rtnfunc (f)Symbol f;{ Address addr; Symbol t; if (not isstopped) { error("can't continue execution"); } else if (f != nil and not isactive(f)) { error("%s is not active", symname(f)); } else { addr = return_addr(); if (addr == nil) { error("no place to return to"); } else { isstopped = false; contto(addr); if (f != nil) { for (;;) { t = whatblock(pc); addr = return_addr(); if (t == f or addr == nil) break; contto(addr); } } if (not bpact()) { isstopped = true; printstatus(); } } }}/* * Single-step over the current machine instruction.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -