This commit is contained in:
rsc 2004-04-19 19:32:07 +00:00
parent 22a7368ef2
commit 564ca709d0
14 changed files with 6578 additions and 0 deletions

49
src/cmd/acid/Notes Normal file
View file

@ -0,0 +1,49 @@
Changes from the Plan 9 acid (beyond the
obvious changes necessary to compile without
Ken's compiler and with the new libmach interface).
========================================
the input-line print verb is %Z, so that %L can be for locations
the register block is explicitly "mapped" at 0 by xget1, xget2, ...
for compatibility with old acid, even though libmach
doesn't participate in this lie anymore.
main accepts pid, file, and core in any order
the ptab only records pids (no ctl fd anymore).
new builtin sysstop(pid) runs pid until the next syscall
map() returns 5-tuples: (name, filename, base, end, offset)
filename is new
map() expects a 5-tuple too
strace expects a list of register names and values like
{"PC", *PC, "SP", *SP}
strace returns 5-tuples now:
{fn, pc, callerpc, paramlist, locallist}
new builtin includepipe(cmd) includes the standard output
of running cmd.
symbols returns 4-tuples now: {name, type, addr, file}
new builtin textfile() returns the current set of open text files
as a list of {file, base} pairs.
new builtin textfile({file, base}) adds a new file's symbols and text
offset by base for relocatables.
new builtin deltextfile(file) removes a file from the set of open text files.
both textfile and deltextfile update symbols.
====
yet to be done:
elflink has the linking info for elf on linux

313
src/cmd/acid/acid.h Normal file
View file

@ -0,0 +1,313 @@
/* acid.h */
enum
{
Eof = -1,
Strsize = 4096,
Hashsize = 128,
Maxarg = 512,
NFD = 100,
Maxproc = 50,
Maxval = 10,
Mempergc = 1024*1024,
};
/* #pragma varargck type "L" void */
typedef struct Node Node;
typedef struct String String;
typedef struct Lsym Lsym;
typedef struct List List;
typedef struct Store Store;
typedef struct Gc Gc;
typedef struct Strc Strc;
typedef struct Rplace Rplace;
typedef struct Ptab Ptab;
typedef struct Value Value;
typedef struct Type Type;
typedef struct Frtype Frtype;
Extern int kernel;
Extern int nlcount;
Extern int remote;
Extern int text;
Extern int cor;
Extern int silent;
Extern Fhdr *fhdr;
Extern Fhdr *chdr;
Extern int line;
Extern Biobuf* bout;
Extern Biobuf* io[32];
Extern int iop;
Extern int pid;
Extern char symbol[Strsize];
Extern int interactive;
Extern Node* code;
Extern int na;
Extern int wtflag;
Extern Regs* correg;
Extern Map* cormap;
Extern Map* symmap;
Extern Lsym* hash[Hashsize];
Extern long dogc;
Extern Rplace* ret;
Extern char* symfil;
Extern char* corfil;
Extern int gotint;
Extern long flen;
Extern Gc* gcl;
Extern int stacked;
Extern jmp_buf err;
Extern Node* prnt;
Extern Node* fomt;
Extern List* tracelist;
Extern int initialising;
Extern int quiet;
Extern Fhdr* corhdr;
Extern Fhdr* symhdr;
extern void (*expop[])(Node*, Node*);
#define expr(n, r) (r)->store.comt=0; (*expop[(unsigned char)((n)->op)])(n, r);
enum
{
TINT,
TFLOAT,
TSTRING,
TLIST,
TCODE,
};
struct Type
{
Type* next;
int offset;
char fmt;
char depth;
Lsym* type;
Lsym* tag;
Lsym* base;
};
struct Frtype
{
Lsym* var;
Type* type;
Frtype* next;
};
struct Ptab
{
int pid;
/* int ctl; */
};
Extern Ptab ptab[Maxproc];
struct Rplace
{
jmp_buf rlab;
Node* stak;
Node* val;
Lsym* local;
Lsym** tail;
};
struct Gc
{
char gcmark;
Gc* gclink;
};
struct Store
{
char fmt;
Type* comt;
union {
vlong ival;
double fval;
String* string;
List* l;
Node* cc;
} u;
};
struct List
{
Gc gc;
List* next;
char type;
Store store;
};
struct Value
{
char set;
char type;
Store store;
Value* pop;
Lsym* scope;
Rplace* ret;
};
struct Lsym
{
char* name;
int lexval;
Lsym* hash;
Value* v;
Type* lt;
Node* proc;
Frtype* local;
void (*builtin)(Node*, Node*);
};
struct Node
{
Gc gc;
char op;
char type;
Node* left;
Node* right;
Lsym* sym;
int builtin;
Store store;
};
#define ZN (Node*)0
struct String
{
Gc gc;
char *string;
int len;
};
List* addlist(List*, List*);
void addvarsym(Fhdr*);
List* al(int);
Node* an(int, Node*, Node*);
void append(Node*, Node*, Node*);
int bool(Node*);
void build(Node*);
void call(char*, Node*, Node*, Node*, Node*);
void catcher(void*, char*);
void checkqid(int, int);
void cmd(void);
Node* con(int);
List* construct(Node*);
void ctrace(int);
void decl(Node*);
void defcomplex(Node*, Node*);
void deinstall(int);
void delete(List*, int n, Node*);
void delvarsym(char*);
void dostop(int);
Lsym* enter(char*, int);
void error(char*, ...);
void execute(Node*);
void fatal(char*, ...);
ulong findframe(ulong);
void flatten(Node**, Node*);
void gc(void);
char* getstatus(int);
void* gmalloc(long);
void indir(Map*, ulong, char, Node*);
void installbuiltin(void);
void kinit(void);
int Zfmt(Fmt*);
int listcmp(List*, List*);
int listlen(List*);
List* listvar(char*, long);
void loadmodule(char*);
void loadvars(void);
Lsym* look(char*);
void ltag(char*);
void marklist(List*);
Lsym* mkvar(char*);
void msg(int, char*);
void notes(int);
int nproc(char**);
void nthelem(List*, int, Node*);
int numsym(char);
void odot(Node*, Node*);
void pcode(Node*, int);
void pexpr(Node*);
int popio(void);
void pstr(String*);
void pushfd(int);
void pushfile(char*);
void pushstr(Node*);
ulong raddr(char*);
void readtext(char*);
void readcore(void);
void restartio(void);
String *runenode(Rune*);
int scmp(String*, String*);
void sproc(int);
String* stradd(String*, String*);
String* strnode(char*);
String* strnodlen(char*, int);
#define system acidsystem
char* system(void);
int trlist(Map*, Regs*, ulong, ulong, Symbol*, int);
void unwind(void);
void userinit(void);
void varreg(void);
void varsym(void);
Waitmsg* waitfor(int);
void whatis(Lsym*);
void windir(Map*, Node*, Node*, Node*);
void yyerror(char*, ...);
int yylex(void);
int yyparse(void);
enum
{
ONAME,
OCONST,
OMUL,
ODIV,
OMOD,
OADD,
OSUB,
ORSH,
OLSH,
OLT,
OGT,
OLEQ,
OGEQ,
OEQ,
ONEQ,
OLAND,
OXOR,
OLOR,
OCAND,
OCOR,
OASGN,
OINDM,
OEDEC,
OEINC,
OPINC,
OPDEC,
ONOT,
OIF,
ODO,
OLIST,
OCALL,
OCTRUCT,
OWHILE,
OELSE,
OHEAD,
OTAIL,
OAPPEND,
ORET,
OINDEX,
OINDC,
ODOT,
OLOCAL,
OFRAME,
OCOMPLEX,
ODELETE,
OCAST,
OFMT,
OEVAL,
OWHAT,
};

1460
src/cmd/acid/builtin.c Normal file

File diff suppressed because it is too large Load diff

413
src/cmd/acid/dbg.y Normal file
View file

@ -0,0 +1,413 @@
%{
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
#define Extern extern
#include "acid.h"
%}
%union
{
Node *node;
Lsym *sym;
ulong ival;
float fval;
String *string;
}
%type <node> expr monexpr term stmnt name args zexpr slist
%type <node> member members mname castexpr idlist
%type <sym> zname
%left ';'
%right '='
%left Tfmt
%left Toror
%left Tandand
%left '|'
%left '^'
%left '&'
%left Teq Tneq
%left '<' '>' Tleq Tgeq
%left Tlsh Trsh
%left '+' '-'
%left '*' '/' '%'
%right Tdec Tinc Tindir '.' '[' '('
%token <sym> Tid
%token <ival> Tconst Tfmt
%token <fval> Tfconst
%token <string> Tstring
%token Tif Tdo Tthen Telse Twhile Tloop Thead Ttail Tappend Tfn Tret Tlocal
%token Tcomplex Twhat Tdelete Teval Tbuiltin
%%
prog :
| prog bigstmnt
;
bigstmnt : stmnt
{
/* hold on to current command for gc */
mkvar("_thiscmd")->proc = $1;
execute($1);
gc();
if(interactive && nlcount){
Bprint(bout, "acid; ");
nlcount = 0;
}
}
| Tfn Tid '(' args ')' zsemi '{' slist '}'
{
$2->proc = an(OLIST, $4, $8);
}
| Tfn Tid
{
$2->proc = nil;
}
| Tcomplex name '{' members '}' ';'
{
defcomplex($2, $4);
}
;
zsemi :
| ';' zsemi
members : member
| members member
{
$$ = an(OLIST, $1, $2);
}
;
mname : Tid
{
$$ = an(ONAME, ZN, ZN);
$$->sym = $1;
}
;
member : Tconst Tconst mname ';'
{
$3->store.u.ival = $2;
$3->store.fmt = $1;
$$ = $3;
}
| Tconst mname Tconst mname ';'
{
$4->store.u.ival = $3;
$4->store.fmt = $1;
$4->right = $2;
$$ = $4;
}
| mname Tconst mname ';'
{
$3->store.u.ival = $2;
$3->left = $1;
$$ = $3;
}
| '{' members '}' ';'
{
$$ = an(OCTRUCT, $2, ZN);
}
;
zname :
{ $$ = 0; }
| Tid
;
slist : stmnt
| slist stmnt
{
$$ = an(OLIST, $1, $2);
}
;
stmnt : zexpr ';'
| '{' slist '}'
{
$$ = $2;
}
| Tif expr Tthen stmnt
{
$$ = an(OIF, $2, $4);
}
| Tif expr Tthen stmnt Telse stmnt
{
$$ = an(OIF, $2, an(OELSE, $4, $6));
}
| Tloop expr ',' expr Tdo stmnt
{
$$ = an(ODO, an(OLIST, $2, $4), $6);
}
| Twhile expr Tdo stmnt
{
$$ = an(OWHILE, $2, $4);
}
| Tret expr ';'
{
$$ = an(ORET, $2, ZN);
}
| Tlocal idlist
{
$$ = an(OLOCAL, $2, ZN);
}
| Tcomplex Tid name ';'
{
$$ = an(OCOMPLEX, $3, ZN);
$$->sym = $2;
}
;
idlist : Tid
{
$$ = an(ONAME, ZN, ZN);
$$->sym = $1;
}
| idlist ',' Tid
{
$$ = an(ONAME, $1, ZN);
$$->sym = $3;
}
;
zexpr :
{ $$ = 0; }
| expr
;
expr : castexpr
| expr '*' expr
{
$$ = an(OMUL, $1, $3);
}
| expr '/' expr
{
$$ = an(ODIV, $1, $3);
}
| expr '%' expr
{
$$ = an(OMOD, $1, $3);
}
| expr '+' expr
{
$$ = an(OADD, $1, $3);
}
| expr '-' expr
{
$$ = an(OSUB, $1, $3);
}
| expr Trsh expr
{
$$ = an(ORSH, $1, $3);
}
| expr Tlsh expr
{
$$ = an(OLSH, $1, $3);
}
| expr '<' expr
{
$$ = an(OLT, $1, $3);
}
| expr '>' expr
{
$$ = an(OGT, $1, $3);
}
| expr Tleq expr
{
$$ = an(OLEQ, $1, $3);
}
| expr Tgeq expr
{
$$ = an(OGEQ, $1, $3);
}
| expr Teq expr
{
$$ = an(OEQ, $1, $3);
}
| expr Tneq expr
{
$$ = an(ONEQ, $1, $3);
}
| expr '&' expr
{
$$ = an(OLAND, $1, $3);
}
| expr '^' expr
{
$$ = an(OXOR, $1, $3);
}
| expr '|' expr
{
$$ = an(OLOR, $1, $3);
}
| expr Tandand expr
{
$$ = an(OCAND, $1, $3);
}
| expr Toror expr
{
$$ = an(OCOR, $1, $3);
}
| expr '=' expr
{
$$ = an(OASGN, $1, $3);
}
| expr Tfmt
{
$$ = an(OFMT, $1, con($2));
}
;
castexpr : monexpr
| '(' Tid ')' monexpr
{
$$ = an(OCAST, $4, ZN);
$$->sym = $2;
}
;
monexpr : term
| '*' monexpr
{
$$ = an(OINDM, $2, ZN);
}
| '@' monexpr
{
$$ = an(OINDC, $2, ZN);
}
| '+' monexpr
{
$$ = con(0);
$$ = an(OADD, $2, $$);
}
| '-' monexpr
{
$$ = con(0);
$$ = an(OSUB, $$, $2);
}
| Tdec monexpr
{
$$ = an(OEDEC, $2, ZN);
}
| Tinc monexpr
{
$$ = an(OEINC, $2, ZN);
}
| Thead monexpr
{
$$ = an(OHEAD, $2, ZN);
}
| Ttail monexpr
{
$$ = an(OTAIL, $2, ZN);
}
| Tappend monexpr ',' monexpr
{
$$ = an(OAPPEND, $2, $4);
}
| Tdelete monexpr ',' monexpr
{
$$ = an(ODELETE, $2, $4);
}
| '!' monexpr
{
$$ = an(ONOT, $2, ZN);
}
| '~' monexpr
{
$$ = an(OXOR, $2, con(-1));
}
| Teval monexpr
{
$$ = an(OEVAL, $2, ZN);
}
;
term : '(' expr ')'
{
$$ = $2;
}
| '{' args '}'
{
$$ = an(OCTRUCT, $2, ZN);
}
| term '[' expr ']'
{
$$ = an(OINDEX, $1, $3);
}
| term Tdec
{
$$ = an(OPDEC, $1, ZN);
}
| term '.' Tid
{
$$ = an(ODOT, $1, ZN);
$$->sym = $3;
}
| term Tindir Tid
{
$$ = an(ODOT, an(OINDM, $1, ZN), ZN);
$$->sym = $3;
}
| term Tinc
{
$$ = an(OPINC, $1, ZN);
}
| name '(' args ')'
{
$$ = an(OCALL, $1, $3);
}
| Tbuiltin name '(' args ')'
{
$$ = an(OCALL, $2, $4);
$$->builtin = 1;
}
| name
| Tconst
{
$$ = con($1);
}
| Tfconst
{
$$ = an(OCONST, ZN, ZN);
$$->type = TFLOAT;
$$->store.fmt = 'f';
$$->store.u.fval = $1;
}
| Tstring
{
$$ = an(OCONST, ZN, ZN);
$$->type = TSTRING;
$$->store.u.string = $1;
$$->store.fmt = 's';
}
| Twhat zname
{
$$ = an(OWHAT, ZN, ZN);
$$->sym = $2;
}
;
name : Tid
{
$$ = an(ONAME, ZN, ZN);
$$->sym = $1;
}
| Tid ':' name
{
$$ = an(OFRAME, $3, ZN);
$$->sym = $1;
}
;
args : zexpr
| args ',' zexpr
{
$$ = an(OLIST, $1, $3);
}
;

153
src/cmd/acid/dot.c Normal file
View file

@ -0,0 +1,153 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"
Type*
srch(Type *t, char *s)
{
Type *f;
f = 0;
while(t) {
if(strcmp(t->tag->name, s) == 0) {
if(f == 0 || t->depth < f->depth)
f = t;
}
t = t->next;
}
return f;
}
void
odot(Node *n, Node *r)
{
char *s;
Type *t;
Node res;
ulong addr;
s = n->sym->name;
if(s == 0)
fatal("dodot: no tag");
expr(n->left, &res);
if(res.store.comt == 0)
error("no type specified for (expr).%s", s);
if(res.type != TINT)
error("pointer must be integer for (expr).%s", s);
t = srch(res.store.comt, s);
if(t == 0)
error("no tag for (expr).%s", s);
/* Propagate types */
if(t->type)
r->store.comt = t->type->lt;
addr = res.store.u.ival+t->offset;
if(t->fmt == 'a') {
r->op = OCONST;
r->store.fmt = 'a';
r->type = TINT;
r->store.u.ival = addr;
}
else
indir(cormap, addr, t->fmt, r);
}
static Type **tail;
static Lsym *base;
void
buildtype(Node *m, int d)
{
Type *t;
if(m == ZN)
return;
switch(m->op) {
case OLIST:
buildtype(m->left, d);
buildtype(m->right, d);
break;
case OCTRUCT:
buildtype(m->left, d+1);
break;
default:
t = malloc(sizeof(Type));
t->next = 0;
t->depth = d;
t->tag = m->sym;
t->base = base;
t->offset = m->store.u.ival;
if(m->left) {
t->type = m->left->sym;
t->fmt = 'a';
}
else {
t->type = 0;
if(m->right)
t->type = m->right->sym;
t->fmt = m->store.fmt;
}
*tail = t;
tail = &t->next;
}
}
void
defcomplex(Node *tn, Node *m)
{
tail = &tn->sym->lt;
base = tn->sym;
buildtype(m, 0);
}
void
decl(Node *n)
{
Node *l;
Value *v;
Frtype *f;
Lsym *type;
type = n->sym;
if(type->lt == 0)
error("%s is not a complex type", type->name);
l = n->left;
if(l->op == ONAME) {
v = l->sym->v;
v->store.comt = type->lt;
v->store.fmt = 'a';
return;
}
/*
* Frame declaration
*/
for(f = l->sym->local; f; f = f->next) {
if(f->var == l->left->sym) {
f->type = n->sym->lt;
return;
}
}
f = malloc(sizeof(Frtype));
if(f == 0)
fatal("out of memory");
f->type = type->lt;
f->var = l->left->sym;
f->next = l->sym->local;
l->sym->local = f;
}

538
src/cmd/acid/exec.c Normal file
View file

@ -0,0 +1,538 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"
void
error(char *fmt, ...)
{
int i;
char buf[2048];
va_list arg;
/* Unstack io channels */
if(iop != 0) {
for(i = 1; i < iop; i++)
Bterm(io[i]);
bout = io[0];
iop = 0;
}
ret = 0;
gotint = 0;
Bflush(bout);
if(silent)
silent = 0;
else {
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
fprint(2, "%Z: (error) %s\n", buf);
}
while(popio())
;
interactive = 1;
longjmp(err, 1);
}
void
unwind(void)
{
int i;
Lsym *s;
Value *v;
for(i = 0; i < Hashsize; i++) {
for(s = hash[i]; s; s = s->hash) {
while(s->v->pop) {
v = s->v->pop;
free(s->v);
s->v = v;
}
}
}
}
void
execute(Node *n)
{
Value *v;
Lsym *sl;
Node *l, *r;
int i, s, e;
Node res, xx;
static int stmnt;
gc();
if(gotint)
error("interrupted");
if(n == 0)
return;
if(stmnt++ > 5000) {
Bflush(bout);
stmnt = 0;
}
l = n->left;
r = n->right;
switch(n->op) {
default:
expr(n, &res);
if(ret || (res.type == TLIST && res.store.u.l == 0))
break;
prnt->right = &res;
expr(prnt, &xx);
break;
case OASGN:
case OCALL:
expr(n, &res);
break;
case OCOMPLEX:
decl(n);
break;
case OLOCAL:
for(n = n->left; n; n = n->left) {
if(ret == 0)
error("local not in function");
sl = n->sym;
if(sl->v->ret == ret)
error("%s declared twice", sl->name);
v = gmalloc(sizeof(Value));
v->ret = ret;
v->pop = sl->v;
sl->v = v;
v->scope = 0;
*(ret->tail) = sl;
ret->tail = &v->scope;
v->set = 0;
}
break;
case ORET:
if(ret == 0)
error("return not in function");
expr(n->left, ret->val);
longjmp(ret->rlab, 1);
case OLIST:
execute(n->left);
execute(n->right);
break;
case OIF:
expr(l, &res);
if(r && r->op == OELSE) {
if(bool(&res))
execute(r->left);
else
execute(r->right);
}
else if(bool(&res))
execute(r);
break;
case OWHILE:
for(;;) {
expr(l, &res);
if(!bool(&res))
break;
execute(r);
}
break;
case ODO:
expr(l->left, &res);
if(res.type != TINT)
error("loop must have integer start");
s = res.store.u.ival;
expr(l->right, &res);
if(res.type != TINT)
error("loop must have integer end");
e = res.store.u.ival;
for(i = s; i <= e; i++)
execute(r);
break;
}
}
int
bool(Node *n)
{
int true = 0;
if(n->op != OCONST)
fatal("bool: not const");
switch(n->type) {
case TINT:
if(n->store.u.ival != 0)
true = 1;
break;
case TFLOAT:
if(n->store.u.fval != 0.0)
true = 1;
break;
case TSTRING:
if(n->store.u.string->len)
true = 1;
break;
case TLIST:
if(n->store.u.l)
true = 1;
break;
}
return true;
}
void
convflt(Node *r, char *flt)
{
char c;
c = flt[0];
if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
r->type = TSTRING;
r->store.fmt = 's';
r->store.u.string = strnode(flt);
}
else {
r->type = TFLOAT;
r->store.u.fval = atof(flt);
}
}
static char*
regbyoff(ulong addr)
{
Regdesc *r;
if(mach == nil)
error("no mach, no registers");
for(r=mach->reglist; r->name; r++)
if(r->offset == addr)
return r->name;
error("no register at %#lux", addr);
return nil;
}
int
xget1(Map *m, ulong addr, u8int *a, int n)
{
if(addr < 0x100)
return lget1(m, correg, locreg(regbyoff(addr)), a, n);
else
return get1(m, addr, a, n);
}
int
xget2(Map *m, ulong addr, u16int *a)
{
if(addr < 0x100)
return lget2(m, correg, locreg(regbyoff(addr)), a);
else
return get2(m, addr, a);
}
int
xget4(Map *m, ulong addr, u32int *a)
{
if(addr < 0x100)
return lget4(m, correg, locreg(regbyoff(addr)), a);
else
return get4(m, addr, a);
}
int
xget8(Map *m, ulong addr, u64int *a)
{
if(addr < 0x100)
return lget8(m, correg, locreg(regbyoff(addr)), a);
else
return get8(m, addr, a);
}
void
indir(Map *m, ulong addr, char fmt, Node *r)
{
int i;
u32int ival;
u64int vval;
int ret;
u8int cval;
u16int sval;
char buf[512], reg[12];
r->op = OCONST;
r->store.fmt = fmt;
switch(fmt) {
default:
error("bad pointer format '%c' for *", fmt);
case 'c':
case 'C':
case 'b':
r->type = TINT;
ret = xget1(m, addr, &cval, 1);
if (ret < 0)
error("indir: %r");
r->store.u.ival = cval;
break;
case 'x':
case 'd':
case 'u':
case 'o':
case 'q':
case 'r':
r->type = TINT;
ret = xget2(m, addr, &sval);
if (ret < 0)
error("indir: %r");
r->store.u.ival = sval;
break;
case 'a':
case 'A':
case 'B':
case 'X':
case 'D':
case 'U':
case 'O':
case 'Q':
r->type = TINT;
ret = xget4(m, addr, &ival);
if (ret < 0)
error("indir: %r");
r->store.u.ival = ival;
break;
case 'V':
case 'W':
case 'Y':
case 'Z':
r->type = TINT;
ret = xget8(m, addr, &vval);
if (ret < 0)
error("indir: %r");
r->store.u.ival = vval;
break;
case 's':
r->type = TSTRING;
for(i = 0; i < sizeof(buf)-1; i++) {
ret = xget1(m, addr, (uchar*)&buf[i], 1);
if (ret < 0)
error("indir: %r");
addr++;
if(buf[i] == '\0')
break;
}
buf[i] = 0;
if(i == 0)
strcpy(buf, "(null)");
r->store.u.string = strnode(buf);
break;
case 'R':
r->type = TSTRING;
for(i = 0; i < sizeof(buf)-2; i += 2) {
ret = xget1(m, addr, (uchar*)&buf[i], 2);
if (ret < 0)
error("indir: %r");
addr += 2;
if(buf[i] == 0 && buf[i+1] == 0)
break;
}
buf[i++] = 0;
buf[i] = 0;
r->store.u.string = runenode((Rune*)buf);
break;
case 'i':
case 'I':
if ((*mach->das)(m, addr, fmt, buf, sizeof(buf)) < 0)
error("indir: %r");
r->type = TSTRING;
r->store.fmt = 's';
r->store.u.string = strnode(buf);
break;
case 'f':
ret = xget1(m, addr, (uchar*)buf, mach->szfloat);
if (ret < 0)
error("indir: %r");
mach->ftoa32(buf, sizeof(buf), (void*) buf);
convflt(r, buf);
break;
case 'g':
ret = xget1(m, addr, (uchar*)buf, mach->szfloat);
if (ret < 0)
error("indir: %r");
mach->ftoa32(buf, sizeof(buf), (void*) buf);
r->type = TSTRING;
r->store.u.string = strnode(buf);
break;
case 'F':
ret = xget1(m, addr, (uchar*)buf, mach->szdouble);
if (ret < 0)
error("indir: %r");
mach->ftoa64(buf, sizeof(buf), (void*) buf);
convflt(r, buf);
break;
case '3': /* little endian ieee 80 with hole in bytes 8&9 */
ret = xget1(m, addr, (uchar*)reg, 10);
if (ret < 0)
error("indir: %r");
memmove(reg+10, reg+8, 2); /* open hole */
memset(reg+8, 0, 2); /* fill it */
leieeeftoa80(buf, sizeof(buf), reg);
convflt(r, buf);
break;
case '8': /* big-endian ieee 80 */
ret = xget1(m, addr, (uchar*)reg, 10);
if (ret < 0)
error("indir: %r");
beieeeftoa80(buf, sizeof(buf), reg);
convflt(r, buf);
break;
case 'G':
ret = xget1(m, addr, (uchar*)buf, mach->szdouble);
if (ret < 0)
error("indir: %r");
mach->ftoa64(buf, sizeof(buf), (void*) buf);
r->type = TSTRING;
r->store.u.string = strnode(buf);
break;
}
}
void
windir(Map *m, Node *addr, Node *rval, Node *r)
{
uchar cval;
ushort sval;
Node res, aes;
int ret;
if(m == 0)
error("no map for */@=");
expr(rval, &res);
expr(addr, &aes);
if(aes.type != TINT)
error("bad type lhs of @/*");
if(m != cormap && wtflag == 0)
error("not in write mode");
r->type = res.type;
r->store.fmt = res.store.fmt;
r->store = res.store;
switch(res.store.fmt) {
default:
error("bad pointer format '%c' for */@=", res.store.fmt);
case 'c':
case 'C':
case 'b':
cval = res.store.u.ival;
ret = put1(m, aes.store.u.ival, &cval, 1);
break;
case 'r':
case 'x':
case 'd':
case 'u':
case 'o':
sval = res.store.u.ival;
ret = put2(m, aes.store.u.ival, sval);
r->store.u.ival = sval;
break;
case 'a':
case 'A':
case 'B':
case 'X':
case 'D':
case 'U':
case 'O':
ret = put4(m, aes.store.u.ival, res.store.u.ival);
break;
case 'V':
case 'W':
case 'Y':
case 'Z':
ret = put8(m, aes.store.u.ival, res.store.u.ival);
break;
case 's':
case 'R':
ret = put1(m, aes.store.u.ival, (uchar*)res.store.u.string->string, res.store.u.string->len);
break;
}
if (ret < 0)
error("windir: %r");
}
void
call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp)
{
int np, i;
Rplace rlab;
Node *n, res;
Value *v, *f;
Lsym *s, *next;
Node *avp[Maxarg], *ava[Maxarg];
rlab.local = 0;
na = 0;
flatten(avp, parameters);
np = na;
na = 0;
flatten(ava, local);
if(np != na) {
if(np < na)
error("%s: too few arguments", fn);
error("%s: too many arguments", fn);
}
rlab.tail = &rlab.local;
ret = &rlab;
for(i = 0; i < np; i++) {
n = ava[i];
switch(n->op) {
default:
error("%s: %d formal not a name", fn, i);
case ONAME:
expr(avp[i], &res);
s = n->sym;
break;
case OINDM:
res.store.u.cc = avp[i];
res.type = TCODE;
res.store.comt = 0;
if(n->left->op != ONAME)
error("%s: %d formal not a name", fn, i);
s = n->left->sym;
break;
}
if(s->v->ret == ret)
error("%s already declared at this scope", s->name);
v = gmalloc(sizeof(Value));
v->ret = ret;
v->pop = s->v;
s->v = v;
v->scope = 0;
*(rlab.tail) = s;
rlab.tail = &v->scope;
v->store = res.store;
v->type = res.type;
v->set = 1;
}
ret->val = retexp;
if(setjmp(rlab.rlab) == 0)
execute(body);
for(s = rlab.local; s; s = next) {
f = s->v;
next = f->scope;
s->v = f->pop;
free(f);
}
}

