2 * process interface for FreeBSD
4 * we could be a little more careful about not using
5 * ptrace unless absolutely necessary. this would let us
6 * look at processes without stopping them.
8 * I'd like to make this a bit more generic (there's too much
9 * duplication with Linux and presumably other systems),
10 * but ptrace is too damn system-specific.
14 #include <sys/ptrace.h>
15 #include <sys/types.h>
17 #include <machine/reg.h>
24 Mach *machcpu = &mach386;
26 typedef struct PtraceRegs PtraceRegs;
33 static int ptracerw(Map*, Seg*, ulong, void*, uint, int);
34 static int ptraceregrw(Regs*, char*, ulong*, int);
43 for(i=0; i<map->nseg; i++)
44 while(i<map->nseg && map->seg[i].pid){
46 memmove(&map->seg[i], &map->seg[i+1],
47 (map->nseg-i)*sizeof(map->seg[0]));
52 mapproc(int pid, Map *map, Regs **rp)
57 if(ptrace(PT_ATTACH, pid, 0, 0) < 0)
58 if(ptrace(PT_READ_I, pid, 0, 0)<0 && errno!=EINVAL)
59 if(ptrace(PT_ATTACH, pid, 0, 0) < 0){
60 werrstr("ptrace attach %d: %r", pid);
64 if(ctlproc(pid, "waitanyway") < 0){
65 ptrace(PT_DETACH, pid, 0, 0);
69 memset(&s, 0, sizeof s);
77 if(addseg(map, s) < 0)
80 if((r = mallocz(sizeof(PtraceRegs), 1)) == nil)
82 r->r.rw = ptraceregrw;
91 return ptrace(PT_DETACH, pid, 0, 0);
95 ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr)
105 u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0);
109 *(u32int*)((char*)v+i) = u;
112 memmove((char*)v+i, buf, n-i);
116 u = *(u32int*)((char*)v+i);
119 u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0);
123 memmove(buf, (char*)v+i, n-i);
126 if(ptrace(PT_WRITE_D, seg->pid, (char*)addr+i, u) < 0)
133 werrstr("ptrace: %r");
137 static char *freebsdregs[] = {
159 reg2freebsd(char *reg)
163 for(i=0; i<nelem(freebsdregs); i++)
164 if(strcmp(freebsdregs[i], reg) == 0)
170 ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
176 addr = reg2freebsd(name);
182 werrstr("register not available");
186 pid = ((PtraceRegs*)regs)->pid;
187 if(ptrace(PT_GETREGS, pid, (char*)&mregs, 0) < 0)
190 *val = *(u32int*)((char*)&mregs+addr);
192 *(u32int*)((char*)&mregs+addr) = *val;
193 if(ptrace(PT_SETREGS, pid, (char*)&mregs, 0) < 0)
200 proctextfile(int pid)
202 static char buf[1024], pbuf[128];
204 snprint(pbuf, sizeof pbuf, "/proc/%d/file", pid);
205 if(readlink(pbuf, buf, sizeof buf) >= 0)
207 if(access(pbuf, AEXIST) >= 0)
214 status The process status. This file is read-only and returns a single
215 line containing multiple space-separated fields as follows:
222 o major,minor of the controlling terminal, or -1,-1 if there is
223 no controlling terminal.
224 o a list of process flags: ctty if there is a controlling ter-
225 minal, sldr if the process is a session leader, noflags if
226 neither of the other two flags are set.
227 o the process start time in seconds and microseconds, comma
229 o the user time in seconds and microseconds, comma separated.
230 o the system time in seconds and microseconds, comma separated.
231 o the wait channel message
232 o the process credentials consisting of the effective user id
233 and the list of groups (whose first member is the effective
234 group id) all comma separated.
238 procnotes(int pid, char ***pnotes)
240 /* figure out the set of pending notes - how? */
248 char buf[1024], *f[12];
251 snprint(buf, sizeof buf, "/proc/%d/status", pid);
252 if((fd = open(buf, OREAD)) < 0)
254 n = read(fd, buf, sizeof buf-1);
260 if((nf = tokenize(buf, f, nelem(f))) < 11)
262 if(strcmp(f[10], "nochan") == 0)
270 ctlproc(int pid, char *msg)
274 if(strcmp(msg, "hang") == 0){
276 return ptrace(PT_TRACE_ME, 0, 0, 0);
277 werrstr("can only hang self");
280 if(strcmp(msg, "kill") == 0)
281 return ptrace(PT_KILL, pid, 0, 0);
282 if(strcmp(msg, "startstop") == 0){
283 if(ptrace(PT_CONTINUE, pid, 0, 0) < 0)
288 if(strcmp(msg, "sysstop") == 0){
289 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
294 if(strcmp(msg, "stop") == 0){
295 if(kill(pid, SIGSTOP) < 0)
299 if(strcmp(msg, "waitanyway") == 0)
301 if(strcmp(msg, "waitstop") == 0){
307 p = waitpid(pid, &status, WUNTRACED);
310 if(WIFEXITED(status) || WIFSTOPPED(status))
314 if(strcmp(msg, "start") == 0)
315 return ptrace(PT_CONTINUE, pid, 0, 0);
316 werrstr("unknown control message '%s'", msg);