URI:
       tDragonFly.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tDragonFly.c (6117B)
       ---
            1 /*
            2  * process interface for DragonFly BSD
            3  *
            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.
            7  *
            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.
           11  */
           12 
           13 #include <u.h>
           14 #include <sys/ptrace.h>
           15 #include <sys/types.h>
           16 #include <sys/wait.h>
           17 #include <machine/reg.h>
           18 #include <signal.h>
           19 #include <errno.h>
           20 #include <libc.h>
           21 #include <mach.h>
           22 #include "ureg386.h"
           23 
           24 Mach *machcpu = &mach386;
           25 
           26 typedef struct PtraceRegs PtraceRegs;
           27 struct PtraceRegs
           28 {
           29         Regs r;
           30         int pid;
           31 };
           32 
           33 static int ptracerw(Map*, Seg*, ulong, void*, uint, int);
           34 static int ptraceregrw(Regs*, char*, ulong*, int);
           35 
           36 void
           37 unmapproc(Map *map)
           38 {
           39         int i;
           40 
           41         if(map == nil)
           42                 return;
           43         for(i=0; i<map->nseg; i++)
           44                 while(i<map->nseg && map->seg[i].pid){
           45                         map->nseg--;
           46                         memmove(&map->seg[i], &map->seg[i+1],
           47                                 (map->nseg-i)*sizeof(map->seg[0]));
           48                 }
           49 }
           50 
           51 int
           52 mapproc(int pid, Map *map, Regs **rp)
           53 {
           54         Seg s;
           55         PtraceRegs *r;
           56 
           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);
           61                 return -1;
           62         }
           63 
           64         if(ctlproc(pid, "waitanyway") < 0){
           65                 ptrace(PT_DETACH, pid, 0, 0);
           66                 return -1;
           67         }
           68 
           69         memset(&s, 0, sizeof s);
           70         s.base = 0;
           71         s.size = 0xFFFFFFFF;
           72         s.offset = 0;
           73         s.name = "data";
           74         s.file = nil;
           75         s.rw = ptracerw;
           76         s.pid = pid;
           77         if(addseg(map, s) < 0)
           78                 return -1;
           79 
           80         if((r = mallocz(sizeof(PtraceRegs), 1)) == nil)
           81                 return -1;
           82         r->r.rw = ptraceregrw;
           83         r->pid = pid;
           84         *rp = (Regs*)r;
           85         return 0;
           86 }
           87 
           88 int
           89 detachproc(int pid)
           90 {
           91         return ptrace(PT_DETACH, pid, 0, 0);
           92 }
           93 
           94 static int
           95 ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr)
           96 {
           97         int i;
           98         u32int u;
           99         uchar buf[4];
          100 
          101         addr += seg->base;
          102         for(i=0; i<n; i+=4){
          103                 if(isr){
          104                         errno = 0;
          105                         u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0);
          106                         if(errno)
          107                                 goto ptraceerr;
          108                         if(n-i >= 4)
          109                                 *(u32int*)((char*)v+i) = u;
          110                         else{
          111                                 *(u32int*)buf = u;
          112                                 memmove((char*)v+i, buf, n-i);
          113                         }
          114                 }else{
          115                         if(n-i >= 4)
          116                                 u = *(u32int*)((char*)v+i);
          117                         else{
          118                                 errno = 0;
          119                                 u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0);
          120                                 if(errno)
          121                                         return -1;
          122                                 *(u32int*)buf = u;
          123                                 memmove(buf, (char*)v+i, n-i);
          124                                 u = *(u32int*)buf;
          125                         }
          126                         if(ptrace(PT_WRITE_D, seg->pid, (char*)addr+i, u) < 0)
          127                                 goto ptraceerr;
          128                 }
          129         }
          130         return 0;
          131 
          132 ptraceerr:
          133         werrstr("ptrace: %r");
          134         return -1;
          135 }
          136 
          137 static char *freebsdregs[] = {
          138         "FS",
          139         "ES",
          140         "DS",
          141         "DI",
          142         "SI",
          143         "BP",
          144         "SP",
          145         "BX",
          146         "DX",
          147         "CX",
          148         "AX",
          149         "TRAP",
          150         "PC",
          151         "CS",
          152         "EFLAGS",
          153         "SP",
          154         "SS",
          155         "GS",
          156 };
          157 
          158 static ulong
          159 reg2freebsd(char *reg)
          160 {
          161         int i;
          162 
          163         for(i=0; i<nelem(freebsdregs); i++)
          164                 if(strcmp(freebsdregs[i], reg) == 0)
          165                         return 4*i;
          166         return ~(ulong)0;
          167 }
          168 
          169 static int
          170 ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
          171 {
          172         int pid;
          173         ulong addr;
          174         struct reg mregs;
          175 
          176         addr = reg2freebsd(name);
          177         if(~addr == 0){
          178                 if(isr){
          179                         *val = ~(ulong)0;
          180                         return 0;
          181                 }
          182                 werrstr("register not available");
          183                 return -1;
          184         }
          185 
          186         pid = ((PtraceRegs*)regs)->pid;
          187         if(ptrace(PT_GETREGS, pid, (char*)&mregs, 0) < 0)
          188                 return -1;
          189         if(isr)
          190                 *val = *(u32int*)((char*)&mregs+addr);
          191         else{
          192                 *(u32int*)((char*)&mregs+addr) = *val;
          193                 if(ptrace(PT_SETREGS, pid, (char*)&mregs, 0) < 0)
          194                         return -1;
          195         }
          196         return 0;
          197 }
          198 
          199 char*
          200 proctextfile(int pid)
          201 {
          202         static char buf[1024], pbuf[128];
          203 
          204         snprint(pbuf, sizeof pbuf, "/proc/%d/file", pid);
          205         if(readlink(pbuf, buf, sizeof buf) >= 0)
          206                 return buf;
          207         if(access(pbuf, AEXIST) >= 0)
          208                 return pbuf;
          209         return nil;
          210 }
          211 
          212 /*
          213 
          214   status  The process status.  This file is read-only and returns a single
          215              line containing multiple space-separated fields as follows:
          216 
          217              o         command name
          218              o         process id
          219              o         parent process id
          220              o         process group id
          221              o         session id
          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
          228                  separated.
          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.
          235 */
          236 
          237 int
          238 procnotes(int pid, char ***pnotes)
          239 {
          240         /* figure out the set of pending notes - how? */
          241         *pnotes = nil;
          242         return 0;
          243 }
          244 
          245 static int
          246 isstopped(int pid)
          247 {
          248         char buf[1024], *f[12];
          249         int fd, n, nf;
          250 
          251         snprint(buf, sizeof buf, "/proc/%d/status", pid);
          252         if((fd = open(buf, OREAD)) < 0)
          253                 return 0;
          254         n = read(fd, buf, sizeof buf-1);
          255         close(fd);
          256         if(n <= 0)
          257                 return 0;
          258         buf[n] = 0;
          259 
          260         if((nf = tokenize(buf, f, nelem(f))) < 11)
          261                 return 0;
          262         if(strcmp(f[10], "nochan") == 0)
          263                 return 1;
          264         return 0;
          265 }
          266 
          267 #undef waitpid
          268 
          269 int
          270 ctlproc(int pid, char *msg)
          271 {
          272         int p, status;
          273 
          274         if(strcmp(msg, "hang") == 0){
          275                 if(pid == getpid())
          276                         return ptrace(PT_TRACE_ME, 0, 0, 0);
          277                 werrstr("can only hang self");
          278                 return -1;
          279         }
          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)
          284                         return -1;
          285                 goto waitstop;
          286         }
          287 /*
          288         if(strcmp(msg, "sysstop") == 0){
          289                 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
          290                         return -1;
          291                 goto waitstop;
          292         }
          293 */
          294         if(strcmp(msg, "stop") == 0){
          295                 if(kill(pid, SIGSTOP) < 0)
          296                         return -1;
          297                 goto waitstop;
          298         }
          299         if(strcmp(msg, "waitanyway") == 0)
          300                 goto waitanyway;
          301         if(strcmp(msg, "waitstop") == 0){
          302         waitstop:
          303                 if(isstopped(pid))
          304                         return 0;
          305         waitanyway:
          306                 for(;;){
          307                         p = waitpid(pid, &status, WUNTRACED);
          308                         if(p <= 0)
          309                                 return -1;
          310                         if(WIFEXITED(status) || WIFSTOPPED(status))
          311                                 return 0;
          312                 }
          313         }
          314         if(strcmp(msg, "start") == 0)
          315                 return ptrace(PT_CONTINUE, pid, 0, 0);
          316         werrstr("unknown control message '%s'", msg);
          317         return -1;
          318 }