1018
src/cmd/acid/expr.c Normal file

File diff suppressed because it is too large Load diff

661
src/cmd/acid/lex.c Normal file
View file

@ -0,0 +1,661 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"
#include "y.tab.h"
struct keywd
{
char *name;
int terminal;
}
keywds[] =
{
"do", Tdo,
"if", Tif,
"then", Tthen,
"else", Telse,
"while", Twhile,
"loop", Tloop,
"head", Thead,
"tail", Ttail,
"append", Tappend,
"defn", Tfn,
"return", Tret,
"local", Tlocal,
"aggr", Tcomplex,
"union", Tcomplex,
"adt", Tcomplex,
"complex", Tcomplex,
"delete", Tdelete,
"whatis", Twhat,
"eval", Teval,
"builtin", Tbuiltin,
0, 0
};
char cmap[256] =
{
['0'] '\0'+1,
['n'] '\n'+1,
['r'] '\r'+1,
['t'] '\t'+1,
['b'] '\b'+1,
['f'] '\f'+1,
['a'] '\a'+1,
['v'] '\v'+1,
['\\'] '\\'+1,
['"'] '"'+1,
};
void
kinit(void)
{
int i;
for(i = 0; keywds[i].name; i++)
enter(keywds[i].name, keywds[i].terminal);
}
typedef struct IOstack IOstack;
struct IOstack
{
char *name;
int line;
char *text;
char *ip;
Biobuf *fin;
IOstack *prev;
};
IOstack *lexio;
void
setacidfile(void)
{
char *name;
Lsym *l;
if(lexio)
name = lexio->name;
else
name = "";
l = mkvar("acidfile");
l->v->set = 1;
l->v->store.fmt = 's';
l->v->type = TSTRING;
l->v->store.u.string = strnode(name);
}
void
pushfile(char *file)
{
Biobuf *b;
IOstack *io;
if(file)
b = Bopen(file, OREAD);
else{
b = Bopen(unsharp("#d/0"), OREAD);
file = "<stdin>";
}
if(b == 0)
error("pushfile: %s: %r", file);
io = malloc(sizeof(IOstack));
if(io == 0)
fatal("no memory");
io->name = strdup(file);
if(io->name == 0)
fatal("no memory");
io->line = line;
line = 1;
io->text = 0;
io->fin = b;
io->prev = lexio;
lexio = io;
setacidfile();
}
void
pushfd(int fd)
{
pushfile("/dev/null");
close(lexio->fin->fid);
free(lexio->name);
lexio->name = smprint("<fd#d>", fd);
lexio->fin->fid = fd;
}
void
pushstr(Node *s)
{
IOstack *io;
io = malloc(sizeof(IOstack));
if(io == 0)
fatal("no memory");
io->line = line;
line = 1;
io->name = strdup("<string>");
if(io->name == 0)
fatal("no memory");
io->line = line;
line = 1;
io->text = strdup(s->store.u.string->string);
if(io->text == 0)
fatal("no memory");
io->ip = io->text;
io->fin = 0;
io->prev = lexio;
lexio = io;
setacidfile();
}
void
restartio(void)
{
Bflush(lexio->fin);
Binit(lexio->fin, 0, OREAD);
}
int
popio(void)
{
IOstack *s;
if(lexio == 0)
return 0;
if(lexio->prev == 0){
if(lexio->fin)
restartio();
return 0;
}
if(lexio->fin)
Bterm(lexio->fin);
else
free(lexio->text);
free(lexio->name);
line = lexio->line;
s = lexio;
lexio = s->prev;
free(s);
setacidfile();
return 1;
}
int
Zfmt(Fmt *f)
{
int i;
char buf[1024];
IOstack *e;
e = lexio;
if(e) {
i = sprint(buf, "%s:%d", e->name, line);
while(e->prev) {
e = e->prev;
if(initialising && e->prev == 0)
break;
i += sprint(buf+i, " [%s:%d]", e->name, e->line);
}
} else
sprint(buf, "no file:0");
fmtstrcpy(f, buf);
return 0;
}
void
unlexc(int s)
{
if(s == '\n')
line--;
if(lexio->fin)
Bungetc(lexio->fin);
else
lexio->ip--;
}
int
lexc(void)
{
int c;
if(lexio->fin) {
c = Bgetc(lexio->fin);
if(gotint)
error("interrupt");
return c;
}
c = *lexio->ip++;
if(c == 0)
return -1;
return c;
}
int
escchar(char c)
{
int n;
char buf[Strsize];
if(c >= '0' && c <= '9') {
n = 1;
buf[0] = c;
for(;;) {
c = lexc();
if(c == Eof)
error("%d: <eof> in escape sequence", line);
if(strchr("0123456789xX", c) == 0) {
unlexc(c);
break;
}
buf[n++] = c;
}
buf[n] = '\0';
return strtol(buf, 0, 0);
}
n = cmap[(unsigned char)c];
if(n == 0)
return c;
return n-1;
}
void
eatstring(void)
{
int esc, c, cnt;
char buf[Strsize];
esc = 0;
for(cnt = 0;;) {
c = lexc();
switch(c) {
case Eof:
error("%d: <eof> in string constant", line);
case '\n':
error("newline in string constant");
goto done;
case '\\':
if(esc)
goto Default;
esc = 1;
break;
case '"':
if(esc == 0)
goto done;
/* Fall through */
default:
Default:
if(esc) {
c = escchar(c);
esc = 0;
}
buf[cnt++] = c;
break;
}
if(cnt >= Strsize)
error("string token too long");
}
done:
buf[cnt] = '\0';
yylval.string = strnode(buf);
}
void
eatnl(void)
{
int c;
line++;
for(;;) {
c = lexc();
if(c == Eof)
error("eof in comment");
if(c == '\n')
return;
}
}
int
yylex(void)
{
int c;
extern char vfmt[];
loop:
Bflush(bout);
c = lexc();
switch(c) {
case Eof:
if(gotint) {
gotint = 0;
stacked = 0;
Bprint(bout, "\nacid; ");
goto loop;
}
return Eof;
case '"':
eatstring();
return Tstring;
case ' ':
case '\t':
goto loop;
case '\n':
line++;
if(interactive == 0)
goto loop;
if(stacked) {
print("\t");
goto loop;
}
nlcount++;
return ';';
case '.':
c = lexc();
unlexc(c);
if(isdigit(c))
return numsym('.');
return '.';
case '(':
case ')':
case '[':
case ']':
case ';':
case ':':
case ',':
case '~':
case '?':
case '*':
case '@':
case '^':
case '%':
return c;
case '{':
stacked++;
return c;
case '}':
stacked--;
return c;
case '\\':
c = lexc();
if(strchr(vfmt, c) == 0) {
unlexc(c);
return '\\';
}
yylval.ival = c;
return Tfmt;
case '!':
c = lexc();
if(c == '=')
return Tneq;
unlexc(c);
return '!';
case '+':
c = lexc();
if(c == '+')
return Tinc;
unlexc(c);
return '+';
case '/':
c = lexc();
if(c == '/') {
eatnl();
goto loop;
}
unlexc(c);
return '/';
case '\'':
c = lexc();
if(c == '\\')
yylval.ival = escchar(lexc());
else
yylval.ival = c;
c = lexc();
if(c != '\'') {
error("missing '");
unlexc(c);
}
return Tconst;
case '&':
c = lexc();
if(c == '&')
return Tandand;
unlexc(c);
return '&';
case '=':
c = lexc();
if(c == '=')
return Teq;
unlexc(c);
return '=';
case '|':
c = lexc();
if(c == '|')
return Toror;
unlexc(c);
return '|';
case '<':
c = lexc();
if(c == '=')
return Tleq;
if(c == '<')
return Tlsh;
unlexc(c);
return '<';
case '>':
c = lexc();
if(c == '=')
return Tgeq;
if(c == '>')
return Trsh;
unlexc(c);
return '>';
case '-':
c = lexc();
if(c == '>')
return Tindir;
if(c == '-')
return Tdec;
unlexc(c);
return '-';
default:
return numsym(c);
}
}
int
numsym(char first)
{
int c, isbin, isfloat, ishex;
char *sel, *p;
Lsym *s;
symbol[0] = first;
p = symbol;
ishex = 0;
isbin = 0;
isfloat = 0;
if(first == '.')
isfloat = 1;
if(isdigit(*p++) || isfloat) {
for(;;) {
c = lexc();
if(c < 0)
error("%d: <eof> eating symbols", line);
if(c == '\n')
line++;
sel = "01234567890.xb";
if(ishex)
sel = "01234567890abcdefABCDEF";
else if(isbin)
sel = "01";
else if(isfloat)
sel = "01234567890eE-+";
if(strchr(sel, c) == 0) {
unlexc(c);
break;
}
if(c == '.')
isfloat = 1;
if(!isbin && c == 'x')
ishex = 1;
if(!ishex && c == 'b')
isbin = 1;
*p++ = c;
}
*p = '\0';
if(isfloat) {
yylval.fval = atof(symbol);
return Tfconst;
}
if(isbin)
yylval.ival = strtoul(symbol+2, 0, 2);
else
yylval.ival = strtoul(symbol, 0, 0);
return Tconst;
}
for(;;) {
c = lexc();
if(c < 0)
error("%d <eof> eating symbols", line);
if(c == '\n')
line++;
if(c != '_' && c != '$' && c <= '~' && !isalnum(c)) { /* checking against ~ lets UTF names through */
unlexc(c);
break;
}
*p++ = c;
}
*p = '\0';
s = look(symbol);
if(s == 0)
s = enter(symbol, Tid);
yylval.sym = s;
return s->lexval;
}
Lsym*
enter(char *name, int t)
{
Lsym *s;
ulong h;
char *p;
Value *v;
h = 0;
for(p = name; *p; p++)
h = h*3 + *p;
h %= Hashsize;
s = gmalloc(sizeof(Lsym));
memset(s, 0, sizeof(Lsym));
s->name = strdup(name);
s->hash = hash[h];
hash[h] = s;
s->lexval = t;
v = gmalloc(sizeof(Value));
s->v = v;
v->store.fmt = 'X';
v->type = TINT;
memset(v, 0, sizeof(Value));
return s;
}
void
delsym(Lsym *s)
{
char *q;
ulong h;
Lsym *p;
h = 0;
for(q = s->name; *q; q++)
h = h*3 + *q;
h %= Hashsize;
if(hash[h] == s)
hash[h] = s->hash;
else{
for(p=hash[h]; p && p->hash != s; p=p->hash)
;
if(p)
p->hash = s->hash;
}
s->hash = nil;
}
Lsym*
look(char *name)
{
Lsym *s;
ulong h;
char *p;
h = 0;
for(p = name; *p; p++)
h = h*3 + *p;
h %= Hashsize;
for(s = hash[h]; s; s = s->hash)
if(strcmp(name, s->name) == 0)
return s;
return 0;
}
Lsym*
mkvar(char *s)
{
Lsym *l;
l = look(s);
if(l == 0)
l = enter(s, Tid);
return l;
}

