📄 process.c
字号:
/*#@(#)process.c 4.1 Ultrix 7/17/90*//* Copyright (c) 1982 Regents of the University of California */static char sccsid[] = "@(#)process.c 1.12 8/19/83";static char rcsid[] = "$Header: process.c,v 1.3 84/03/27 10:23:24 linton Exp $";/* * 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/param.h>#include <sys/dir.h>#include <sys/user.h>#include <machine/reg.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 CSIZE 1003 /* size of instruction cache */typedef 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 */ int exitval; /* return value from exit() */ long sigset; /* bit array of traced signals */ CacheWord word[CSIZE]; /* 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 100 /* 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(); for (i = 0; i < NREG; i++) { sprintf(buf, "$r%d", i); defregname(identname(buf, false), i); } defregname(identname("$ap", true), ARGP); 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]; getsrcpos(); } 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; } if (remade(objname)) { reinit(argv, infile, outfile); } pstart(process, argv, infile, outfile); if (process->status == STOPPED) { pc = 0; 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); psigtrace(p, SIGTSTP, false); psigtrace(p, SIGCONT, false); psigtrace(p, SIGCHLD, 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 Intfunc *dbintr;private intr();#define succeeds == true#define fails == falsepublic 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 (bpact() fails) { printstatus(); } } stepover(); } /* NOTREACHED */}/* * This routine is called if we get an interrupt while "running" px * 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 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) { error("program unexpectedly exited with %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 (bpact() fails) { isstopped = true; printstatus(); } } }}/* * Single-step over the current machine instruction. * * If we're single-stepping by source line we want to step to the * next source line. Otherwise we're going to continue so there's * no reason to do all the work necessary to single-step to the next * source line. */public stepover(){ Boolean b; if (traceexec) { printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); } if (single_stepping) { dostep(false); } else { b = inst_tracing; inst_tracing = true; dostep(false); inst_tracing = b; } if (traceexec) { printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); }}/* * Resume execution up to the given address. It is assumed that * no breakpoints exist between the current address and the one * we're stepping to. This saves us from setting all the breakpoints. */public stepto(addr)Address addr;{ xto(addr, false);}private contto (addr)Address addr;{ xto(addr, true);}private xto (addr, catchbps)Address addr;boolean catchbps;{ Address curpc; if (catchbps) { stepover(); } curpc = process->reg[PROGCTR]; if (addr != curpc) { if (traceexec) { printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); } if (catchbps) { setallbps(); } setbp(addr); resume(DEFSIG); unsetbp(addr); if (catchbps) { unsetallbps(); } if (not isbperr()) { printstatus(); } }}/* * Print the status of the process. * This routine does not return. */public printstatus(){ int status; if (process->status == FINISHED) { exit(0); } else { setcurfunc(whatblock(pc)); getsrcpos(); if (process->signo == SIGINT) { isstopped = true; printerror(); } else if (isbperr() and isstopped) { printf("stopped "); printloc(); putchar('\n'); if (curline > 0) { printlines(curline, curline); } else { printinst(pc, pc); } erecover(); } else { fixintr(); isstopped = true; printerror(); } }}/* * Print out the current location in the debuggee. */public printloc(){ printf("in "); printname(stdout, curfunc); putchar(' '); if (curline > 0 and not useInstLoc) { printsrcpos(); } else { useInstLoc = false; curline = 0; printf("at 0x%x", pc); }}/* * Some functions for testing the state of the process. */public Boolean notstarted(p)Process p;{ return (Boolean) (p->status == NOTSTARTED);}public Boolean isfinished(p)Process p;{ return (Boolean) (p->status == FINISHED);}/* * Return the signal number which stopped the process. */public Integer errnum(p)Process p;{ return p->signo;}/* * Return the termination code of the process. */public Integer exitcode(p)Process p;{ return p->exitval;}/* * These routines are used to access the debuggee process from * outside this module. * * They invoke "pio" which eventually leads to a call to "ptrace". * The system generates an I/O error when a ptrace fails. During reads * these are ignored, during writes they are reported as an error, and * for anything else they cause a fatal error. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -