plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

DragonFly.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 }