270
src/cmd/acid/list.c Normal file
View file

@ -0,0 +1,270 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"
static List **tail;
List*
construct(Node *l)
{
List *lh, **save;
save = tail;
lh = 0;
tail = &lh;
build(l);
tail = save;
return lh;
}
int
listlen(List *l)
{
int len;
len = 0;
while(l) {
len++;
l = l->next;
}
return len;
}
void
build(Node *n)
{
List *l;
Node res;
if(n == 0)
return;
switch(n->op) {
case OLIST:
build(n->left);
build(n->right);
return;
default:
expr(n, &res);
l = al(res.type);
l->store = res.store;
*tail = l;
tail = &l->next;
}
}
List*
addlist(List *l, List *r)
{
List *f;
if(l == 0)
return r;
for(f = l; f->next; f = f->next)
;
f->next = r;
return l;
}
void
append(Node *r, Node *list, Node *val)
{
List *l, *f;
l = al(val->type);
l->store = val->store;
l->next = 0;
r->op = OCONST;
r->type = TLIST;
if(list->store.u.l == 0) {
list->store.u.l = l;
r->store.u.l = l;
return;
}
for(f = list->store.u.l; f->next; f = f->next)
;
f->next = l;
r->store.u.l = list->store.u.l;
}
int
listcmp(List *l, List *r)
{
if(l == r)
return 1;
while(l) {
if(r == 0)
return 0;
if(l->type != r->type)
return 0;
switch(l->type) {
case TINT:
if(l->store.u.ival != r->store.u.ival)
return 0;
break;
case TFLOAT:
if(l->store.u.fval != r->store.u.fval)
return 0;
break;
case TSTRING:
if(scmp(l->store.u.string, r->store.u.string) == 0)
return 0;
break;
case TLIST:
if(listcmp(l->store.u.l, r->store.u.l) == 0)
return 0;
break;
}
l = l->next;
r = r->next;
}
if(l != r)
return 0;
return 1;
}
void
nthelem(List *l, int n, Node *res)
{
if(n < 0)
error("negative index in []");
while(l && n--)
l = l->next;
res->op = OCONST;
if(l == 0) {
res->type = TLIST;
res->store.u.l = 0;
return;
}
res->type = l->type;
res->store = l->store;
}
void
delete(List *l, int n, Node *res)
{
List **tl;
if(n < 0)
error("negative index in delete");
res->op = OCONST;
res->type = TLIST;
res->store.u.l = l;
for(tl = &res->store.u.l; l && n--; l = l->next)
tl = &l->next;
if(l == 0)
error("element beyond end of list");
*tl = l->next;
}
List*
listvar(char *s, long v)
{
List *l, *tl;
tl = al(TLIST);
l = al(TSTRING);
tl->store.u.l = l;
l->store.fmt = 's';
l->store.u.string = strnode(s);
l->next = al(TINT);
l = l->next;
l->store.fmt = 'X';
l->store.u.ival = v;
return tl;
}
static List*
listlocals(Map *map, Regs *regs, Symbol *fn, int class)
{
int i;
u32int val;
Symbol s;
List **tail, *l2;
l2 = 0;
tail = &l2;
if(fn == nil)
return l2;
for(i = 0; indexlsym(fn, i, &s)>=0; i++) {
if(s.class != class)
continue;
if(class == CAUTO && s.name[0] == '.')
continue;
if(lget4(map, regs, s.loc, &val) < 0)
continue;
*tail = listvar(s.name, val);
tail = &(*tail)->next;
}
return l2;
}
static List*
listparams(Map *map, Regs *regs, Symbol *fn)
{
return listlocals(map, regs, fn, CPARAM);
}
static List*
listautos(Map *map, Regs *regs, Symbol *fn)
{
return listlocals(map, regs, fn, CAUTO);
}
int
trlist(Map *map, Regs *regs, ulong pc, ulong callerpc, Symbol *sym, int depth)
{
List *q, *l;
static List **tail;
if (tracelist == 0) /* first time */
tail = &tracelist;
q = al(TLIST);
*tail = q;
tail = &q->next;
l = al(TINT); /* Function address */
q->store.u.l = l;
l->store.u.ival = sym ? sym->loc.addr : pc;
l->store.fmt = 'X';
l->next = al(TINT); /* actual pc address */
l = l->next;
l->store.u.ival = pc;
l->store.fmt = 'X';
l->next = al(TINT); /* called from address */
l = l->next;
l->store.u.ival = callerpc;
l->store.fmt = 'X';
l->next = al(TLIST); /* make list of params */
l = l->next;
if(sym)
l->store.u.l = listparams(map, regs, sym);
l->next = al(TLIST); /* make list of locals */
l = l->next;
if(sym)
l->store.u.l = listautos(map, regs, sym);
return depth<40;
}

