diff options
author | Shenghou Ma <minux.ma@gmail.com> | 2014-02-27 23:17:47 -0500 |
---|---|---|
committer | Shenghou Ma <minux.ma@gmail.com> | 2014-02-27 23:17:47 -0500 |
commit | 20035ed43cfd67cddd01969e155794e1e057d9e6 (patch) | |
tree | b8d840938e7f506f433ff6abc0b816e0b7cf3206 /src/libmach | |
parent | db800afb4e7b46df67feba70cda683f34110619b (diff) | |
download | plan9port-20035ed43cfd67cddd01969e155794e1e057d9e6.tar.gz plan9port-20035ed43cfd67cddd01969e155794e1e057d9e6.tar.bz2 plan9port-20035ed43cfd67cddd01969e155794e1e057d9e6.zip |
all: DragonFly port.
Fix compilation problems, libdraw still doesn't work right yet.
LGTM=rsc
R=rsc
https://codereview.appspot.com/67820046
Diffstat (limited to 'src/libmach')
-rw-r--r-- | src/libmach/DragonFly.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/libmach/DragonFly.c b/src/libmach/DragonFly.c new file mode 100644 index 00000000..92ffdb92 --- /dev/null +++ b/src/libmach/DragonFly.c @@ -0,0 +1,318 @@ +/* + * process interface for DragonFly BSD + * + * we could be a little more careful about not using + * ptrace unless absolutely necessary. this would let us + * look at processes without stopping them. + * + * I'd like to make this a bit more generic (there's too much + * duplication with Linux and presumably other systems), + * but ptrace is too damn system-specific. + */ + +#include <u.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <machine/reg.h> +#include <signal.h> +#include <errno.h> +#include <libc.h> +#include <mach.h> +#include "ureg386.h" + +Mach *machcpu = &mach386; + +typedef struct PtraceRegs PtraceRegs; +struct PtraceRegs +{ + Regs r; + int pid; +}; + +static int ptracerw(Map*, Seg*, ulong, void*, uint, int); +static int ptraceregrw(Regs*, char*, ulong*, int); + +void +unmapproc(Map *map) +{ + int i; + + if(map == nil) + return; + for(i=0; i<map->nseg; i++) + while(i<map->nseg && map->seg[i].pid){ + map->nseg--; + memmove(&map->seg[i], &map->seg[i+1], + (map->nseg-i)*sizeof(map->seg[0])); + } +} + +int +mapproc(int pid, Map *map, Regs **rp) +{ + Seg s; + PtraceRegs *r; + + if(ptrace(PT_ATTACH, pid, 0, 0) < 0) + if(ptrace(PT_READ_I, pid, 0, 0)<0 && errno!=EINVAL) + if(ptrace(PT_ATTACH, pid, 0, 0) < 0){ + werrstr("ptrace attach %d: %r", pid); + return -1; + } + + if(ctlproc(pid, "waitanyway") < 0){ + ptrace(PT_DETACH, pid, 0, 0); + return -1; + } + + memset(&s, 0, sizeof s); + s.base = 0; + s.size = 0xFFFFFFFF; + s.offset = 0; + s.name = "data"; + s.file = nil; + s.rw = ptracerw; + s.pid = pid; + if(addseg(map, s) < 0) + return -1; + + if((r = mallocz(sizeof(PtraceRegs), 1)) == nil) + return -1; + r->r.rw = ptraceregrw; + r->pid = pid; + *rp = (Regs*)r; + return 0; +} + +int +detachproc(int pid) +{ + return ptrace(PT_DETACH, pid, 0, 0); +} + +static int +ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr) +{ + int i; + u32int u; + uchar buf[4]; + + addr += seg->base; + for(i=0; i<n; i+=4){ + if(isr){ + errno = 0; + u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0); + if(errno) + goto ptraceerr; + if(n-i >= 4) + *(u32int*)((char*)v+i) = u; + else{ + *(u32int*)buf = u; + memmove((char*)v+i, buf, n-i); + } + }else{ + if(n-i >= 4) + u = *(u32int*)((char*)v+i); + else{ + errno = 0; + u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0); + if(errno) + return -1; + *(u32int*)buf = u; + memmove(buf, (char*)v+i, n-i); + u = *(u32int*)buf; + } + if(ptrace(PT_WRITE_D, seg->pid, (char*)addr+i, u) < 0) + goto ptraceerr; + } + } + return 0; + +ptraceerr: + werrstr("ptrace: %r"); + return -1; +} + +static char *freebsdregs[] = { + "FS", + "ES", + "DS", + "DI", + "SI", + "BP", + "SP", + "BX", + "DX", + "CX", + "AX", + "TRAP", + "PC", + "CS", + "EFLAGS", + "SP", + "SS", + "GS", +}; + +static ulong +reg2freebsd(char *reg) +{ + int i; + + for(i=0; i<nelem(freebsdregs); i++) + if(strcmp(freebsdregs[i], reg) == 0) + return 4*i; + return ~(ulong)0; +} + +static int +ptraceregrw(Regs *regs, char *name, ulong *val, int isr) +{ + int pid; + ulong addr; + struct reg mregs; + + addr = reg2freebsd(name); + if(~addr == 0){ + if(isr){ + *val = ~(ulong)0; + return 0; + } + werrstr("register not available"); + return -1; + } + + pid = ((PtraceRegs*)regs)->pid; + if(ptrace(PT_GETREGS, pid, (char*)&mregs, 0) < 0) + return -1; + if(isr) + *val = *(u32int*)((char*)&mregs+addr); + else{ + *(u32int*)((char*)&mregs+addr) = *val; + if(ptrace(PT_SETREGS, pid, (char*)&mregs, 0) < 0) + return -1; + } + return 0; +} + +char* +proctextfile(int pid) +{ + static char buf[1024], pbuf[128]; + + snprint(pbuf, sizeof pbuf, "/proc/%d/file", pid); + if(readlink(pbuf, buf, sizeof buf) >= 0) + return buf; + if(access(pbuf, AEXIST) >= 0) + return pbuf; + return nil; +} + +/* + + status The process status. This file is read-only and returns a single + line containing multiple space-separated fields as follows: + + o command name + o process id + o parent process id + o process group id + o session id + o major,minor of the controlling terminal, or -1,-1 if there is + no controlling terminal. + o a list of process flags: ctty if there is a controlling ter- + minal, sldr if the process is a session leader, noflags if + neither of the other two flags are set. + o the process start time in seconds and microseconds, comma + separated. + o the user time in seconds and microseconds, comma separated. + o the system time in seconds and microseconds, comma separated. + o the wait channel message + o the process credentials consisting of the effective user id + and the list of groups (whose first member is the effective + group id) all comma separated. +*/ + +int +procnotes(int pid, char ***pnotes) +{ + /* figure out the set of pending notes - how? */ + *pnotes = nil; + return 0; +} + +static int +isstopped(int pid) +{ + char buf[1024], *f[12]; + int fd, n, nf; + + snprint(buf, sizeof buf, "/proc/%d/status", pid); + if((fd = open(buf, OREAD)) < 0) + return 0; + n = read(fd, buf, sizeof buf-1); + close(fd); + if(n <= 0) + return 0; + buf[n] = 0; + + if((nf = tokenize(buf, f, nelem(f))) < 11) + return 0; + if(strcmp(f[10], "nochan") == 0) + return 1; + return 0; +} + +#undef waitpid + +int +ctlproc(int pid, char *msg) +{ + int p, status; + + if(strcmp(msg, "hang") == 0){ + if(pid == getpid()) + return ptrace(PT_TRACE_ME, 0, 0, 0); + werrstr("can only hang self"); + return -1; + } + if(strcmp(msg, "kill") == 0) + return ptrace(PT_KILL, pid, 0, 0); + if(strcmp(msg, "startstop") == 0){ + if(ptrace(PT_CONTINUE, pid, 0, 0) < 0) + return -1; + goto waitstop; + } +/* + if(strcmp(msg, "sysstop") == 0){ + if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) + return -1; + goto waitstop; + } +*/ + if(strcmp(msg, "stop") == 0){ + if(kill(pid, SIGSTOP) < 0) + return -1; + goto waitstop; + } + if(strcmp(msg, "waitanyway") == 0) + goto waitanyway; + if(strcmp(msg, "waitstop") == 0){ + waitstop: + if(isstopped(pid)) + return 0; + waitanyway: + for(;;){ + p = waitpid(pid, &status, WUNTRACED); + if(p <= 0) + return -1; + if(WIFEXITED(status) || WIFSTOPPED(status)) + return 0; + } + } + if(strcmp(msg, "start") == 0) + return ptrace(PT_CONTINUE, pid, 0, 0); + werrstr("unknown control message '%s'", msg); + return -1; +} |