121620Sdist /* 238105Sbostic * Copyright (c) 1983 The Regents of the University of California. 338105Sbostic * All rights reserved. 438105Sbostic * 538105Sbostic * Redistribution and use in source and binary forms are permitted 638105Sbostic * provided that the above copyright notice and this paragraph are 738105Sbostic * duplicated in all such forms and that any documentation, 838105Sbostic * advertising materials, and other materials related to such 938105Sbostic * distribution and use acknowledge that the software was developed 1038105Sbostic * by the University of California, Berkeley. The name of the 1138105Sbostic * University may not be used to endorse or promote products derived 1238105Sbostic * from this software without specific prior written permission. 1338105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1438105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1538105Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621620Sdist */ 179677Slinton 1821620Sdist #ifndef lint 19*39163Sbostic static char sccsid[] = "@(#)process.c 5.5 (Berkeley) 09/15/89"; 2038105Sbostic #endif /* not lint */ 219677Slinton 229677Slinton /* 239677Slinton * Process management. 249677Slinton * 259677Slinton * This module contains the routines to manage the execution and 269677Slinton * tracing of the debuggee process. 279677Slinton */ 289677Slinton 299677Slinton #include "defs.h" 309677Slinton #include "process.h" 319677Slinton #include "machine.h" 329677Slinton #include "events.h" 339677Slinton #include "tree.h" 3414757Slinton #include "eval.h" 359677Slinton #include "operators.h" 369677Slinton #include "source.h" 379677Slinton #include "object.h" 389677Slinton #include "mappings.h" 399677Slinton #include "main.h" 409677Slinton #include "coredump.h" 419677Slinton #include <signal.h> 429677Slinton #include <errno.h> 439677Slinton #include <sys/stat.h> 449677Slinton 459677Slinton #ifndef public 469677Slinton 479677Slinton typedef struct Process *Process; 489677Slinton 499677Slinton Process process; 509677Slinton 5114757Slinton #define DEFSIG -1 5214757Slinton 539677Slinton #include "machine.h" 549677Slinton 559677Slinton #endif 569677Slinton 579677Slinton #define NOTSTARTED 1 589677Slinton #define STOPPED 0177 599677Slinton #define FINISHED 0 609677Slinton 619677Slinton /* 6216617Ssam * A cache of the instruction segment is kept to reduce the number 6316617Ssam * of system calls. Might be better just to read the entire 6416617Ssam * code space into memory. 659677Slinton */ 669677Slinton 6733331Sdonn #define CACHESIZE 1003 689677Slinton 699677Slinton typedef struct { 709677Slinton Word addr; 719677Slinton Word val; 729677Slinton } CacheWord; 739677Slinton 749677Slinton /* 759677Slinton * This structure holds the information we need from the user structure. 769677Slinton */ 779677Slinton 789677Slinton struct Process { 799677Slinton int pid; /* process being traced */ 8011768Slinton int mask; /* process status word */ 8111768Slinton Word reg[NREG]; /* process' registers */ 829677Slinton Word oreg[NREG]; /* registers when process last stopped */ 839677Slinton short status; /* either STOPPED or FINISHED */ 849677Slinton short signo; /* signal that stopped process */ 8518230Slinton short sigcode; /* extra signal information */ 869677Slinton int exitval; /* return value from exit() */ 879677Slinton long sigset; /* bit array of traced signals */ 8833331Sdonn CacheWord word[CACHESIZE]; /* text segment cache */ 8911768Slinton Ttyinfo ttyinfo; /* process' terminal characteristics */ 9016617Ssam Address sigstatus; /* process' handler for current signal */ 919677Slinton }; 929677Slinton 939677Slinton /* 949677Slinton * These definitions are for the arguments to "pio". 959677Slinton */ 969677Slinton 979677Slinton typedef enum { PREAD, PWRITE } PioOp; 989677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 999677Slinton 1009677Slinton private struct Process pbuf; 1019677Slinton 10218230Slinton #define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */ 1039677Slinton 10414395Slinton extern int errno; 10514395Slinton 1069677Slinton private Boolean just_started; 1079677Slinton private int argc; 1089677Slinton private String argv[MAXNCMDARGS]; 1099677Slinton private String infile, outfile; 1109677Slinton 1119677Slinton /* 1129677Slinton * Initialize process information. 1139677Slinton */ 1149677Slinton 1159677Slinton public process_init() 1169677Slinton { 11733331Sdonn register integer i; 11833331Sdonn char buf[10]; 1199677Slinton 1209677Slinton process = &pbuf; 1219677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 1229677Slinton setsigtrace(); 12333331Sdonn # if vax || tahoe 12433331Sdonn for (i = 0; i < NREG; i++) { 12533331Sdonn sprintf(buf, "$r%d", i); 12633331Sdonn defregname(identname(buf, false), i); 12733331Sdonn } 12833331Sdonn # ifdef vax 12933331Sdonn defregname(identname("$ap", true), ARGP); 13033331Sdonn # endif 13133331Sdonn # else 13233331Sdonn # ifdef mc68000 13333331Sdonn for (i = 0; i < 8; i++) { 13433331Sdonn sprintf(buf, "$d%d", i); 13533331Sdonn defregname(identname(buf, false), i); 13633331Sdonn sprintf(buf, "$a%d", i); 13733331Sdonn defregname(identname(buf, false), i + 8); 13833331Sdonn } 13933331Sdonn # endif 14033331Sdonn # endif 1419677Slinton defregname(identname("$fp", true), FRP); 1429677Slinton defregname(identname("$sp", true), STKP); 1439677Slinton defregname(identname("$pc", true), PROGCTR); 1449677Slinton if (coredump) { 1459677Slinton coredump_readin(process->mask, process->reg, process->signo); 14612484Slinton pc = process->reg[PROGCTR]; 1479677Slinton } 14812484Slinton arginit(); 1499677Slinton } 1509677Slinton 1519677Slinton /* 1529677Slinton * Routines to get at process information from outside this module. 1539677Slinton */ 1549677Slinton 1559677Slinton public Word reg(n) 1569677Slinton Integer n; 1579677Slinton { 1589677Slinton register Word w; 1599677Slinton 1609677Slinton if (n == NREG) { 1619677Slinton w = process->mask; 1629677Slinton } else { 1639677Slinton w = process->reg[n]; 1649677Slinton } 1659677Slinton return w; 1669677Slinton } 1679677Slinton 1689677Slinton public setreg(n, w) 1699677Slinton Integer n; 1709677Slinton Word w; 1719677Slinton { 1729677Slinton process->reg[n] = w; 1739677Slinton } 1749677Slinton 1759677Slinton /* 1769677Slinton * Begin execution. 1779677Slinton * 1789677Slinton * We set a breakpoint at the end of the code so that the 1799677Slinton * process data doesn't disappear after the program terminates. 1809677Slinton */ 1819677Slinton 1829677Slinton private Boolean remade(); 1839677Slinton 1849677Slinton public start(argv, infile, outfile) 1859677Slinton String argv[]; 1869677Slinton String infile, outfile; 1879677Slinton { 1889677Slinton String pargv[4]; 1899677Slinton Node cond; 1909677Slinton 1919677Slinton if (coredump) { 1929677Slinton coredump = false; 1939677Slinton fclose(corefile); 1949677Slinton coredump_close(); 1959677Slinton } 1969677Slinton if (argv == nil) { 1979677Slinton argv = pargv; 1989677Slinton pargv[0] = objname; 1999677Slinton pargv[1] = nil; 2009677Slinton } else { 2019677Slinton argv[argc] = nil; 2029677Slinton } 20318230Slinton pstart(process, argv, infile, outfile); 2049677Slinton if (remade(objname)) { 2059677Slinton reinit(argv, infile, outfile); 2069677Slinton } 2079677Slinton if (process->status == STOPPED) { 20833331Sdonn pc = CODESTART; 20916617Ssam setcurfunc(program); 2109677Slinton if (objsize != 0) { 2119677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 2129677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 2139677Slinton } 2149677Slinton } 2159677Slinton } 2169677Slinton 2179677Slinton /* 2189677Slinton * Check to see if the object file has changed since the symbolic 2199677Slinton * information last was read. 2209677Slinton */ 2219677Slinton 2229677Slinton private time_t modtime; 2239677Slinton 2249677Slinton private Boolean remade(filename) 2259677Slinton String filename; 2269677Slinton { 2279677Slinton struct stat s; 2289677Slinton Boolean b; 2299677Slinton 2309677Slinton stat(filename, &s); 2319677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 2329677Slinton modtime = s.st_mtime; 2339677Slinton return b; 2349677Slinton } 2359677Slinton 2369677Slinton /* 2379677Slinton * Set up what signals we want to trace. 2389677Slinton */ 2399677Slinton 2409677Slinton private setsigtrace() 2419677Slinton { 2429677Slinton register Integer i; 2439677Slinton register Process p; 2449677Slinton 2459677Slinton p = process; 2469677Slinton for (i = 1; i <= NSIG; i++) { 2479677Slinton psigtrace(p, i, true); 2489677Slinton } 2499677Slinton psigtrace(p, SIGHUP, false); 2509677Slinton psigtrace(p, SIGKILL, false); 2519677Slinton psigtrace(p, SIGALRM, false); 25233331Sdonn # ifdef SIGTSTP 25333331Sdonn psigtrace(p, SIGTSTP, false); 25433331Sdonn psigtrace(p, SIGCONT, false); 25533331Sdonn # endif 2569677Slinton psigtrace(p, SIGCHLD, false); 25726333Ssam psigtrace(p, SIGWINCH, false); 2589677Slinton } 2599677Slinton 2609677Slinton /* 2619677Slinton * Initialize the argument list. 2629677Slinton */ 2639677Slinton 2649677Slinton public arginit() 2659677Slinton { 2669677Slinton infile = nil; 2679677Slinton outfile = nil; 2689677Slinton argv[0] = objname; 2699677Slinton argc = 1; 2709677Slinton } 2719677Slinton 2729677Slinton /* 2739677Slinton * Add an argument to the list for the debuggee. 2749677Slinton */ 2759677Slinton 2769677Slinton public newarg(arg) 2779677Slinton String arg; 2789677Slinton { 2799677Slinton if (argc >= MAXNCMDARGS) { 2809677Slinton error("too many arguments"); 2819677Slinton } 2829677Slinton argv[argc++] = arg; 2839677Slinton } 2849677Slinton 2859677Slinton /* 2869677Slinton * Set the standard input for the debuggee. 2879677Slinton */ 2889677Slinton 2899677Slinton public inarg(filename) 2909677Slinton String filename; 2919677Slinton { 2929677Slinton if (infile != nil) { 2939677Slinton error("multiple input redirects"); 2949677Slinton } 2959677Slinton infile = filename; 2969677Slinton } 2979677Slinton 2989677Slinton /* 2999677Slinton * Set the standard output for the debuggee. 3009677Slinton * Probably should check to avoid overwriting an existing file. 3019677Slinton */ 3029677Slinton 3039677Slinton public outarg(filename) 3049677Slinton String filename; 3059677Slinton { 3069677Slinton if (outfile != nil) { 3079677Slinton error("multiple output redirect"); 3089677Slinton } 3099677Slinton outfile = filename; 3109677Slinton } 3119677Slinton 3129677Slinton /* 3139677Slinton * Start debuggee executing. 3149677Slinton */ 3159677Slinton 3169677Slinton public run() 3179677Slinton { 3189677Slinton process->status = STOPPED; 3199677Slinton fixbps(); 3209677Slinton curline = 0; 3219677Slinton start(argv, infile, outfile); 3229677Slinton just_started = true; 3239677Slinton isstopped = false; 32414757Slinton cont(0); 3259677Slinton } 3269677Slinton 3279677Slinton /* 3289677Slinton * Continue execution wherever we left off. 3299677Slinton * 3309677Slinton * Note that this routine never returns. Eventually bpact() will fail 3319677Slinton * and we'll call printstatus or step will call it. 3329677Slinton */ 3339677Slinton 3349677Slinton typedef int Intfunc(); 3359677Slinton 336*39163Sbostic private sig_t dbintr; 337*39163Sbostic private void intr(); 3389677Slinton 33911867Slinton public cont(signo) 34016617Ssam integer signo; 3419677Slinton { 34216617Ssam integer s; 34316617Ssam 3449677Slinton dbintr = signal(SIGINT, intr); 3459677Slinton if (just_started) { 3469677Slinton just_started = false; 3479677Slinton } else { 3489677Slinton if (not isstopped) { 3499677Slinton error("can't continue execution"); 3509677Slinton } 3519677Slinton isstopped = false; 35211867Slinton stepover(); 3539677Slinton } 35416617Ssam s = signo; 3559677Slinton for (;;) { 3569677Slinton if (single_stepping) { 3579677Slinton printnews(); 3589677Slinton } else { 3599677Slinton setallbps(); 36016617Ssam resume(s); 3619677Slinton unsetallbps(); 36216617Ssam s = DEFSIG; 36318230Slinton if (not isbperr() or not bpact()) { 3649677Slinton printstatus(); 3659677Slinton } 3669677Slinton } 36711867Slinton stepover(); 3689677Slinton } 3699677Slinton /* NOTREACHED */ 3709677Slinton } 3719677Slinton 3729677Slinton /* 37318230Slinton * This routine is called if we get an interrupt while "running" 3749677Slinton * but actually in the debugger. Could happen, for example, while 3759677Slinton * processing breakpoints. 3769677Slinton * 3779677Slinton * We basically just want to keep going; the assumption is 37818230Slinton * that when the process resumes it will get the interrupt, 3799677Slinton * which will then be handled. 3809677Slinton */ 3819677Slinton 382*39163Sbostic private void intr() 3839677Slinton { 3849677Slinton signal(SIGINT, intr); 3859677Slinton } 3869677Slinton 3879677Slinton public fixintr() 3889677Slinton { 3899677Slinton signal(SIGINT, dbintr); 3909677Slinton } 3919677Slinton 3929677Slinton /* 3939677Slinton * Resume execution. 3949677Slinton */ 3959677Slinton 39611867Slinton public resume(signo) 39711867Slinton int signo; 3989677Slinton { 3999677Slinton register Process p; 4009677Slinton 4019677Slinton p = process; 40211867Slinton pcont(p, signo); 4039677Slinton pc = process->reg[PROGCTR]; 40411832Slinton if (p->status != STOPPED) { 40511867Slinton if (p->signo != 0) { 40611867Slinton error("program terminated by signal %d", p->signo); 40714757Slinton } else if (not runfirst) { 40818230Slinton if (p->exitval == 0) { 40918230Slinton error("program exited"); 41018230Slinton } else { 41118230Slinton error("program exited with code %d", p->exitval); 41218230Slinton } 41311867Slinton } 41411832Slinton } 4159677Slinton } 4169677Slinton 4179677Slinton /* 4189677Slinton * Continue execution up to the next source line. 4199677Slinton * 4209677Slinton * There are two ways to define the next source line depending on what 4219677Slinton * is desired when a procedure or function call is encountered. Step 4229677Slinton * stops at the beginning of the procedure or call; next skips over it. 4239677Slinton */ 4249677Slinton 4259677Slinton /* 4269677Slinton * Stepc is what is called when the step command is given. 4279677Slinton * It has to play with the "isstopped" information. 4289677Slinton */ 4299677Slinton 4309677Slinton public stepc() 4319677Slinton { 4329677Slinton if (not isstopped) { 4339677Slinton error("can't continue execution"); 4349677Slinton } 4359677Slinton isstopped = false; 4369677Slinton dostep(false); 4379677Slinton isstopped = true; 4389677Slinton } 4399677Slinton 4409677Slinton public next() 4419677Slinton { 44216617Ssam Address oldfrp, newfrp; 44316617Ssam 4449677Slinton if (not isstopped) { 4459677Slinton error("can't continue execution"); 4469677Slinton } 4479677Slinton isstopped = false; 44816617Ssam oldfrp = reg(FRP); 44916617Ssam do { 45016617Ssam dostep(true); 45116617Ssam pc = reg(PROGCTR); 45216617Ssam newfrp = reg(FRP); 45316617Ssam } while (newfrp < oldfrp and newfrp != 0); 4549677Slinton isstopped = true; 4559677Slinton } 4569677Slinton 45711867Slinton /* 45816617Ssam * Continue execution until the current function returns, or, 45916617Ssam * if the given argument is non-nil, until execution returns to 46016617Ssam * somewhere within the given function. 46116617Ssam */ 46216617Ssam 46316617Ssam public rtnfunc (f) 46416617Ssam Symbol f; 46516617Ssam { 46616617Ssam Address addr; 46716617Ssam Symbol t; 46816617Ssam 46916617Ssam if (not isstopped) { 47016617Ssam error("can't continue execution"); 47116617Ssam } else if (f != nil and not isactive(f)) { 47216617Ssam error("%s is not active", symname(f)); 47316617Ssam } else { 47416617Ssam addr = return_addr(); 47516617Ssam if (addr == nil) { 47616617Ssam error("no place to return to"); 47716617Ssam } else { 47816617Ssam isstopped = false; 47916617Ssam contto(addr); 48016617Ssam if (f != nil) { 48116617Ssam for (;;) { 48216617Ssam t = whatblock(pc); 48316617Ssam addr = return_addr(); 48416617Ssam if (t == f or addr == nil) break; 48516617Ssam contto(addr); 48616617Ssam } 48716617Ssam } 48818230Slinton if (not bpact()) { 48916617Ssam isstopped = true; 49016617Ssam printstatus(); 49116617Ssam } 49216617Ssam } 49316617Ssam } 49416617Ssam } 49516617Ssam 49616617Ssam /* 49711867Slinton * Single-step over the current machine instruction. 49811867Slinton * 49911867Slinton * If we're single-stepping by source line we want to step to the 50011867Slinton * next source line. Otherwise we're going to continue so there's 50111867Slinton * no reason to do all the work necessary to single-step to the next 50211867Slinton * source line. 50311867Slinton */ 50411867Slinton 50516617Ssam public stepover() 5069677Slinton { 50711867Slinton Boolean b; 50811867Slinton 50916617Ssam if (traceexec) { 51016617Ssam printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); 51116617Ssam } 51211867Slinton if (single_stepping) { 51311867Slinton dostep(false); 51411867Slinton } else { 51511867Slinton b = inst_tracing; 51611867Slinton inst_tracing = true; 51711867Slinton dostep(false); 51811867Slinton inst_tracing = b; 51911867Slinton } 52016617Ssam if (traceexec) { 52116617Ssam printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); 52216617Ssam } 5239677Slinton } 5249677Slinton 5259677Slinton /* 52618230Slinton * Resume execution up to the given address. We can either ignore 52718230Slinton * breakpoints (stepto) or catch them (contto). 5289677Slinton */ 5299677Slinton 5309677Slinton public stepto(addr) 5319677Slinton Address addr; 5329677Slinton { 53316617Ssam xto(addr, false); 53416617Ssam } 53516617Ssam 53616617Ssam private contto (addr) 53716617Ssam Address addr; 53816617Ssam { 53916617Ssam xto(addr, true); 54016617Ssam } 54116617Ssam 54216617Ssam private xto (addr, catchbps) 54316617Ssam Address addr; 54416617Ssam boolean catchbps; 54516617Ssam { 54616617Ssam Address curpc; 54716617Ssam 54816617Ssam if (catchbps) { 54916617Ssam stepover(); 5509677Slinton } 55116617Ssam curpc = process->reg[PROGCTR]; 55216617Ssam if (addr != curpc) { 55316617Ssam if (traceexec) { 55416617Ssam printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); 55516617Ssam } 55616617Ssam if (catchbps) { 55716617Ssam setallbps(); 55816617Ssam } 55916617Ssam setbp(addr); 56016617Ssam resume(DEFSIG); 56116617Ssam unsetbp(addr); 56216617Ssam if (catchbps) { 56316617Ssam unsetallbps(); 56416617Ssam } 56516617Ssam if (not isbperr()) { 56616617Ssam printstatus(); 56716617Ssam } 56816617Ssam } 5699677Slinton } 5709677Slinton 5719677Slinton /* 5729677Slinton * Print the status of the process. 5739677Slinton * This routine does not return. 5749677Slinton */ 5759677Slinton 57633331Sdonn public printstatus () 5779677Slinton { 57814395Slinton int status; 57914395Slinton 5809843Slinton if (process->status == FINISHED) { 5819843Slinton exit(0); 5829843Slinton } else { 58333331Sdonn if (runfirst) { 58433331Sdonn fprintf(stderr, "\nEntering debugger ...\n"); 58533331Sdonn printheading(); 58633331Sdonn init(); 58733331Sdonn } 58816617Ssam setcurfunc(whatblock(pc)); 5899677Slinton getsrcpos(); 5909843Slinton if (process->signo == SIGINT) { 5919843Slinton isstopped = true; 5929843Slinton printerror(); 5939843Slinton } else if (isbperr() and isstopped) { 5949843Slinton printf("stopped "); 59511172Slinton printloc(); 59611172Slinton putchar('\n'); 5979843Slinton if (curline > 0) { 5989843Slinton printlines(curline, curline); 5999843Slinton } else { 6009843Slinton printinst(pc, pc); 6019843Slinton } 6029843Slinton erecover(); 6039677Slinton } else { 6049843Slinton fixintr(); 6059677Slinton isstopped = true; 6069677Slinton printerror(); 6079677Slinton } 6089677Slinton } 6099677Slinton } 6109677Slinton 6119677Slinton /* 61211172Slinton * Print out the current location in the debuggee. 61311172Slinton */ 61411172Slinton 61511172Slinton public printloc() 61611172Slinton { 61711172Slinton printf("in "); 61811172Slinton printname(stdout, curfunc); 61911172Slinton putchar(' '); 62014757Slinton if (curline > 0 and not useInstLoc) { 62111172Slinton printsrcpos(); 62211172Slinton } else { 62314757Slinton useInstLoc = false; 62414757Slinton curline = 0; 62511172Slinton printf("at 0x%x", pc); 62611172Slinton } 62711172Slinton } 62811172Slinton 62911172Slinton /* 6309677Slinton * Some functions for testing the state of the process. 6319677Slinton */ 6329677Slinton 6339677Slinton public Boolean notstarted(p) 6349677Slinton Process p; 6359677Slinton { 6369677Slinton return (Boolean) (p->status == NOTSTARTED); 6379677Slinton } 6389677Slinton 6399677Slinton public Boolean isfinished(p) 6409677Slinton Process p; 6419677Slinton { 6429677Slinton return (Boolean) (p->status == FINISHED); 6439677Slinton } 6449677Slinton 6459677Slinton /* 64618230Slinton * Predicate to test if the reason the process stopped was because 64718230Slinton * of a breakpoint. If so, as a side effect clear the local copy of 64818230Slinton * signal handler associated with process. We must do this so as to 64918230Slinton * not confuse future stepping or continuing by possibly concluding 65018230Slinton * the process should continue with a SIGTRAP handler. 6519677Slinton */ 6529677Slinton 65318230Slinton public boolean isbperr() 65418230Slinton { 65518230Slinton Process p; 65618230Slinton boolean b; 65718230Slinton 65818230Slinton p = process; 65918230Slinton if (p->status == STOPPED and p->signo == SIGTRAP) { 66018230Slinton b = true; 66118230Slinton p->sigstatus = 0; 66218230Slinton } else { 66318230Slinton b = false; 66418230Slinton } 66518230Slinton return b; 66618230Slinton } 66718230Slinton 66818230Slinton /* 66918230Slinton * Return the signal number that stopped the process. 67018230Slinton */ 67118230Slinton 67218230Slinton public integer errnum (p) 6739677Slinton Process p; 6749677Slinton { 6759677Slinton return p->signo; 6769677Slinton } 6779677Slinton 67818230Slinton /* 67918230Slinton * Return the signal code associated with the signal. 68018230Slinton */ 68118230Slinton 68218230Slinton public integer errcode (p) 68316931Ssam Process p; 68416931Ssam { 68516931Ssam return p->sigcode; 68616931Ssam } 68716931Ssam 6889677Slinton /* 6899677Slinton * Return the termination code of the process. 6909677Slinton */ 6919677Slinton 69218230Slinton public integer exitcode (p) 6939677Slinton Process p; 6949677Slinton { 6959677Slinton return p->exitval; 6969677Slinton } 6979677Slinton 6989677Slinton /* 6999677Slinton * These routines are used to access the debuggee process from 7009677Slinton * outside this module. 7019677Slinton * 7029677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 70314757Slinton * The system generates an I/O error when a ptrace fails. During reads 70414757Slinton * these are ignored, during writes they are reported as an error, and 70514757Slinton * for anything else they cause a fatal error. 7069677Slinton */ 7079677Slinton 7089677Slinton extern Intfunc *onsyserr(); 7099677Slinton 7109677Slinton private badaddr; 71114757Slinton private read_err(), write_err(); 7129677Slinton 7139677Slinton /* 7149677Slinton * Read from the process' instruction area. 7159677Slinton */ 7169677Slinton 7179677Slinton public iread(buff, addr, nbytes) 7189677Slinton char *buff; 7199677Slinton Address addr; 7209677Slinton int nbytes; 7219677Slinton { 7229677Slinton Intfunc *f; 7239677Slinton 72414757Slinton f = onsyserr(EIO, read_err); 7259677Slinton badaddr = addr; 7269677Slinton if (coredump) { 7279677Slinton coredump_readtext(buff, addr, nbytes); 7289677Slinton } else { 7299677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 7309677Slinton } 7319677Slinton onsyserr(EIO, f); 7329677Slinton } 7339677Slinton 7349677Slinton /* 7359677Slinton * Write to the process' instruction area, usually in order to set 7369677Slinton * or unset a breakpoint. 7379677Slinton */ 7389677Slinton 7399677Slinton public iwrite(buff, addr, nbytes) 7409677Slinton char *buff; 7419677Slinton Address addr; 7429677Slinton int nbytes; 7439677Slinton { 7449677Slinton Intfunc *f; 7459677Slinton 7469677Slinton if (coredump) { 7479677Slinton error("no process to write to"); 7489677Slinton } 74914757Slinton f = onsyserr(EIO, write_err); 7509677Slinton badaddr = addr; 7519677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 7529677Slinton onsyserr(EIO, f); 7539677Slinton } 7549677Slinton 7559677Slinton /* 7569677Slinton * Read for the process' data area. 7579677Slinton */ 7589677Slinton 7599677Slinton public dread(buff, addr, nbytes) 7609677Slinton char *buff; 7619677Slinton Address addr; 7629677Slinton int nbytes; 7639677Slinton { 7649677Slinton Intfunc *f; 7659677Slinton 7669677Slinton badaddr = addr; 7679677Slinton if (coredump) { 76818230Slinton f = onsyserr(EFAULT, read_err); 7699677Slinton coredump_readdata(buff, addr, nbytes); 77018230Slinton onsyserr(EFAULT, f); 7719677Slinton } else { 77218230Slinton f = onsyserr(EIO, read_err); 7739677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 77418230Slinton onsyserr(EIO, f); 7759677Slinton } 7769677Slinton } 7779677Slinton 7789677Slinton /* 7799677Slinton * Write to the process' data area. 7809677Slinton */ 7819677Slinton 7829677Slinton public dwrite(buff, addr, nbytes) 7839677Slinton char *buff; 7849677Slinton Address addr; 7859677Slinton int nbytes; 7869677Slinton { 7879677Slinton Intfunc *f; 7889677Slinton 7899677Slinton if (coredump) { 7909677Slinton error("no process to write to"); 7919677Slinton } 79214757Slinton f = onsyserr(EIO, write_err); 7939677Slinton badaddr = addr; 7949677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 7959677Slinton onsyserr(EIO, f); 7969677Slinton } 7979677Slinton 7989677Slinton /* 79914757Slinton * Trap for errors in reading or writing to a process. 80014757Slinton * The current approach is to "ignore" read errors and complain 80114757Slinton * bitterly about write errors. 8029677Slinton */ 8039677Slinton 80414757Slinton private read_err() 8059677Slinton { 80611560Slinton /* 80714757Slinton * Ignore. 80811560Slinton */ 8099677Slinton } 8109677Slinton 81114757Slinton private write_err() 81214757Slinton { 81314757Slinton error("can't write to process (address 0x%x)", badaddr); 81414757Slinton } 81514757Slinton 8169677Slinton /* 8179677Slinton * Ptrace interface. 8189677Slinton */ 8199677Slinton 8209677Slinton #define WMASK (~(sizeof(Word) - 1)) 82133331Sdonn #define cachehash(addr) ((unsigned) ((addr >> 2) % CACHESIZE)) 8229677Slinton 8239677Slinton #define FIRSTSIG SIGINT 8249677Slinton #define LASTSIG SIGQUIT 8259677Slinton #define ischild(pid) ((pid) == 0) 82618230Slinton #define traceme() ptrace(0, 0, 0, 0) 8279677Slinton #define setrep(n) (1 << ((n)-1)) 8289677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 8299677Slinton 8309677Slinton /* 83118230Slinton * Ptrace options (specified in first argument). 83218230Slinton */ 83318230Slinton 83418230Slinton #define UREAD 3 /* read from process's user structure */ 83518230Slinton #define UWRITE 6 /* write to process's user structure */ 83618230Slinton #define IREAD 1 /* read from process's instruction space */ 83718230Slinton #define IWRITE 4 /* write to process's instruction space */ 83818230Slinton #define DREAD 2 /* read from process's data space */ 83918230Slinton #define DWRITE 5 /* write to process's data space */ 84018230Slinton #define CONT 7 /* continue stopped process */ 84118230Slinton #define SSTEP 9 /* continue for approximately one instruction */ 84218230Slinton #define PKILL 8 /* terminate the process */ 84318230Slinton 84433331Sdonn #ifdef IRIS 84533331Sdonn # define readreg(p, r) ptrace(10, p->pid, r, 0) 84633331Sdonn # define writereg(p, r, v) ptrace(11, p->pid, r, v) 84733331Sdonn #else 84833331Sdonn # define readreg(p, r) ptrace(UREAD, p->pid, regloc(r), 0); 84933331Sdonn # define writereg(p, r, v) ptrace(UWRITE, p->pid, regloc(r), v); 85033331Sdonn #endif 85133331Sdonn 85218230Slinton /* 8539677Slinton * Start up a new process by forking and exec-ing the 8549677Slinton * given argument list, returning when the process is loaded 8559677Slinton * and ready to execute. The PROCESS information (pointed to 8569677Slinton * by the first argument) is appropriately filled. 8579677Slinton * 8589677Slinton * If the given PROCESS structure is associated with an already running 8599677Slinton * process, we terminate it. 8609677Slinton */ 8619677Slinton 8629677Slinton /* VARARGS2 */ 8639677Slinton private pstart(p, argv, infile, outfile) 8649677Slinton Process p; 8659677Slinton String argv[]; 8669677Slinton String infile; 8679677Slinton String outfile; 8689677Slinton { 8699677Slinton int status; 8709677Slinton 87116617Ssam if (p->pid != 0) { 87216617Ssam pterm(p); 87318230Slinton cacheflush(p); 8749677Slinton } 87518230Slinton fflush(stdout); 8769677Slinton psigtrace(p, SIGTRAP, true); 87733331Sdonn # ifdef IRIS 87833331Sdonn p->pid = fork(); 87933331Sdonn # else 88033331Sdonn p->pid = vfork(); 88133331Sdonn # endif 88214395Slinton if (p->pid == -1) { 8839677Slinton panic("can't fork"); 8849677Slinton } 8859677Slinton if (ischild(p->pid)) { 88618230Slinton nocatcherrs(); 8879677Slinton traceme(); 8889677Slinton if (infile != nil) { 88916617Ssam infrom(infile); 8909677Slinton } 8919677Slinton if (outfile != nil) { 89216617Ssam outto(outfile); 8939677Slinton } 89411832Slinton execv(argv[0], argv); 89511172Slinton _exit(1); 8969677Slinton } 8979677Slinton pwait(p->pid, &status); 8989677Slinton getinfo(p, status); 8999677Slinton if (p->status != STOPPED) { 90018230Slinton beginerrmsg(); 90118230Slinton fprintf(stderr, "warning: cannot execute %s\n", argv[0]); 90218230Slinton } else { 90318230Slinton ptraced(p->pid); 9049677Slinton } 9059677Slinton } 9069677Slinton 9079677Slinton /* 90816617Ssam * Terminate a ptrace'd process. 90916617Ssam */ 91016617Ssam 91116617Ssam public pterm (p) 91216617Ssam Process p; 91316617Ssam { 91416617Ssam integer status; 91516617Ssam 91616617Ssam if (p != nil and p->pid != 0) { 91718230Slinton ptrace(PKILL, p->pid, 0, 0); 91816617Ssam pwait(p->pid, &status); 91916617Ssam unptraced(p->pid); 92016617Ssam } 92116617Ssam } 92216617Ssam 92316617Ssam /* 92411867Slinton * Continue a stopped process. The first argument points to a Process 92511867Slinton * structure. Before the process is restarted it's user area is modified 92611867Slinton * according to the values in the structure. When this routine finishes, 9279677Slinton * the structure has the new values from the process's user area. 9289677Slinton * 9299677Slinton * Pcont terminates when the process stops with a signal pending that 9309677Slinton * is being traced (via psigtrace), or when the process terminates. 9319677Slinton */ 9329677Slinton 93311867Slinton private pcont(p, signo) 9349677Slinton Process p; 93511867Slinton int signo; 9369677Slinton { 93716617Ssam int s, status; 9389677Slinton 9399677Slinton if (p->pid == 0) { 94018230Slinton error("program is not active"); 9419677Slinton } 94216617Ssam s = signo; 9439677Slinton do { 94416617Ssam setinfo(p, s); 94516617Ssam if (traceexec) { 94616617Ssam printf("!! pcont from 0x%x with signal %d (%d)\n", 94716617Ssam p->reg[PROGCTR], s, p->signo); 94816617Ssam fflush(stdout); 94916617Ssam } 9509677Slinton sigs_off(); 95118230Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 95214395Slinton panic("error %d trying to continue process", errno); 9539677Slinton } 9549677Slinton pwait(p->pid, &status); 9559677Slinton sigs_on(); 9569677Slinton getinfo(p, status); 95718230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 95818230Slinton printf("!! ignored signal %d at 0x%x\n", 95918230Slinton p->signo, p->reg[PROGCTR]); 96016617Ssam fflush(stdout); 96116617Ssam } 96216617Ssam s = p->signo; 9639677Slinton } while (p->status == STOPPED and not istraced(p)); 96416617Ssam if (traceexec) { 96516617Ssam printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); 96616617Ssam fflush(stdout); 96716617Ssam } 9689677Slinton } 9699677Slinton 9709677Slinton /* 9719677Slinton * Single step as best ptrace can. 9729677Slinton */ 9739677Slinton 97416617Ssam public pstep(p, signo) 9759677Slinton Process p; 97616617Ssam integer signo; 9779677Slinton { 97818230Slinton int s, status; 9799677Slinton 98018230Slinton s = signo; 98118230Slinton do { 98218230Slinton setinfo(p, s); 98318230Slinton if (traceexec) { 98418230Slinton printf("!! pstep from 0x%x with signal %d (%d)\n", 98518230Slinton p->reg[PROGCTR], s, p->signo); 98618230Slinton fflush(stdout); 98718230Slinton } 98818230Slinton sigs_off(); 98918230Slinton if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) { 99018230Slinton panic("error %d trying to step process", errno); 99118230Slinton } 99218230Slinton pwait(p->pid, &status); 99318230Slinton sigs_on(); 99418230Slinton getinfo(p, status); 99533331Sdonn # if mc68000 || m68000 99633331Sdonn if (p->status == STOPPED and p->signo == SIGTRAP) { 99733331Sdonn p->reg[PROGCTR] += 2; 99833331Sdonn } 99933331Sdonn # endif 100018230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 100118230Slinton printf("!! pstep ignored signal %d at 0x%x\n", 100218230Slinton p->signo, p->reg[PROGCTR]); 100318230Slinton fflush(stdout); 100418230Slinton } 100518230Slinton s = p->signo; 100618230Slinton } while (p->status == STOPPED and not istraced(p)); 100716617Ssam if (traceexec) { 100818230Slinton printf("!! pstep to 0x%x on signal %d\n", 100918230Slinton p->reg[PROGCTR], p->signo); 101016617Ssam fflush(stdout); 101116617Ssam } 101216617Ssam if (p->status != STOPPED) { 101318230Slinton if (p->exitval == 0) { 101418230Slinton error("program exited\n"); 101518230Slinton } else { 101618230Slinton error("program exited with code %d\n", p->exitval); 101718230Slinton } 101816617Ssam } 10199677Slinton } 10209677Slinton 10219677Slinton /* 10229677Slinton * Return from execution when the given signal is pending. 10239677Slinton */ 10249677Slinton 10259677Slinton public psigtrace(p, sig, sw) 10269677Slinton Process p; 10279677Slinton int sig; 10289677Slinton Boolean sw; 10299677Slinton { 10309677Slinton if (sw) { 10319677Slinton p->sigset |= setrep(sig); 10329677Slinton } else { 10339677Slinton p->sigset &= ~setrep(sig); 10349677Slinton } 10359677Slinton } 10369677Slinton 10379677Slinton /* 10389677Slinton * Don't catch any signals. 10399677Slinton * Particularly useful when letting a process finish uninhibited. 10409677Slinton */ 10419677Slinton 10429677Slinton public unsetsigtraces(p) 10439677Slinton Process p; 10449677Slinton { 10459677Slinton p->sigset = 0; 10469677Slinton } 10479677Slinton 10489677Slinton /* 10499677Slinton * Turn off attention to signals not being caught. 10509677Slinton */ 10519677Slinton 1052*39163Sbostic private sig_t sigfunc[NSIG]; 10539677Slinton 10549677Slinton private sigs_off() 10559677Slinton { 10569677Slinton register int i; 10579677Slinton 10589677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10599677Slinton if (i != SIGKILL) { 10609677Slinton sigfunc[i] = signal(i, SIG_IGN); 10619677Slinton } 10629677Slinton } 10639677Slinton } 10649677Slinton 10659677Slinton /* 10669677Slinton * Turn back on attention to signals. 10679677Slinton */ 10689677Slinton 10699677Slinton private sigs_on() 10709677Slinton { 10719677Slinton register int i; 10729677Slinton 10739677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10749677Slinton if (i != SIGKILL) { 10759677Slinton signal(i, sigfunc[i]); 10769677Slinton } 10779677Slinton } 10789677Slinton } 10799677Slinton 10809677Slinton /* 10819677Slinton * Get process information from user area. 10829677Slinton */ 10839677Slinton 108433331Sdonn private getinfo (p, status) 10859677Slinton register Process p; 10869677Slinton register int status; 10879677Slinton { 10889677Slinton register int i; 108916617Ssam Address addr; 10909677Slinton 10919677Slinton p->signo = (status&0177); 10929677Slinton p->exitval = ((status >> 8)&0377); 10939677Slinton if (p->signo != STOPPED) { 10949677Slinton p->status = FINISHED; 109514757Slinton p->pid = 0; 109616617Ssam p->reg[PROGCTR] = 0; 10979677Slinton } else { 10989677Slinton p->status = p->signo; 10999677Slinton p->signo = p->exitval; 11009677Slinton p->exitval = 0; 110133331Sdonn # ifdef IRIS 110233331Sdonn p->mask = readreg(p, RPS); 110333331Sdonn # else 110433331Sdonn p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0); 110533331Sdonn p->mask = readreg(p, PS); 110633331Sdonn # endif 11079677Slinton for (i = 0; i < NREG; i++) { 110833331Sdonn p->reg[i] = readreg(p, rloc[i]); 11099677Slinton p->oreg[i] = p->reg[i]; 11109677Slinton } 111133331Sdonn # ifdef mc68000 111233331Sdonn if (p->status == STOPPED and p->signo == SIGTRAP and 111333331Sdonn p->reg[PROGCTR] > CODESTART 111433331Sdonn ) { 111533331Sdonn p->reg[PROGCTR] -= 2; 111633331Sdonn } 111733331Sdonn # endif 111811768Slinton savetty(stdout, &(p->ttyinfo)); 111916617Ssam addr = (Address) &(((struct user *) 0)->u_signal[p->signo]); 112018230Slinton p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0); 11219677Slinton } 11229677Slinton } 11239677Slinton 11249677Slinton /* 11259677Slinton * Set process's user area information from given process structure. 11269677Slinton */ 11279677Slinton 112833331Sdonn private setinfo (p, signo) 11299677Slinton register Process p; 113011867Slinton int signo; 11319677Slinton { 11329677Slinton register int i; 11339677Slinton register int r; 11349677Slinton 113514757Slinton if (signo == DEFSIG) { 113616617Ssam if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) { 113714757Slinton p->signo = 0; 113814757Slinton } 113914757Slinton } else { 114011867Slinton p->signo = signo; 11419677Slinton } 11429677Slinton for (i = 0; i < NREG; i++) { 11439677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 114433331Sdonn writereg(p, rloc[i], r); 11459677Slinton } 11469677Slinton } 114711768Slinton restoretty(stdout, &(p->ttyinfo)); 11489677Slinton } 11499677Slinton 11509677Slinton /* 115116617Ssam * Return the address associated with the current signal. 115216617Ssam * (Plus two since the address points to the beginning of a procedure). 115316617Ssam */ 115416617Ssam 115516617Ssam public Address usignal (p) 115616617Ssam Process p; 115716617Ssam { 115816617Ssam Address r; 115916617Ssam 116016617Ssam r = p->sigstatus; 116116617Ssam if (r != 0 and r != 1) { 116233331Sdonn r += FUNCOFFSET; 116316617Ssam } 116416617Ssam return r; 116516617Ssam } 116616617Ssam 116716617Ssam /* 11689677Slinton * Structure for reading and writing by words, but dealing with bytes. 11699677Slinton */ 11709677Slinton 11719677Slinton typedef union { 11729677Slinton Word pword; 11739677Slinton Byte pbyte[sizeof(Word)]; 11749677Slinton } Pword; 11759677Slinton 11769677Slinton /* 11779677Slinton * Read (write) from (to) the process' address space. 11789677Slinton * We must deal with ptrace's inability to look anywhere other 11799677Slinton * than at a word boundary. 11809677Slinton */ 11819677Slinton 11829677Slinton private Word fetch(); 11839677Slinton private store(); 11849677Slinton 11859677Slinton private pio(p, op, seg, buff, addr, nbytes) 11869677Slinton Process p; 11879677Slinton PioOp op; 11889677Slinton PioSeg seg; 11899677Slinton char *buff; 11909677Slinton Address addr; 11919677Slinton int nbytes; 11929677Slinton { 11939677Slinton register int i; 11949677Slinton register Address newaddr; 11959677Slinton register char *cp; 11969677Slinton char *bufend; 11979677Slinton Pword w; 11989677Slinton Address wordaddr; 11999677Slinton int byteoff; 12009677Slinton 12019677Slinton if (p->status != STOPPED) { 12029677Slinton error("program is not active"); 12039677Slinton } 12049677Slinton cp = buff; 12059677Slinton newaddr = addr; 12069677Slinton wordaddr = (newaddr&WMASK); 12079677Slinton if (wordaddr != newaddr) { 12089677Slinton w.pword = fetch(p, seg, wordaddr); 12099677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 12109677Slinton if (op == PREAD) { 12119677Slinton *cp++ = w.pbyte[i]; 12129677Slinton } else { 12139677Slinton w.pbyte[i] = *cp++; 12149677Slinton } 12159677Slinton nbytes--; 12169677Slinton } 12179677Slinton if (op == PWRITE) { 12189677Slinton store(p, seg, wordaddr, w.pword); 12199677Slinton } 12209677Slinton newaddr = wordaddr + sizeof(Word); 12219677Slinton } 12229677Slinton byteoff = (nbytes&(~WMASK)); 12239677Slinton nbytes -= byteoff; 12249677Slinton bufend = cp + nbytes; 122526333Ssam #ifdef tahoe 122626333Ssam if (((int)cp)&WMASK) { 122726333Ssam /* 122826333Ssam * Must copy a byte at a time, buffer not word addressable. 122926333Ssam */ 123026333Ssam while (cp < bufend) { 123126333Ssam if (op == PREAD) { 123226333Ssam w.pword = fetch(p, seg, newaddr); 123326333Ssam for (i = 0; i < sizeof(Word); i++) 123426333Ssam *cp++ = w.pbyte[i]; 123526333Ssam } else { 123626333Ssam for (i = 0; i < sizeof(Word); i++) 123726333Ssam w.pbyte[i] = *cp++; 123826333Ssam store(p, seg, newaddr, w.pword); 123926333Ssam } 124026333Ssam newaddr += sizeof(Word); 124126333Ssam } 124226333Ssam } else { 124326333Ssam /* 124426333Ssam * Buffer, word aligned, act normally... 124526333Ssam */ 124626333Ssam #endif 12479677Slinton while (cp < bufend) { 12489677Slinton if (op == PREAD) { 12499677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 12509677Slinton } else { 12519677Slinton store(p, seg, newaddr, *((Word *) cp)); 12529677Slinton } 12539677Slinton cp += sizeof(Word); 12549677Slinton newaddr += sizeof(Word); 12559677Slinton } 125626333Ssam #ifdef tahoe 125726333Ssam } 125826333Ssam #endif 12599677Slinton if (byteoff > 0) { 12609677Slinton w.pword = fetch(p, seg, newaddr); 12619677Slinton for (i = 0; i < byteoff; i++) { 12629677Slinton if (op == PREAD) { 12639677Slinton *cp++ = w.pbyte[i]; 12649677Slinton } else { 12659677Slinton w.pbyte[i] = *cp++; 12669677Slinton } 12679677Slinton } 12689677Slinton if (op == PWRITE) { 12699677Slinton store(p, seg, newaddr, w.pword); 12709677Slinton } 12719677Slinton } 12729677Slinton } 12739677Slinton 12749677Slinton /* 12759677Slinton * Get a word from a process at the given address. 12769677Slinton * The address is assumed to be on a word boundary. 12779677Slinton * 12789677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 12799677Slinton * to the instruction space since it is assumed to be pure. 12809677Slinton * 12819677Slinton * It is necessary to use a write-through scheme so that 12829677Slinton * breakpoints right next to each other don't interfere. 12839677Slinton */ 12849677Slinton 12859677Slinton private Integer nfetchs, nreads, nwrites; 12869677Slinton 12879677Slinton private Word fetch(p, seg, addr) 12889677Slinton Process p; 12899677Slinton PioSeg seg; 12909677Slinton register int addr; 12919677Slinton { 12929677Slinton register CacheWord *wp; 12939677Slinton register Word w; 12949677Slinton 12959677Slinton switch (seg) { 12969677Slinton case TEXTSEG: 12979677Slinton ++nfetchs; 12989677Slinton wp = &p->word[cachehash(addr)]; 12999677Slinton if (addr == 0 or wp->addr != addr) { 13009677Slinton ++nreads; 130118230Slinton w = ptrace(IREAD, p->pid, addr, 0); 13029677Slinton wp->addr = addr; 13039677Slinton wp->val = w; 13049677Slinton } else { 13059677Slinton w = wp->val; 13069677Slinton } 13079677Slinton break; 13089677Slinton 13099677Slinton case DATASEG: 131018230Slinton w = ptrace(DREAD, p->pid, addr, 0); 13119677Slinton break; 13129677Slinton 13139677Slinton default: 13149677Slinton panic("fetch: bad seg %d", seg); 13159677Slinton /* NOTREACHED */ 13169677Slinton } 13179677Slinton return w; 13189677Slinton } 13199677Slinton 13209677Slinton /* 13219677Slinton * Put a word into the process' address space at the given address. 13229677Slinton * The address is assumed to be on a word boundary. 13239677Slinton */ 13249677Slinton 13259677Slinton private store(p, seg, addr, data) 13269677Slinton Process p; 13279677Slinton PioSeg seg; 13289677Slinton int addr; 13299677Slinton Word data; 13309677Slinton { 13319677Slinton register CacheWord *wp; 13329677Slinton 13339677Slinton switch (seg) { 13349677Slinton case TEXTSEG: 13359677Slinton ++nwrites; 13369677Slinton wp = &p->word[cachehash(addr)]; 13379677Slinton wp->addr = addr; 13389677Slinton wp->val = data; 133918230Slinton ptrace(IWRITE, p->pid, addr, data); 13409677Slinton break; 13419677Slinton 13429677Slinton case DATASEG: 134318230Slinton ptrace(DWRITE, p->pid, addr, data); 13449677Slinton break; 13459677Slinton 13469677Slinton default: 13479677Slinton panic("store: bad seg %d", seg); 13489677Slinton /* NOTREACHED */ 13499677Slinton } 13509677Slinton } 13519677Slinton 135218230Slinton /* 135318230Slinton * Flush the instruction cache associated with a process. 135418230Slinton */ 135518230Slinton 135618230Slinton private cacheflush (p) 135718230Slinton Process p; 135818230Slinton { 135918230Slinton bzero(p->word, sizeof(p->word)); 136018230Slinton } 136118230Slinton 13629677Slinton public printptraceinfo() 13639677Slinton { 13649677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 13659677Slinton } 13669677Slinton 13679677Slinton /* 136816617Ssam * Redirect input. 136916617Ssam * Assuming this is called from a child, we should be careful to avoid 137016617Ssam * (possibly) shared standard I/O buffers. 13719677Slinton */ 13729677Slinton 137316617Ssam private infrom (filename) 137416617Ssam String filename; 137516617Ssam { 137616617Ssam Fileid in; 137716617Ssam 137816617Ssam in = open(filename, 0); 137916617Ssam if (in == -1) { 138016617Ssam write(2, "can't read ", 11); 138116617Ssam write(2, filename, strlen(filename)); 138216617Ssam write(2, "\n", 1); 138316617Ssam _exit(1); 138416617Ssam } 138516617Ssam fswap(0, in); 138616617Ssam } 138716617Ssam 138816617Ssam /* 138916617Ssam * Redirect standard output. 139016617Ssam * Same assumptions as for "infrom" above. 139116617Ssam */ 139216617Ssam 139316617Ssam private outto (filename) 139416617Ssam String filename; 139516617Ssam { 139616617Ssam Fileid out; 139716617Ssam 139816617Ssam out = creat(filename, 0666); 139916617Ssam if (out == -1) { 140016617Ssam write(2, "can't write ", 12); 140116617Ssam write(2, filename, strlen(filename)); 140216617Ssam write(2, "\n", 1); 140316617Ssam _exit(1); 140416617Ssam } 140516617Ssam fswap(1, out); 140616617Ssam } 140716617Ssam 140816617Ssam /* 140916617Ssam * Swap file numbers, useful for redirecting standard input or output. 141016617Ssam */ 141116617Ssam 14129677Slinton private fswap(oldfd, newfd) 141316617Ssam Fileid oldfd; 141416617Ssam Fileid newfd; 14159677Slinton { 14169677Slinton if (oldfd != newfd) { 14179677Slinton close(oldfd); 14189677Slinton dup(newfd); 14199677Slinton close(newfd); 14209677Slinton } 14219677Slinton } 142216928Ssam 142316928Ssam /* 142418230Slinton * Signal name manipulation. 142516928Ssam */ 142618230Slinton 142718230Slinton private String signames[NSIG] = { 142818230Slinton 0, 142918230Slinton "HUP", "INT", "QUIT", "ILL", "TRAP", 143018230Slinton "IOT", "EMT", "FPE", "KILL", "BUS", 143118230Slinton "SEGV", "SYS", "PIPE", "ALRM", "TERM", 143218230Slinton 0, "STOP", "TSTP", "CONT", "CHLD", 143318230Slinton "TTIN", "TTOU", "TINT", "XCPU", "XFSZ", 143426333Ssam "VTALRM", "PROF", "WINCH", "USR1", "USR2" 143516928Ssam }; 143616928Ssam 143716928Ssam /* 143818230Slinton * Get the signal number associated with a given name. 143918230Slinton * The name is first translated to upper case if necessary. 144016928Ssam */ 144118230Slinton 144218230Slinton public integer siglookup (s) 144316928Ssam String s; 144416928Ssam { 144518230Slinton register char *p, *q; 144618230Slinton char buf[100]; 144718230Slinton integer i; 144816928Ssam 144918230Slinton p = s; 145018230Slinton q = buf; 145118230Slinton while (*p != '\0') { 145218230Slinton if (*p >= 'a' and *p <= 'z') { 145318230Slinton *q = (*p - 'a') + 'A'; 145418230Slinton } else { 145518230Slinton *q = *p; 145618230Slinton } 145718230Slinton ++p; 145818230Slinton ++q; 145918230Slinton } 146018230Slinton *q = '\0'; 146118230Slinton p = buf; 146218230Slinton if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') { 146318230Slinton p += 3; 146418230Slinton } 146518230Slinton i = 1; 146618230Slinton for (;;) { 146718230Slinton if (i >= sizeof(signames) div sizeof(signames[0])) { 146818230Slinton error("signal \"%s\" unknown", s); 146918230Slinton i = 0; 147018230Slinton break; 147118230Slinton } 147218230Slinton if (signames[i] != nil and streq(signames[i], p)) { 147318230Slinton break; 147418230Slinton } 147518230Slinton ++i; 147618230Slinton } 147718230Slinton return i; 147816928Ssam } 147916928Ssam 148016928Ssam /* 148118230Slinton * Print all signals being ignored by the debugger. 148218230Slinton * These signals are auotmatically 148316928Ssam * passed on to the debugged process. 148416928Ssam */ 148518230Slinton 148618230Slinton public printsigsignored (p) 148716931Ssam Process p; 148816928Ssam { 148916931Ssam printsigs(~p->sigset); 149016928Ssam } 149116928Ssam 149216928Ssam /* 149316928Ssam * Print all signals being intercepted by 149416928Ssam * the debugger for the specified process. 149516928Ssam */ 149618230Slinton 149716931Ssam public printsigscaught(p) 149816931Ssam Process p; 149916928Ssam { 150016931Ssam printsigs(p->sigset); 150116931Ssam } 150216931Ssam 150318230Slinton private printsigs (set) 150418230Slinton integer set; 150516931Ssam { 150618230Slinton integer s; 150718230Slinton char separator[2]; 150816931Ssam 150918230Slinton separator[0] = '\0'; 151018230Slinton for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) { 151118230Slinton if (set & setrep(s)) { 151218230Slinton if (signames[s] != nil) { 151318230Slinton printf("%s%s", separator, signames[s]); 151418230Slinton separator[0] = ' '; 151518230Slinton separator[1] = '\0'; 151618230Slinton } 151716928Ssam } 151818230Slinton } 151918230Slinton if (separator[0] == ' ') { 152016931Ssam putchar('\n'); 152116931Ssam } 152216928Ssam } 1523