630
src/cmd/acid/main.c Normal file
View file

@ -0,0 +1,630 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
#define Extern
#include "acid.h"
#include "y.tab.h"
extern int __ifmt(Fmt*);
static Biobuf bioout;
static char* lm[16];
static int nlm;
static char* mtype;
static int attachfiles(int, char**);
int xfmt(Fmt*);
int isnumeric(char*);
void die(void);
void setcore(Fhdr*);
void
usage(void)
{
fprint(2, "usage: acid [-c core] [-l module] [-m machine] [-qrw] [-k] [pid] [file]\n");
exits("usage");
}
void
main(int argc, char *argv[])
{
Lsym *l;
Node *n;
char buf[128], *s;
int pid, i;
argv0 = argv[0];
pid = 0;
quiet = 1;
mtype = 0;
ARGBEGIN{
case 'A':
abort();
break;
case 'm':
mtype = ARGF();
break;
case 'w':
wtflag = 1;
break;
case 'l':
s = ARGF();
if(s == 0)
usage();
lm[nlm++] = s;
break;
case 'k':
kernel++;
break;
case 'q':
quiet = 0;
break;
case 'r':
pid = 1;
remote++;
kernel++;
break;
default:
usage();
}ARGEND
fmtinstall('x', xfmt);
fmtinstall('Z', Zfmt);
fmtinstall('L', locfmt);
Binit(&bioout, 1, OWRITE);
bout = &bioout;
kinit();
initialising = 1;
pushfile(0);
loadvars();
installbuiltin();
if(mtype && machbyname(mtype) == 0)
print("unknown machine %s", mtype);
if (attachfiles(argc, argv) < 0)
varreg(); /* use default register set on error */
if(mach == nil)
mach = machcpu;
symhdr = nil; /* not supposed to use this anymore */
l = mkvar("acid");
l->v->set = 1;
l->v->type = TLIST;
l->v->store.u.l = nil;
loadmodule("/usr/local/plan9/acid/port");
for(i = 0; i < nlm; i++) {
if(access(lm[i], AREAD) >= 0)
loadmodule(lm[i]);
else {
sprint(buf, "/usr/local/plan9/acid/%s", lm[i]);
loadmodule(buf);
}
}
userinit();
varsym();
l = look("acidmap");
if(l && l->proc) {
n = an(ONAME, ZN, ZN);
n->sym = l;
n = an(OCALL, n, ZN);
execute(n);
}
interactive = 1;
initialising = 0;
line = 1;
notify(catcher);
for(;;) {
if(setjmp(err)) {
Binit(&bioout, 1, OWRITE);
unwind();
}
stacked = 0;
Bprint(bout, "acid; ");
if(yyparse() != 1)
die();
restartio();
unwind();
}
Bputc(bout, '\n');
exits(0);
}
static int
attachfiles(int argc, char **argv)
{
char *s;
int i, omode;
Fhdr *hdr;
Lsym *l;
Value *v;
interactive = 0;
if(setjmp(err))
return -1;
/*
* Unix and Plan 9 differ on what the right order of pid, text, and core is.
* I never remember anyway. Let's just accept them in any order.
*/
omode = wtflag ? ORDWR : OREAD;
for(i=0; i<argc; i++){
if(isnumeric(argv[i])){
if(pid){
fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]);
continue;
}
if(corhdr){
fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid);
continue;
}
pid = atoi(argv[i]);
continue;
}
if((hdr = crackhdr(argv[i], omode)) == nil){
fprint(2, "crackhdr %s: %r\n", argv[i]);
continue;
}
fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
if(hdr->ftype == FCORE){
if(pid){
fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]);
uncrackhdr(hdr);
continue;
}
if(corhdr){
fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);
uncrackhdr(hdr);
continue;
}
corhdr = hdr;
corfil = argv[i];
}else{
if(symhdr){
fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);
uncrackhdr(hdr);
continue;
}
symhdr = hdr;
symfil = argv[i];
}
}
if(symhdr==nil){
symfil = "a.out";
if(pid){
if((s = proctextfile(pid)) != nil){
fprint(2, "pid %d: text %s\n", pid, s);
symfil = s;
}
}
/* XXX pull command from core */
if((hdr = crackhdr(symfil, omode)) == nil){
fprint(2, "crackhdr %s: %r\n", symfil);
symfil = nil;
}
}
if(symhdr)
syminit(symhdr);
if(!mach)
mach = machcpu;
/*
* Set up maps.
*/
symmap = allocmap();
cormap = allocmap();
if(symmap == nil || cormap == nil)
sysfatal("allocating maps: %r");
if(symhdr){
if(mapfile(symhdr, 0, symmap, nil) < 0)
fprint(2, "mapping %s: %r\n", symfil);
mapfile(symhdr, 0, cormap, nil);
}
l = mkvar("objtype");
v = l->v;
v->store.fmt = 's';
v->set = 1;
v->store.u.string = strnode(mach->name);
v->type = TSTRING;
l = mkvar("textfile");
v = l->v;
v->store.fmt = 's';
v->set = 1;
v->store.u.string = strnode(symfil ? symfil : "");
v->type = TSTRING;
l = mkvar("systype");
v = l->v;
v->store.fmt = 's';
v->set = 1;
v->store.u.string = strnode(symhdr ? symhdr->aname : "");
v->type = TSTRING;
l = mkvar("corefile");
v = l->v;
v->store.fmt = 's';
v->set = 1;
v->store.u.string = strnode(corfil ? corfil : "");
v->type = TSTRING;
if(pid)
sproc(pid);
if(corhdr)
setcore(corhdr);
varreg();
return 0;
}
void
setcore(Fhdr *hdr)
{
unmapproc(cormap);
unmapfile(corhdr, cormap);
free(correg);
correg = nil;
if(hdr == nil)
error("no core");
if(mapfile(hdr, 0, cormap, &correg) < 0)
error("mapfile %s: %r", hdr->filename);
corhdr = hdr;
corfil = hdr->filename;
}
void
die(void)
{
Lsym *s;
List *f;
Bprint(bout, "\n");
s = look("proclist");
if(s && s->v->type == TLIST) {
for(f = s->v->store.u.l; f; f = f->next){
detachproc((int)f->store.u.ival);
Bprint(bout, "/bin/kill -9 %d\n", (int)f->store.u.ival);
}
}
exits(0);
}
void
userinit(void)
{
Lsym *l;
Node *n;
char buf[128], *p;
sprint(buf, "/usr/local/plan9/acid/%s", mach->name);
loadmodule(buf);
p = getenv("home");
if(p != 0) {
sprint(buf, "%s/lib/acid", p);
silent = 1;
loadmodule(buf);
}
interactive = 0;
if(setjmp(err)) {
unwind();
return;
}
l = look("acidinit");
if(l && l->proc) {
n = an(ONAME, ZN, ZN);
n->sym = l;
n = an(OCALL, n, ZN);
execute(n);
}
}
void
loadmodule(char *s)
{
interactive = 0;
if(setjmp(err)) {
unwind();
return;
}
pushfile(s);
silent = 0;
yyparse();
popio();
return;
}
Node*
an(int op, Node *l, Node *r)
{
Node *n;
n = gmalloc(sizeof(Node));
memset(n, 0, sizeof(Node));
n->gc.gclink = gcl;
gcl = (Gc*)n;
n->op = op;
n->left = l;
n->right = r;
return n;
}
List*
al(int t)
{
List *l;
l = gmalloc(sizeof(List));
memset(l, 0, sizeof(List));
l->type = t;
l->gc.gclink = gcl;
gcl = (Gc*)l;
return l;
}
Node*
con(int v)
{
Node *n;
n = an(OCONST, ZN, ZN);
n->store.u.ival = v;
n->store.fmt = 'X';
n->type = TINT;
return n;
}
void
fatal(char *fmt, ...)
{
char buf[128];
va_list arg;
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
fprint(2, "%s: %Z (fatal problem) %s\n", argv0, buf);
exits(buf);
}
void
yyerror(char *fmt, ...)
{
char buf[128];
va_list arg;
if(strcmp(fmt, "syntax error") == 0) {
yyerror("syntax error, near symbol '%s'", symbol);
return;
}
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
print("%Z: %s\n", buf);
}
void
marktree(Node *n)
{
if(n == 0)
return;
marktree(n->left);
marktree(n->right);
n->gc.gcmark = 1;
if(n->op != OCONST)
return;
switch(n->type) {
case TSTRING:
n->store.u.string->gc.gcmark = 1;
break;
case TLIST:
marklist(n->store.u.l);
break;
case TCODE:
marktree(n->store.u.cc);
break;
}
}
void
marklist(List *l)
{
while(l) {
l->gc.gcmark = 1;
switch(l->type) {
case TSTRING:
l->store.u.string->gc.gcmark = 1;
break;
case TLIST:
marklist(l->store.u.l);
break;
case TCODE:
marktree(l->store.u.cc);
break;
}
l = l->next;
}
}
void
gc(void)
{
int i;
Lsym *f;
Value *v;
Gc *m, **p, *next;
if(dogc < Mempergc)
return;
dogc = 0;
/* Mark */
for(m = gcl; m; m = m->gclink)
m->gcmark = 0;
/* Scan */
for(i = 0; i < Hashsize; i++) {
for(f = hash[i]; f; f = f->hash) {
marktree(f->proc);
if(f->lexval != Tid)
continue;
for(v = f->v; v; v = v->pop) {
switch(v->type) {
case TSTRING:
v->store.u.string->gc.gcmark = 1;
break;
case TLIST:
marklist(v->store.u.l);
break;
case TCODE:
marktree(v->store.u.cc);
break;
}
}
}
}
/* Free */
p = &gcl;
for(m = gcl; m; m = next) {
next = m->gclink;
if(m->gcmark == 0) {
*p = next;
free(m); /* Sleazy reliance on my malloc */
}
else
p = &m->gclink;
}
}
void*
gmalloc(long l)
{
void *p;
dogc += l;
p = malloc(l);
if(p == 0)
fatal("out of memory");
return p;
}
void
checkqid(int f1, int pid)
{
int fd;
Dir *d1, *d2;
char buf[128];
if(kernel)
return;
d1 = dirfstat(f1);
if(d1 == nil){
print("checkqid: (qid not checked) dirfstat: %r\n");
return;
}
sprint(buf, "/proc/%d/text", pid);
fd = open(buf, OREAD);
if(fd < 0 || (d2 = dirfstat(fd)) == nil){
print("checkqid: (qid not checked) dirstat %s: %r\n", buf);
free(d1);
if(fd >= 0)
close(fd);
return;
}
close(fd);
if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){
print("path %llux %llux vers %lud %lud type %d %d\n",
d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);
print("warning: image does not match text for pid %d\n", pid);
}
free(d1);
free(d2);
}
void
catcher(void *junk, char *s)
{
USED(junk);
if(strstr(s, "interrupt")) {
gotint = 1;
noted(NCONT);
}
if(strstr(s, "child"))
noted(NCONT);
fprint(2, "note: %s\n", s);
noted(NDFLT);
}
char*
system(void)
{
char *cpu, *p, *q;
static char kernel[128];
cpu = getenv("cputype");
if(cpu == 0) {
cpu = "mips";
print("$cputype not set; assuming %s\n", cpu);
}
p = getenv("terminal");
if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {
p = "9power";
print("missing or bad $terminal; assuming %s\n", p);
}
else{
p++;
q = strchr(p, ' ');
if(q)
*q = 0;
sprint(kernel, "/%s/9%s", cpu, p);
}
return kernel;
}
int
isnumeric(char *s)
{
while(*s) {
if(*s < '0' || *s > '9')
return 0;
s++;
}
return 1;
}
int
xfmt(Fmt *f)
{
f->flags ^= FmtSharp;
return __ifmt(f);
}

