121620Sdist /* 221620Sdist * Copyright (c) 1983 Regents of the University of California. 321620Sdist * All rights reserved. The Berkeley software License Agreement 421620Sdist * specifies the terms and conditions for redistribution. 521620Sdist */ 69677Slinton 721620Sdist #ifndef lint 8*33331Sdonn static char sccsid[] = "@(#)process.c 5.3 (Berkeley) 01/12/88"; 921620Sdist #endif not lint 109677Slinton 11*33331Sdonn static char rcsid[] = "$Header: process.c,v 1.4 88/01/10 00:49:31 donn Exp $"; 1218230Slinton 139677Slinton /* 149677Slinton * Process management. 159677Slinton * 169677Slinton * This module contains the routines to manage the execution and 179677Slinton * tracing of the debuggee process. 189677Slinton */ 199677Slinton 209677Slinton #include "defs.h" 219677Slinton #include "process.h" 229677Slinton #include "machine.h" 239677Slinton #include "events.h" 249677Slinton #include "tree.h" 2514757Slinton #include "eval.h" 269677Slinton #include "operators.h" 279677Slinton #include "source.h" 289677Slinton #include "object.h" 299677Slinton #include "mappings.h" 309677Slinton #include "main.h" 319677Slinton #include "coredump.h" 329677Slinton #include <signal.h> 339677Slinton #include <errno.h> 349677Slinton #include <sys/stat.h> 359677Slinton 369677Slinton #ifndef public 379677Slinton 389677Slinton typedef struct Process *Process; 399677Slinton 409677Slinton Process process; 419677Slinton 4214757Slinton #define DEFSIG -1 4314757Slinton 449677Slinton #include "machine.h" 459677Slinton 469677Slinton #endif 479677Slinton 489677Slinton #define NOTSTARTED 1 499677Slinton #define STOPPED 0177 509677Slinton #define FINISHED 0 519677Slinton 529677Slinton /* 5316617Ssam * A cache of the instruction segment is kept to reduce the number 5416617Ssam * of system calls. Might be better just to read the entire 5516617Ssam * code space into memory. 569677Slinton */ 579677Slinton 58*33331Sdonn #define CACHESIZE 1003 599677Slinton 609677Slinton typedef struct { 619677Slinton Word addr; 629677Slinton Word val; 639677Slinton } CacheWord; 649677Slinton 659677Slinton /* 669677Slinton * This structure holds the information we need from the user structure. 679677Slinton */ 689677Slinton 699677Slinton struct Process { 709677Slinton int pid; /* process being traced */ 7111768Slinton int mask; /* process status word */ 7211768Slinton Word reg[NREG]; /* process' registers */ 739677Slinton Word oreg[NREG]; /* registers when process last stopped */ 749677Slinton short status; /* either STOPPED or FINISHED */ 759677Slinton short signo; /* signal that stopped process */ 7618230Slinton short sigcode; /* extra signal information */ 779677Slinton int exitval; /* return value from exit() */ 789677Slinton long sigset; /* bit array of traced signals */ 79*33331Sdonn CacheWord word[CACHESIZE]; /* text segment cache */ 8011768Slinton Ttyinfo ttyinfo; /* process' terminal characteristics */ 8116617Ssam Address sigstatus; /* process' handler for current signal */ 829677Slinton }; 839677Slinton 849677Slinton /* 859677Slinton * These definitions are for the arguments to "pio". 869677Slinton */ 879677Slinton 889677Slinton typedef enum { PREAD, PWRITE } PioOp; 899677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 909677Slinton 919677Slinton private struct Process pbuf; 929677Slinton 9318230Slinton #define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */ 949677Slinton 9514395Slinton extern int errno; 9614395Slinton 979677Slinton private Boolean just_started; 989677Slinton private int argc; 999677Slinton private String argv[MAXNCMDARGS]; 1009677Slinton private String infile, outfile; 1019677Slinton 1029677Slinton /* 1039677Slinton * Initialize process information. 1049677Slinton */ 1059677Slinton 1069677Slinton public process_init() 1079677Slinton { 108*33331Sdonn register integer i; 109*33331Sdonn char buf[10]; 1109677Slinton 1119677Slinton process = &pbuf; 1129677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 1139677Slinton setsigtrace(); 114*33331Sdonn # if vax || tahoe 115*33331Sdonn for (i = 0; i < NREG; i++) { 116*33331Sdonn sprintf(buf, "$r%d", i); 117*33331Sdonn defregname(identname(buf, false), i); 118*33331Sdonn } 119*33331Sdonn # ifdef vax 120*33331Sdonn defregname(identname("$ap", true), ARGP); 121*33331Sdonn # endif 122*33331Sdonn # else 123*33331Sdonn # ifdef mc68000 124*33331Sdonn for (i = 0; i < 8; i++) { 125*33331Sdonn sprintf(buf, "$d%d", i); 126*33331Sdonn defregname(identname(buf, false), i); 127*33331Sdonn sprintf(buf, "$a%d", i); 128*33331Sdonn defregname(identname(buf, false), i + 8); 129*33331Sdonn } 130*33331Sdonn # endif 131*33331Sdonn # endif 1329677Slinton defregname(identname("$fp", true), FRP); 1339677Slinton defregname(identname("$sp", true), STKP); 1349677Slinton defregname(identname("$pc", true), PROGCTR); 1359677Slinton if (coredump) { 1369677Slinton coredump_readin(process->mask, process->reg, process->signo); 13712484Slinton pc = process->reg[PROGCTR]; 1389677Slinton } 13912484Slinton arginit(); 1409677Slinton } 1419677Slinton 1429677Slinton /* 1439677Slinton * Routines to get at process information from outside this module. 1449677Slinton */ 1459677Slinton 1469677Slinton public Word reg(n) 1479677Slinton Integer n; 1489677Slinton { 1499677Slinton register Word w; 1509677Slinton 1519677Slinton if (n == NREG) { 1529677Slinton w = process->mask; 1539677Slinton } else { 1549677Slinton w = process->reg[n]; 1559677Slinton } 1569677Slinton return w; 1579677Slinton } 1589677Slinton 1599677Slinton public setreg(n, w) 1609677Slinton Integer n; 1619677Slinton Word w; 1629677Slinton { 1639677Slinton process->reg[n] = w; 1649677Slinton } 1659677Slinton 1669677Slinton /* 1679677Slinton * Begin execution. 1689677Slinton * 1699677Slinton * We set a breakpoint at the end of the code so that the 1709677Slinton * process data doesn't disappear after the program terminates. 1719677Slinton */ 1729677Slinton 1739677Slinton private Boolean remade(); 1749677Slinton 1759677Slinton public start(argv, infile, outfile) 1769677Slinton String argv[]; 1779677Slinton String infile, outfile; 1789677Slinton { 1799677Slinton String pargv[4]; 1809677Slinton Node cond; 1819677Slinton 1829677Slinton if (coredump) { 1839677Slinton coredump = false; 1849677Slinton fclose(corefile); 1859677Slinton coredump_close(); 1869677Slinton } 1879677Slinton if (argv == nil) { 1889677Slinton argv = pargv; 1899677Slinton pargv[0] = objname; 1909677Slinton pargv[1] = nil; 1919677Slinton } else { 1929677Slinton argv[argc] = nil; 1939677Slinton } 19418230Slinton pstart(process, argv, infile, outfile); 1959677Slinton if (remade(objname)) { 1969677Slinton reinit(argv, infile, outfile); 1979677Slinton } 1989677Slinton if (process->status == STOPPED) { 199*33331Sdonn pc = CODESTART; 20016617Ssam setcurfunc(program); 2019677Slinton if (objsize != 0) { 2029677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 2039677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 2049677Slinton } 2059677Slinton } 2069677Slinton } 2079677Slinton 2089677Slinton /* 2099677Slinton * Check to see if the object file has changed since the symbolic 2109677Slinton * information last was read. 2119677Slinton */ 2129677Slinton 2139677Slinton private time_t modtime; 2149677Slinton 2159677Slinton private Boolean remade(filename) 2169677Slinton String filename; 2179677Slinton { 2189677Slinton struct stat s; 2199677Slinton Boolean b; 2209677Slinton 2219677Slinton stat(filename, &s); 2229677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 2239677Slinton modtime = s.st_mtime; 2249677Slinton return b; 2259677Slinton } 2269677Slinton 2279677Slinton /* 2289677Slinton * Set up what signals we want to trace. 2299677Slinton */ 2309677Slinton 2319677Slinton private setsigtrace() 2329677Slinton { 2339677Slinton register Integer i; 2349677Slinton register Process p; 2359677Slinton 2369677Slinton p = process; 2379677Slinton for (i = 1; i <= NSIG; i++) { 2389677Slinton psigtrace(p, i, true); 2399677Slinton } 2409677Slinton psigtrace(p, SIGHUP, false); 2419677Slinton psigtrace(p, SIGKILL, false); 2429677Slinton psigtrace(p, SIGALRM, false); 243*33331Sdonn # ifdef SIGTSTP 244*33331Sdonn psigtrace(p, SIGTSTP, false); 245*33331Sdonn psigtrace(p, SIGCONT, false); 246*33331Sdonn # endif 2479677Slinton psigtrace(p, SIGCHLD, false); 24826333Ssam psigtrace(p, SIGWINCH, false); 2499677Slinton } 2509677Slinton 2519677Slinton /* 2529677Slinton * Initialize the argument list. 2539677Slinton */ 2549677Slinton 2559677Slinton public arginit() 2569677Slinton { 2579677Slinton infile = nil; 2589677Slinton outfile = nil; 2599677Slinton argv[0] = objname; 2609677Slinton argc = 1; 2619677Slinton } 2629677Slinton 2639677Slinton /* 2649677Slinton * Add an argument to the list for the debuggee. 2659677Slinton */ 2669677Slinton 2679677Slinton public newarg(arg) 2689677Slinton String arg; 2699677Slinton { 2709677Slinton if (argc >= MAXNCMDARGS) { 2719677Slinton error("too many arguments"); 2729677Slinton } 2739677Slinton argv[argc++] = arg; 2749677Slinton } 2759677Slinton 2769677Slinton /* 2779677Slinton * Set the standard input for the debuggee. 2789677Slinton */ 2799677Slinton 2809677Slinton public inarg(filename) 2819677Slinton String filename; 2829677Slinton { 2839677Slinton if (infile != nil) { 2849677Slinton error("multiple input redirects"); 2859677Slinton } 2869677Slinton infile = filename; 2879677Slinton } 2889677Slinton 2899677Slinton /* 2909677Slinton * Set the standard output for the debuggee. 2919677Slinton * Probably should check to avoid overwriting an existing file. 2929677Slinton */ 2939677Slinton 2949677Slinton public outarg(filename) 2959677Slinton String filename; 2969677Slinton { 2979677Slinton if (outfile != nil) { 2989677Slinton error("multiple output redirect"); 2999677Slinton } 3009677Slinton outfile = filename; 3019677Slinton } 3029677Slinton 3039677Slinton /* 3049677Slinton * Start debuggee executing. 3059677Slinton */ 3069677Slinton 3079677Slinton public run() 3089677Slinton { 3099677Slinton process->status = STOPPED; 3109677Slinton fixbps(); 3119677Slinton curline = 0; 3129677Slinton start(argv, infile, outfile); 3139677Slinton just_started = true; 3149677Slinton isstopped = false; 31514757Slinton cont(0); 3169677Slinton } 3179677Slinton 3189677Slinton /* 3199677Slinton * Continue execution wherever we left off. 3209677Slinton * 3219677Slinton * Note that this routine never returns. Eventually bpact() will fail 3229677Slinton * and we'll call printstatus or step will call it. 3239677Slinton */ 3249677Slinton 3259677Slinton typedef int Intfunc(); 3269677Slinton 3279677Slinton private Intfunc *dbintr; 3289677Slinton private intr(); 3299677Slinton 33011867Slinton public cont(signo) 33116617Ssam integer signo; 3329677Slinton { 33316617Ssam integer s; 33416617Ssam 3359677Slinton dbintr = signal(SIGINT, intr); 3369677Slinton if (just_started) { 3379677Slinton just_started = false; 3389677Slinton } else { 3399677Slinton if (not isstopped) { 3409677Slinton error("can't continue execution"); 3419677Slinton } 3429677Slinton isstopped = false; 34311867Slinton stepover(); 3449677Slinton } 34516617Ssam s = signo; 3469677Slinton for (;;) { 3479677Slinton if (single_stepping) { 3489677Slinton printnews(); 3499677Slinton } else { 3509677Slinton setallbps(); 35116617Ssam resume(s); 3529677Slinton unsetallbps(); 35316617Ssam s = DEFSIG; 35418230Slinton if (not isbperr() or not bpact()) { 3559677Slinton printstatus(); 3569677Slinton } 3579677Slinton } 35811867Slinton stepover(); 3599677Slinton } 3609677Slinton /* NOTREACHED */ 3619677Slinton } 3629677Slinton 3639677Slinton /* 36418230Slinton * This routine is called if we get an interrupt while "running" 3659677Slinton * but actually in the debugger. Could happen, for example, while 3669677Slinton * processing breakpoints. 3679677Slinton * 3689677Slinton * We basically just want to keep going; the assumption is 36918230Slinton * that when the process resumes it will get the interrupt, 3709677Slinton * which will then be handled. 3719677Slinton */ 3729677Slinton 3739677Slinton private intr() 3749677Slinton { 3759677Slinton signal(SIGINT, intr); 3769677Slinton } 3779677Slinton 3789677Slinton public fixintr() 3799677Slinton { 3809677Slinton signal(SIGINT, dbintr); 3819677Slinton } 3829677Slinton 3839677Slinton /* 3849677Slinton * Resume execution. 3859677Slinton */ 3869677Slinton 38711867Slinton public resume(signo) 38811867Slinton int signo; 3899677Slinton { 3909677Slinton register Process p; 3919677Slinton 3929677Slinton p = process; 39311867Slinton pcont(p, signo); 3949677Slinton pc = process->reg[PROGCTR]; 39511832Slinton if (p->status != STOPPED) { 39611867Slinton if (p->signo != 0) { 39711867Slinton error("program terminated by signal %d", p->signo); 39814757Slinton } else if (not runfirst) { 39918230Slinton if (p->exitval == 0) { 40018230Slinton error("program exited"); 40118230Slinton } else { 40218230Slinton error("program exited with code %d", p->exitval); 40318230Slinton } 40411867Slinton } 40511832Slinton } 4069677Slinton } 4079677Slinton 4089677Slinton /* 4099677Slinton * Continue execution up to the next source line. 4109677Slinton * 4119677Slinton * There are two ways to define the next source line depending on what 4129677Slinton * is desired when a procedure or function call is encountered. Step 4139677Slinton * stops at the beginning of the procedure or call; next skips over it. 4149677Slinton */ 4159677Slinton 4169677Slinton /* 4179677Slinton * Stepc is what is called when the step command is given. 4189677Slinton * It has to play with the "isstopped" information. 4199677Slinton */ 4209677Slinton 4219677Slinton public stepc() 4229677Slinton { 4239677Slinton if (not isstopped) { 4249677Slinton error("can't continue execution"); 4259677Slinton } 4269677Slinton isstopped = false; 4279677Slinton dostep(false); 4289677Slinton isstopped = true; 4299677Slinton } 4309677Slinton 4319677Slinton public next() 4329677Slinton { 43316617Ssam Address oldfrp, newfrp; 43416617Ssam 4359677Slinton if (not isstopped) { 4369677Slinton error("can't continue execution"); 4379677Slinton } 4389677Slinton isstopped = false; 43916617Ssam oldfrp = reg(FRP); 44016617Ssam do { 44116617Ssam dostep(true); 44216617Ssam pc = reg(PROGCTR); 44316617Ssam newfrp = reg(FRP); 44416617Ssam } while (newfrp < oldfrp and newfrp != 0); 4459677Slinton isstopped = true; 4469677Slinton } 4479677Slinton 44811867Slinton /* 44916617Ssam * Continue execution until the current function returns, or, 45016617Ssam * if the given argument is non-nil, until execution returns to 45116617Ssam * somewhere within the given function. 45216617Ssam */ 45316617Ssam 45416617Ssam public rtnfunc (f) 45516617Ssam Symbol f; 45616617Ssam { 45716617Ssam Address addr; 45816617Ssam Symbol t; 45916617Ssam 46016617Ssam if (not isstopped) { 46116617Ssam error("can't continue execution"); 46216617Ssam } else if (f != nil and not isactive(f)) { 46316617Ssam error("%s is not active", symname(f)); 46416617Ssam } else { 46516617Ssam addr = return_addr(); 46616617Ssam if (addr == nil) { 46716617Ssam error("no place to return to"); 46816617Ssam } else { 46916617Ssam isstopped = false; 47016617Ssam contto(addr); 47116617Ssam if (f != nil) { 47216617Ssam for (;;) { 47316617Ssam t = whatblock(pc); 47416617Ssam addr = return_addr(); 47516617Ssam if (t == f or addr == nil) break; 47616617Ssam contto(addr); 47716617Ssam } 47816617Ssam } 47918230Slinton if (not bpact()) { 48016617Ssam isstopped = true; 48116617Ssam printstatus(); 48216617Ssam } 48316617Ssam } 48416617Ssam } 48516617Ssam } 48616617Ssam 48716617Ssam /* 48811867Slinton * Single-step over the current machine instruction. 48911867Slinton * 49011867Slinton * If we're single-stepping by source line we want to step to the 49111867Slinton * next source line. Otherwise we're going to continue so there's 49211867Slinton * no reason to do all the work necessary to single-step to the next 49311867Slinton * source line. 49411867Slinton */ 49511867Slinton 49616617Ssam public stepover() 4979677Slinton { 49811867Slinton Boolean b; 49911867Slinton 50016617Ssam if (traceexec) { 50116617Ssam printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); 50216617Ssam } 50311867Slinton if (single_stepping) { 50411867Slinton dostep(false); 50511867Slinton } else { 50611867Slinton b = inst_tracing; 50711867Slinton inst_tracing = true; 50811867Slinton dostep(false); 50911867Slinton inst_tracing = b; 51011867Slinton } 51116617Ssam if (traceexec) { 51216617Ssam printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); 51316617Ssam } 5149677Slinton } 5159677Slinton 5169677Slinton /* 51718230Slinton * Resume execution up to the given address. We can either ignore 51818230Slinton * breakpoints (stepto) or catch them (contto). 5199677Slinton */ 5209677Slinton 5219677Slinton public stepto(addr) 5229677Slinton Address addr; 5239677Slinton { 52416617Ssam xto(addr, false); 52516617Ssam } 52616617Ssam 52716617Ssam private contto (addr) 52816617Ssam Address addr; 52916617Ssam { 53016617Ssam xto(addr, true); 53116617Ssam } 53216617Ssam 53316617Ssam private xto (addr, catchbps) 53416617Ssam Address addr; 53516617Ssam boolean catchbps; 53616617Ssam { 53716617Ssam Address curpc; 53816617Ssam 53916617Ssam if (catchbps) { 54016617Ssam stepover(); 5419677Slinton } 54216617Ssam curpc = process->reg[PROGCTR]; 54316617Ssam if (addr != curpc) { 54416617Ssam if (traceexec) { 54516617Ssam printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); 54616617Ssam } 54716617Ssam if (catchbps) { 54816617Ssam setallbps(); 54916617Ssam } 55016617Ssam setbp(addr); 55116617Ssam resume(DEFSIG); 55216617Ssam unsetbp(addr); 55316617Ssam if (catchbps) { 55416617Ssam unsetallbps(); 55516617Ssam } 55616617Ssam if (not isbperr()) { 55716617Ssam printstatus(); 55816617Ssam } 55916617Ssam } 5609677Slinton } 5619677Slinton 5629677Slinton /* 5639677Slinton * Print the status of the process. 5649677Slinton * This routine does not return. 5659677Slinton */ 5669677Slinton 567*33331Sdonn public printstatus () 5689677Slinton { 56914395Slinton int status; 57014395Slinton 5719843Slinton if (process->status == FINISHED) { 5729843Slinton exit(0); 5739843Slinton } else { 574*33331Sdonn if (runfirst) { 575*33331Sdonn fprintf(stderr, "\nEntering debugger ...\n"); 576*33331Sdonn printheading(); 577*33331Sdonn init(); 578*33331Sdonn } 57916617Ssam setcurfunc(whatblock(pc)); 5809677Slinton getsrcpos(); 5819843Slinton if (process->signo == SIGINT) { 5829843Slinton isstopped = true; 5839843Slinton printerror(); 5849843Slinton } else if (isbperr() and isstopped) { 5859843Slinton printf("stopped "); 58611172Slinton printloc(); 58711172Slinton putchar('\n'); 5889843Slinton if (curline > 0) { 5899843Slinton printlines(curline, curline); 5909843Slinton } else { 5919843Slinton printinst(pc, pc); 5929843Slinton } 5939843Slinton erecover(); 5949677Slinton } else { 5959843Slinton fixintr(); 5969677Slinton isstopped = true; 5979677Slinton printerror(); 5989677Slinton } 5999677Slinton } 6009677Slinton } 6019677Slinton 6029677Slinton /* 60311172Slinton * Print out the current location in the debuggee. 60411172Slinton */ 60511172Slinton 60611172Slinton public printloc() 60711172Slinton { 60811172Slinton printf("in "); 60911172Slinton printname(stdout, curfunc); 61011172Slinton putchar(' '); 61114757Slinton if (curline > 0 and not useInstLoc) { 61211172Slinton printsrcpos(); 61311172Slinton } else { 61414757Slinton useInstLoc = false; 61514757Slinton curline = 0; 61611172Slinton printf("at 0x%x", pc); 61711172Slinton } 61811172Slinton } 61911172Slinton 62011172Slinton /* 6219677Slinton * Some functions for testing the state of the process. 6229677Slinton */ 6239677Slinton 6249677Slinton public Boolean notstarted(p) 6259677Slinton Process p; 6269677Slinton { 6279677Slinton return (Boolean) (p->status == NOTSTARTED); 6289677Slinton } 6299677Slinton 6309677Slinton public Boolean isfinished(p) 6319677Slinton Process p; 6329677Slinton { 6339677Slinton return (Boolean) (p->status == FINISHED); 6349677Slinton } 6359677Slinton 6369677Slinton /* 63718230Slinton * Predicate to test if the reason the process stopped was because 63818230Slinton * of a breakpoint. If so, as a side effect clear the local copy of 63918230Slinton * signal handler associated with process. We must do this so as to 64018230Slinton * not confuse future stepping or continuing by possibly concluding 64118230Slinton * the process should continue with a SIGTRAP handler. 6429677Slinton */ 6439677Slinton 64418230Slinton public boolean isbperr() 64518230Slinton { 64618230Slinton Process p; 64718230Slinton boolean b; 64818230Slinton 64918230Slinton p = process; 65018230Slinton if (p->status == STOPPED and p->signo == SIGTRAP) { 65118230Slinton b = true; 65218230Slinton p->sigstatus = 0; 65318230Slinton } else { 65418230Slinton b = false; 65518230Slinton } 65618230Slinton return b; 65718230Slinton } 65818230Slinton 65918230Slinton /* 66018230Slinton * Return the signal number that stopped the process. 66118230Slinton */ 66218230Slinton 66318230Slinton public integer errnum (p) 6649677Slinton Process p; 6659677Slinton { 6669677Slinton return p->signo; 6679677Slinton } 6689677Slinton 66918230Slinton /* 67018230Slinton * Return the signal code associated with the signal. 67118230Slinton */ 67218230Slinton 67318230Slinton public integer errcode (p) 67416931Ssam Process p; 67516931Ssam { 67616931Ssam return p->sigcode; 67716931Ssam } 67816931Ssam 6799677Slinton /* 6809677Slinton * Return the termination code of the process. 6819677Slinton */ 6829677Slinton 68318230Slinton public integer exitcode (p) 6849677Slinton Process p; 6859677Slinton { 6869677Slinton return p->exitval; 6879677Slinton } 6889677Slinton 6899677Slinton /* 6909677Slinton * These routines are used to access the debuggee process from 6919677Slinton * outside this module. 6929677Slinton * 6939677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 69414757Slinton * The system generates an I/O error when a ptrace fails. During reads 69514757Slinton * these are ignored, during writes they are reported as an error, and 69614757Slinton * for anything else they cause a fatal error. 6979677Slinton */ 6989677Slinton 6999677Slinton extern Intfunc *onsyserr(); 7009677Slinton 7019677Slinton private badaddr; 70214757Slinton private read_err(), write_err(); 7039677Slinton 7049677Slinton /* 7059677Slinton * Read from the process' instruction area. 7069677Slinton */ 7079677Slinton 7089677Slinton public iread(buff, addr, nbytes) 7099677Slinton char *buff; 7109677Slinton Address addr; 7119677Slinton int nbytes; 7129677Slinton { 7139677Slinton Intfunc *f; 7149677Slinton 71514757Slinton f = onsyserr(EIO, read_err); 7169677Slinton badaddr = addr; 7179677Slinton if (coredump) { 7189677Slinton coredump_readtext(buff, addr, nbytes); 7199677Slinton } else { 7209677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 7219677Slinton } 7229677Slinton onsyserr(EIO, f); 7239677Slinton } 7249677Slinton 7259677Slinton /* 7269677Slinton * Write to the process' instruction area, usually in order to set 7279677Slinton * or unset a breakpoint. 7289677Slinton */ 7299677Slinton 7309677Slinton public iwrite(buff, addr, nbytes) 7319677Slinton char *buff; 7329677Slinton Address addr; 7339677Slinton int nbytes; 7349677Slinton { 7359677Slinton Intfunc *f; 7369677Slinton 7379677Slinton if (coredump) { 7389677Slinton error("no process to write to"); 7399677Slinton } 74014757Slinton f = onsyserr(EIO, write_err); 7419677Slinton badaddr = addr; 7429677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 7439677Slinton onsyserr(EIO, f); 7449677Slinton } 7459677Slinton 7469677Slinton /* 7479677Slinton * Read for the process' data area. 7489677Slinton */ 7499677Slinton 7509677Slinton public dread(buff, addr, nbytes) 7519677Slinton char *buff; 7529677Slinton Address addr; 7539677Slinton int nbytes; 7549677Slinton { 7559677Slinton Intfunc *f; 7569677Slinton 7579677Slinton badaddr = addr; 7589677Slinton if (coredump) { 75918230Slinton f = onsyserr(EFAULT, read_err); 7609677Slinton coredump_readdata(buff, addr, nbytes); 76118230Slinton onsyserr(EFAULT, f); 7629677Slinton } else { 76318230Slinton f = onsyserr(EIO, read_err); 7649677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 76518230Slinton onsyserr(EIO, f); 7669677Slinton } 7679677Slinton } 7689677Slinton 7699677Slinton /* 7709677Slinton * Write to the process' data area. 7719677Slinton */ 7729677Slinton 7739677Slinton public dwrite(buff, addr, nbytes) 7749677Slinton char *buff; 7759677Slinton Address addr; 7769677Slinton int nbytes; 7779677Slinton { 7789677Slinton Intfunc *f; 7799677Slinton 7809677Slinton if (coredump) { 7819677Slinton error("no process to write to"); 7829677Slinton } 78314757Slinton f = onsyserr(EIO, write_err); 7849677Slinton badaddr = addr; 7859677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 7869677Slinton onsyserr(EIO, f); 7879677Slinton } 7889677Slinton 7899677Slinton /* 79014757Slinton * Trap for errors in reading or writing to a process. 79114757Slinton * The current approach is to "ignore" read errors and complain 79214757Slinton * bitterly about write errors. 7939677Slinton */ 7949677Slinton 79514757Slinton private read_err() 7969677Slinton { 79711560Slinton /* 79814757Slinton * Ignore. 79911560Slinton */ 8009677Slinton } 8019677Slinton 80214757Slinton private write_err() 80314757Slinton { 80414757Slinton error("can't write to process (address 0x%x)", badaddr); 80514757Slinton } 80614757Slinton 8079677Slinton /* 8089677Slinton * Ptrace interface. 8099677Slinton */ 8109677Slinton 8119677Slinton #define WMASK (~(sizeof(Word) - 1)) 812*33331Sdonn #define cachehash(addr) ((unsigned) ((addr >> 2) % CACHESIZE)) 8139677Slinton 8149677Slinton #define FIRSTSIG SIGINT 8159677Slinton #define LASTSIG SIGQUIT 8169677Slinton #define ischild(pid) ((pid) == 0) 81718230Slinton #define traceme() ptrace(0, 0, 0, 0) 8189677Slinton #define setrep(n) (1 << ((n)-1)) 8199677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 8209677Slinton 8219677Slinton /* 82218230Slinton * Ptrace options (specified in first argument). 82318230Slinton */ 82418230Slinton 82518230Slinton #define UREAD 3 /* read from process's user structure */ 82618230Slinton #define UWRITE 6 /* write to process's user structure */ 82718230Slinton #define IREAD 1 /* read from process's instruction space */ 82818230Slinton #define IWRITE 4 /* write to process's instruction space */ 82918230Slinton #define DREAD 2 /* read from process's data space */ 83018230Slinton #define DWRITE 5 /* write to process's data space */ 83118230Slinton #define CONT 7 /* continue stopped process */ 83218230Slinton #define SSTEP 9 /* continue for approximately one instruction */ 83318230Slinton #define PKILL 8 /* terminate the process */ 83418230Slinton 835*33331Sdonn #ifdef IRIS 836*33331Sdonn # define readreg(p, r) ptrace(10, p->pid, r, 0) 837*33331Sdonn # define writereg(p, r, v) ptrace(11, p->pid, r, v) 838*33331Sdonn #else 839*33331Sdonn # define readreg(p, r) ptrace(UREAD, p->pid, regloc(r), 0); 840*33331Sdonn # define writereg(p, r, v) ptrace(UWRITE, p->pid, regloc(r), v); 841*33331Sdonn #endif 842*33331Sdonn 84318230Slinton /* 8449677Slinton * Start up a new process by forking and exec-ing the 8459677Slinton * given argument list, returning when the process is loaded 8469677Slinton * and ready to execute. The PROCESS information (pointed to 8479677Slinton * by the first argument) is appropriately filled. 8489677Slinton * 8499677Slinton * If the given PROCESS structure is associated with an already running 8509677Slinton * process, we terminate it. 8519677Slinton */ 8529677Slinton 8539677Slinton /* VARARGS2 */ 8549677Slinton private pstart(p, argv, infile, outfile) 8559677Slinton Process p; 8569677Slinton String argv[]; 8579677Slinton String infile; 8589677Slinton String outfile; 8599677Slinton { 8609677Slinton int status; 8619677Slinton 86216617Ssam if (p->pid != 0) { 86316617Ssam pterm(p); 86418230Slinton cacheflush(p); 8659677Slinton } 86618230Slinton fflush(stdout); 8679677Slinton psigtrace(p, SIGTRAP, true); 868*33331Sdonn # ifdef IRIS 869*33331Sdonn p->pid = fork(); 870*33331Sdonn # else 871*33331Sdonn p->pid = vfork(); 872*33331Sdonn # endif 87314395Slinton if (p->pid == -1) { 8749677Slinton panic("can't fork"); 8759677Slinton } 8769677Slinton if (ischild(p->pid)) { 87718230Slinton nocatcherrs(); 8789677Slinton traceme(); 8799677Slinton if (infile != nil) { 88016617Ssam infrom(infile); 8819677Slinton } 8829677Slinton if (outfile != nil) { 88316617Ssam outto(outfile); 8849677Slinton } 88511832Slinton execv(argv[0], argv); 88611172Slinton _exit(1); 8879677Slinton } 8889677Slinton pwait(p->pid, &status); 8899677Slinton getinfo(p, status); 8909677Slinton if (p->status != STOPPED) { 89118230Slinton beginerrmsg(); 89218230Slinton fprintf(stderr, "warning: cannot execute %s\n", argv[0]); 89318230Slinton } else { 89418230Slinton ptraced(p->pid); 8959677Slinton } 8969677Slinton } 8979677Slinton 8989677Slinton /* 89916617Ssam * Terminate a ptrace'd process. 90016617Ssam */ 90116617Ssam 90216617Ssam public pterm (p) 90316617Ssam Process p; 90416617Ssam { 90516617Ssam integer status; 90616617Ssam 90716617Ssam if (p != nil and p->pid != 0) { 90818230Slinton ptrace(PKILL, p->pid, 0, 0); 90916617Ssam pwait(p->pid, &status); 91016617Ssam unptraced(p->pid); 91116617Ssam } 91216617Ssam } 91316617Ssam 91416617Ssam /* 91511867Slinton * Continue a stopped process. The first argument points to a Process 91611867Slinton * structure. Before the process is restarted it's user area is modified 91711867Slinton * according to the values in the structure. When this routine finishes, 9189677Slinton * the structure has the new values from the process's user area. 9199677Slinton * 9209677Slinton * Pcont terminates when the process stops with a signal pending that 9219677Slinton * is being traced (via psigtrace), or when the process terminates. 9229677Slinton */ 9239677Slinton 92411867Slinton private pcont(p, signo) 9259677Slinton Process p; 92611867Slinton int signo; 9279677Slinton { 92816617Ssam int s, status; 9299677Slinton 9309677Slinton if (p->pid == 0) { 93118230Slinton error("program is not active"); 9329677Slinton } 93316617Ssam s = signo; 9349677Slinton do { 93516617Ssam setinfo(p, s); 93616617Ssam if (traceexec) { 93716617Ssam printf("!! pcont from 0x%x with signal %d (%d)\n", 93816617Ssam p->reg[PROGCTR], s, p->signo); 93916617Ssam fflush(stdout); 94016617Ssam } 9419677Slinton sigs_off(); 94218230Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 94314395Slinton panic("error %d trying to continue process", errno); 9449677Slinton } 9459677Slinton pwait(p->pid, &status); 9469677Slinton sigs_on(); 9479677Slinton getinfo(p, status); 94818230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 94918230Slinton printf("!! ignored signal %d at 0x%x\n", 95018230Slinton p->signo, p->reg[PROGCTR]); 95116617Ssam fflush(stdout); 95216617Ssam } 95316617Ssam s = p->signo; 9549677Slinton } while (p->status == STOPPED and not istraced(p)); 95516617Ssam if (traceexec) { 95616617Ssam printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); 95716617Ssam fflush(stdout); 95816617Ssam } 9599677Slinton } 9609677Slinton 9619677Slinton /* 9629677Slinton * Single step as best ptrace can. 9639677Slinton */ 9649677Slinton 96516617Ssam public pstep(p, signo) 9669677Slinton Process p; 96716617Ssam integer signo; 9689677Slinton { 96918230Slinton int s, status; 9709677Slinton 97118230Slinton s = signo; 97218230Slinton do { 97318230Slinton setinfo(p, s); 97418230Slinton if (traceexec) { 97518230Slinton printf("!! pstep from 0x%x with signal %d (%d)\n", 97618230Slinton p->reg[PROGCTR], s, p->signo); 97718230Slinton fflush(stdout); 97818230Slinton } 97918230Slinton sigs_off(); 98018230Slinton if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) { 98118230Slinton panic("error %d trying to step process", errno); 98218230Slinton } 98318230Slinton pwait(p->pid, &status); 98418230Slinton sigs_on(); 98518230Slinton getinfo(p, status); 986*33331Sdonn # if mc68000 || m68000 987*33331Sdonn if (p->status == STOPPED and p->signo == SIGTRAP) { 988*33331Sdonn p->reg[PROGCTR] += 2; 989*33331Sdonn } 990*33331Sdonn # endif 99118230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 99218230Slinton printf("!! pstep ignored signal %d at 0x%x\n", 99318230Slinton p->signo, p->reg[PROGCTR]); 99418230Slinton fflush(stdout); 99518230Slinton } 99618230Slinton s = p->signo; 99718230Slinton } while (p->status == STOPPED and not istraced(p)); 99816617Ssam if (traceexec) { 99918230Slinton printf("!! pstep to 0x%x on signal %d\n", 100018230Slinton p->reg[PROGCTR], p->signo); 100116617Ssam fflush(stdout); 100216617Ssam } 100316617Ssam if (p->status != STOPPED) { 100418230Slinton if (p->exitval == 0) { 100518230Slinton error("program exited\n"); 100618230Slinton } else { 100718230Slinton error("program exited with code %d\n", p->exitval); 100818230Slinton } 100916617Ssam } 10109677Slinton } 10119677Slinton 10129677Slinton /* 10139677Slinton * Return from execution when the given signal is pending. 10149677Slinton */ 10159677Slinton 10169677Slinton public psigtrace(p, sig, sw) 10179677Slinton Process p; 10189677Slinton int sig; 10199677Slinton Boolean sw; 10209677Slinton { 10219677Slinton if (sw) { 10229677Slinton p->sigset |= setrep(sig); 10239677Slinton } else { 10249677Slinton p->sigset &= ~setrep(sig); 10259677Slinton } 10269677Slinton } 10279677Slinton 10289677Slinton /* 10299677Slinton * Don't catch any signals. 10309677Slinton * Particularly useful when letting a process finish uninhibited. 10319677Slinton */ 10329677Slinton 10339677Slinton public unsetsigtraces(p) 10349677Slinton Process p; 10359677Slinton { 10369677Slinton p->sigset = 0; 10379677Slinton } 10389677Slinton 10399677Slinton /* 10409677Slinton * Turn off attention to signals not being caught. 10419677Slinton */ 10429677Slinton 10439677Slinton private Intfunc *sigfunc[NSIG]; 10449677Slinton 10459677Slinton private sigs_off() 10469677Slinton { 10479677Slinton register int i; 10489677Slinton 10499677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10509677Slinton if (i != SIGKILL) { 10519677Slinton sigfunc[i] = signal(i, SIG_IGN); 10529677Slinton } 10539677Slinton } 10549677Slinton } 10559677Slinton 10569677Slinton /* 10579677Slinton * Turn back on attention to signals. 10589677Slinton */ 10599677Slinton 10609677Slinton private sigs_on() 10619677Slinton { 10629677Slinton register int i; 10639677Slinton 10649677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10659677Slinton if (i != SIGKILL) { 10669677Slinton signal(i, sigfunc[i]); 10679677Slinton } 10689677Slinton } 10699677Slinton } 10709677Slinton 10719677Slinton /* 10729677Slinton * Get process information from user area. 10739677Slinton */ 10749677Slinton 1075*33331Sdonn private getinfo (p, status) 10769677Slinton register Process p; 10779677Slinton register int status; 10789677Slinton { 10799677Slinton register int i; 108016617Ssam Address addr; 10819677Slinton 10829677Slinton p->signo = (status&0177); 10839677Slinton p->exitval = ((status >> 8)&0377); 10849677Slinton if (p->signo != STOPPED) { 10859677Slinton p->status = FINISHED; 108614757Slinton p->pid = 0; 108716617Ssam p->reg[PROGCTR] = 0; 10889677Slinton } else { 10899677Slinton p->status = p->signo; 10909677Slinton p->signo = p->exitval; 10919677Slinton p->exitval = 0; 1092*33331Sdonn # ifdef IRIS 1093*33331Sdonn p->mask = readreg(p, RPS); 1094*33331Sdonn # else 1095*33331Sdonn p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0); 1096*33331Sdonn p->mask = readreg(p, PS); 1097*33331Sdonn # endif 10989677Slinton for (i = 0; i < NREG; i++) { 1099*33331Sdonn p->reg[i] = readreg(p, rloc[i]); 11009677Slinton p->oreg[i] = p->reg[i]; 11019677Slinton } 1102*33331Sdonn # ifdef mc68000 1103*33331Sdonn if (p->status == STOPPED and p->signo == SIGTRAP and 1104*33331Sdonn p->reg[PROGCTR] > CODESTART 1105*33331Sdonn ) { 1106*33331Sdonn p->reg[PROGCTR] -= 2; 1107*33331Sdonn } 1108*33331Sdonn # endif 110911768Slinton savetty(stdout, &(p->ttyinfo)); 111016617Ssam addr = (Address) &(((struct user *) 0)->u_signal[p->signo]); 111118230Slinton p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0); 11129677Slinton } 11139677Slinton } 11149677Slinton 11159677Slinton /* 11169677Slinton * Set process's user area information from given process structure. 11179677Slinton */ 11189677Slinton 1119*33331Sdonn private setinfo (p, signo) 11209677Slinton register Process p; 112111867Slinton int signo; 11229677Slinton { 11239677Slinton register int i; 11249677Slinton register int r; 11259677Slinton 112614757Slinton if (signo == DEFSIG) { 112716617Ssam if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) { 112814757Slinton p->signo = 0; 112914757Slinton } 113014757Slinton } else { 113111867Slinton p->signo = signo; 11329677Slinton } 11339677Slinton for (i = 0; i < NREG; i++) { 11349677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 1135*33331Sdonn writereg(p, rloc[i], r); 11369677Slinton } 11379677Slinton } 113811768Slinton restoretty(stdout, &(p->ttyinfo)); 11399677Slinton } 11409677Slinton 11419677Slinton /* 114216617Ssam * Return the address associated with the current signal. 114316617Ssam * (Plus two since the address points to the beginning of a procedure). 114416617Ssam */ 114516617Ssam 114616617Ssam public Address usignal (p) 114716617Ssam Process p; 114816617Ssam { 114916617Ssam Address r; 115016617Ssam 115116617Ssam r = p->sigstatus; 115216617Ssam if (r != 0 and r != 1) { 1153*33331Sdonn r += FUNCOFFSET; 115416617Ssam } 115516617Ssam return r; 115616617Ssam } 115716617Ssam 115816617Ssam /* 11599677Slinton * Structure for reading and writing by words, but dealing with bytes. 11609677Slinton */ 11619677Slinton 11629677Slinton typedef union { 11639677Slinton Word pword; 11649677Slinton Byte pbyte[sizeof(Word)]; 11659677Slinton } Pword; 11669677Slinton 11679677Slinton /* 11689677Slinton * Read (write) from (to) the process' address space. 11699677Slinton * We must deal with ptrace's inability to look anywhere other 11709677Slinton * than at a word boundary. 11719677Slinton */ 11729677Slinton 11739677Slinton private Word fetch(); 11749677Slinton private store(); 11759677Slinton 11769677Slinton private pio(p, op, seg, buff, addr, nbytes) 11779677Slinton Process p; 11789677Slinton PioOp op; 11799677Slinton PioSeg seg; 11809677Slinton char *buff; 11819677Slinton Address addr; 11829677Slinton int nbytes; 11839677Slinton { 11849677Slinton register int i; 11859677Slinton register Address newaddr; 11869677Slinton register char *cp; 11879677Slinton char *bufend; 11889677Slinton Pword w; 11899677Slinton Address wordaddr; 11909677Slinton int byteoff; 11919677Slinton 11929677Slinton if (p->status != STOPPED) { 11939677Slinton error("program is not active"); 11949677Slinton } 11959677Slinton cp = buff; 11969677Slinton newaddr = addr; 11979677Slinton wordaddr = (newaddr&WMASK); 11989677Slinton if (wordaddr != newaddr) { 11999677Slinton w.pword = fetch(p, seg, wordaddr); 12009677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 12019677Slinton if (op == PREAD) { 12029677Slinton *cp++ = w.pbyte[i]; 12039677Slinton } else { 12049677Slinton w.pbyte[i] = *cp++; 12059677Slinton } 12069677Slinton nbytes--; 12079677Slinton } 12089677Slinton if (op == PWRITE) { 12099677Slinton store(p, seg, wordaddr, w.pword); 12109677Slinton } 12119677Slinton newaddr = wordaddr + sizeof(Word); 12129677Slinton } 12139677Slinton byteoff = (nbytes&(~WMASK)); 12149677Slinton nbytes -= byteoff; 12159677Slinton bufend = cp + nbytes; 121626333Ssam #ifdef tahoe 121726333Ssam if (((int)cp)&WMASK) { 121826333Ssam /* 121926333Ssam * Must copy a byte at a time, buffer not word addressable. 122026333Ssam */ 122126333Ssam while (cp < bufend) { 122226333Ssam if (op == PREAD) { 122326333Ssam w.pword = fetch(p, seg, newaddr); 122426333Ssam for (i = 0; i < sizeof(Word); i++) 122526333Ssam *cp++ = w.pbyte[i]; 122626333Ssam } else { 122726333Ssam for (i = 0; i < sizeof(Word); i++) 122826333Ssam w.pbyte[i] = *cp++; 122926333Ssam store(p, seg, newaddr, w.pword); 123026333Ssam } 123126333Ssam newaddr += sizeof(Word); 123226333Ssam } 123326333Ssam } else { 123426333Ssam /* 123526333Ssam * Buffer, word aligned, act normally... 123626333Ssam */ 123726333Ssam #endif 12389677Slinton while (cp < bufend) { 12399677Slinton if (op == PREAD) { 12409677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 12419677Slinton } else { 12429677Slinton store(p, seg, newaddr, *((Word *) cp)); 12439677Slinton } 12449677Slinton cp += sizeof(Word); 12459677Slinton newaddr += sizeof(Word); 12469677Slinton } 124726333Ssam #ifdef tahoe 124826333Ssam } 124926333Ssam #endif 12509677Slinton if (byteoff > 0) { 12519677Slinton w.pword = fetch(p, seg, newaddr); 12529677Slinton for (i = 0; i < byteoff; i++) { 12539677Slinton if (op == PREAD) { 12549677Slinton *cp++ = w.pbyte[i]; 12559677Slinton } else { 12569677Slinton w.pbyte[i] = *cp++; 12579677Slinton } 12589677Slinton } 12599677Slinton if (op == PWRITE) { 12609677Slinton store(p, seg, newaddr, w.pword); 12619677Slinton } 12629677Slinton } 12639677Slinton } 12649677Slinton 12659677Slinton /* 12669677Slinton * Get a word from a process at the given address. 12679677Slinton * The address is assumed to be on a word boundary. 12689677Slinton * 12699677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 12709677Slinton * to the instruction space since it is assumed to be pure. 12719677Slinton * 12729677Slinton * It is necessary to use a write-through scheme so that 12739677Slinton * breakpoints right next to each other don't interfere. 12749677Slinton */ 12759677Slinton 12769677Slinton private Integer nfetchs, nreads, nwrites; 12779677Slinton 12789677Slinton private Word fetch(p, seg, addr) 12799677Slinton Process p; 12809677Slinton PioSeg seg; 12819677Slinton register int addr; 12829677Slinton { 12839677Slinton register CacheWord *wp; 12849677Slinton register Word w; 12859677Slinton 12869677Slinton switch (seg) { 12879677Slinton case TEXTSEG: 12889677Slinton ++nfetchs; 12899677Slinton wp = &p->word[cachehash(addr)]; 12909677Slinton if (addr == 0 or wp->addr != addr) { 12919677Slinton ++nreads; 129218230Slinton w = ptrace(IREAD, p->pid, addr, 0); 12939677Slinton wp->addr = addr; 12949677Slinton wp->val = w; 12959677Slinton } else { 12969677Slinton w = wp->val; 12979677Slinton } 12989677Slinton break; 12999677Slinton 13009677Slinton case DATASEG: 130118230Slinton w = ptrace(DREAD, p->pid, addr, 0); 13029677Slinton break; 13039677Slinton 13049677Slinton default: 13059677Slinton panic("fetch: bad seg %d", seg); 13069677Slinton /* NOTREACHED */ 13079677Slinton } 13089677Slinton return w; 13099677Slinton } 13109677Slinton 13119677Slinton /* 13129677Slinton * Put a word into the process' address space at the given address. 13139677Slinton * The address is assumed to be on a word boundary. 13149677Slinton */ 13159677Slinton 13169677Slinton private store(p, seg, addr, data) 13179677Slinton Process p; 13189677Slinton PioSeg seg; 13199677Slinton int addr; 13209677Slinton Word data; 13219677Slinton { 13229677Slinton register CacheWord *wp; 13239677Slinton 13249677Slinton switch (seg) { 13259677Slinton case TEXTSEG: 13269677Slinton ++nwrites; 13279677Slinton wp = &p->word[cachehash(addr)]; 13289677Slinton wp->addr = addr; 13299677Slinton wp->val = data; 133018230Slinton ptrace(IWRITE, p->pid, addr, data); 13319677Slinton break; 13329677Slinton 13339677Slinton case DATASEG: 133418230Slinton ptrace(DWRITE, p->pid, addr, data); 13359677Slinton break; 13369677Slinton 13379677Slinton default: 13389677Slinton panic("store: bad seg %d", seg); 13399677Slinton /* NOTREACHED */ 13409677Slinton } 13419677Slinton } 13429677Slinton 134318230Slinton /* 134418230Slinton * Flush the instruction cache associated with a process. 134518230Slinton */ 134618230Slinton 134718230Slinton private cacheflush (p) 134818230Slinton Process p; 134918230Slinton { 135018230Slinton bzero(p->word, sizeof(p->word)); 135118230Slinton } 135218230Slinton 13539677Slinton public printptraceinfo() 13549677Slinton { 13559677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 13569677Slinton } 13579677Slinton 13589677Slinton /* 135916617Ssam * Redirect input. 136016617Ssam * Assuming this is called from a child, we should be careful to avoid 136116617Ssam * (possibly) shared standard I/O buffers. 13629677Slinton */ 13639677Slinton 136416617Ssam private infrom (filename) 136516617Ssam String filename; 136616617Ssam { 136716617Ssam Fileid in; 136816617Ssam 136916617Ssam in = open(filename, 0); 137016617Ssam if (in == -1) { 137116617Ssam write(2, "can't read ", 11); 137216617Ssam write(2, filename, strlen(filename)); 137316617Ssam write(2, "\n", 1); 137416617Ssam _exit(1); 137516617Ssam } 137616617Ssam fswap(0, in); 137716617Ssam } 137816617Ssam 137916617Ssam /* 138016617Ssam * Redirect standard output. 138116617Ssam * Same assumptions as for "infrom" above. 138216617Ssam */ 138316617Ssam 138416617Ssam private outto (filename) 138516617Ssam String filename; 138616617Ssam { 138716617Ssam Fileid out; 138816617Ssam 138916617Ssam out = creat(filename, 0666); 139016617Ssam if (out == -1) { 139116617Ssam write(2, "can't write ", 12); 139216617Ssam write(2, filename, strlen(filename)); 139316617Ssam write(2, "\n", 1); 139416617Ssam _exit(1); 139516617Ssam } 139616617Ssam fswap(1, out); 139716617Ssam } 139816617Ssam 139916617Ssam /* 140016617Ssam * Swap file numbers, useful for redirecting standard input or output. 140116617Ssam */ 140216617Ssam 14039677Slinton private fswap(oldfd, newfd) 140416617Ssam Fileid oldfd; 140516617Ssam Fileid newfd; 14069677Slinton { 14079677Slinton if (oldfd != newfd) { 14089677Slinton close(oldfd); 14099677Slinton dup(newfd); 14109677Slinton close(newfd); 14119677Slinton } 14129677Slinton } 141316928Ssam 141416928Ssam /* 141518230Slinton * Signal name manipulation. 141616928Ssam */ 141718230Slinton 141818230Slinton private String signames[NSIG] = { 141918230Slinton 0, 142018230Slinton "HUP", "INT", "QUIT", "ILL", "TRAP", 142118230Slinton "IOT", "EMT", "FPE", "KILL", "BUS", 142218230Slinton "SEGV", "SYS", "PIPE", "ALRM", "TERM", 142318230Slinton 0, "STOP", "TSTP", "CONT", "CHLD", 142418230Slinton "TTIN", "TTOU", "TINT", "XCPU", "XFSZ", 142526333Ssam "VTALRM", "PROF", "WINCH", "USR1", "USR2" 142616928Ssam }; 142716928Ssam 142816928Ssam /* 142918230Slinton * Get the signal number associated with a given name. 143018230Slinton * The name is first translated to upper case if necessary. 143116928Ssam */ 143218230Slinton 143318230Slinton public integer siglookup (s) 143416928Ssam String s; 143516928Ssam { 143618230Slinton register char *p, *q; 143718230Slinton char buf[100]; 143818230Slinton integer i; 143916928Ssam 144018230Slinton p = s; 144118230Slinton q = buf; 144218230Slinton while (*p != '\0') { 144318230Slinton if (*p >= 'a' and *p <= 'z') { 144418230Slinton *q = (*p - 'a') + 'A'; 144518230Slinton } else { 144618230Slinton *q = *p; 144718230Slinton } 144818230Slinton ++p; 144918230Slinton ++q; 145018230Slinton } 145118230Slinton *q = '\0'; 145218230Slinton p = buf; 145318230Slinton if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') { 145418230Slinton p += 3; 145518230Slinton } 145618230Slinton i = 1; 145718230Slinton for (;;) { 145818230Slinton if (i >= sizeof(signames) div sizeof(signames[0])) { 145918230Slinton error("signal \"%s\" unknown", s); 146018230Slinton i = 0; 146118230Slinton break; 146218230Slinton } 146318230Slinton if (signames[i] != nil and streq(signames[i], p)) { 146418230Slinton break; 146518230Slinton } 146618230Slinton ++i; 146718230Slinton } 146818230Slinton return i; 146916928Ssam } 147016928Ssam 147116928Ssam /* 147218230Slinton * Print all signals being ignored by the debugger. 147318230Slinton * These signals are auotmatically 147416928Ssam * passed on to the debugged process. 147516928Ssam */ 147618230Slinton 147718230Slinton public printsigsignored (p) 147816931Ssam Process p; 147916928Ssam { 148016931Ssam printsigs(~p->sigset); 148116928Ssam } 148216928Ssam 148316928Ssam /* 148416928Ssam * Print all signals being intercepted by 148516928Ssam * the debugger for the specified process. 148616928Ssam */ 148718230Slinton 148816931Ssam public printsigscaught(p) 148916931Ssam Process p; 149016928Ssam { 149116931Ssam printsigs(p->sigset); 149216931Ssam } 149316931Ssam 149418230Slinton private printsigs (set) 149518230Slinton integer set; 149616931Ssam { 149718230Slinton integer s; 149818230Slinton char separator[2]; 149916931Ssam 150018230Slinton separator[0] = '\0'; 150118230Slinton for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) { 150218230Slinton if (set & setrep(s)) { 150318230Slinton if (signames[s] != nil) { 150418230Slinton printf("%s%s", separator, signames[s]); 150518230Slinton separator[0] = ' '; 150618230Slinton separator[1] = '\0'; 150718230Slinton } 150816928Ssam } 150918230Slinton } 151018230Slinton if (separator[0] == ' ') { 151116931Ssam putchar('\n'); 151216931Ssam } 151316928Ssam } 1514