1i#define WANT_M.g/"edf.h"/d,s/->ref =/->ref.ref =/g,s/ref(p->dot)/ref(\&p->dot->ref)/g,s/ref(p->fgrp)/ref(\&p->fgrp->ref)/g,s/ref(p->pgrp)/ref(\&p->pgrp->ref)/g,s/ref(p->egrp)/ref(\&p->egrp->ref)/g,s/lock(img)/lock(\&img->ref.lk)/g,s/ref(img)/ref(\&img->ref)/g,s/return0(void\*)/return0(void *v)/g,s/(s = up->seg\[i\])/(&)/g,s;MACHP(0)->ticks;msec();g/ESEG.*= newseg/a flushmmu(); // Needed for Plan 9 VX.,s;sleep(\&phore;sleep(\&phore.rendez;g,s;lock(\&s->sema);lock(\&s->sema.rendez.lk);g,s;wakeup(p);wakeup(\&p->rendez);g,s;lock(up->rgrp);lock(\&up->rgrp->ref.lk);g,s;ref(up->rgrp);ref(\&up->rgrp->ref);g/sysr1/ s/(ulong\*)/(uint32 *x)//Admitted/,/ yield/c yield();./^ checkpagerefs/ c vx32sysr1();./^sysrfork/ s/ulong/uint32//^l2be/ s/long/uint32/-1 s/ulong/uint32//^sysexec/ s/ulong/uint32/-1istatic char Echanged[] = "exec arguments changed underfoot"; ./^{/+1;/^}/-1 c char *volatile elem, *volatile file, *ufile; Chan *volatile tc; /* * Open the file, remembering the final element and the full name. */ file = nil; elem = nil; tc = nil; if(waserror()){ if(file) free(file); if(elem) free(elem); if(tc) cclose(tc); nexterror(); } ufile = uvalidaddr(arg[0], 1, 0); file = validnamedup(ufile, 1); tc = namec(file, Aopen, OEXEC, 0); kstrdup((char**)&elem, up->genbuf); /* * Read the header. If it's a #!, fill in progarg[] with info and repeat. */ int i, n, nprogarg; char *progarg[sizeof(Exec)/2+1]; char *prog, *p; char line[sizeof(Exec)+1]; Exec exec; nprogarg = 0; n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); if(n < 2) error(Ebadexec); p = (char*)&exec; if(p[0] == '#' && p[1] == '!'){ memmove(line, p, n); nprogarg = shargs(line, n, progarg); if(nprogarg == 0) error(Ebadexec); /* The original file becomes an extra arg after #! line */ progarg[nprogarg++] = file; /* * Take the #! $0 as a file to open, and replace * $0 with the original path's name. */ prog = progarg[0]; progarg[0] = elem; cclose(tc); tc = nil; /* in case namec errors out */ tc = namec(prog, Aopen, OEXEC, 0); n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); if(n < 2) error(Ebadexec); } /* * #! has had its chance, now we need a real binary */ uint32 magic, entry, text, etext, data, edata, bss, ebss; magic = l2be(exec.magic); if(n != sizeof(Exec) || l2be(exec.magic) != AOUT_MAGIC) error(Ebadexec); entry = l2be(exec.entry); text = l2be(exec.text); data = l2be(exec.data); bss = l2be(exec.bss); etext = ROUND(UTZERO+sizeof(Exec)+text, BY2PG); edata = ROUND(etext + data, BY2PG); ebss = ROUND(etext + data + bss, BY2PG); //iprint("entry %#lux text %#lux data %#lux bss %#lux\n", entry, text, data, bss);//iprint("etext %#lux edata %#lux ebss %#lux\n", etext, edata, ebss); if(entry < UTZERO+sizeof(Exec) || entry >= UTZERO+sizeof(Exec)+text) error(Ebadexec); /* many overflow possibilities */ if(text >= USTKTOP || data >= USTKTOP || bss >= USTKTOP || etext >= USTKTOP || edata >= USTKTOP || ebss >= USTKTOP || etext >= USTKTOP || edata < etext || ebss < edata) error(Ebadexec); /* * Copy argv into new stack segment temporarily mapped elsewhere. * Be careful: multithreaded program could be changing argv during this. * Pass 1: count number of arguments, string bytes. */ int nargv, strbytes; uint32 argp, ssize, spage; strbytes = 0; for(i=0; i<nprogarg; i++) strbytes += strlen(progarg[i]) + 1; argp = arg[1]; for(nargv=0;; nargv++, argp += BY2WD){ uint32 a; char *str; a = *(uint32*)uvalidaddr(argp, BY2WD, 0); if(a == 0) break; str = uvalidaddr(a, 1, 0); n = ((char*)vmemchr(str, 0, 0x7FFFFFFF) - str) + 1; if(nprogarg > 0 && nargv == 0) continue; /* going to skip argv[0] on #! */ strbytes += n; } if(nargv == 0) error("exec missing argv"); /* * Skip over argv[0] if using #!. Waited until now so that * string would still be checked for validity during loop. */ if(nprogarg > 0){ nargv--; arg[1] += BY2WD; } ssize = BY2WD*((nprogarg+nargv)+1) + ROUND(strbytes, BY2WD) + sizeof(Tos); /* * 8-byte align SP for those (e.g. sparc) that need it. * execregs() will subtract another 4 bytes for argc. */ if((ssize+4) & 7) ssize += 4; spage = (ssize+(BY2PG-1)) >> PGSHIFT; /* * Pass 2: build the stack segment, being careful not to assume * that the counts from pass 1 are still valid. */ if(spage > TSTKSIZ) error(Enovmem); qlock(&up->seglock); if(waserror()){ if(up->seg[ESEG]){ putseg(up->seg[ESEG]); up->seg[ESEG] = nil; } qunlock(&up->seglock); nexterror(); } up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); flushmmu(); // Needed for Plan 9 VX XXX really? /* * Top-of-stack structure. */ uchar *uzero; uzero = up->pmmu.uzero; Tos *tos; uint32 utos; utos = USTKTOP - sizeof(Tos); tos = (Tos*)(uzero + utos + TSTKTOP - USTKTOP); tos->cyclefreq = m->cyclefreq; cycles((uvlong*)&tos->pcycles); tos->pcycles = -tos->pcycles; tos->kcycles = tos->pcycles; tos->clock = 0; /* * Argument pointers and strings, together. */ char *bp, *ep; uint32 *targp; uint32 ustrp, uargp; ustrp = utos - ROUND(strbytes, BY2WD); uargp = ustrp - BY2WD*((nprogarg+nargv)+1); bp = (char*)(uzero + ustrp + TSTKTOP - USTKTOP); ep = bp + strbytes; p = bp; targp = (uint32*)(uzero + uargp + TSTKTOP - USTKTOP); /* #! args are trusted */ for(i=0; i<nprogarg; i++){ n = strlen(progarg[i]) + 1; if(n > ep - p) error(Echanged); memmove(p, progarg[i], n); p += n; *targp++ = ustrp; ustrp += n; } /* the rest are not */ argp = arg[1]; for(i=0; i<nargv; i++){ uint32 a; char *str; a = *(uint32*)uvalidaddr(argp, BY2WD, 0); argp += BY2WD; str = uvalidaddr(a, 1, 0); n = ((char*)vmemchr(str, 0, 0x7FFFFFFF) - str) + 1; if(n > ep - p) error(Echanged); memmove(p, str, n); p += n; *targp++ = ustrp; ustrp += n; } if(*(uint32*)uvalidaddr(argp, BY2WD, 0) != 0) error(Echanged); *targp = 0; /* * But wait, there's more: prepare an arg copy for up->args * using the copy we just made in the temporary segment. */ char *args; int nargs; n = p - bp; /* includes NUL on last arg, so must be > 0 */ if(n <= 0) /* nprogarg+nargv > 0; checked above */ error(Egreg); if(n > 128) n = 128; args = smalloc(n); if(waserror()){ free(args); nexterror(); } memmove(args, bp, n); /* find beginning of UTF character boundary to place final NUL */ while(n > 0 && (args[n-1]&0xC0) == 0x80) n--; args[n-1] = '\0'; nargs = n; /* * Now we're ready to commit. */ free(up->text); up->text = elem; free(up->args); up->args = args; up->nargs = n; elem = nil; poperror(); /* args */ /* * Free old memory. Special segments maintained across exec. */ Segment *s; for(i = SSEG; i <= BSEG; i++) { putseg(up->seg[i]); up->seg[i] = nil; /* in case of error */ } for(i = BSEG+1; i< NSEG; i++) { s = up->seg[i]; if(s && (s->type&SG_CEXEC)) { putseg(s); up->seg[i] = nil; } } /* * Close on exec */ Fgrp *f; f = up->fgrp; for(i=0; i<=f->maxfd; i++) fdclose(i, CCEXEC); /* Text. Shared. Attaches to cache image if possible */ /* attachimage returns a locked cache image */ Image *img; Segment *ts; img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (etext-UTZERO)>>PGSHIFT); ts = img->s; up->seg[TSEG] = ts; ts->flushme = 1; ts->fstart = 0; ts->flen = sizeof(Exec)+text; unlock(&img->ref.lk); /* Data. Shared. */ s = newseg(SG_DATA, etext, (edata-etext)>>PGSHIFT); up->seg[DSEG] = s; /* Attached by hand */ incref(&img->ref); s->image = img; s->fstart = ts->fstart+ts->flen; s->flen = data; /* BSS. Zero fill on demand */ up->seg[BSEG] = newseg(SG_BSS, edata, (ebss-edata)>>PGSHIFT); /* * Move the stack */ s = up->seg[ESEG]; up->seg[ESEG] = 0; up->seg[SSEG] = s; qunlock(&up->seglock); poperror(); /* seglock */ s->base = USTKTOP-USTKSIZE; s->top = USTKTOP; relocateseg(s, USTKTOP-TSTKTOP); /* * '/' processes are higher priority (hack to make /ip more responsive). */ if(devtab[tc->type]->dc == L'/') up->basepri = PriRoot; up->priority = up->basepri; poperror(); /* tc, elem, file */ cclose(tc); free(file); // elem is now up->text /* * At this point, the mmu contains info about the old address * space and needs to be flushed */ flushmmu(); qlock(&up->debug); up->nnote = 0; up->notify = 0; up->notified = 0; up->privatemem = 0; procsetup(up); qunlock(&up->debug); if(up->hang) up->procctl = Proc_stopme; return execregs(entry, USTKTOP - uargp, nprogarg+nargv);./^syssleep/s/ulong/uint32//^sysalarm/s/ulong/uint32//^sysexits/s/ulong/uint32//status/;/if(status)/ c char *status; char *inval = "invalid exit string"; char buf[ERRMAX]; if(arg[0]){./validaddr/c status = uvalidaddr(arg[0], 1, 0);./^ }/ c }else status = nil;./^sys_wait/s/ulong/uint32//validaddr(arg\[0\], sizeof(OWaitmsg), 1)/ c ow = uvalidaddr(arg[0], sizeof(OWaitmsg), 1);./ow =/d/^sysawait/s/ulong/uint32//ulong n/ s/ulong/uint32/a char *buf;./validaddr/ s/v/buf = uv//i = / s/(char\*)arg\[0\]/buf//^generrstr/ s/char \*buf/uint32 addr//^$/i char *buf;./validaddr/ s/v/buf = uv/s/(ulong)buf/addr//^syserrstr/s/ulong/uint32//return/s/(char\*)///^sys_errstr/s/ulong/uint32//return/s/(char\*)///^sysnotify/s/ulong/uint32//validaddr/;/up->notify/c uvalidaddr(arg[0], 1, 0); up->notify = arg[0]; /* checked again when used */./^sysnoted/s/ulong/uint32//^syssegbrk/s/ulong/uint32//addr/s/ulong/uint32//^syssegattach/s/ulong/uint32//return/s/(char\*)arg\[1\]/uvalidaddr(arg[1], 1, 0)//^syssegdetach/s/ulong/uint32//addr/s/ulong/uint32//^syssegfree/s/ulong/uint32//from/s/ulong/uint32//^sysbrk_/s/ulong/uint32//^sysrendezvous/s/ulong/uint32//^syssemacquire/s/ulong/uint32//validaddr/ s/v/addr = uv//addr =/d/(ulong)addr/s/(ulong)addr/arg[0]//^syssemrelease/s/ulong/uint32//validaddr/ s/v/addr = uv//addr =/d/(ulong)addr/s/(ulong)addr/arg[0]/
1i
#define WANT_M
.
g/"edf.h"/d
,s/->ref =/->ref.ref =/g
,s/ref(p->dot)/ref(\&p->dot->ref)/g
,s/ref(p->fgrp)/ref(\&p->fgrp->ref)/g
,s/ref(p->pgrp)/ref(\&p->pgrp->ref)/g
,s/ref(p->egrp)/ref(\&p->egrp->ref)/g
,s/lock(img)/lock(\&img->ref.lk)/g
,s/ref(img)/ref(\&img->ref)/g
,s/return0(void\*)/return0(void *v)/g
,s/(s = up->seg\[i\])/(&)/g
,s;MACHP(0)->ticks;msec();g
/ESEG.*= newseg/a
flushmmu(); // Needed for Plan 9 VX
.
,s;sleep(\&phore;sleep(\&phore.rendez;g
,s;lock(\&s->sema);lock(\&s->sema.rendez.lk);g
,s;wakeup(p);wakeup(\&p->rendez);g
,s;lock(up->rgrp);lock(\&up->rgrp->ref.lk);g
,s;ref(up->rgrp);ref(\&up->rgrp->ref);g
/sysr1/ s/(ulong\*)/(uint32 *x)/
/Admitted/,/ yield/c
yield();
.
/^ checkpagerefs/ c
vx32sysr1();
.
/^sysrfork/ s/ulong/uint32/
/^l2be/ s/long/uint32/
-1 s/ulong/uint32/
/^sysexec/ s/ulong/uint32/
-1i
static char Echanged[] = "exec arguments changed underfoot";
.
/^{/+1;/^}/-1 c
char *volatile elem, *volatile file, *ufile;
Chan *volatile tc;
/*
* Open the file, remembering the final element and the full name.
*/
file = nil;
elem = nil;
tc = nil;
if(waserror()){
if(file)
free(file);
if(elem)
free(elem);
if(tc)
cclose(tc);
nexterror();
}
ufile = uvalidaddr(arg[0], 1, 0);
file = validnamedup(ufile, 1);
tc = namec(file, Aopen, OEXEC, 0);
kstrdup((char**)&elem, up->genbuf);
/*
* Read the header. If it's a #!, fill in progarg[] with info and repeat.
*/
int i, n, nprogarg;
char *progarg[sizeof(Exec)/2+1];
char *prog, *p;
char line[sizeof(Exec)+1];
Exec exec;
nprogarg = 0;
n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
if(n < 2)
error(Ebadexec);
p = (char*)&exec;
if(p[0] == '#' && p[1] == '!'){
memmove(line, p, n);
nprogarg = shargs(line, n, progarg);
if(nprogarg == 0)
error(Ebadexec);
/* The original file becomes an extra arg after #! line */
progarg[nprogarg++] = file;
/*
* Take the #! $0 as a file to open, and replace
* $0 with the original path's name.
*/
prog = progarg[0];
progarg[0] = elem;
cclose(tc);
tc = nil; /* in case namec errors out */
tc = namec(prog, Aopen, OEXEC, 0);
n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
if(n < 2)
error(Ebadexec);
}
/*
* #! has had its chance, now we need a real binary
*/
uint32 magic, entry, text, etext, data, edata, bss, ebss;
magic = l2be(exec.magic);
if(n != sizeof(Exec) || l2be(exec.magic) != AOUT_MAGIC)
error(Ebadexec);
entry = l2be(exec.entry);
text = l2be(exec.text);
data = l2be(exec.data);
bss = l2be(exec.bss);
etext = ROUND(UTZERO+sizeof(Exec)+text, BY2PG);
edata = ROUND(etext + data, BY2PG);
ebss = ROUND(etext + data + bss, BY2PG);
//iprint("entry %#lux text %#lux data %#lux bss %#lux\n", entry, text, data, bss);
//iprint("etext %#lux edata %#lux ebss %#lux\n", etext, edata, ebss);
if(entry < UTZERO+sizeof(Exec) || entry >= UTZERO+sizeof(Exec)+text)
error(Ebadexec);
/* many overflow possibilities */
if(text >= USTKTOP || data >= USTKTOP || bss >= USTKTOP
|| etext >= USTKTOP || edata >= USTKTOP || ebss >= USTKTOP
|| etext >= USTKTOP || edata < etext || ebss < edata)
error(Ebadexec);
/*
* Copy argv into new stack segment temporarily mapped elsewhere.
* Be careful: multithreaded program could be changing argv during this.
* Pass 1: count number of arguments, string bytes.
*/
int nargv, strbytes;
uint32 argp, ssize, spage;
strbytes = 0;
for(i=0; i<nprogarg; i++)
strbytes += strlen(progarg[i]) + 1;
argp = arg[1];
for(nargv=0;; nargv++, argp += BY2WD){
uint32 a;
char *str;
a = *(uint32*)uvalidaddr(argp, BY2WD, 0);
if(a == 0)
break;
str = uvalidaddr(a, 1, 0);
n = ((char*)vmemchr(str, 0, 0x7FFFFFFF) - str) + 1;
if(nprogarg > 0 && nargv == 0)
continue; /* going to skip argv[0] on #! */
strbytes += n;
}
if(nargv == 0)
error("exec missing argv");
/*
* Skip over argv[0] if using #!. Waited until now so that
* string would still be checked for validity during loop.
*/
if(nprogarg > 0){
nargv--;
arg[1] += BY2WD;
}
ssize = BY2WD*((nprogarg+nargv)+1) + ROUND(strbytes, BY2WD) + sizeof(Tos);
/*
* 8-byte align SP for those (e.g. sparc) that need it.
* execregs() will subtract another 4 bytes for argc.
*/
if((ssize+4) & 7)
ssize += 4;
spage = (ssize+(BY2PG-1)) >> PGSHIFT;
/*
* Pass 2: build the stack segment, being careful not to assume
* that the counts from pass 1 are still valid.
*/
if(spage > TSTKSIZ)
error(Enovmem);
qlock(&up->seglock);
if(waserror()){
if(up->seg[ESEG]){
putseg(up->seg[ESEG]);
up->seg[ESEG] = nil;
}
qunlock(&up->seglock);
nexterror();
}
up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG);
flushmmu(); // Needed for Plan 9 VX XXX really?
/*
* Top-of-stack structure.
*/
uchar *uzero;
uzero = up->pmmu.uzero;
Tos *tos;
uint32 utos;
utos = USTKTOP - sizeof(Tos);
tos = (Tos*)(uzero + utos + TSTKTOP - USTKTOP);
tos->cyclefreq = m->cyclefreq;
cycles((uvlong*)&tos->pcycles);
tos->pcycles = -tos->pcycles;
tos->kcycles = tos->pcycles;
tos->clock = 0;
/*
* Argument pointers and strings, together.
*/
char *bp, *ep;
uint32 *targp;
uint32 ustrp, uargp;
ustrp = utos - ROUND(strbytes, BY2WD);
uargp = ustrp - BY2WD*((nprogarg+nargv)+1);
bp = (char*)(uzero + ustrp + TSTKTOP - USTKTOP);
ep = bp + strbytes;
p = bp;
targp = (uint32*)(uzero + uargp + TSTKTOP - USTKTOP);
/* #! args are trusted */
for(i=0; i<nprogarg; i++){
n = strlen(progarg[i]) + 1;
if(n > ep - p)
error(Echanged);
memmove(p, progarg[i], n);
p += n;
*targp++ = ustrp;
ustrp += n;
}
/* the rest are not */
argp = arg[1];
for(i=0; i<nargv; i++){
uint32 a;
char *str;
a = *(uint32*)uvalidaddr(argp, BY2WD, 0);
argp += BY2WD;
str = uvalidaddr(a, 1, 0);
n = ((char*)vmemchr(str, 0, 0x7FFFFFFF) - str) + 1;
if(n > ep - p)
error(Echanged);
memmove(p, str, n);
p += n;
*targp++ = ustrp;
ustrp += n;
}
if(*(uint32*)uvalidaddr(argp, BY2WD, 0) != 0)
error(Echanged);
*targp = 0;
/*
* But wait, there's more: prepare an arg copy for up->args
* using the copy we just made in the temporary segment.
*/
char *args;
int nargs;
n = p - bp; /* includes NUL on last arg, so must be > 0 */
if(n <= 0) /* nprogarg+nargv > 0; checked above */
error(Egreg);
if(n > 128)
n = 128;
args = smalloc(n);
if(waserror()){
free(args);
nexterror();
}
memmove(args, bp, n);
/* find beginning of UTF character boundary to place final NUL */
while(n > 0 && (args[n-1]&0xC0) == 0x80)
n--;
args[n-1] = '\0';
nargs = n;
/*
* Now we're ready to commit.
*/
free(up->text);
up->text = elem;
free(up->args);
up->args = args;
up->nargs = n;
elem = nil;
poperror(); /* args */
/*
* Free old memory. Special segments maintained across exec.
*/
Segment *s;
for(i = SSEG; i <= BSEG; i++) {
putseg(up->seg[i]);
up->seg[i] = nil; /* in case of error */
}
for(i = BSEG+1; i< NSEG; i++) {
s = up->seg[i];
if(s && (s->type&SG_CEXEC)) {
putseg(s);
up->seg[i] = nil;
}
}
/*
* Close on exec
*/
Fgrp *f;
f = up->fgrp;
for(i=0; i<=f->maxfd; i++)
fdclose(i, CCEXEC);
/* Text. Shared. Attaches to cache image if possible */
/* attachimage returns a locked cache image */
Image *img;
Segment *ts;
img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (etext-UTZERO)>>PGSHIFT);
ts = img->s;
up->seg[TSEG] = ts;
ts->flushme = 1;
ts->fstart = 0;
ts->flen = sizeof(Exec)+text;
unlock(&img->ref.lk);
/* Data. Shared. */
s = newseg(SG_DATA, etext, (edata-etext)>>PGSHIFT);
up->seg[DSEG] = s;
/* Attached by hand */
incref(&img->ref);
s->image = img;
s->fstart = ts->fstart+ts->flen;
s->flen = data;
/* BSS. Zero fill on demand */
up->seg[BSEG] = newseg(SG_BSS, edata, (ebss-edata)>>PGSHIFT);
/*
* Move the stack
*/
s = up->seg[ESEG];
up->seg[ESEG] = 0;
up->seg[SSEG] = s;
qunlock(&up->seglock);
poperror(); /* seglock */
s->base = USTKTOP-USTKSIZE;
s->top = USTKTOP;
relocateseg(s, USTKTOP-TSTKTOP);
/*
* '/' processes are higher priority (hack to make /ip more responsive).
*/
if(devtab[tc->type]->dc == L'/')
up->basepri = PriRoot;
up->priority = up->basepri;
poperror(); /* tc, elem, file */
cclose(tc);
free(file);
// elem is now up->text
/*
* At this point, the mmu contains info about the old address
* space and needs to be flushed
*/
flushmmu();
qlock(&up->debug);
up->nnote = 0;
up->notify = 0;
up->notified = 0;
up->privatemem = 0;
procsetup(up);
qunlock(&up->debug);
if(up->hang)
up->procctl = Proc_stopme;
return execregs(entry, USTKTOP - uargp, nprogarg+nargv);
.
/^syssleep/s/ulong/uint32/
/^sysalarm/s/ulong/uint32/
/^sysexits/s/ulong/uint32/
/status/;/if(status)/ c
char *status;
char *inval = "invalid exit string";
char buf[ERRMAX];
if(arg[0]){
.
/validaddr/c
status = uvalidaddr(arg[0], 1, 0);
.
/^ }/ c
}else
status = nil;
.
/^sys_wait/s/ulong/uint32/
/validaddr(arg\[0\], sizeof(OWaitmsg), 1)/ c
ow = uvalidaddr(arg[0], sizeof(OWaitmsg), 1);
.
/ow =/d
/^sysawait/s/ulong/uint32/
/ulong n/ s/ulong/uint32/
a
char *buf;
.
/validaddr/ s/v/buf = uv/
/i = / s/(char\*)arg\[0\]/buf/
/^generrstr/ s/char \*buf/uint32 addr/
/^$/i
char *buf;
.
/validaddr/ s/v/buf = uv/
s/(ulong)buf/addr/
/^syserrstr/s/ulong/uint32/
/return/s/(char\*)//
/^sys_errstr/s/ulong/uint32/
/return/s/(char\*)//
/^sysnotify/s/ulong/uint32/
/validaddr/;/up->notify/c
uvalidaddr(arg[0], 1, 0);
up->notify = arg[0]; /* checked again when used */
.
/^sysnoted/s/ulong/uint32/
/^syssegbrk/s/ulong/uint32/
/addr/s/ulong/uint32/
/^syssegattach/s/ulong/uint32/
/return/s/(char\*)arg\[1\]/uvalidaddr(arg[1], 1, 0)/
/^syssegdetach/s/ulong/uint32/
/addr/s/ulong/uint32/
/^syssegfree/s/ulong/uint32/
/from/s/ulong/uint32/
/^sysbrk_/s/ulong/uint32/
/^sysrendezvous/s/ulong/uint32/
/^syssemacquire/s/ulong/uint32/
/validaddr/ s/v/addr = uv/
/addr =/d
/(ulong)addr/s/(ulong)addr/arg[0]/
/^syssemrelease/s/ulong/uint32/
/validaddr/ s/v/addr = uv/
/addr =/d
/(ulong)addr/s/(ulong)addr/arg[0]/