32
src/cmd/acid/mkfile Normal file
View file

@ -0,0 +1,32 @@
<$PLAN9/src/mkhdr
TARG=acid
UOFILES=\
main.$O\
lex.$O\
util.$O\
exec.$O\
expr.$O\
list.$O\
builtin.$O\
proc.$O\
dot.$O\
print.$O\
OFILES=$UOFILES y.tab.$O
YFILES=dbg.y
HFILES=acid.h
BIN=/home/rsc/bin
SHORTLIB=mach2 regexp9 bio 9
<$PLAN9/src/mkone
CFLAGS=$CFLAGS -I../libmach2
lex.$O: y.tab.h
util.$O: y.tab.h
builtin.$O: y.tab.h
main.$O: y.tab.h

446
src/cmd/acid/print.c Normal file
View file

@ -0,0 +1,446 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"
static char *binop[] =
{
[OMUL] "*",
[ODIV] "/",
[OMOD] "%",
[OADD] "+",
[OSUB] "-",
[ORSH] ">>",
[OLSH] "<<",
[OLT] "<",
[OGT] ">",
[OLEQ] "<=",
[OGEQ] ">=",
[OEQ] "==",
[ONEQ] "!=",
[OLAND] "&",
[OXOR] "^",
[OLOR] "|",
[OCAND] "&&",
[OCOR] "||",
[OASGN] " = ",
};
static char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
char *typenames[] =
{
[TINT] "integer",
[TFLOAT] "float",
[TSTRING] "string",
[TLIST] "list",
[TCODE] "code",
};
int
cmp(const void *va, const void *vb)
{
char **a = (char**)va;
char **b = (char**)vb;
return strcmp(*a, *b);
}
void
fundefs(void)
{
Lsym *l;
char **vec;
int i, j, n, max, col, f, g, s;
max = 0;
f = 0;
g = 100;
vec = malloc(sizeof(char*)*g);
if(vec == 0)
fatal("out of memory");
for(i = 0; i < Hashsize; i++) {
for(l = hash[i]; l; l = l->hash) {
if(l->proc == 0 && l->builtin == 0)
continue;
n = strlen(l->name);
if(n > max)
max = n;
if(f >= g) {
g *= 2;
vec = realloc(vec, sizeof(char*)*g);
if(vec == 0)
fatal("out of memory");
}
vec[f++] = l->name;
}
}
qsort(vec, f, sizeof(char*), cmp);
max++;
col = 60/max;
s = (f+col-1)/col;
for(i = 0; i < s; i++) {
for(j = i; j < f; j += s)
Bprint(bout, "%-*s", max, vec[j]);
Bprint(bout, "\n");
}
}
void
whatis(Lsym *l)
{
int t;
int def;
Type *ti;
if(l == 0) {
fundefs();
return;
}
def = 0;
if(l->v->set) {
t = l->v->type;
Bprint(bout, "%s variable", typenames[t]);
if(t == TINT || t == TFLOAT)
Bprint(bout, " format %c", l->v->store.fmt);
if(l->v->store.comt)
Bprint(bout, " complex %s",
l->v->store.comt->base->name);
Bputc(bout, '\n');
def = 1;
}
if(l->lt) {
Bprint(bout, "complex %s {\n", l->name);
for(ti = l->lt; ti; ti = ti->next) {
if(ti->type) {
if(ti->fmt == 'a') {
Bprint(bout, "\t%s %d %s;\n",
ti->type->name, ti->offset,
ti->tag->name);
}
else {
Bprint(bout, "\t'%c' %s %d %s;\n",
ti->fmt, ti->type->name, ti->offset,
ti->tag->name);
}
}
else
Bprint(bout, "\t'%c' %d %s;\n",
ti->fmt, ti->offset, ti->tag->name);
}
Bprint(bout, "};\n");
def = 1;
}
if(l->proc) {
Bprint(bout, "defn %s(", l->name);
pexpr(l->proc->left);
Bprint(bout, ") {\n");
pcode(l->proc->right, 1);
Bprint(bout, "}\n");
def = 1;
}
if(l->builtin) {
Bprint(bout, "builtin function\n");
def = 1;
}
if(def == 0)
Bprint(bout, "%s is undefined\n", l->name);
}
void
slist(Node *n, int d)
{
if(n == 0)
return;
if(n->op == OLIST)
Bprint(bout, "%.*s{\n", d-1, tabs);
pcode(n, d);
if(n->op == OLIST)
Bprint(bout, "%.*s}\n", d-1, tabs);
}
void
pcode(Node *n, int d)
{
Node *r, *l;
if(n == 0)
return;
r = n->right;
l = n->left;
switch(n->op) {
default:
Bprint(bout, "%.*s", d, tabs);
pexpr(n);
Bprint(bout, ";\n");
break;
case OLIST:
pcode(n->left, d);
pcode(n->right, d);
break;
case OLOCAL:
Bprint(bout, "%.*slocal", d, tabs);
while(l) {
Bprint(bout, " %s", l->sym->name);
l = l->left;
if(l == 0)
Bprint(bout, ";\n");
else
Bprint(bout, ",");
}
break;
case OCOMPLEX:
Bprint(bout, "%.*scomplex %s %s;\n", d, tabs, n->sym->name, l->sym->name);
break;
case OIF:
Bprint(bout, "%.*sif ", d, tabs);
pexpr(l);
d++;
Bprint(bout, " then\n");
if(r && r->op == OELSE) {
slist(r->left, d);
Bprint(bout, "%.*selse\n", d-1, tabs);
slist(r->right, d);
}
else
slist(r, d);
break;
case OWHILE:
Bprint(bout, "%.*swhile ", d, tabs);
pexpr(l);
d++;
Bprint(bout, " do\n");
slist(r, d);
break;
case ORET:
Bprint(bout, "%.*sreturn ", d, tabs);
pexpr(l);
Bprint(bout, ";\n");
break;
case ODO:
Bprint(bout, "%.*sloop ", d, tabs);
pexpr(l->left);
Bprint(bout, ", ");
pexpr(l->right);
Bprint(bout, " do\n");
slist(r, d+1);
}
}
void
pexpr(Node *n)
{
Node *r, *l;
if(n == 0)
return;
r = n->right;
l = n->left;
switch(n->op) {
case ONAME:
Bprint(bout, "%s", n->sym->name);
break;
case OCONST:
switch(n->type) {
case TINT:
Bprint(bout, "%d", (int)n->store.u.ival);
break;
case TFLOAT:
Bprint(bout, "%g", n->store.u.fval);
break;
case TSTRING:
pstr(n->store.u.string);
break;
case TLIST:
break;
}
break;
case OMUL:
case ODIV:
case OMOD:
case OADD:
case OSUB:
case ORSH:
case OLSH:
case OLT:
case OGT:
case OLEQ:
case OGEQ:
case OEQ:
case ONEQ:
case OLAND:
case OXOR:
case OLOR:
case OCAND:
case OCOR:
Bputc(bout, '(');
pexpr(l);
Bprint(bout, binop[(uchar)n->op]);
pexpr(r);
Bputc(bout, ')');
break;
case OASGN:
pexpr(l);
Bprint(bout, binop[(uchar)n->op]);
pexpr(r);
break;
case OINDM:
Bprint(bout, "*");
pexpr(l);
break;
case OEDEC:
Bprint(bout, "--");
pexpr(l);
break;
case OEINC:
Bprint(bout, "++");
pexpr(l);
break;
case OPINC:
pexpr(l);
Bprint(bout, "++");
break;
case OPDEC:
pexpr(l);
Bprint(bout, "--");
break;
case ONOT:
Bprint(bout, "!");
pexpr(l);
break;
case OLIST:
pexpr(l);
if(r) {
Bprint(bout, ",");
pexpr(r);
}
break;
case OCALL:
pexpr(l);
Bprint(bout, "(");
pexpr(r);
Bprint(bout, ")");
break;
case OCTRUCT:
Bprint(bout, "{");
pexpr(l);
Bprint(bout, "}");
break;
case OHEAD:
Bprint(bout, "head ");
pexpr(l);
break;
case OTAIL:
Bprint(bout, "tail ");
pexpr(l);
break;
case OAPPEND:
Bprint(bout, "append ");
pexpr(l);
Bprint(bout, ",");
pexpr(r);
break;
case ODELETE:
Bprint(bout, "delete ");
pexpr(l);
Bprint(bout, ",");
pexpr(r);
break;
case ORET:
Bprint(bout, "return ");
pexpr(l);
break;
case OINDEX:
pexpr(l);
Bprint(bout, "[");
pexpr(r);
Bprint(bout, "]");
break;
case OINDC:
Bprint(bout, "@");
pexpr(l);
break;
case ODOT:
pexpr(l);
Bprint(bout, ".%s", n->sym->name);
break;
case OFRAME:
Bprint(bout, "%s:%s", n->sym->name, l->sym->name);
break;
case OCAST:
Bprint(bout, "(%s)", n->sym->name);
pexpr(l);
break;
case OFMT:
pexpr(l);
Bprint(bout, "\\%c", (int)r->store.u.ival);
break;
case OEVAL:
Bprint(bout, "eval ");
pexpr(l);
break;
case OWHAT:
Bprint(bout, "whatis");
if(n->sym)
Bprint(bout, " %s", n->sym->name);
break;
}
}
void
pstr(String *s)
{
int i, c;
Bputc(bout, '"');
for(i = 0; i < s->len; i++) {
c = s->string[i];
switch(c) {
case '\0':
c = '0';
break;
case '\n':
c = 'n';
break;
case '\r':
c = 'r';
break;
case '\t':
c = 't';
break;
case '\b':
c = 'b';
break;
case '\f':
c = 'f';
break;
case '\a':
c = 'a';
break;
case '\v':
c = 'v';
break;
case '\\':
c = '\\';
break;
case '"':
c = '"';
break;
default:
Bputc(bout, c);
continue;
}
Bputc(bout, '\\');
Bputc(bout, c);
}
Bputc(bout, '"');
}

