#include "inc/priv.h" #include #include #include #include #include "inc/cvalues.h" #include "inc/types.h" #include "inc/io.h" static char aout[1024]; static sl_v gpregsym, fpregsym, mkregsym, mksymbolsym, mkframesym; static sl_type *bptype; static Map* coremap; static Fhdr fhdr; static ios *proc_stdin; void lsd_init(void) { gpregsym = mk_csym(":gpreg"); fpregsym = mk_csym(":fpreg"); mksymbolsym = mk_csym("mk-symbol"); mkregsym = mk_csym("mk-reg"); mkframesym = mk_csym("mk-frame"); bptype = get_type(mk_list2(sl_arrsym, sl_u8sym), 0); } sl_v mk_lsdptr(u64int n) { return mach->szreg == 8 ? mk_p64(n) : mk_p32(n); } static Reglist* rname(char *name) { Reglist *rp; for(rp = mach->reglist; rp->rname; rp++) if(strcmp(name, rp->rname) == 0) return rp; return nil; } static uvlong rget(Map *map, char *name) { Reglist *rp; ulong x; uvlong v; int r; rp = rname(name); if(rp == nil) cthrow(error(sl_errio, "invalid register name %s", name), map); switch(rp->rformat){ default: r = get4(map, rp->roffs, &x); v = x; break; case 'V': case 'W': case 'Y': case 'Z': r = get8(map, rp->roffs, &v); break; } if(r < 0) cthrow(error(sl_errio, "could not get register %s: %r", name), map); return v; } static sl_v mk_symbol(Symbol *s) { sl_v r; r = s->type; return sl_applyn(3, sym_value(mksymbolsym), str_from_cstr(s->name), mk_rune(r), mk_lsdptr(s->value)); } static sl_v symslist(int (*loadsym)(Symbol*, int)) { Symbol s; sl_v syms; int i; syms = sl_nil; sl_gc_handle(&syms); for(i = 0; loadsym(&s, i); i++){ if(s.name[0] == '.' || strchr(s.name, '$') != nil) continue; syms = mk_cons(mk_symbol(&s), syms); } sl_free_gc_handles(1); return syms; } static sl_v localslist(Symbol *fn, uvlong sp) { sl_v locals; int i; Symbol s; locals = sl_nil; sl_gc_handle(&locals); s = *fn; for(i = 0; localsym(&s, i); i++){ if(s.name[0] == '.') continue; switch(s.class){ case CAUTO: s.value = sp-s.value; break; case CPARAM: s.value = sp+mach->szaddr+s.value; break; } locals = mk_cons(mk_symbol(&s), locals); } sl_free_gc_handles(1); return locals; } static void load(int dummy) { int fd; long nsym; Map *symmap; fd = open(aout, OREAD); if(fd < 0) cthrow(error(sl_errio, "could not open \"%s\"", aout), dummy); if(!crackhdr(fd, &fhdr)){ close(fd); cthrow(error(sl_errio, "could not decode file header for \"%s\"", aout), dummy); } machbytype(fhdr.type); symmap = loadmap(nil, fd, &fhdr); if(symmap == nil){ close(fd); cthrow(error(sl_errio, "could not load segments for \"%s\"", aout), dummy); } nsym = syminit(fd, &fhdr); if(nsym < 0){ close(fd); cthrow(error(sl_errio, "could not initialize the symbol table for \"%s\"", aout), dummy); } close(fd); ios_printf(ios_stdout, "%s:%s\n", aout, fhdr.name); } static void freecore(void) { int i; if(coremap == nil) return; for(i = 0; i < coremap->nsegs; i++) if(coremap->seg[i].inuse && coremap->seg[i].fd >= 0) close(coremap->seg[i].fd); MEM_FREE(coremap); coremap = nil; } static void attach(int pid) { static char buf[128]; int fd; if(pid < 0) return; snprint(buf, sizeof(buf), "/proc/%d/mem", pid); fd = open(buf, ORDWR); if(fd < 0) cthrow(error(sl_errio, "could not open \"%s\"", buf), pid); freecore(); coremap = attachproc(pid, 0, fd, &fhdr); if(coremap == nil) cthrow(error(sl_errio, "could not make coremap: %r"), pid); } void window(Rectangle *r) { char buf[512]; char *wsyssrv; int fd; if((wsyssrv = getenv("wsys")) == nil) sysfatal("cannot find $wsys: %r"); if((fd = open(wsyssrv, ORDWR)) < 0) sysfatal("cannot open $wsys: %r"); free(wsyssrv); if(r != nil) snprint(buf, sizeof(buf), "new -r %d %d %d %d", r->min.x, r->min.y, r->max.x, r->max.y); else snprint(buf, sizeof(buf), "new"); if(mount(fd, -1, "/mnt/wsys", MREPL, buf) < 0) sysfatal("cannot create new window: %r"); close(fd); if(bind("/mnt/wsys", "/dev", MBEFORE) < 0) sysfatal("cannot create new window: %r"); close(1); close(2); open("/dev/cons", OWRITE); open("/dev/cons", OWRITE); } static int newproc(char **argv, int *outp, bool win, Rectangle *r) { int pid, fd, p[2]; char buf[128]; if(pipe(p) < 0) cthrow(error(sl_errio, "could not create a pipe"), argv); pid = rfork(RFPROC|RFFDG|RFREND|RFNAMEG|RFNOTEG); switch(pid){ case -1: cthrow(error(sl_errio, "could not fork"), argv); case 0: if(win) window(r); snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid()); fd = open(buf, ORDWR); if(fd < 0) sysfatal("could not open %s: %r", buf); write(fd, "hang", 4); close(fd); close(p[0]); dup(p[1], 0); close(p[1]); exec(argv[0], argv); sysfatal("could not exec %s: %r", aout); } close(p[1]); attach(pid); *outp = p[0]; return pid; } sl_v new(sl_v *args, int nargs, bool win, Rectangle *r) { sl_v v; int pid, p, i; static char *argv[512]; if(nargs+2 >= nelem(argv)) bthrow(error(sl_errio, "too many arguments")); argv[0] = aout; for(i = 0; i < nargs; i++){ if(sl_unlikely(!isstr(args[i]))) bthrow(type_error(nil, "str", args[i])); argv[i+1] = cvalue_data(args[i]); } argv[i+1] = nil; pid = newproc(argv, &p, win, r); if(proc_stdin != nil){ MEM_FREE(proc_stdin->filename); MEM_FREE(proc_stdin); } proc_stdin = MEM_ALLOC(sizeof(*proc_stdin)); ios_fd(proc_stdin, p, "proc-stdin", false, false); v = alloc_vec(2, 0); sl_gc_handle(&v); vec_elt(v, 0) = fixnum(pid); vec_elt(v, 1) = cvalue_from_ref(sl_iotype, proc_stdin, sizeof(*proc_stdin)); sl_free_gc_handles(1); return v; } static sl_v tracelist; static void trlist(Map *map, uvlong retpc, uvlong sp, Symbol *fn) { USED(map); tracelist = mk_cons(sl_applyn(4, sym_value(mkframesym), mk_symbol(fn), mk_lsdptr(retpc), mk_lsdptr(sp), localslist(fn, sp)), tracelist); } BUILTIN("lsd-ctrace", lsd_ctrace) { sl_v *a; uvlong pc, sp, res; argcount(3); for(a = args; a < args+3; a++) if(sl_unlikely(!sl_isnum(*a))) bthrow(type_error(nil, "num", *a)); pc = tosize(args[0]); sp = tosize(args[1]); res = tosize(args[2]); tracelist = sl_nil; sl_gc_handle(&tracelist); if(machdata->ctrace(coremap, pc, sp, res, trlist) <= 0){ sl_free_gc_handles(1); bthrow(error(sl_errio, "could not retrieve stack frame: %r")); } sl_free_gc_handles(1); return tracelist; } BUILTIN("lsd-cleanup", lsd_cleanup) { USED(args); noargs(); freecore(); return sl_void; } BUILTIN("lsd-load", lsd_load) { Reglist *r; sl_v v, registers, ptrsz; int pid, len; pid = -1; argcount(1); if(sl_unlikely(!isstr(args[0]) && !sl_isnum(args[0]))) bthrow(type_error("program", "(or str num)", args[0])); if(sl_isnum(args[0])){ pid = tosize(args[0]); snprint(aout, sizeof(aout), "/proc/%d/text", pid); }else{ len = cvalue_len(args[0]); if(len+1 > sizeof(aout)) bthrow(error(sl_errio, "path too long")); strecpy(aout, aout+sizeof(aout), cvalue_data(args[0])); } load(0); attach(pid); registers = sl_nil; v = sl_nil; sl_gc_handle(®isters); sl_gc_handle(&v); for(r = mach->reglist; r->rname != nil; r++){ switch(r->rformat){ default: ptrsz = sl_u32sym; break; case 'V': case 'W': case 'Y': case 'Z': ptrsz = sl_u64sym; break; } v = sl_applyn(4, sym_value(mkregsym), str_from_cstr(r->rname), r->rflags == RINT ? gpregsym : fpregsym, size_wrap(r->roffs), ptrsz); set(mk_sym(r->rname, true), v); registers = mk_cons(v, registers); } sl_free_gc_handles(2); v = alloc_vec(6, 0); sl_gc_handle(&v); vec_elt(v, 0) = fixnum(pid); vec_elt(v, 1) = registers; vec_elt(v, 2) = cvalue_from_ref(bptype, machdata->bpinst, machdata->bpsize); vec_elt(v, 3) = symslist(textsym); vec_elt(v, 4) = symslist(globalsym); vec_elt(v, 5) = sym_value(mach->szreg == 8 ? sl_p64sym : sl_p32sym); sl_free_gc_handles(1); return v; } BUILTIN("lsd-new", lsd_new) { return new(args, nargs, false, nil); } BUILTIN("lsd-winr", lsd_winr) { argcount_least(4); Rectangle r = Rect(numval(args[0]), numval(args[1]), numval(args[2]), numval(args[3])); return new(args+4, nargs-4, true, &r); } BUILTIN("lsd-win", lsd_win) { return new(args, nargs, true, nil); } BUILTIN("lsd-follow", lsd_follow) { int n; uvlong addr, f[10], *p; sl_v foll; argcount(1); if(sl_unlikely(!sl_isnum(args[0]))) bthrow(type_error("addr", "num", args[0])); addr = tosize(args[0]); n = machdata->foll(coremap, addr, rget, f); if(n < 0) bthrow(error(sl_errio, "follow(%ux): %r", addr)); foll = sl_nil; sl_gc_handle(&foll); for(p = f; p < f+n; p++) foll = mk_cons(mk_lsdptr(*p), foll); sl_free_gc_handles(1); return foll; } BUILTIN("lsd-das", lsd_das) { static char buf[512]; uvlong addr; argcount(1); if(sl_unlikely(!sl_isnum(args[0]))) bthrow(type_error("addr", "num", args[0])); addr = tosize(args[0]); if(machdata->das(coremap, addr, 'i', buf, sizeof(buf)) < 0) bthrow(error(sl_errio, "could not disassemble at %ud", addr)); return str_from_cstr(buf); } BUILTIN("lsd-instsize", lsd_instsize) { uvlong addr; int sz; argcount(1); if(sl_unlikely(!sl_isnum(args[0]))) bthrow(type_error("addr", "num", args[0])); addr = tosize(args[0]); sz = machdata->instsize(coremap, addr); if(sz < 0) bthrow(error(sl_errio, "could not get instruction size at %ud", addr)); return size_wrap(sz); } BUILTIN("lsd-fileline", lsd_fileline) { static char buf[1024]; uvlong addr; argcount(1); if(sl_unlikely(!sl_isnum(args[0]))) bthrow(type_error("addr", "num", args[0])); addr = tosize(args[0]); if(!fileline(buf, sizeof(buf), addr)) bthrow(error(sl_errio, "could not locate source code line at %ud", addr)); return str_from_cstr(buf); } BUILTIN("lsd-file2pc", lsd_file2pc) { uvlong addr; char *file; int line; argcount(2); if(sl_unlikely(!isstr(args[0]))) bthrow(type_error("file", "str", args[0])); if(sl_unlikely(!isfixnum(args[1]))) bthrow(type_error("line", "num", args[1])); file = cvalue_data(args[0]); line = numval(args[1]); addr = file2pc(file, line); if(addr == ~0) bthrow(error(sl_errio, "could not find address of %s:%d", file, line)); return mk_lsdptr(addr); } BUILTIN("lsd-findsym", lsd_findsym) { Symbol s; uvlong addr; argcount(1); if(sl_unlikely(!sl_isnum(args[0]))) bthrow(type_error("addr", "num", args[0])); addr = tosize(args[0]); if(!findsym(addr, CTEXT, &s)) bthrow(error(sl_errio, "could not locate sym near %ud", addr)); return mk_symbol(&s); }