2004-04-19 19:32:07 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include <bio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <mach.h>
|
|
|
|
#include <regexp.h>
|
|
|
|
#define Extern extern
|
|
|
|
#include "acid.h"
|
|
|
|
#include "y.tab.h"
|
|
|
|
|
|
|
|
void cvtatof(Node*, Node*);
|
|
|
|
void cvtatoi(Node*, Node*);
|
|
|
|
void cvtitoa(Node*, Node*);
|
|
|
|
void bprint(Node*, Node*);
|
|
|
|
void funcbound(Node*, Node*);
|
|
|
|
void printto(Node*, Node*);
|
|
|
|
void getfile(Node*, Node*);
|
|
|
|
void fmt(Node*, Node*);
|
|
|
|
void pcfile(Node*, Node*);
|
|
|
|
void pcline(Node*, Node*);
|
|
|
|
void setproc(Node*, Node*);
|
|
|
|
void strace(Node*, Node*);
|
|
|
|
void follow(Node*, Node*);
|
|
|
|
void reason(Node*, Node*);
|
|
|
|
void newproc(Node*, Node*);
|
|
|
|
void startstop(Node*, Node*);
|
|
|
|
void match(Node*, Node*);
|
|
|
|
void status(Node*, Node*);
|
|
|
|
void xkill(Node*,Node*);
|
|
|
|
void waitstop(Node*, Node*);
|
|
|
|
void sysstop(Node*, Node*);
|
|
|
|
void stop(Node*, Node*);
|
|
|
|
void start(Node*, Node*);
|
|
|
|
void filepc(Node*, Node*);
|
|
|
|
void doerror(Node*, Node*);
|
|
|
|
void rc(Node*, Node*);
|
|
|
|
void doaccess(Node*, Node*);
|
|
|
|
void map(Node*, Node*);
|
|
|
|
void readfile(Node*, Node*);
|
|
|
|
void interpret(Node*, Node*);
|
|
|
|
void include(Node*, Node*);
|
|
|
|
void includepipe(Node*, Node*);
|
|
|
|
void regexp(Node*, Node*);
|
|
|
|
void textfile(Node*, Node*);
|
|
|
|
void deltextfile(Node*, Node*);
|
2004-09-23 03:04:33 +00:00
|
|
|
void stringn(Node*, Node*);
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
void xregister(Node*, Node*);
|
|
|
|
void refconst(Node*, Node*);
|
|
|
|
void dolook(Node*, Node*);
|
2004-04-19 19:32:07 +00:00
|
|
|
|
|
|
|
typedef struct Btab Btab;
|
|
|
|
struct Btab
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
void (*fn)(Node*, Node*);
|
|
|
|
} tab[] =
|
|
|
|
{
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
"access", doaccess,
|
2004-04-19 19:32:07 +00:00
|
|
|
"atof", cvtatof,
|
|
|
|
"atoi", cvtatoi,
|
|
|
|
"deltextfile", deltextfile,
|
|
|
|
"error", doerror,
|
|
|
|
"file", getfile,
|
|
|
|
"filepc", filepc,
|
|
|
|
"fnbound", funcbound,
|
|
|
|
"fmt", fmt,
|
|
|
|
"follow", follow,
|
|
|
|
"include", include,
|
|
|
|
"includepipe", includepipe,
|
|
|
|
"interpret", interpret,
|
|
|
|
"itoa", cvtitoa,
|
|
|
|
"kill", xkill,
|
|
|
|
"map", map,
|
|
|
|
"match", match,
|
|
|
|
"newproc", newproc,
|
|
|
|
"pcfile", pcfile,
|
|
|
|
"pcline", pcline,
|
|
|
|
"print", bprint,
|
|
|
|
"printto", printto,
|
|
|
|
"rc", rc,
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
"readfile", readfile,
|
2004-04-19 19:32:07 +00:00
|
|
|
"reason", reason,
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
"refconst", refconst,
|
2004-04-19 19:32:07 +00:00
|
|
|
"regexp", regexp,
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
"register", xregister,
|
2004-04-19 19:32:07 +00:00
|
|
|
"setproc", setproc,
|
|
|
|
"start", start,
|
|
|
|
"startstop", startstop,
|
|
|
|
"status", status,
|
|
|
|
"stop", stop,
|
|
|
|
"strace", strace,
|
2004-09-23 03:04:33 +00:00
|
|
|
"stringn", stringn,
|
2004-04-19 19:32:07 +00:00
|
|
|
"sysstop", sysstop,
|
|
|
|
"textfile", textfile,
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
"var", dolook,
|
2004-04-19 19:32:07 +00:00
|
|
|
"waitstop", waitstop,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
mkprint(Lsym *s)
|
|
|
|
{
|
|
|
|
prnt = malloc(sizeof(Node));
|
|
|
|
memset(prnt, 0, sizeof(Node));
|
|
|
|
prnt->op = OCALL;
|
|
|
|
prnt->left = malloc(sizeof(Node));
|
|
|
|
memset(prnt->left, 0, sizeof(Node));
|
|
|
|
prnt->left->sym = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
installbuiltin(void)
|
|
|
|
{
|
|
|
|
Btab *b;
|
|
|
|
Lsym *s;
|
|
|
|
|
|
|
|
b = tab;
|
|
|
|
while(b->name) {
|
|
|
|
s = look(b->name);
|
|
|
|
if(s == 0)
|
|
|
|
s = enter(b->name, Tid);
|
|
|
|
|
|
|
|
s->builtin = b->fn;
|
|
|
|
if(b->fn == bprint)
|
|
|
|
mkprint(s);
|
|
|
|
b++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
match(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
List *f;
|
|
|
|
Node *av[Maxarg];
|
|
|
|
Node resi, resl;
|
|
|
|
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
if(na != 2)
|
|
|
|
error("match(obj, list): arg count");
|
|
|
|
|
|
|
|
expr(av[1], &resl);
|
|
|
|
if(resl.type != TLIST)
|
|
|
|
error("match(obj, list): need list");
|
|
|
|
expr(av[0], &resi);
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TINT;
|
|
|
|
r->store.fmt = 'D';
|
|
|
|
r->store.u.ival = -1;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
for(f = resl.store.u.l; f; f = f->next) {
|
|
|
|
if(resi.type == f->type) {
|
|
|
|
switch(resi.type) {
|
|
|
|
case TINT:
|
|
|
|
if(resi.store.u.ival == f->store.u.ival) {
|
|
|
|
r->store.u.ival = i;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TFLOAT:
|
|
|
|
if(resi.store.u.fval == f->store.u.fval) {
|
|
|
|
r->store.u.ival = i;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TSTRING:
|
|
|
|
if(scmp(resi.store.u.string, f->store.u.string)) {
|
|
|
|
r->store.u.ival = i;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TLIST:
|
|
|
|
error("match(obj, list): not defined for list");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
newproc(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Node res;
|
|
|
|
char *p, *e;
|
|
|
|
char *argv[Maxarg], buf[Strsize];
|
|
|
|
|
|
|
|
i = 1;
|
|
|
|
argv[0] = symfil;
|
|
|
|
|
|
|
|
if(args) {
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("newproc(): arg not string");
|
|
|
|
if(res.store.u.string->len >= sizeof(buf))
|
|
|
|
error("newproc(): too many arguments");
|
|
|
|
memmove(buf, res.store.u.string->string, res.store.u.string->len);
|
|
|
|
buf[res.store.u.string->len] = '\0';
|
|
|
|
p = buf;
|
|
|
|
e = buf+res.store.u.string->len;
|
|
|
|
for(;;) {
|
|
|
|
while(p < e && (*p == '\t' || *p == ' '))
|
|
|
|
*p++ = '\0';
|
|
|
|
if(p >= e)
|
|
|
|
break;
|
|
|
|
argv[i++] = p;
|
|
|
|
if(i >= Maxarg)
|
|
|
|
error("newproc: too many arguments");
|
|
|
|
while(p < e && *p != '\t' && *p != ' ')
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
argv[i] = 0;
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TINT;
|
|
|
|
r->store.fmt = 'D';
|
|
|
|
r->store.u.ival = nproc(argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
startstop(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("startstop(pid): no pid");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("startstop(pid): arg type");
|
|
|
|
|
|
|
|
msg(res.store.u.ival, "startstop");
|
|
|
|
notes(res.store.u.ival);
|
|
|
|
dostop(res.store.u.ival);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
waitstop(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("waitstop(pid): no pid");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("waitstop(pid): arg type");
|
|
|
|
|
|
|
|
Bflush(bout);
|
|
|
|
msg(res.store.u.ival, "waitstop");
|
|
|
|
notes(res.store.u.ival);
|
|
|
|
dostop(res.store.u.ival);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sysstop(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("waitstop(pid): no pid");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("waitstop(pid): arg type");
|
|
|
|
|
|
|
|
Bflush(bout);
|
|
|
|
msg(res.store.u.ival, "sysstop");
|
|
|
|
notes(res.store.u.ival);
|
|
|
|
dostop(res.store.u.ival);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
start(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("start(pid): no pid");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("start(pid): arg type");
|
|
|
|
|
|
|
|
msg(res.store.u.ival, "start");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
stop(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("stop(pid): no pid");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("stop(pid): arg type");
|
|
|
|
|
|
|
|
Bflush(bout);
|
|
|
|
msg(res.store.u.ival, "stop");
|
|
|
|
notes(res.store.u.ival);
|
|
|
|
dostop(res.store.u.ival);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xkill(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("kill(pid): no pid");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("kill(pid): arg type");
|
|
|
|
|
|
|
|
msg(res.store.u.ival, "kill");
|
|
|
|
deinstall(res.store.u.ival);
|
|
|
|
}
|
|
|
|
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
void
|
|
|
|
xregister(Node *r, Node *args)
|
|
|
|
{
|
2005-02-11 00:01:49 +00:00
|
|
|
int tid;
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
Regdesc *rp;
|
2005-02-11 00:01:49 +00:00
|
|
|
Node res, resid;
|
|
|
|
Node *av[Maxarg];
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
|
2005-02-11 00:01:49 +00:00
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
2005-02-11 16:54:59 +00:00
|
|
|
if(na != 1/* && na != 2 */)
|
|
|
|
error("register(name): arg count");
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
|
2005-02-11 00:01:49 +00:00
|
|
|
expr(av[0], &res);
|
|
|
|
if(res.type != TSTRING)
|
2005-02-11 16:54:59 +00:00
|
|
|
error("register(name): arg type: name should be string");
|
2005-02-11 00:01:49 +00:00
|
|
|
tid = 0;
|
|
|
|
if(na == 2){
|
|
|
|
expr(av[1], &resid);
|
|
|
|
if(resid.type != TINT)
|
|
|
|
error("register(name[, threadid]): arg type: threadid should be int");
|
|
|
|
tid = resid.store.u.ival;
|
|
|
|
}
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
if((rp = regdesc(res.store.u.string->string)) == nil)
|
|
|
|
error("no such register");
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TREG;
|
|
|
|
r->store.fmt = rp->format;
|
2005-02-11 00:01:49 +00:00
|
|
|
r->store.u.reg.name = rp->name;
|
|
|
|
r->store.u.reg.thread = tid;
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
refconst(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node *n;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("refconst(expr): arg count");
|
|
|
|
|
|
|
|
n = an(OCONST, ZN, ZN);
|
|
|
|
expr(args, n);
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TCON;
|
|
|
|
r->store.u.con = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dolook(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
Lsym *l;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("var(string): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("var(string): arg type");
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
if((l = look(res.store.u.string->string)) == nil || l->v->set == 0){
|
|
|
|
r->type = TLIST;
|
|
|
|
r->store.u.l = nil;
|
|
|
|
}else{
|
|
|
|
r->type = l->v->type;
|
|
|
|
r->store = l->v->store;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-04-19 19:32:07 +00:00
|
|
|
void
|
|
|
|
status(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("status(pid): no pid");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("status(pid): arg type");
|
|
|
|
|
|
|
|
p = getstatus(res.store.u.ival);
|
|
|
|
r->store.u.string = strnode(p);
|
|
|
|
r->op = OCONST;
|
|
|
|
r->store.fmt = 's';
|
|
|
|
r->type = TSTRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
reason(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("reason(cause): no cause");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("reason(cause): arg type");
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TSTRING;
|
|
|
|
r->store.fmt = 's';
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
r->store.u.string = strnode((*mach->exc)(cormap, acidregs));
|
2004-04-19 19:32:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
follow(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int n, i;
|
|
|
|
Node res;
|
|
|
|
ulong f[10];
|
|
|
|
List **tail, *l;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("follow(addr): no addr");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("follow(addr): arg type");
|
|
|
|
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
n = (*mach->foll)(cormap, acidregs, res.store.u.ival, f);
|
2004-04-19 19:32:07 +00:00
|
|
|
if (n < 0)
|
|
|
|
error("follow(addr): %r");
|
|
|
|
tail = &r->store.u.l;
|
|
|
|
for(i = 0; i < n; i++) {
|
|
|
|
l = al(TINT);
|
|
|
|
l->store.u.ival = f[i];
|
|
|
|
l->store.fmt = 'X';
|
|
|
|
*tail = l;
|
|
|
|
tail = &l->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
funcbound(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
Node res;
|
|
|
|
ulong bounds[2];
|
|
|
|
List *l;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("fnbound(addr): no addr");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("fnbound(addr): arg type");
|
|
|
|
|
|
|
|
n = fnbound(res.store.u.ival, bounds);
|
|
|
|
if (n != 0) {
|
|
|
|
r->store.u.l = al(TINT);
|
|
|
|
l = r->store.u.l;
|
|
|
|
l->store.u.ival = bounds[0];
|
|
|
|
l->store.fmt = 'X';
|
|
|
|
l->next = al(TINT);
|
|
|
|
l = l->next;
|
|
|
|
l->store.u.ival = bounds[1];
|
|
|
|
l->store.fmt = 'X';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
setproc(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("setproc(pid): no pid");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("setproc(pid): arg type");
|
|
|
|
|
|
|
|
sproc(res.store.u.ival);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
filepc(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Node res;
|
|
|
|
char *p, c;
|
|
|
|
ulong v;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("filepc(filename:line): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("filepc(filename:line): arg type");
|
|
|
|
|
|
|
|
p = strchr(res.store.u.string->string, ':');
|
|
|
|
if(p == 0)
|
|
|
|
error("filepc(filename:line): bad arg format");
|
|
|
|
|
|
|
|
c = *p;
|
|
|
|
*p++ = '\0';
|
|
|
|
i = file2pc(res.store.u.string->string, atoi(p), &v);
|
|
|
|
p[-1] = c;
|
|
|
|
if(i < 0)
|
|
|
|
error("filepc(filename:line): can't find address");
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TINT;
|
|
|
|
r->store.fmt = 'D';
|
|
|
|
r->store.u.ival = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
interpret(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
int isave;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("interpret(string): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("interpret(string): arg type");
|
|
|
|
|
|
|
|
pushstr(&res);
|
|
|
|
|
|
|
|
isave = interactive;
|
|
|
|
interactive = 0;
|
|
|
|
r->store.u.ival = yyparse();
|
|
|
|
interactive = isave;
|
|
|
|
popio();
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TINT;
|
|
|
|
r->store.fmt = 'D';
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
include(Node *r, Node *args)
|
|
|
|
{
|
2004-04-21 05:34:37 +00:00
|
|
|
char *file, *libfile;
|
|
|
|
static char buf[1024];
|
2004-04-19 19:32:07 +00:00
|
|
|
Node res;
|
|
|
|
int isave;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("include(string): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("include(string): arg type");
|
|
|
|
|
|
|
|
Bflush(bout);
|
2004-04-21 05:34:37 +00:00
|
|
|
|
|
|
|
libfile = nil;
|
|
|
|
file = res.store.u.string->string;
|
|
|
|
if(access(file, AREAD) < 0 && file[0] != '/'){
|
|
|
|
snprint(buf, sizeof buf, "#9/acid/%s", file);
|
|
|
|
libfile = unsharp(buf);
|
|
|
|
if(access(libfile, AREAD) >= 0){
|
|
|
|
strecpy(buf, buf+sizeof buf, libfile);
|
|
|
|
file = buf;
|
|
|
|
}
|
|
|
|
free(libfile);
|
|
|
|
}
|
2004-04-19 19:32:07 +00:00
|
|
|
|
2004-04-21 22:49:15 +00:00
|
|
|
pushfile(file);
|
2004-04-19 19:32:07 +00:00
|
|
|
isave = interactive;
|
|
|
|
interactive = 0;
|
|
|
|
r->store.u.ival = yyparse();
|
|
|
|
interactive = isave;
|
|
|
|
popio();
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TINT;
|
|
|
|
r->store.fmt = 'D';
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
includepipe(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
int i, isave, pid, pip[2];
|
|
|
|
char *argv[4];
|
|
|
|
Waitmsg *w;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("includepipe(string): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("includepipe(string): arg type");
|
|
|
|
|
|
|
|
Bflush(bout);
|
|
|
|
|
|
|
|
argv[0] = "rc";
|
|
|
|
argv[1] = "-c";
|
|
|
|
argv[2] = res.store.u.string->string;
|
|
|
|
argv[3] = 0;
|
|
|
|
|
|
|
|
if(pipe(pip) < 0)
|
|
|
|
error("pipe: %r");
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
switch(pid) {
|
|
|
|
case -1:
|
|
|
|
close(pip[0]);
|
|
|
|
close(pip[1]);
|
|
|
|
error("fork: %r");
|
|
|
|
case 0:
|
|
|
|
close(pip[0]);
|
|
|
|
close(0);
|
|
|
|
open("/dev/null", OREAD);
|
|
|
|
dup(pip[1], 1);
|
|
|
|
if(pip[1] > 1)
|
|
|
|
close(pip[1]);
|
|
|
|
for(i=3; i<100; i++)
|
|
|
|
close(i);
|
|
|
|
exec("rc", argv);
|
|
|
|
sysfatal("exec rc: %r");
|
|
|
|
}
|
|
|
|
|
|
|
|
close(pip[1]);
|
|
|
|
pushfd(pip[0]);
|
|
|
|
|
|
|
|
isave = interactive;
|
|
|
|
interactive = 0;
|
|
|
|
r->store.u.ival = yyparse();
|
|
|
|
interactive = isave;
|
|
|
|
popio();
|
2004-04-21 22:49:15 +00:00
|
|
|
|
2004-04-19 19:32:07 +00:00
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TINT;
|
|
|
|
r->store.fmt = 'D';
|
|
|
|
|
|
|
|
w = waitfor(pid);
|
|
|
|
if(w->msg && w->msg[0])
|
|
|
|
error("includepipe(\"%s\"): %s", argv[2], w->msg); /* leaks w */
|
|
|
|
free(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rc(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
int pid;
|
|
|
|
char *p, *q, *argv[4];
|
|
|
|
Waitmsg *w;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("rc(string): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("rc(string): arg type");
|
|
|
|
|
|
|
|
argv[0] = "rc";
|
|
|
|
argv[1] = "-c";
|
|
|
|
argv[2] = res.store.u.string->string;
|
|
|
|
argv[3] = 0;
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
switch(pid) {
|
|
|
|
case -1:
|
|
|
|
error("fork %r");
|
|
|
|
case 0:
|
|
|
|
exec("rc", argv);
|
|
|
|
exits(0);
|
|
|
|
default:
|
|
|
|
w = waitfor(pid);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p = w->msg;
|
|
|
|
q = strrchr(p, ':');
|
|
|
|
if (q)
|
|
|
|
p = q+1;
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TSTRING;
|
|
|
|
r->store.u.string = strnode(p);
|
|
|
|
free(w);
|
|
|
|
r->store.fmt = 's';
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
doerror(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
if(args == 0)
|
|
|
|
error("error(string): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("error(string): arg type");
|
|
|
|
|
|
|
|
error(res.store.u.string->string);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
doaccess(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("access(filename): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("access(filename): arg type");
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TINT;
|
2004-04-20 05:51:36 +00:00
|
|
|
r->store.fmt = 'D';
|
2004-04-19 19:32:07 +00:00
|
|
|
r->store.u.ival = 0;
|
|
|
|
if(access(res.store.u.string->string, 4) == 0)
|
|
|
|
r->store.u.ival = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
readfile(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
int n, fd;
|
|
|
|
char *buf;
|
|
|
|
Dir *db;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("readfile(filename): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("readfile(filename): arg type");
|
|
|
|
|
|
|
|
fd = open(res.store.u.string->string, OREAD);
|
|
|
|
if(fd < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
db = dirfstat(fd);
|
|
|
|
if(db == nil || db->length == 0)
|
|
|
|
n = 8192;
|
|
|
|
else
|
|
|
|
n = db->length;
|
|
|
|
free(db);
|
|
|
|
|
|
|
|
buf = malloc(n);
|
|
|
|
n = read(fd, buf, n);
|
|
|
|
|
|
|
|
if(n > 0) {
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TSTRING;
|
|
|
|
r->store.u.string = strnodlen(buf, n);
|
|
|
|
r->store.fmt = 's';
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
getfile(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
char *p;
|
|
|
|
Node res;
|
|
|
|
String *s;
|
|
|
|
Biobuf *bp;
|
|
|
|
List **l, *new;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("file(filename): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("file(filename): arg type");
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TLIST;
|
|
|
|
r->store.u.l = 0;
|
|
|
|
|
|
|
|
p = res.store.u.string->string;
|
|
|
|
bp = Bopen(p, OREAD);
|
|
|
|
if(bp == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
l = &r->store.u.l;
|
|
|
|
for(;;) {
|
|
|
|
p = Brdline(bp, '\n');
|
|
|
|
n = Blinelen(bp);
|
|
|
|
if(p == 0) {
|
|
|
|
if(n == 0)
|
|
|
|
break;
|
|
|
|
s = strnodlen(0, n);
|
|
|
|
Bread(bp, s->string, n);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
s = strnodlen(p, n-1);
|
|
|
|
|
|
|
|
new = al(TSTRING);
|
|
|
|
new->store.u.string = s;
|
|
|
|
new->store.fmt = 's';
|
|
|
|
*l = new;
|
|
|
|
l = &new->next;
|
|
|
|
}
|
|
|
|
Bterm(bp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cvtatof(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("atof(string): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("atof(string): arg type");
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TFLOAT;
|
|
|
|
r->store.u.fval = atof(res.store.u.string->string);
|
|
|
|
r->store.fmt = 'f';
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cvtatoi(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("atoi(string): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("atoi(string): arg type");
|
|
|
|
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TINT;
|
|
|
|
r->store.u.ival = strtoul(res.store.u.string->string, 0, 0);
|
|
|
|
r->store.fmt = 'D';
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cvtitoa(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
Node *av[Maxarg];
|
|
|
|
int ival;
|
|
|
|
char buf[128], *fmt;
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
err:
|
|
|
|
error("itoa(number [, printformat]): arg count");
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
if(na == 0 || na > 2)
|
|
|
|
goto err;
|
|
|
|
expr(av[0], &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("itoa(integer): arg type");
|
|
|
|
ival = (int)res.store.u.ival;
|
|
|
|
fmt = "%d";
|
|
|
|
if(na == 2){
|
|
|
|
expr(av[1], &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("itoa(integer, string): arg type");
|
|
|
|
fmt = res.store.u.string->string;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprint(buf, fmt, ival);
|
|
|
|
r->op = OCONST;
|
|
|
|
r->type = TSTRING;
|
|
|
|
r->store.u.string = strnode(buf);
|
|
|
|
r->store.fmt = 's';
|
|
|
|
}
|
|
|
|
|
|
|
|
List*
|
|
|
|
mapent(Map *m)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
List *l, *n, **t, *h;
|
|
|
|
|
|
|
|
h = 0;
|
|
|
|
t = &h;
|
|
|
|
for(i = 0; i < m->nseg; i++) {
|
|
|
|
l = al(TSTRING);
|
|
|
|
n = al(TLIST);
|
|
|
|
n->store.u.l = l;
|
|
|
|
*t = n;
|
|
|
|
t = &n->next;
|
|
|
|
l->store.u.string = strnode(m->seg[i].name);
|
|
|
|
l->store.fmt = 's';
|
|
|
|
l->next = al(TSTRING);
|
|
|
|
l = l->next;
|
|
|
|
l->store.u.string = strnode(m->seg[i].file ? m->seg[i].file : "");
|
|
|
|
l->store.fmt = 's';
|
|
|
|
l->next = al(TINT);
|
|
|
|
l = l->next;
|
|
|
|
l->store.u.ival = m->seg[i].base;
|
|
|
|
l->store.fmt = 'X';
|
|
|
|
l->next = al(TINT);
|
|
|
|
l = l->next;
|
|
|
|
l->store.u.ival = m->seg[i].base + m->seg[i].size;
|
|
|
|
l->store.fmt = 'X';
|
|
|
|
l->next = al(TINT);
|
|
|
|
l = l->next;
|
|
|
|
l->store.u.ival = m->seg[i].offset;
|
|
|
|
l->store.fmt = 'X';
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
map(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Map *m;
|
|
|
|
List *l;
|
|
|
|
char *nam, *fil;
|
|
|
|
Node *av[Maxarg], res;
|
|
|
|
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
|
|
|
|
if(na != 0) {
|
|
|
|
expr(av[0], &res);
|
|
|
|
if(res.type != TLIST)
|
|
|
|
error("map(list): map needs a list");
|
|
|
|
if(listlen(res.store.u.l) != 5)
|
|
|
|
error("map(list): list must have 5 entries");
|
|
|
|
|
|
|
|
l = res.store.u.l;
|
|
|
|
if(l->type != TSTRING)
|
|
|
|
error("map name must be a string");
|
|
|
|
nam = l->store.u.string->string;
|
|
|
|
l = l->next;
|
|
|
|
if(l->type != TSTRING)
|
|
|
|
error("map file must be a string");
|
|
|
|
fil = l->store.u.string->string;
|
|
|
|
m = symmap;
|
|
|
|
i = findseg(m, nam, fil);
|
|
|
|
if(i < 0) {
|
|
|
|
m = cormap;
|
|
|
|
i = findseg(m, nam, fil);
|
|
|
|
}
|
|
|
|
if(i < 0)
|
|
|
|
error("%s %s is not a map entry", nam, fil);
|
|
|
|
l = l->next;
|
|
|
|
if(l->type != TINT)
|
|
|
|
error("map entry not int");
|
|
|
|
m->seg[i].base = l->store.u.ival;
|
|
|
|
/*
|
|
|
|
if (strcmp(ent, "text") == 0)
|
|
|
|
textseg(l->store.u.ival, &fhdr);
|
|
|
|
*/
|
|
|
|
l = l->next;
|
|
|
|
if(l->type != TINT)
|
|
|
|
error("map entry not int");
|
|
|
|
m->seg[i].size = l->store.u.ival - m->seg[i].base;
|
|
|
|
l = l->next;
|
|
|
|
if(l->type != TINT)
|
|
|
|
error("map entry not int");
|
|
|
|
m->seg[i].offset = l->store.u.ival;
|
|
|
|
}
|
|
|
|
|
|
|
|
r->type = TLIST;
|
|
|
|
r->store.u.l = 0;
|
|
|
|
if(symmap)
|
|
|
|
r->store.u.l = mapent(symmap);
|
|
|
|
if(cormap) {
|
|
|
|
if(r->store.u.l == 0)
|
|
|
|
r->store.u.l = mapent(cormap);
|
|
|
|
else {
|
|
|
|
for(l = r->store.u.l; l->next; l = l->next)
|
|
|
|
;
|
|
|
|
l->next = mapent(cormap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
flatten(Node **av, Node *n)
|
|
|
|
{
|
|
|
|
if(n == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch(n->op) {
|
|
|
|
case OLIST:
|
|
|
|
flatten(av, n->left);
|
|
|
|
flatten(av, n->right);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
av[na++] = n;
|
|
|
|
if(na >= Maxarg)
|
|
|
|
error("too many function arguments");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
ulong val;
|
|
|
|
} sregs[Maxarg/2];
|
|
|
|
static int nsregs;
|
|
|
|
|
|
|
|
static int
|
|
|
|
straceregrw(Regs *regs, char *name, ulong *val, int isr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(!isr){
|
|
|
|
werrstr("saved registers cannot be written");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for(i=0; i<nsregs; i++)
|
|
|
|
if(strcmp(sregs[i].name, name) == 0){
|
|
|
|
*val = sregs[i].val;
|
|
|
|
return 0;
|
|
|
|
}
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
return rget(acidregs, name, val);
|
2004-04-19 19:32:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
strace(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node *av[Maxarg], res;
|
|
|
|
List *l;
|
|
|
|
Regs regs;
|
|
|
|
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
|
|
|
|
if(na != 1)
|
|
|
|
error("strace(list): want one arg");
|
|
|
|
|
|
|
|
expr(av[0], &res);
|
|
|
|
if(res.type != TLIST)
|
|
|
|
error("strace(list): strace needs a list");
|
|
|
|
l = res.store.u.l;
|
|
|
|
if(listlen(l)%2)
|
|
|
|
error("strace(list): strace needs an even-length list");
|
|
|
|
for(nsregs=0; l; nsregs++){
|
|
|
|
if(l->type != TSTRING)
|
|
|
|
error("strace({r,v,r,v,...}): non-string name");
|
|
|
|
sregs[nsregs].name = l->store.u.string->string;
|
|
|
|
if(regdesc(sregs[nsregs].name) == nil)
|
|
|
|
error("strace: bad register '%s'", sregs[nsregs].name);
|
|
|
|
l = l->next;
|
|
|
|
|
|
|
|
if(l == nil)
|
|
|
|
error("cannot happen in strace");
|
|
|
|
if(l->type != TINT)
|
|
|
|
error("strace: non-int value for %s", sregs[nsregs].name);
|
|
|
|
sregs[nsregs].val = l->store.u.ival;
|
|
|
|
l = l->next;
|
|
|
|
}
|
|
|
|
regs.rw = straceregrw;
|
|
|
|
|
|
|
|
tracelist = 0;
|
|
|
|
if(stacktrace(cormap, ®s, trlist) <= 0)
|
|
|
|
error("no stack frame");
|
|
|
|
r->type = TLIST;
|
|
|
|
r->store.u.l = tracelist;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
regerror(char *msg)
|
|
|
|
{
|
|
|
|
error(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
regexp(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
Reprog *rp;
|
|
|
|
Node *av[Maxarg];
|
|
|
|
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
if(na != 2)
|
|
|
|
error("regexp(pattern, string): arg count");
|
|
|
|
expr(av[0], &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("regexp(pattern, string): pattern must be string");
|
|
|
|
rp = regcomp(res.store.u.string->string);
|
|
|
|
if(rp == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
expr(av[1], &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("regexp(pattern, string): bad string");
|
|
|
|
|
|
|
|
r->store.fmt = 'D';
|
|
|
|
r->type = TINT;
|
|
|
|
r->store.u.ival = regexec(rp, res.store.u.string->string, 0, 0);
|
|
|
|
free(rp);
|
|
|
|
}
|
|
|
|
|
|
|
|
char vfmt[] = "aBbcCdDfFgGiIoOqQrRsSuUVxXYZ";
|
|
|
|
|
|
|
|
void
|
|
|
|
fmt(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
Node *av[Maxarg];
|
|
|
|
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
if(na != 2)
|
|
|
|
error("fmt(obj, fmt): arg count");
|
|
|
|
expr(av[1], &res);
|
|
|
|
if(res.type != TINT || strchr(vfmt, res.store.u.ival) == 0)
|
|
|
|
error("fmt(obj, fmt): bad format '%c'", (char)res.store.u.ival);
|
|
|
|
expr(av[0], r);
|
|
|
|
r->store.fmt = res.store.u.ival;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
patom(char type, Store *res)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char buf[512];
|
|
|
|
extern char *typenames[];
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
Node *n;
|
|
|
|
|
|
|
|
switch(type){
|
|
|
|
case TREG:
|
2005-02-11 00:01:49 +00:00
|
|
|
if(res->u.reg.thread)
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "register(\"%s\", %#ux)", res->u.reg.name, res->u.reg.thread);
|
2005-02-11 00:01:49 +00:00
|
|
|
else
|
|
|
|
Bprint(bout, "register(\"%s\")", res->u.reg.name);
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
return;
|
|
|
|
case TCON:
|
|
|
|
Bprint(bout, "refconst(");
|
|
|
|
n = res->u.con;
|
|
|
|
patom(n->type, &n->store);
|
|
|
|
Bprint(bout, ")");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(res->fmt){
|
|
|
|
case 'c':
|
|
|
|
case 'C':
|
|
|
|
case 'r':
|
|
|
|
case 'B':
|
|
|
|
case 'b':
|
|
|
|
case 'X':
|
|
|
|
case 'x':
|
|
|
|
case 'W':
|
|
|
|
case 'D':
|
|
|
|
case 'd':
|
|
|
|
case 'u':
|
|
|
|
case 'U':
|
|
|
|
case 'Z':
|
|
|
|
case 'V':
|
|
|
|
case 'Y':
|
|
|
|
case 'o':
|
|
|
|
case 'O':
|
|
|
|
case 'q':
|
|
|
|
case 'Q':
|
|
|
|
case 'a':
|
|
|
|
case 'A':
|
|
|
|
case 'I':
|
|
|
|
case 'i':
|
|
|
|
if(type != TINT){
|
|
|
|
badtype:
|
|
|
|
Bprint(bout, "*%s\\%c*", typenames[(uchar)type], res->fmt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
case 'F':
|
|
|
|
if(type != TFLOAT)
|
|
|
|
goto badtype;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 's':
|
|
|
|
case 'g':
|
|
|
|
case 'G':
|
|
|
|
case 'R':
|
|
|
|
if(type != TSTRING)
|
|
|
|
goto badtype;
|
|
|
|
break;
|
|
|
|
}
|
2004-04-19 19:32:07 +00:00
|
|
|
|
|
|
|
switch(res->fmt) {
|
|
|
|
case 'c':
|
|
|
|
Bprint(bout, "%c", (int)res->u.ival);
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
if(res->u.ival < ' ' || res->u.ival >= 0x7f)
|
|
|
|
Bprint(bout, "%3d", (int)res->u.ival&0xff);
|
|
|
|
else
|
|
|
|
Bprint(bout, "%3c", (int)res->u.ival);
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
Bprint(bout, "%C", (int)res->u.ival);
|
|
|
|
break;
|
|
|
|
case 'B':
|
|
|
|
memset(buf, '0', 34);
|
|
|
|
buf[1] = 'b';
|
|
|
|
for(i = 0; i < 32; i++) {
|
|
|
|
if(res->u.ival & (1<<i))
|
|
|
|
buf[33-i] = '1';
|
|
|
|
}
|
|
|
|
buf[35] = '\0';
|
|
|
|
Bprint(bout, "%s", buf);
|
|
|
|
break;
|
|
|
|
case 'b':
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "%#.2x", (int)res->u.ival&0xff);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'X':
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "%#.8lux", (ulong)res->u.ival);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'x':
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "%#.4lux", (ulong)res->u.ival&0xffff);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'W':
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "%#.16llux", res->u.ival);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
Bprint(bout, "%d", (int)res->u.ival);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
Bprint(bout, "%d", (ushort)res->u.ival);
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
Bprint(bout, "%d", (int)res->u.ival&0xffff);
|
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
Bprint(bout, "%lud", (ulong)res->u.ival);
|
|
|
|
break;
|
|
|
|
case 'Z':
|
|
|
|
Bprint(bout, "%llud", res->u.ival);
|
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
Bprint(bout, "%lld", res->u.ival);
|
|
|
|
break;
|
|
|
|
case 'Y':
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "%#.16llux", res->u.ival);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'o':
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "%#.11uo", (int)res->u.ival&0xffff);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'O':
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "%#.6uo", (int)res->u.ival);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'q':
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "%#.11o", (short)(res->u.ival&0xffff));
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'Q':
|
2005-02-11 16:54:59 +00:00
|
|
|
Bprint(bout, "%#.6o", (int)res->u.ival);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
case 'F':
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
Bprint(bout, "%g", res->u.fval);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
case 'g':
|
|
|
|
case 'G':
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
Bwrite(bout, res->u.string->string, res->u.string->len);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'R':
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
Bprint(bout, "%S", (Rune*)res->u.string->string);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
case 'A':
|
|
|
|
symoff(buf, sizeof(buf), res->u.ival, CANY);
|
|
|
|
Bprint(bout, "%s", buf);
|
|
|
|
break;
|
|
|
|
case 'I':
|
|
|
|
case 'i':
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
if (symmap == nil || (*mach->das)(symmap, res->u.ival, res->fmt, buf, sizeof(buf)) < 0)
|
|
|
|
Bprint(bout, "no instruction");
|
|
|
|
else
|
|
|
|
Bprint(bout, "%s", buf);
|
2004-04-19 19:32:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
blprint(List *l)
|
|
|
|
{
|
|
|
|
Store *res;
|
|
|
|
|
|
|
|
Bprint(bout, "{");
|
|
|
|
while(l) {
|
|
|
|
switch(l->type) {
|
|
|
|
case TINT:
|
|
|
|
res = &l->store;
|
|
|
|
if(res->fmt == 'c'){
|
|
|
|
Bprint(bout, "\'%c\'", (int)res->u.ival);
|
|
|
|
break;
|
|
|
|
}else if(res->fmt == 'r'){
|
|
|
|
Bprint(bout, "\'%C\'", (int)res->u.ival);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
default:
|
|
|
|
patom(l->type, &l->store);
|
|
|
|
break;
|
|
|
|
case TSTRING:
|
|
|
|
Bputc(bout, '"');
|
|
|
|
patom(l->type, &l->store);
|
|
|
|
Bputc(bout, '"');
|
|
|
|
break;
|
|
|
|
case TLIST:
|
|
|
|
blprint(l->store.u.l);
|
|
|
|
break;
|
|
|
|
case TCODE:
|
|
|
|
pcode(l->store.u.cc, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
l = l->next;
|
|
|
|
if(l)
|
|
|
|
Bprint(bout, ", ");
|
|
|
|
}
|
|
|
|
Bprint(bout, "}");
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
comx(Node res)
|
|
|
|
{
|
|
|
|
Lsym *sl;
|
|
|
|
Node *n, xx;
|
|
|
|
|
|
|
|
if(res.store.fmt != 'a' && res.store.fmt != 'A')
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(res.store.comt == 0 || res.store.comt->base == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
sl = res.store.comt->base;
|
|
|
|
if(sl->proc) {
|
|
|
|
res.left = ZN;
|
|
|
|
res.right = ZN;
|
|
|
|
n = an(ONAME, ZN, ZN);
|
|
|
|
n->sym = sl;
|
|
|
|
n = an(OCALL, n, &res);
|
|
|
|
n->left->sym = sl;
|
|
|
|
expr(n, &xx);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
print("(%s)", sl->name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bprint(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int i, nas;
|
|
|
|
Node res, *av[Maxarg];
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
nas = na;
|
|
|
|
for(i = 0; i < nas; i++) {
|
|
|
|
expr(av[i], &res);
|
|
|
|
switch(res.type) {
|
|
|
|
default:
|
|
|
|
if(comx(res))
|
|
|
|
break;
|
|
|
|
patom(res.type, &res.store);
|
|
|
|
break;
|
|
|
|
case TCODE:
|
|
|
|
pcode(res.store.u.cc, 0);
|
|
|
|
break;
|
|
|
|
case TLIST:
|
|
|
|
blprint(res.store.u.l);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(ret == 0)
|
|
|
|
Bputc(bout, '\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
printto(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
Biobuf *b;
|
|
|
|
int i, nas;
|
|
|
|
Node res, *av[Maxarg];
|
|
|
|
|
|
|
|
USED(r);
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
nas = na;
|
|
|
|
|
|
|
|
expr(av[0], &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("printto(string, ...): need string");
|
|
|
|
|
|
|
|
fd = create(res.store.u.string->string, OWRITE, 0666);
|
|
|
|
if(fd < 0)
|
|
|
|
fd = open(res.store.u.string->string, OWRITE);
|
|
|
|
if(fd < 0)
|
|
|
|
error("printto: open %s: %r", res.store.u.string->string);
|
|
|
|
|
|
|
|
b = gmalloc(sizeof(Biobuf));
|
|
|
|
Binit(b, fd, OWRITE);
|
|
|
|
|
|
|
|
Bflush(bout);
|
|
|
|
io[iop++] = bout;
|
|
|
|
bout = b;
|
|
|
|
|
|
|
|
for(i = 1; i < nas; i++) {
|
|
|
|
expr(av[i], &res);
|
|
|
|
switch(res.type) {
|
|
|
|
default:
|
|
|
|
if(comx(res))
|
|
|
|
break;
|
|
|
|
patom(res.type, &res.store);
|
|
|
|
break;
|
|
|
|
case TLIST:
|
|
|
|
blprint(res.store.u.l);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(ret == 0)
|
|
|
|
Bputc(bout, '\n');
|
|
|
|
|
|
|
|
Bterm(b);
|
|
|
|
close(fd);
|
|
|
|
free(b);
|
|
|
|
bout = io[--iop];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pcfile(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
char *p, buf[128];
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("pcfile(addr): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("pcfile(addr): arg type");
|
|
|
|
|
|
|
|
r->type = TSTRING;
|
|
|
|
r->store.fmt = 's';
|
|
|
|
if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
|
|
|
|
r->store.u.string = strnode("?file?");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
p = strrchr(buf, ':');
|
|
|
|
if(p == 0)
|
|
|
|
error("pcfile(addr): funny file %s", buf);
|
|
|
|
*p = '\0';
|
|
|
|
r->store.u.string = strnode(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pcline(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
Node res;
|
|
|
|
char *p, buf[128];
|
|
|
|
|
|
|
|
if(args == 0)
|
|
|
|
error("pcline(addr): arg count");
|
|
|
|
expr(args, &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("pcline(addr): arg type");
|
|
|
|
|
|
|
|
r->type = TINT;
|
|
|
|
r->store.fmt = 'D';
|
|
|
|
if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
|
|
|
|
r->store.u.ival = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = strrchr(buf, ':');
|
|
|
|
if(p == 0)
|
|
|
|
error("pcline(addr): funny file %s", buf);
|
|
|
|
r->store.u.ival = atoi(p+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
textfile(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
char *file;
|
|
|
|
long base;
|
|
|
|
Fhdr *fp;
|
|
|
|
Node res, *av[Maxarg];
|
|
|
|
List *l, *l2, **tail, *list, *tl;
|
|
|
|
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
|
|
|
|
if(na != 0) {
|
|
|
|
expr(av[0], &res);
|
|
|
|
if(res.type != TLIST)
|
|
|
|
error("textfile(list): textfile needs a list");
|
|
|
|
if(listlen(res.store.u.l) != 2)
|
|
|
|
error("textfile(list): list must have 2 entries");
|
|
|
|
|
|
|
|
l = res.store.u.l;
|
|
|
|
if(l->type != TSTRING)
|
|
|
|
error("textfile name must be a string");
|
|
|
|
file = l->store.u.string->string;
|
|
|
|
|
|
|
|
l = l->next;
|
|
|
|
if(l->type != TINT)
|
|
|
|
error("textfile base must be an int");
|
|
|
|
base = l->store.u.ival;
|
|
|
|
|
|
|
|
if((fp = crackhdr(file, OREAD)) == nil)
|
|
|
|
error("crackhdr %s: %r", file);
|
|
|
|
Bflush(bout);
|
|
|
|
fp->base = base;
|
|
|
|
fprint(2, "%s: %s %s %s\n", file, fp->aname, fp->mname, fp->fname);
|
|
|
|
if(mapfile(fp, base, symmap, nil) < 0)
|
|
|
|
fprint(2, "mapping %s: %r\n", file);
|
|
|
|
if(corhdr){
|
|
|
|
unmapfile(corhdr, cormap);
|
|
|
|
mapfile(fp, base, cormap, nil);
|
|
|
|
free(correg);
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
correg = nil;
|
2004-04-19 19:32:07 +00:00
|
|
|
mapfile(corhdr, 0, cormap, &correg);
|
|
|
|
}
|
2005-01-07 20:45:11 +00:00
|
|
|
if(symopen(fp) < 0)
|
|
|
|
fprint(2, "symopen %s: %r\n", file);
|
2004-04-19 19:32:07 +00:00
|
|
|
else
|
|
|
|
addvarsym(fp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
l2 = nil;
|
|
|
|
tail = &l2;
|
|
|
|
for(fp=fhdrlist; fp; fp=fp->next){
|
|
|
|
if(fp->ftype == FCORE)
|
|
|
|
continue;
|
|
|
|
tl = al(TLIST);
|
|
|
|
*tail = tl;
|
|
|
|
tail = &tl->next;
|
|
|
|
|
|
|
|
list = al(TSTRING);
|
|
|
|
tl->store.u.l = list;
|
|
|
|
list->store.u.string = strnode(fp->filename);
|
|
|
|
list->store.fmt = 's';
|
|
|
|
list->next = al(TINT);
|
|
|
|
list = list->next;
|
|
|
|
list->store.fmt = 'X';
|
|
|
|
list->store.u.ival = fp->base;
|
|
|
|
}
|
|
|
|
|
|
|
|
r->type = TLIST;
|
|
|
|
r->store.u.l = l2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
deltextfile(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
int did;
|
|
|
|
char *file;
|
|
|
|
Fhdr *fp, *fpnext;
|
|
|
|
Node res, *av[Maxarg];
|
|
|
|
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
|
|
|
|
if(na != 1)
|
|
|
|
error("deltextfile(string): arg count");
|
|
|
|
|
|
|
|
expr(av[0], &res);
|
|
|
|
if(res.type != TSTRING)
|
|
|
|
error("deltextfile(string): arg type");
|
|
|
|
file = res.store.u.string->string;
|
|
|
|
|
|
|
|
did = 0;
|
|
|
|
for(fp=fhdrlist; fp; fp=fpnext){
|
|
|
|
fpnext = fp->next;
|
|
|
|
if(fp->ftype == FCORE)
|
|
|
|
continue;
|
|
|
|
if(strcmp(file, fp->filename) == 0){
|
|
|
|
did = 1;
|
|
|
|
if(fp == symhdr)
|
|
|
|
error("cannot remove symbols from main text file");
|
|
|
|
unmapfile(fp, symmap);
|
|
|
|
uncrackhdr(fp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delvarsym(file);
|
|
|
|
if(!did)
|
|
|
|
error("symbol file %s not open", file);
|
|
|
|
}
|
|
|
|
|
2004-09-23 03:04:33 +00:00
|
|
|
void
|
|
|
|
stringn(Node *r, Node *args)
|
|
|
|
{
|
|
|
|
uint addr;
|
|
|
|
int i, n, ret;
|
|
|
|
Node res, *av[Maxarg];
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
na = 0;
|
|
|
|
flatten(av, args);
|
|
|
|
if(na != 2)
|
|
|
|
error("stringn(addr, n): arg count");
|
|
|
|
|
|
|
|
expr(av[0], &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("stringn(addr, n): arg type");
|
|
|
|
addr = res.store.u.ival;
|
|
|
|
|
|
|
|
expr(av[1], &res);
|
|
|
|
if(res.type != TINT)
|
|
|
|
error("stringn(addr,n): arg type");
|
|
|
|
n = res.store.u.ival;
|
|
|
|
|
|
|
|
buf = malloc(n+1);
|
|
|
|
if(buf == nil)
|
|
|
|
error("out of memory");
|
|
|
|
|
|
|
|
r->type = TSTRING;
|
|
|
|
for(i=0; i<n; i++){
|
Working on better handling of multithreading in general
and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00
|
|
|
ret = get1(cormap, addr, (uchar*)&buf[i], 1);
|
2004-09-23 03:04:33 +00:00
|
|
|
if(ret < 0){
|
|
|
|
free(buf);
|
|
|
|
error("indir: %r");
|
|
|
|
}
|
|
|
|
addr++;
|
|
|
|
}
|
|
|
|
buf[n] = 0;
|
|
|
|
r->store.u.string = strnode(buf);
|
|
|
|
free(buf);
|
|
|
|
}
|