251
src/cmd/acid/proc.c Normal file
View file

@ -0,0 +1,251 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"
#include "y.tab.h"
static void install(int);
void
sproc(int xpid)
{
Lsym *s;
int i;
if(symmap == 0)
error("no map");
if(pid == xpid)
return;
if(xpid <= 0)
error("bad pid");
unmapproc(cormap);
unmapfile(corhdr, cormap);
free(correg);
correg = nil;
if(mapproc(xpid, cormap, &correg) < 0)
error("setproc %d: %r", pid);
/* XXX check text file here? */
pid = xpid;
s = look("pid");
s->v->store.u.ival = pid;
for(i=0; i<cormap->nseg; i++)
if(cormap->seg[i].file == nil){
if(strcmp(cormap->seg[i].name, "data") == 0)
cormap->seg[i].name = "*data";
if(strcmp(cormap->seg[i].name, "text") == 0)
cormap->seg[i].name = "*text";
}
install(pid);
}
int
nproc(char **argv)
{
char buf[128];
int pid, i, fd;
pid = fork();
switch(pid) {
case -1:
error("new: fork %r");
case 0:
rfork(RFNAMEG|RFNOTEG);
if(ctlproc(getpid(), "hang") < 0)
fatal("new: hang %d: %r", getpid());
close(0);
close(1);
close(2);
for(i = 3; i < NFD; i++)
close(i);
open("/dev/tty", OREAD);
open("/dev/tty", OWRITE);
open("/dev/tty", OWRITE);
exec(argv[0], argv);
fatal("new: exec %s: %r");
default:
install(pid);
msg(pid, "waitstop");
notes(pid);
sproc(pid);
dostop(pid);
break;
}
return pid;
}
void
notes(int pid)
{
Lsym *s;
Value *v;
int i, n;
char **notes;
List *l, **tail;
s = look("notes");
if(s == 0)
return;
v = s->v;
n = procnotes(pid, &notes);
if(n < 0)
error("procnotes pid=%d: %r", pid);
v->set = 1;
v->type = TLIST;
v->store.u.l = 0;
tail = &v->store.u.l;
for(i=0; i<n; i++) {
l = al(TSTRING);
l->store.u.string = strnode(notes[i]);
l->store.fmt = 's';
*tail = l;
tail = &l->next;
}
free(notes);
}
void
dostop(int pid)
{
Lsym *s;
Node *np, *p;
s = look("stopped");
if(s && s->proc) {
np = an(ONAME, ZN, ZN);
np->sym = s;
np->store.fmt = 'D';
np->type = TINT;
p = con(pid);
p->store.fmt = 'D';
np = an(OCALL, np, p);
execute(np);
}
}
static void
install(int pid)
{
Lsym *s;
List *l;
int i, new, p;
new = -1;
for(i = 0; i < Maxproc; i++) {
p = ptab[i].pid;
if(p == pid)
return;
if(p == 0 && new == -1)
new = i;
}
if(new == -1)
error("no free process slots");
ptab[new].pid = pid;
s = look("proclist");
l = al(TINT);
l->store.fmt = 'D';
l->store.u.ival = pid;
l->next = s->v->store.u.l;
s->v->store.u.l = l;
s->v->set = 1;
}
void
deinstall(int pid)
{
int i;
Lsym *s;
List *f, **d;
for(i = 0; i < Maxproc; i++) {
if(ptab[i].pid == pid) {
detachproc(pid);
// close(ptab[i].ctl);
ptab[i].pid = 0;
s = look("proclist");
d = &s->v->store.u.l;
for(f = *d; f; f = f->next) {
if(f->store.u.ival == pid) {
*d = f->next;
break;
}
}
s = look("pid");
if(s->v->store.u.ival == pid)
s->v->store.u.ival = 0;
return;
}
}
}
void
msg(int pid, char *msg)
{
int i;
char err[ERRMAX];
for(i = 0; i < Maxproc; i++) {
if(ptab[i].pid == pid) {
if(ctlproc(pid, msg) < 0){
errstr(err, sizeof err);
if(strcmp(err, "process exited") == 0)
deinstall(pid);
error("msg: pid=%d %s: %s", pid, msg, err);
}
return;
}
}
error("msg: pid=%d: not found for %s", pid, msg);
}
char *
getstatus(int pid)
{
int fd;
char *p;
static char buf[128];
sprint(buf, "/proc/%d/status", pid);
fd = open(buf, OREAD);
if(fd < 0)
error("open %s: %r", buf);
read(fd, buf, sizeof(buf));
close(fd);
p = buf+56+12; /* Do better! */
while(*p == ' ')
p--;
p[1] = '\0';
return buf+56; /* ditto */
}
Waitmsg*
waitfor(int pid)
{
Waitmsg *w;
for(;;) {
if((w = wait()) == nil)
error("wait %r");
if(w->pid == pid)
return w;
free(w);
}
return nil; /* ken */
}

