strace: Block the target when the strace q is full
[akaros.git] / kern / drivers / dev / proc.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 //#define DEBUG
11 /* proc on plan 9 has lots of capabilities, some of which we might
12  * want for akaros:
13  * debug control
14  * event tracing
15  * process control (no need for signal system call, etc.)
16  * textual status
17  * rather than excise code that won't work, I'm bracketing it with
18  * #if 0 until we know we don't want it
19  */
20 #include <vfs.h>
21 #include <kfs.h>
22 #include <slab.h>
23 #include <kmalloc.h>
24 #include <kref.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <assert.h>
28 #include <error.h>
29 #include <cpio.h>
30 #include <pmap.h>
31 #include <smp.h>
32 #include <umem.h>
33 #include <arch/vmm/vmm.h>
34 #include <ros/vmm.h>
35
36 struct dev procdevtab;
37
38 static char *devname(void)
39 {
40         return procdevtab.name;
41 }
42
43 enum {
44         Qdir,
45         Qtrace,
46         Qtracepids,
47         Qself,
48         Qns,
49         Qargs,
50         Qctl,
51         Qfd,
52         Qfpregs,
53         Qkregs,
54         Qmaps,
55         Qmem,
56         Qnote,
57         Qnoteid,
58         Qnotepg,
59         Qproc,
60         Qregs,
61         Quser,
62         Qsegment,
63         Qstatus,
64         Qstrace,
65         Qstrace_traceset,
66         Qvmstatus,
67         Qtext,
68         Qwait,
69         Qprofile,
70         Qsyscall,
71         Qcore,
72 };
73
74 enum {
75         CMclose,
76         CMclosefiles,
77         CMfixedpri,
78         CMhang,
79         CMkill,
80         CMnohang,
81         CMnoswap,
82         CMpri,
83         CMprivate,
84         CMprofile,
85         CMstart,
86         CMstartstop,
87         CMstartsyscall,
88         CMstop,
89         CMwaitstop,
90         CMwired,
91         CMcore,
92         CMvminit,
93         CMvmstart,
94         CMvmkill,
95         CMstraceme,
96         CMstraceall,
97         CMstrace_drop,
98 };
99
100 enum {
101         Nevents = 0x4000,
102         Emask = Nevents - 1,
103         Ntracedpids = 1024,
104         STATSIZE = 8 + 1 + 10 + 1 + 6 + 2,
105 };
106
107 /*
108  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
109  * particularly on shared servers.
110  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
111  */
112 struct dirtab procdir[] = {
113         {"args", {Qargs}, 0, 0660},
114         {"ctl", {Qctl}, 0, 0660},
115         {"fd", {Qfd}, 0, 0444},
116         {"fpregs", {Qfpregs}, 0, 0000},
117         //  {"kregs",   {Qkregs},   sizeof(Ureg),       0600},
118         {"maps", {Qmaps}, 0, 0000},
119         {"mem", {Qmem}, 0, 0000},
120         {"note", {Qnote}, 0, 0000},
121         {"noteid", {Qnoteid}, 0, 0664},
122         {"notepg", {Qnotepg}, 0, 0000},
123         {"ns", {Qns}, 0, 0444},
124         {"proc", {Qproc}, 0, 0400},
125         //  {"regs",        {Qregs},    sizeof(Ureg),       0000},
126         {"user", {Quser}, 0, 0444},
127         {"segment", {Qsegment}, 0, 0444},
128         {"status", {Qstatus}, STATSIZE, 0444},
129         {"strace", {Qstrace}, 0, 0444},
130         {"strace_traceset", {Qstrace_traceset}, 0, 0666},
131         {"vmstatus", {Qvmstatus}, 0, 0444},
132         {"text", {Qtext}, 0, 0000},
133         {"wait", {Qwait}, 0, 0400},
134         {"profile", {Qprofile}, 0, 0400},
135         {"syscall", {Qsyscall}, 0, 0400},
136         {"core", {Qcore}, 0, 0444},
137 };
138
139 static
140 struct cmdtab proccmd[] = {
141         {CMclose, "close", 2},
142         {CMclosefiles, "closefiles", 1},
143         {CMfixedpri, "fixedpri", 2},
144         {CMhang, "hang", 1},
145         {CMnohang, "nohang", 1},
146         {CMnoswap, "noswap", 1},
147         {CMkill, "kill", 1},
148         {CMpri, "pri", 2},
149         {CMprivate, "private", 1},
150         {CMprofile, "profile", 1},
151         {CMstart, "start", 1},
152         {CMstartstop, "startstop", 1},
153         {CMstartsyscall, "startsyscall", 1},
154         {CMstop, "stop", 1},
155         {CMwaitstop, "waitstop", 1},
156         {CMwired, "wired", 2},
157         {CMcore, "core", 2},
158         {CMcore, "core", 2},
159         {CMcore, "core", 2},
160         {CMvminit, "vminit", 0},
161         {CMvmstart, "vmstart", 0},
162         {CMvmkill, "vmkill", 0},
163         {CMstraceme, "straceme", 0},
164         {CMstraceall, "straceall", 0},
165         {CMstrace_drop, "strace_drop", 2},
166 };
167
168 /*
169  * struct qids are, in path:
170  *       5 bits of file type (qids above) (old comment said 4 here)
171  *      23 bits of process slot number + 1 (pid + 1 is stored)
172  *           in vers,
173  *      32 bits of pid, for consistency checking
174  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
175  */
176 #define QSHIFT  5       /* location in qid of proc slot # */
177 #define SLOTBITS 23     /* number of bits in the slot */
178 #define QIDMASK ((1<<QSHIFT)-1)
179 #define SLOTMASK        (((1<<SLOTBITS)-1) << QSHIFT)
180
181 #define QID(q)          ((((uint32_t)(q).path)&QIDMASK)>>0)
182 #define SLOT(q)         (((((uint32_t)(q).path)&SLOTMASK)>>QSHIFT)-1)
183 #define PID(q)          ((q).vers)
184 #define NOTEID(q)       ((q).vers)
185
186 static void procctlreq(struct proc *, char *, int);
187 static int procctlmemio(struct proc *, uintptr_t, int, void *, int);
188 //static struct chan*   proctext(struct chan*, struct proc*);
189 //static Segment* txt2data(struct proc*, Segment*);
190 //static int    procstopped(void*);
191 static void mntscan(struct mntwalk *, struct proc *);
192
193 //static Traceevent *tevents;
194 static char *tpids, *tpidsc, *tpidse;
195 static spinlock_t tlock;
196 static int topens;
197 static int tproduced, tconsumed;
198 //static void notrace(struct proc*, int, int64_t);
199
200 //void (*proctrace)(struct proc*, int, int64_t) = notrace;
201
202 #if 0
203 static void profclock(Ureg * ur, Timer *)
204 {
205         Tos *tos;
206
207         if (up == NULL || current->state != Running)
208                 return;
209
210         /* user profiling clock */
211         if (userureg(ur)) {
212                 tos = (Tos *) (USTKTOP - sizeof(Tos));
213                 tos->clock += TK2MS(1);
214                 segclock(userpc(ur));
215         }
216 }
217 #endif
218 static int
219 procgen(struct chan *c, char *name, struct dirtab *tab, int unused, int s,
220                 struct dir *dp)
221 {
222         struct qid qid;
223         struct proc *p;
224         char *ename;
225
226         int pid;
227         uint32_t path, perm, len;
228         if (s == DEVDOTDOT) {
229                 mkqid(&qid, Qdir, 0, QTDIR);
230                 devdir(c, qid, devname(), 0, eve.name, 0555, dp);
231                 return 1;
232         }
233
234         if (c->qid.path == Qdir) {
235                 if (s == 0) {
236                         strlcpy(get_cur_genbuf(), "trace", GENBUF_SZ);
237                         mkqid(&qid, Qtrace, -1, QTFILE);
238                         devdir(c, qid, get_cur_genbuf(), 0, eve.name, 0444, dp);
239                         return 1;
240                 }
241                 if (s == 1) {
242                         strlcpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
243                         mkqid(&qid, Qtracepids, -1, QTFILE);
244                         devdir(c, qid, get_cur_genbuf(), 0, eve.name, 0444, dp);
245                         return 1;
246                 }
247                 if (s == 2) {
248                         p = current;
249                         strlcpy(get_cur_genbuf(), "self", GENBUF_SZ);
250                         mkqid(&qid, (p->pid + 1) << QSHIFT, p->pid, QTDIR);
251                         devdir(c, qid, get_cur_genbuf(), 0, p->user.name, DMDIR | 0555, dp);
252                         return 1;
253                 }
254                 s -= 3;
255                 if (name != NULL) {
256                         /* ignore s and use name to find pid */
257                         pid = strtol(name, &ename, 10);
258                         if (pid <= 0 || ename[0] != '\0')
259                                 return -1;
260                         p = pid2proc(pid);
261                         if (!p)
262                                 return -1;
263                         /* Need to update s, so that it's the correct 'index' for our proc
264                          * (aka, the pid).  We use s later when making the qid. */
265                         s = pid;
266                 } else {
267                         /* This is a shitty iterator, and the list isn't guaranteed to give
268                          * you the same ordering twice in a row. (procs come and go). */
269                         p = pid_nth(s);
270                         if (!p)
271                                 return -1;
272                         pid = p->pid;
273                 }
274
275                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%u", pid);
276                 /*
277                  * String comparison is done in devwalk so
278                  * name must match its formatted pid.
279                  */
280                 if (name != NULL && strcmp(name, get_cur_genbuf()) != 0) {
281                         printk("pid-name mismatch, name: %s, pid %d\n", name, pid);
282                         proc_decref(p);
283                         return -1;
284                 }
285                 mkqid(&qid, (s + 1) << QSHIFT, pid, QTDIR);
286                 devdir(c, qid, get_cur_genbuf(), 0, p->user.name, DMDIR | 0555, dp);
287                 proc_decref(p);
288                 return 1;
289         }
290         if (c->qid.path == Qtrace) {
291                 strlcpy(get_cur_genbuf(), "trace", GENBUF_SZ);
292                 mkqid(&qid, Qtrace, -1, QTFILE);
293                 devdir(c, qid, get_cur_genbuf(), 0, eve.name, 0444, dp);
294                 return 1;
295         }
296         if (c->qid.path == Qtracepids) {
297                 strlcpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
298                 mkqid(&qid, Qtracepids, -1, QTFILE);
299                 devdir(c, qid, get_cur_genbuf(), 0, eve.name, 0444, dp);
300                 return 1;
301         }
302         if (s >= ARRAY_SIZE(procdir))
303                 return -1;
304         if (tab)
305                 panic("procgen");
306
307         tab = &procdir[s];
308         /* path is everything other than the QID part.  Not sure from the orig code
309          * if they wanted just the pid part (SLOTMASK) or everything above QID */
310         path = c->qid.path & ~QIDMASK;  /* slot component */
311         if ((p = pid2proc(SLOT(c->qid))) == NULL)
312                 return -1;
313         perm = 0444 | tab->perm;
314 #if 0
315         if (perm == 0)
316                 perm = p->procmode;
317         else    /* just copy read bits */
318                 perm |= p->procmode & 0444;
319 #endif
320
321         len = tab->length;
322 #if 0
323         switch (QID(c->qid)) {
324                 case Qwait:
325                         len = p->nwait; /* incorrect size, but >0 means there's something to read */
326                         break;
327                 case Qprofile:
328                         q = p->seg[TSEG];
329                         if (q && q->profile) {
330                                 len = (q->top - q->base) >> LRESPROF;
331                                 len *= sizeof(*q->profile);
332                         }
333                         break;
334         }
335 #endif
336
337         mkqid(&qid, path | tab->qid.path, c->qid.vers, QTFILE);
338         devdir(c, qid, tab->name, len, p->user.name, perm, dp);
339         proc_decref(p);
340         return 1;
341 }
342
343 #if 0
344 static void notrace(struct proc *, Tevent, int64_t)
345 {
346 }
347
348 static spinlock_t tlck = SPINLOCK_INITIALIZER_IRQSAVE;
349
350 static void _proctrace(struct proc *p, Tevent etype, int64_t ts)
351 {
352         Traceevent *te;
353         int tp;
354
355         ilock(&tlck);
356         if (p->trace == 0 || topens == 0 || tproduced - tconsumed >= Nevents) {
357                 iunlock(&tlck);
358                 return;
359         }
360         tp = tproduced++;
361         iunlock(&tlck);
362
363         te = &tevents[tp & Emask];
364         te->pid = p->pid;
365         te->etype = etype;
366         if (ts == 0)
367                 te->time = todget(NULL);
368         else
369                 te->time = ts;
370         te->core = m->machno;
371 }
372
373 void proctracepid(struct proc *p)
374 {
375         if (p->trace == 1 && proctrace != notrace) {
376                 p->trace = 2;
377                 ilock(&tlck);
378                 tpidsc = seprint(tpidsc, tpidse, "%d %s\n", p->pid, p->text);
379                 iunlock(&tlck);
380         }
381 }
382
383 #endif
384 static void procinit(void)
385 {
386 #if 0
387         if (conf.nproc >= (SLOTMASK >> QSHIFT) - 1)
388                 printd("warning: too many procs for devproc\n");
389         addclock0link((void (*)(void))profclock, 113);  /* Relative prime to HZ */
390 #endif
391 }
392
393 static struct chan *procattach(char *spec)
394 {
395         return devattach(devname(), spec);
396 }
397
398 static struct walkqid *procwalk(struct chan *c, struct chan *nc, char **name,
399                                                                 int nname)
400 {
401         return devwalk(c, nc, name, nname, 0, 0, procgen);
402 }
403
404 static int procstat(struct chan *c, uint8_t * db, int n)
405 {
406         return devstat(c, db, n, 0, 0, procgen);
407 }
408
409 /*
410  *  none can't read or write state on other
411  *  processes.  This is to contain access of
412  *  servers running as none should they be
413  *  subverted by, for example, a stack attack.
414  */
415 static void nonone(struct proc *p)
416 {
417         return;
418 #if 0
419         if (p == up)
420                 return;
421         if (strcmp(current->user.name, "none") != 0)
422                 return;
423         if (iseve())
424                 return;
425         error(EPERM, ERROR_FIXME);
426 #endif
427 }
428
429 struct bm_helper {
430         void                                            *buf;
431         size_t                                          buflen;
432         size_t                                          sofar;
433 };
434
435 static void get_needed_sz_cb(struct vm_region *vmr, void *arg)
436 {
437         struct bm_helper *bmh = (struct bm_helper*)arg;
438
439         /* ballpark estimate of a line */
440         bmh->buflen += 150;
441 }
442
443 static void build_maps_cb(struct vm_region *vmr, void *arg)
444 {
445         struct bm_helper *bmh = (struct bm_helper*)arg;
446         size_t old_sofar;
447         char path_buf[MAX_FILENAME_SZ];
448         char *path;
449         unsigned long inode_nr;
450
451         if (vmr->vm_file) {
452                 path = file_abs_path(vmr->vm_file, path_buf, sizeof(path_buf));
453                 inode_nr = vmr->vm_file->f_dentry->d_inode->i_ino;
454         } else {
455                 strlcpy(path_buf, "[heap]", sizeof(path_buf));
456                 path = path_buf;
457                 inode_nr = 0;
458         }
459
460         old_sofar = bmh->sofar;
461         bmh->sofar += snprintf(bmh->buf + bmh->sofar, bmh->buflen - bmh->sofar,
462                                "%08lx-%08lx %c%c%c%c %08x %02d:%02d %d ",
463                                vmr->vm_base, vmr->vm_end,
464                                vmr->vm_prot & PROT_READ    ? 'r' : '-',
465                                vmr->vm_prot & PROT_WRITE   ? 'w' : '-',
466                                vmr->vm_prot & PROT_EXEC    ? 'x' : '-',
467                                vmr->vm_flags & MAP_PRIVATE ? 'p' : '-',
468                                vmr->vm_file ? vmr->vm_foff : 0,
469                                vmr->vm_file ? 1 : 0,    /* VFS == 1 for major */
470                                0,
471                                inode_nr);
472         /* Align the filename to the 74th char, like Linux (73 chars so far) */
473         bmh->sofar += snprintf(bmh->buf + bmh->sofar, bmh->buflen - bmh->sofar,
474                                "%*s", 73 - (bmh->sofar - old_sofar), "");
475         bmh->sofar += snprintf(bmh->buf + bmh->sofar, bmh->buflen - bmh->sofar,
476                                "%s\n", path);
477 }
478
479 static struct sized_alloc *build_maps(struct proc *p)
480 {
481         struct bm_helper bmh[1];
482         struct sized_alloc *sza;
483
484         /* Try to figure out the size needed: start with extra space, then add a bit
485          * for each VMR */
486         bmh->buflen = 150;
487         enumerate_vmrs(p, get_needed_sz_cb, bmh);
488         sza = sized_kzmalloc(bmh->buflen, MEM_WAIT);
489         bmh->buf = sza->buf;
490         bmh->sofar = 0;
491         enumerate_vmrs(p, build_maps_cb, bmh);
492         return sza;
493 }
494
495 static struct chan *procopen(struct chan *c, int omode)
496 {
497         ERRSTACK(2);
498         struct proc *p;
499         struct pgrp *pg;
500         struct chan *tc;
501         int pid;
502
503         if (c->qid.type & QTDIR)
504                 return devopen(c, omode, 0, 0, procgen);
505
506         if (QID(c->qid) == Qtrace) {
507                 error(ENOSYS, ERROR_FIXME);
508 #if 0
509                 if (omode != OREAD)
510                         error(EPERM, ERROR_FIXME);
511                 lock(&tlock);
512                 if (waserror()) {
513                         unlock(&tlock);
514                         nexterror();
515                 }
516                 if (topens > 0)
517                         error(EFAIL, "already open");
518                 topens++;
519                 if (tevents == NULL) {
520                         tevents = (Traceevent *) kzmalloc(sizeof(Traceevent) * Nevents,
521                                                                                           MEM_WAIT);
522                         if (tevents == NULL)
523                                 error(ENOMEM, ERROR_FIXME);
524                         tpids = kzmalloc(Ntracedpids * 20, MEM_WAIT);
525                         if (tpids == NULL) {
526                                 kfree(tpids);
527                                 tpids = NULL;
528                                 error(ENOMEM, ERROR_FIXME);
529                         }
530                         tpidsc = tpids;
531                         tpidse = tpids + Ntracedpids * 20;
532                         *tpidsc = 0;
533                         tproduced = tconsumed = 0;
534                 }
535                 proctrace = _proctrace;
536                 poperror();
537                 unlock(&tlock);
538
539                 c->mode = openmode(omode);
540                 c->flag |= COPEN;
541                 c->offset = 0;
542                 return c;
543 #endif
544         }
545         if (QID(c->qid) == Qtracepids) {
546                 error(ENOSYS, ERROR_FIXME);
547 #if 0
548                 if (omode != OREAD)
549                         error(EPERM, ERROR_FIXME);
550                 c->mode = openmode(omode);
551                 c->flag |= COPEN;
552                 c->offset = 0;
553                 return c;
554 #endif
555         }
556         if ((p = pid2proc(SLOT(c->qid))) == NULL)
557                 error(ESRCH, ERROR_FIXME);
558         //qlock(&p->debug);
559         if (waserror()) {
560                 //qunlock(&p->debug);
561                 proc_decref(p);
562                 nexterror();
563         }
564         pid = PID(c->qid);
565         if (p->pid != pid)
566                 error(ESRCH, ERROR_FIXME);
567
568         omode = openmode(omode);
569
570         switch (QID(c->qid)) {
571                 case Qtext:
572                         error(ENOSYS, ERROR_FIXME);
573 /*
574                         if (omode != OREAD)
575                                 error(EPERM, ERROR_FIXME);
576                         tc = proctext(c, p);
577                         tc->offset = 0;
578                         poperror();
579                         qunlock(&p->debug);
580                         proc_decref(p);
581                         cclose(c);
582                         return tc;
583 */
584                 case Qproc:
585                 case Qsegment:
586                 case Qprofile:
587                 case Qfd:
588                         if (omode != O_READ)
589                                 error(EPERM, ERROR_FIXME);
590                         break;
591
592                 case Qnote:
593 //          if (p->privatemem)
594                         error(EPERM, ERROR_FIXME);
595                         break;
596
597                 case Qmem:
598 //          if (p->privatemem)
599                         error(EPERM, ERROR_FIXME);
600                         //nonone(p);
601                         break;
602
603                 case Qargs:
604                 case Qnoteid:
605                 case Qwait:
606                 case Qregs:
607                 case Qfpregs:
608                 case Qkregs:
609                 case Qsyscall:
610                 case Qcore:
611                         nonone(p);
612                         break;
613
614                 case Qns:
615                         if (omode != O_READ)
616                                 error(EPERM, ERROR_FIXME);
617                         c->aux = kzmalloc(sizeof(struct mntwalk), MEM_WAIT);
618                         break;
619                 case Quser:
620                 case Qstatus:
621                 case Qvmstatus:
622                 case Qctl:
623                         break;
624
625                 case Qstrace:
626                         if (!p->strace)
627                                 error(ENOENT, "Process does not have tracing enabled");
628                         spin_lock(&p->strace->lock);
629                         if (p->strace->tracing) {
630                                 spin_unlock(&p->strace->lock);
631                                 error(EBUSY, "Process is already being traced");
632                         }
633                         /* It's not critical that we reopen before setting tracing, but it's
634                          * a little cleaner (concurrent syscalls could be trying to use the
635                          * queue before it was reopened, and they'd throw). */
636                         qreopen(p->strace->q);
637                         p->strace->tracing = TRUE;
638                         spin_unlock(&p->strace->lock);
639                         /* the ref we are upping is the one we put in __proc_free, which is
640                          * the one we got from CMstrace{on,me}.  We have a ref on p, so we
641                          * know we won't free until we decref the proc. */
642                         kref_get(&p->strace->users, 1);
643                         c->aux = p->strace;
644                         break;
645                 case Qstrace_traceset:
646                         if (!p->strace)
647                                 error(ENOENT, "Process does not have tracing enabled");
648                         kref_get(&p->strace->users, 1);
649                         c->aux = p->strace;
650                         break;
651                 case Qmaps:
652                         c->aux = build_maps(p);
653                         break;
654                 case Qnotepg:
655                         error(ENOSYS, ERROR_FIXME);
656 #if 0
657                         nonone(p);
658                         pg = p->pgrp;
659                         if (pg == NULL)
660                                 error(ESRCH, ERROR_FIXME);
661                         if (omode != OWRITE || pg->pgrpid == 1)
662                                 error(EPERM, ERROR_FIXME);
663                         c->pgrpid.path = pg->pgrpid + 1;
664                         c->pgrpid.vers = p->noteid;
665 #endif
666                         break;
667
668                 default:
669                         printk("procopen %#llux\n", c->qid.path);
670                         error(EINVAL, ERROR_FIXME);
671         }
672
673         /* Affix pid to qid */
674 //  if (p->state != Dead)
675         c->qid.vers = p->pid;
676         /* make sure the process slot didn't get reallocated while we were playing */
677         //coherence();
678         /* TODO: think about what we really want here.  In akaros, we wouldn't have
679          * our pid changed like that. */
680         if (p->pid != pid)
681                 error(ESRCH, ERROR_FIXME);
682
683         tc = devopen(c, omode, 0, 0, procgen);
684         poperror();
685         //qunlock(&p->debug);
686         proc_decref(p);
687         return tc;
688 }
689
690 static int procwstat(struct chan *c, uint8_t * db, int n)
691 {
692         ERRSTACK(2);
693         error(ENOSYS, ERROR_FIXME);
694 #if 0
695         struct proc *p;
696         struct dir *d;
697
698         if (c->qid.type & QTDIR)
699                 error(EPERM, ERROR_FIXME);
700
701         if (QID(c->qid) == Qtrace)
702                 return devwstat(c, db, n);
703
704         if ((p = pid2proc(SLOT(c->qid))) == NULL)
705                 error(ESRCH, ERROR_FIXME);
706         nonone(p);
707         d = NULL;
708         qlock(&p->debug);
709         if (waserror()) {
710                 qunlock(&p->debug);
711                 proc_decref(p);
712                 kfree(d);
713                 nexterror();
714         }
715
716         if (p->pid != PID(c->qid))
717                 error(ESRCH, ERROR_FIXME);
718
719         if (strcmp(current->user.name, p->user.name) != 0 && !iseve())
720                 error(EPERM, ERROR_FIXME);
721
722         d = kzmalloc(sizeof(struct dir) + n, MEM_WAIT);
723         n = convM2D(db, n, &d[0], (char *)&d[1]);
724         if (n == 0)
725                 error(ENOENT, ERROR_FIXME);
726         if (!emptystr(d->uid) && strcmp(d->uid, p->user.name) != 0) {
727                 if (!iseve())
728                         error(EPERM, ERROR_FIXME);
729                 else
730                         proc_set_username(p, d->uid);
731         }
732         if (d->mode != ~0UL)
733                 p->procmode = d->mode & 0777;
734
735         poperror();
736         qunlock(&p->debug);
737         proc_decref(p);
738         kfree(d);
739
740         return n;
741 #endif
742 }
743
744 #if 0
745 static long procoffset(long offset, char *va, int *np)
746 {
747         if (offset > 0) {
748                 offset -= *np;
749                 if (offset < 0) {
750                         memmove(va, va + *np + offset, -offset);
751                         *np = -offset;
752                 } else
753                         *np = 0;
754         }
755         return offset;
756 }
757
758 static int procqidwidth(struct chan *c)
759 {
760         char buf[32];
761
762         return sprint(buf, "%lu", c->qid.vers);
763 }
764
765 int procfdprint(struct chan *c, int fd, int w, char *s, int ns)
766 {
767         int n;
768
769         if (w == 0)
770                 w = procqidwidth(c);
771         n = snprint(s, ns,
772                                 "%3d %.2s %C %4ud (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd,
773                                 &"r w rw"[(c->mode & 3) << 1], c->dev->dc, c->devno,
774                                 c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset,
775                                 c->name->s);
776         return n;
777 }
778
779 static int procfds(struct proc *p, char *va, int count, long offset)
780 {
781         ERRSTACK(2);
782         struct fgrp *f;
783         struct chan *c;
784         char buf[256];
785         int n, i, w, ww;
786         char *a;
787
788         /* print to buf to avoid holding fgrp lock while writing to user space */
789         if (count > sizeof buf)
790                 count = sizeof buf;
791         a = buf;
792
793         qlock(&p->debug);
794         f = p->fgrp;
795         if (f == NULL) {
796                 qunlock(&p->debug);
797                 return 0;
798         }
799         lock(f);
800         if (waserror()) {
801                 unlock(f);
802                 qunlock(&p->debug);
803                 nexterror();
804         }
805
806         n = readstr(0, a, count, p->dot->name->s);
807         n += snprint(a + n, count - n, "\n");
808         offset = procoffset(offset, a, &n);
809         /* compute width of qid.path */
810         w = 0;
811         for (i = 0; i <= f->maxfd; i++) {
812                 c = f->fd[i];
813                 if (c == NULL)
814                         continue;
815                 ww = procqidwidth(c);
816                 if (ww > w)
817                         w = ww;
818         }
819         for (i = 0; i <= f->maxfd; i++) {
820                 c = f->fd[i];
821                 if (c == NULL)
822                         continue;
823                 n += procfdprint(c, i, w, a + n, count - n);
824                 offset = procoffset(offset, a, &n);
825         }
826         poperror();
827         unlock(f);
828         qunlock(&p->debug);
829
830         /* copy result to user space, now that locks are released */
831         memmove(va, buf, n);
832
833         return n;
834 }
835 #endif
836 static void procclose(struct chan *c)
837 {
838         if (QID(c->qid) == Qtrace) {
839                 spin_lock(&tlock);
840                 if (topens > 0)
841                         topens--;
842                 /* ??
843                    if(topens == 0)
844                    proctrace = notrace;
845                  */
846                 spin_unlock(&tlock);
847         }
848         if (QID(c->qid) == Qsyscall) {
849                 if (c->aux)
850                         qclose(c->aux);
851                 c->aux = NULL;
852         }
853         if (QID(c->qid) == Qns && c->aux != 0)
854                 kfree(c->aux);
855         if (QID(c->qid) == Qmaps && c->aux != 0)
856                 kfree(c->aux);
857         if (QID(c->qid) == Qstrace && c->aux != 0) {
858                 struct strace *s = c->aux;
859
860                 assert(c->flag & COPEN);        /* only way aux should have been set */
861                 s->tracing = FALSE;
862                 qhangup(s->q, NULL);
863                 kref_put(&s->users);
864                 c->aux = NULL;
865         }
866         if (QID(c->qid) == Qstrace_traceset && c->aux != 0) {
867                 struct strace *s = c->aux;
868
869                 assert(c->flag & COPEN);
870                 kref_put(&s->users);
871                 c->aux = NULL;
872         }
873 }
874
875 void int2flag(int flag, char *s)
876 {
877         if (flag == 0) {
878                 *s = '\0';
879                 return;
880         }
881         *s++ = '-';
882         if (flag & MAFTER)
883                 *s++ = 'a';
884         if (flag & MBEFORE)
885                 *s++ = 'b';
886         if (flag & MCREATE)
887                 *s++ = 'c';
888         if (flag & MCACHE)
889                 *s++ = 'C';
890         *s = '\0';
891 }
892
893 #if 0
894 static char *argcpy(char *s, char *p)
895 {
896         char *t, *tp, *te;
897         int n;
898
899         n = p - s;
900         if (n > 128)
901                 n = 128;
902         if (n <= 0) {
903                 t = kzmalloc(1, MEM_WAIT);
904                 *t = 0;
905                 return t;
906         }
907         t = kzmalloc(n, MEM_WAIT);
908         tp = t;
909         te = t + n;
910
911         while (tp + 1 < te) {
912                 for (p--; p > s && p[-1] != 0; p--) ;
913                 tp = seprint(tp, te, "%q ", p);
914                 if (p == s)
915                         break;
916         }
917         if (*tp == ' ')
918                 *tp = 0;
919         return t;
920 }
921
922 static int procargs(struct proc *p, char *buf, int nbuf)
923 {
924         char *s;
925
926         if (p->setargs == 0) {
927                 s = argcpy(p->args, p->args + p->nargs);
928                 kfree(p->args);
929                 p->nargs = strlen(s);
930                 p->args = s;
931                 p->setargs = 1;
932         }
933         return snprint(buf, nbuf, "%s", p->args);
934 }
935
936 static int eventsavailable(void *)
937 {
938         return tproduced > tconsumed;
939 }
940 #endif
941
942 static long procread(struct chan *c, void *va, long n, int64_t off)
943 {
944         ERRSTACK(1);
945         struct proc *p;
946         long l, r;
947         int i, j, navail, pid, rsize;
948         char flag[10], *sps, *srv;
949         uintptr_t offset, u;
950         int tesz;
951         uint8_t *rptr;
952         struct mntwalk *mw;
953         struct strace *s;
954         struct sized_alloc *sza;
955
956         if (c->qid.type & QTDIR) {
957                 int nn;
958                 printd("procread: dir\n");
959                 nn = devdirread(c, va, n, 0, 0, procgen);
960                 printd("procread: %d\n", nn);
961                 return nn;
962         }
963
964         offset = off;
965         /* Some shit in proc doesn't need to grab the reference.  For strace, we
966          * already have the chan open, and all we want to do is read the queue,
967          * which exists because of our kref on it. */
968         switch (QID(c->qid)) {
969         case Qstrace:
970                 s = c->aux;
971                 n = qread(s->q, va, n);
972                 return n;
973         case Qstrace_traceset:
974                 s = c->aux;
975                 return readmem(offset, va, n, s->trace_set,
976                                bitmap_size(MAX_SYSCALL_NR));
977         }
978
979         if ((p = pid2proc(SLOT(c->qid))) == NULL)
980                 error(ESRCH, "%d: no such process", SLOT(c->qid));
981         if (p->pid != PID(c->qid)) {
982                 proc_decref(p);
983                 error(ESRCH, "weird: p->pid is %d, PID(c->qid) is %d: mismatch",
984                       p->pid, PID(c->qid));
985         }
986         switch (QID(c->qid)) {
987                 default:
988                         proc_decref(p);
989                         break;
990                 case Quser: {
991                                 int i;
992
993                                 i = readstr(off, va, n, p->user.name);
994                                 proc_decref(p);
995                                 return i;
996                         }
997                 case Qstatus:{
998                                 /* the old code grew the stack and was hideous.
999                                  * status is not a high frequency operation; just malloc. */
1000                                 char *buf = kmalloc(4096, MEM_WAIT);
1001                                 char *s = buf, *e = buf + 4096;
1002                                 int i;
1003
1004                                 s = seprintf(s, e,
1005                                          "%8d %-*s %-10s %6d", p->pid, PROC_PROGNAME_SZ,
1006                                          p->progname, procstate2str(p->state),
1007                                          p->ppid);
1008                                 if (p->strace)
1009                                         s = seprintf(s, e, " %d trace users %d traced procs",
1010                                                      kref_refcnt(&p->strace->users),
1011                                                      kref_refcnt(&p->strace->procs));
1012                                 proc_decref(p);
1013                                 i = readstr(off, va, n, buf);
1014                                 kfree(buf);
1015                                 return i;
1016                         }
1017
1018                 case Qvmstatus:
1019                         {
1020                                 size_t buflen = 50 * 65 + 2;
1021                                 char *buf = kmalloc(buflen, MEM_WAIT);
1022                                 int i, offset;
1023                                 offset = 0;
1024                                 offset += snprintf(buf + offset, buflen - offset, "{\n");
1025                                 for (i = 0; i < 65; i++) {
1026                                         if (p->vmm.vmexits[i] != 0) {
1027                                                 offset += snprintf(buf + offset, buflen - offset,
1028                                                                    "\"%s\":\"%lld\",\n",
1029                                                                    VMX_EXIT_REASON_NAMES[i],
1030                                                                    p->vmm.vmexits[i]);
1031                                         }
1032                                 }
1033                                 offset += snprintf(buf + offset, buflen - offset, "}\n");
1034                                 proc_decref(p);
1035                                 n = readstr(off, va, n, buf);
1036                                 kfree(buf);
1037                                 return n;
1038                         }
1039                 case Qns:
1040                         //qlock(&p->debug);
1041                         if (waserror()) {
1042                                 //qunlock(&p->debug);
1043                                 proc_decref(p);
1044                                 nexterror();
1045                         }
1046                         if (p->pgrp == NULL || p->pid != PID(c->qid))
1047                                 error(ESRCH, ERROR_FIXME);
1048                         mw = c->aux;
1049                         if (mw->cddone) {
1050                                 poperror();
1051                                 //qunlock(&p->debug);
1052                                 proc_decref(p);
1053                                 return 0;
1054                         }
1055                         mntscan(mw, p);
1056                         if (mw->mh == 0) {
1057                                 mw->cddone = 1;
1058                                 i = snprintf(va, n, "cd %s\n", p->dot->name->s);
1059                                 poperror();
1060                                 //qunlock(&p->debug);
1061                                 proc_decref(p);
1062                                 return i;
1063                         }
1064                         int2flag(mw->cm->mflag, flag);
1065                         if (strcmp(mw->cm->to->name->s, "#M") == 0) {
1066                                 srv = srvname(mw->cm->to->mchan);
1067                                 i = snprintf(va, n, "mount %s %s %s %s\n", flag,
1068                                                          srv == NULL ? mw->cm->to->mchan->name->s : srv,
1069                                                          mw->mh->from->name->s,
1070                                                          mw->cm->spec ? mw->cm->spec : "");
1071                                 kfree(srv);
1072                         } else
1073                                 i = snprintf(va, n, "bind %s %s %s\n", flag,
1074                                                          mw->cm->to->name->s, mw->mh->from->name->s);
1075                         poperror();
1076                         //qunlock(&p->debug);
1077                         proc_decref(p);
1078                         return i;
1079                 case Qmaps:
1080                         sza = c->aux;
1081                         i = readmem(off, va, n, sza->buf, sza->size);
1082                         proc_decref(p);
1083                         return i;
1084         }
1085         error(EINVAL, "QID %d did not match any QIDs for #proc", QID(c->qid));
1086         return 0;       /* not reached */
1087 }
1088
1089 static void mntscan(struct mntwalk *mw, struct proc *p)
1090 {
1091         struct pgrp *pg;
1092         struct mount *t;
1093         struct mhead *f;
1094         int best, i, last, nxt;
1095
1096         pg = p->pgrp;
1097         rlock(&pg->ns);
1098
1099         nxt = 0;
1100         best = (int)(~0U >> 1); /* largest 2's complement int */
1101
1102         last = 0;
1103         if (mw->mh)
1104                 last = mw->cm->mountid;
1105
1106         for (i = 0; i < MNTHASH; i++) {
1107                 for (f = pg->mnthash[i]; f; f = f->hash) {
1108                         for (t = f->mount; t; t = t->next) {
1109                                 if (mw->mh == 0 || (t->mountid > last && t->mountid < best)) {
1110                                         mw->cm = t;
1111                                         mw->mh = f;
1112                                         best = mw->cm->mountid;
1113                                         nxt = 1;
1114                                 }
1115                         }
1116                 }
1117         }
1118         if (nxt == 0)
1119                 mw->mh = 0;
1120
1121         runlock(&pg->ns);
1122 }
1123
1124 static long procwrite(struct chan *c, void *va, long n, int64_t off)
1125 {
1126         ERRSTACK(2);
1127
1128         struct proc *p, *t;
1129         int i, id, l;
1130         char *args;
1131         uintptr_t offset = off;
1132         struct strace *s;
1133
1134         if (c->qid.type & QTDIR)
1135                 error(EISDIR, ERROR_FIXME);
1136
1137         if ((p = pid2proc(SLOT(c->qid))) == NULL)
1138                 error(ESRCH, ERROR_FIXME);
1139
1140         if (waserror()) {
1141                 proc_decref(p);
1142                 nexterror();
1143         }
1144         if (p->pid != PID(c->qid))
1145                 error(ESRCH, ERROR_FIXME);
1146
1147         offset = off;
1148
1149         switch (QID(c->qid)) {
1150 #if 0
1151                 case Qargs:
1152                         if (n == 0)
1153                                 error(EINVAL, ERROR_FIXME);
1154                         if (n >= sizeof buf - strlen(p->text) - 1)
1155                                 error(E2BIG, ERROR_FIXME);
1156                         l = snprintf(buf, sizeof buf, "%s [%s]", p->text, (char *)va);
1157                         args = kzmalloc(l + 1, MEM_WAIT);
1158                         if (args == NULL)
1159                                 error(ENOMEM, ERROR_FIXME);
1160                         memmove(args, buf, l);
1161                         args[l] = 0;
1162                         kfree(p->args);
1163                         p->nargs = l;
1164                         p->args = args;
1165                         p->setargs = 1;
1166                         break;
1167
1168                 case Qmem:
1169                         if (p->state != Stopped)
1170                                 error(EINVAL, ERROR_FIXME);
1171
1172                         n = procctlmemio(p, offset, n, va, 0);
1173                         break;
1174
1175                 case Qregs:
1176                         if (offset >= sizeof(Ureg))
1177                                 n = 0;
1178                         else if (offset + n > sizeof(Ureg))
1179                                 n = sizeof(Ureg) - offset;
1180                         if (p->dbgreg == 0)
1181                                 error(ENODATA, ERROR_FIXME);
1182                         setregisters(p->dbgreg, (char *)(p->dbgreg) + offset, va, n);
1183                         break;
1184
1185                 case Qfpregs:
1186                         n = fpudevprocio(p, va, n, offset, 1);
1187                         break;
1188 #endif
1189                 case Qctl:
1190                         procctlreq(p, va, n);
1191                         break;
1192                 case Qstrace_traceset:
1193                         s = c->aux;
1194                         if (n + offset > bitmap_size(MAX_SYSCALL_NR))
1195                                 error(EINVAL, "strace_traceset: Short write (%llu at off %llu)",
1196                                       n, offset);
1197                         if (memcpy_from_user(current, (void*)s->trace_set + offset, va, n))
1198                                 error(EFAULT, "strace_traceset: Bad addr (%p + %llu)", va, n);
1199                         break;
1200                 default:
1201                         error(EFAIL, "unknown qid %#llux in procwrite\n", c->qid.path);
1202         }
1203         poperror();
1204         proc_decref(p);
1205         return n;
1206 }
1207
1208 struct dev procdevtab __devtab = {
1209         .name = "proc",
1210
1211         .reset = devreset,
1212         .init = procinit,
1213         .shutdown = devshutdown,
1214         .attach = procattach,
1215         .walk = procwalk,
1216         .stat = procstat,
1217         .open = procopen,
1218         .create = devcreate,
1219         .close = procclose,
1220         .read = procread,
1221         .bread = devbread,
1222         .write = procwrite,
1223         .bwrite = devbwrite,
1224         .remove = devremove,
1225         .wstat = procwstat,
1226         .power = devpower,
1227         .chaninfo = devchaninfo,
1228 };
1229
1230 #if 0
1231 static struct chan *proctext(struct chan *c, struct proc *p)
1232 {
1233         ERRSTACK(2);
1234         struct chan *tc;
1235         Image *i;
1236         Segment *s;
1237
1238         s = p->seg[TSEG];
1239         if (s == 0)
1240                 error(ENOENT, ERROR_FIXME);
1241         if (p->state == Dead)
1242                 error(ESRCH, ERROR_FIXME);
1243
1244         lock(s);
1245         i = s->image;
1246         if (i == 0) {
1247                 unlock(s);
1248                 error(ESRCH, ERROR_FIXME);
1249         }
1250         unlock(s);
1251
1252         lock(i);
1253         if (waserror()) {
1254                 unlock(i);
1255                 nexterror();
1256         }
1257
1258         tc = i->c;
1259         if (tc == 0)
1260                 error(ESRCH, ERROR_FIXME);
1261
1262         /* TODO: what do you want here?  you can't get a kref and have the new val
1263          * be 1.  Here is the old code: if (kref_get(&tc->ref, 1) == 1 || ... ) */
1264         if (kref_refcnt(&tc->ref, 1) == 1 || (tc->flag & COPEN) == 0
1265                 || tc->mode != OREAD) {
1266                 cclose(tc);
1267                 error(ESRCH, ERROR_FIXME);
1268         }
1269
1270         if (p->pid != PID(c->qid)) {
1271                 cclose(tc);
1272                 error(ESRCH, ERROR_FIXME);
1273         }
1274
1275         poperror();
1276         unlock(i);
1277
1278         return tc;
1279 }
1280
1281 /* TODO: this will fail at compile time, since we don't have a proc-wide rendez,
1282  * among other things, and we'll need to rewrite this for akaros */
1283 void procstopwait(struct proc *p, int ctl)
1284 {
1285         ERRSTACK(2);
1286         int pid;
1287
1288         if (p->pdbg)
1289                 error(EBUSY, ERROR_FIXME);
1290         if (procstopped(p) || p->state == Broken)
1291                 return;
1292
1293         if (ctl != 0)
1294                 p->procctl = ctl;
1295         p->pdbg = up;
1296         pid = p->pid;
1297         qunlock(&p->debug);
1298         current->psstate = "Stopwait";
1299         if (waserror()) {
1300                 p->pdbg = 0;
1301                 qlock(&p->debug);
1302                 nexterror();
1303         }
1304         rendez_sleep(&current->sleep, procstopped, p);
1305         poperror();
1306         qlock(&p->debug);
1307         if (p->pid != pid)
1308                 error(ESRCH, ERROR_FIXME);
1309 }
1310
1311 #endif
1312 static void procctlcloseone(struct proc *p, int fd)
1313 {
1314 // TODO: resolve this and sys_close
1315         struct file *file = get_file_from_fd(&p->open_files, fd);
1316         int retval = 0;
1317         printd("%s %d\n", __func__, fd);
1318         /* VFS */
1319         if (file) {
1320                 put_file_from_fd(&p->open_files, fd);
1321                 kref_put(&file->f_kref);        /* Drop the ref from get_file */
1322                 return;
1323         }
1324         /* 9ns, should also handle errors (bad FD, etc) */
1325         retval = sysclose(fd);
1326         return;
1327
1328         //sys_close(p, fd);
1329 }
1330
1331 void procctlclosefiles(struct proc *p, int all, int fd)
1332 {
1333         int i;
1334
1335         if (all)
1336                 for (i = 0; i < NR_FILE_DESC_MAX; i++)
1337                         procctlcloseone(p, i);
1338         else
1339                 procctlcloseone(p, fd);
1340 }
1341
1342 static void strace_shutdown(struct kref *a)
1343 {
1344         struct strace *strace = container_of(a, struct strace, procs);
1345         static const char base_msg[] = "# Traced ~%lu syscs, Dropped %lu";
1346         size_t msg_len = NUMSIZE64 * 2 + sizeof(base_msg);
1347         char *msg = kmalloc(msg_len, 0);
1348
1349         if (msg)
1350                 snprintf(msg, msg_len, base_msg, strace->appx_nr_sysc,
1351                          atomic_read(&strace->nr_drops));
1352         qhangup(strace->q, msg);
1353         kfree(msg);
1354 }
1355
1356 static void strace_release(struct kref *a)
1357 {
1358         struct strace *strace = container_of(a, struct strace, users);
1359
1360         qfree(strace->q);
1361         kfree(strace);
1362 }
1363
1364 static void procctlreq(struct proc *p, char *va, int n)
1365 {
1366         ERRSTACK(1);
1367         int8_t irq_state = 0;
1368         int npc, pri, core;
1369         struct cmdbuf *cb;
1370         struct cmdtab *ct;
1371         int64_t time;
1372         char *e;
1373         struct strace *strace;
1374
1375         cb = parsecmd(va, n);
1376         if (waserror()) {
1377                 kfree(cb);
1378                 nexterror();
1379         }
1380
1381         ct = lookupcmd(cb, proccmd, ARRAY_SIZE(proccmd));
1382
1383         switch (ct->index) {
1384         case CMstraceall:
1385         case CMstraceme:
1386         case CMstrace_drop:
1387                 /* common allocation.  if we inherited, we might have one already */
1388                 if (!p->strace) {
1389                         strace = kzmalloc(sizeof(*p->strace), MEM_WAIT);
1390                         spinlock_init(&strace->lock);
1391                         bitmap_set(strace->trace_set, 0, MAX_SYSCALL_NR);
1392                         strace->q = qopen(65536, 0, NULL, NULL);
1393                         /* The queue is reopened and hungup whenever we open the Qstrace
1394                          * file.  This hangup might not be necessary, but is safer. */
1395                         qhangup(strace->q, NULL);
1396                         /* both of these refs are put when the proc is freed.  procs is for
1397                          * every process that has this p->strace.  users is procs + every
1398                          * user (e.g. from open()).
1399                          *
1400                          * it is possible to kref_put the procs kref in proc_destroy, which
1401                          * would make strace's job easier (no need to do an async wait on
1402                          * the child), and we wouldn't need to decref p in
1403                          * procread(Qstrace).  But the downside is that proc_destroy races
1404                          * with us here with the kref initialization. */
1405                         kref_init(&strace->procs, strace_shutdown, 1);
1406                         kref_init(&strace->users, strace_release, 1);
1407                         if (!atomic_cas_ptr((void**)&p->strace, 0, strace)) {
1408                                 /* someone else won the race and installed strace. */
1409                                 qfree(strace->q);
1410                                 kfree(strace);
1411                                 error(EAGAIN, "Concurrent strace init, try again");
1412                         }
1413                 }
1414                 break;
1415         }
1416
1417         /* actually do the command. */
1418         switch (ct->index) {
1419         case CMvmstart:
1420         case CMvmkill:
1421         default:
1422                 error(EFAIL, "Command not implemented");
1423                 break;
1424         case CMclose:
1425                 procctlclosefiles(p, 0, atoi(cb->f[1]));
1426                 break;
1427         case CMclosefiles:
1428                 procctlclosefiles(p, 1, 0);
1429                 break;
1430 #if 0
1431                 we may want this.Let us pause a proc.case CMhang:p->hang = 1;
1432                 break;
1433 #endif
1434         case CMkill:
1435                 p = pid2proc(strtol(cb->f[1], 0, 0));
1436                 if (!p)
1437                         error(EFAIL, "No such proc\n");
1438
1439                 enable_irqsave(&irq_state);
1440                 proc_destroy(p);
1441                 disable_irqsave(&irq_state);
1442                 proc_decref(p);
1443                 /* this is a little ghetto. it's not fully free yet, but we are also
1444                  * slowing it down by messing with it, esp with the busy waiting on a
1445                  * hyperthreaded core. */
1446                 spin_on(p->env_cr3);
1447                 break;
1448         case CMvminit:
1449                 break;
1450         case CMstraceme:
1451                 p->strace->inherit = FALSE;
1452                 break;
1453         case CMstraceall:
1454                 p->strace->inherit = TRUE;
1455                 break;
1456         case CMstrace_drop:
1457                 if (!strcmp(cb->f[1], "on"))
1458                         p->strace->drop_overflow = TRUE;
1459                 else if (!strcmp(cb->f[1], "off"))
1460                         p->strace->drop_overflow = FALSE;
1461                 else
1462                         error(EINVAL, "strace_drop takes on|off %s", cb->f[1]);
1463                 break;
1464         }
1465         poperror();
1466         kfree(cb);
1467 }
1468
1469 #if 0
1470 static int procstopped(void *a)
1471 {
1472         struct proc *p = a;
1473         return p->state == Stopped;
1474 }
1475
1476 static int
1477 procctlmemio(struct proc *p, uintptr_t offset, int n, void *va, int read)
1478 {
1479         KMap *k;
1480         Pte *pte;
1481         Page *pg;
1482         Segment *s;
1483         uintptr_t soff, l;                      /* hmmmm */
1484         uint8_t *b;
1485         uintmem pgsz;
1486
1487         for (;;) {
1488                 s = seg(p, offset, 1);
1489                 if (s == 0)
1490                         error(EINVAL, ERROR_FIXME);
1491
1492                 if (offset + n >= s->top)
1493                         n = s->top - offset;
1494
1495                 if (!read && (s->type & SG_TYPE) == SG_TEXT)
1496                         s = txt2data(p, s);
1497
1498                 s->steal++;
1499                 soff = offset - s->base;
1500                 if (waserror()) {
1501                         s->steal--;
1502                         nexterror();
1503                 }
1504                 if (fixfault(s, offset, read, 0, s->color) == 0)
1505                         break;
1506                 poperror();
1507                 s->steal--;
1508         }
1509         poperror();
1510         pte = s->map[soff / PTEMAPMEM];
1511         if (pte == 0)
1512                 panic("procctlmemio");
1513         pgsz = m->pgsz[s->pgszi];
1514         pg = pte->pages[(soff & (PTEMAPMEM - 1)) / pgsz];
1515         if (pagedout(pg))
1516                 panic("procctlmemio1");
1517
1518         l = pgsz - (offset & (pgsz - 1));
1519         if (n > l)
1520                 n = l;
1521
1522         k = kmap(pg);
1523         if (waserror()) {
1524                 s->steal--;
1525                 kunmap(k);
1526                 nexterror();
1527         }
1528         b = (uint8_t *) VA(k);
1529         b += offset & (pgsz - 1);
1530         if (read == 1)
1531                 memmove(va, b, n);      /* This can fault */
1532         else
1533                 memmove(b, va, n);
1534         poperror();
1535         kunmap(k);
1536
1537         /* Ensure the process sees text page changes */
1538         if (s->flushme)
1539                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1540
1541         s->steal--;
1542
1543         if (read == 0)
1544                 p->newtlb = 1;
1545
1546         return n;
1547 }
1548
1549 static Segment *txt2data(struct proc *p, Segment * s)
1550 {
1551         int i;
1552         Segment *ps;
1553
1554         ps = newseg(SG_DATA, s->base, s->size);
1555         ps->image = s->image;
1556         kref_get(&ps->image->ref, 1);
1557         ps->fstart = s->fstart;
1558         ps->flen = s->flen;
1559         ps->flushme = 1;
1560
1561         qlock(&p->seglock);
1562         for (i = 0; i < NSEG; i++)
1563                 if (p->seg[i] == s)
1564                         break;
1565         if (i == NSEG)
1566                 panic("segment gone");
1567
1568         qunlock(&s->lk);
1569         putseg(s);
1570         qlock(&ps->lk);
1571         p->seg[i] = ps;
1572         qunlock(&p->seglock);
1573
1574         return ps;
1575 }
1576
1577 Segment *data2txt(Segment * s)
1578 {
1579         Segment *ps;
1580
1581         ps = newseg(SG_TEXT, s->base, s->size);
1582         ps->image = s->image;
1583         kref_get(&ps->image->ref, 1);
1584         ps->fstart = s->fstart;
1585         ps->flen = s->flen;
1586         ps->flushme = 1;
1587
1588         return ps;
1589 }
1590 #endif