aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/acid/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/acid/main.c')
-rw-r--r--src/cmd/acid/main.c630
1 files changed, 630 insertions, 0 deletions
diff --git a/src/cmd/acid/main.c b/src/cmd/acid/main.c
new file mode 100644
index 00000000..dccff268
--- /dev/null
+++ b/src/cmd/acid/main.c
@@ -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);
+}