344
src/cmd/acid/util.c Normal file
View file

@ -0,0 +1,344 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"
#include "y.tab.h"
static int syren;
Lsym*
unique(char *buf, Symbol *s)
{
Lsym *l;
int i, renamed;
renamed = 0;
strcpy(buf, s->name);
for(;;) {
l = look(buf);
if(l == 0 || (l->lexval == Tid && l->v->set == 0))
break;
if(syren == 0 && !quiet) {
print("Symbol renames:\n");
syren = 1;
}
i = strlen(buf)+1;
memmove(buf+1, buf, i);
buf[0] = '$';
renamed++;
if(renamed > 5 && !quiet) {
print("Too many renames; must be X source!\n");
break;
}
}
if(renamed && !quiet)
print("\t%s=%s %c/%Z\n", s->name, buf, s->type, s->loc);
if(l == 0)
l = enter(buf, Tid);
return l;
}
void
varsym(void)
{
Lsym *l;
Fhdr *fp;
l = mkvar("symbols");
if(l->v->set)
return;
l->v->set = 1;
l->v->type = TLIST;
l->v->store.u.l = nil;
for(fp=fhdrlist; fp; fp=fp->next){
if(fp->ftype == FCORE)
continue;
addvarsym(fp);
}
if(l->v->store.u.l == nil)
print("no debugging symbols\n");
}
void
addvarsym(Fhdr *fp)
{
int i;
Symbol s;
Lsym *l;
String *file;
ulong v;
char buf[1024];
List *list, **tail, *tl;
if(fp == nil)
return;
l = look("symbols");
if(l == nil)
return;
l->v->set = 1;
l->v->type = TLIST;
tail = &l->v->store.u.l;
while(*tail)
tail = &(*tail)->next;
file = strnode(fp->filename);
for(i=0; findexsym(fp, i, &s)>=0; i++){
switch(s.type) {
case 'T':
case 'L':
case 'D':
case 'B':
case 'b':
case 'd':
case 'l':
case 't':
if(s.name[0] == '.')
continue;
if(s.loc.type != LADDR)
continue;
v = s.loc.addr;
tl = al(TLIST);
*tail = tl;
tail = &tl->next;
l = unique(buf, &s);
l->v->set = 1;
l->v->type = TINT;
l->v->store.u.ival = v;
if(l->v->store.comt == 0)
l->v->store.fmt = 'X';
/* Enter as list of { name, type, value, file } */
list = al(TSTRING);
tl->store.u.l = list;
list->store.u.string = strnode(buf);
list->store.fmt = 's';
list->next = al(TINT);
list = list->next;
list->store.fmt = 'c';
list->store.u.ival = s.type;
list->next = al(TINT);
list = list->next;
list->store.fmt = 'X';
list->store.u.ival = v;
list->next = al(TSTRING);
list = list->next;
list->store.fmt = 's';
list->store.u.string = file;
}
}
*tail = nil;
}
static int
infile(List *list, char *file, char **name)
{
/* name */
if(list->type != TSTRING)
return 0;
*name = list->store.u.string->string;
if(list->next == nil)
return 0;
list = list->next;
/* type character */
if(list->next == nil)
return 0;
list = list->next;
/* address */
if(list->next == nil)
return 0;
list = list->next;
/* file */
if(list->type != TSTRING)
return 0;
return strcmp(list->store.u.string->string, file) == 0;
}
void
delvarsym(char *file)
{
char *name;
Lsym *l;
List **lp, *p;
l = look("symbols");
if(l == nil)
return;
if(l->v->type != TLIST)
return;
for(lp=&l->v->store.u.l; *lp; lp=&(*lp)->next){
while(*lp){
p = *lp;
if(p->type != TLIST)
break;
if(!infile(p->store.u.l, file, &name))
break;
*lp = p->next;
/* XXX remove from hash tables */
}
if(*lp == nil)
break;
}
}
void
varreg(void)
{
Lsym *l;
Value *v;
Regdesc *r;
List **tail, *li;
l = mkvar("registers");
v = l->v;
v->set = 1;
v->type = TLIST;
v->store.u.l = 0;
tail = &v->store.u.l;
if(mach == nil)
return;
for(r = mach->reglist; r->name; r++) {
l = mkvar(r->name);
v = l->v;
v->set = 1;
v->store.u.ival = r->offset;
v->store.fmt = r->format;
v->type = TINT;
li = al(TSTRING);
li->store.u.string = strnode(r->name);
li->store.fmt = 's';
*tail = li;
tail = &li->next;
}
l = mkvar("bpinst"); /* Breakpoint text */
v = l->v;
v->type = TSTRING;
v->store.fmt = 's';
v->set = 1;
v->store.u.string = gmalloc(sizeof(String));
v->store.u.string->len = mach->bpsize;
v->store.u.string->string = gmalloc(mach->bpsize);
memmove(v->store.u.string->string, mach->bpinst, mach->bpsize);
}
void
loadvars(void)
{
Lsym *l;
Value *v;
l = mkvar("proc");
v = l->v;
v->type = TINT;
v->store.fmt = 'X';
v->set = 1;
v->store.u.ival = 0;
l = mkvar("pid"); /* Current process */
v = l->v;
v->type = TINT;
v->store.fmt = 'D';
v->set = 1;
v->store.u.ival = 0;
mkvar("notes"); /* Pending notes */
l = mkvar("proclist"); /* Attached processes */
l->v->type = TLIST;
}
String*
strnodlen(char *name, int len)
{
String *s;
s = gmalloc(sizeof(String)+len+1);
s->string = (char*)s+sizeof(String);
s->len = len;
if(name != 0)
memmove(s->string, name, len);
s->string[len] = '\0';
s->gc.gclink = gcl;
gcl = (Gc*)s;
return s;
}
String*
strnode(char *name)
{
return strnodlen(name, strlen(name));
}
String*
runenode(Rune *name)
{
int len;
Rune *p;
String *s;
p = name;
for(len = 0; *p; p++)
len++;
len++;
len *= sizeof(Rune);
s = gmalloc(sizeof(String)+len);
s->string = (char*)s+sizeof(String);
s->len = len;
memmove(s->string, name, len);
s->gc.gclink = gcl;
gcl = (Gc*)s;
return s;
}
String*
stradd(String *l, String *r)
{
int len;
String *s;
len = l->len+r->len;
s = gmalloc(sizeof(String)+len+1);
s->gc.gclink = gcl;
gcl = (Gc*)s;
s->len = len;
s->string = (char*)s+sizeof(String);
memmove(s->string, l->string, l->len);
memmove(s->string+l->len, r->string, r->len);
s->string[s->len] = 0;
return s;
}
int
scmp(String *sr, String *sl)
{
if(sr->len != sl->len)
return 0;
if(memcmp(sr->string, sl->string, sl->len))
return 0;
return 1;
}