ref: bbfee60f6716dce8cf7a802c044cf7d0fe8bb6f2
dir: /src/plan9/lsd.c/
#include "sl.h" #include <bio.h> #include <ctype.h> #include <mach.h> #include "cvalues.h" #include "io.h" static char aout[1024]; static sl_v lsd_gpregsym, lsd_fpregsym, lsd_regsym, lsd_symsym, lsd_framesym; static Map* coremap; static Fhdr fhdr; static sl_ios *proc_stdin; void lsd_init(void) { lsd_gpregsym = mk_csym(":gpreg"); lsd_fpregsym = mk_csym(":fpreg"); lsd_symsym = mk_csym("symbol"); lsd_regsym = mk_csym("reg"); lsd_framesym = mk_csym("frame"); } 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) lerrorf(sl_errio, "invalid register name %s", name); 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) lerrorf(sl_errio, "could not get register %s: %r", name); return v; } static sl_v mk_symbol(Symbol *s) { sl_v v; Rune r; static char b[2]; b[0] = s->type; chartorune(&r, b); v = alloc_vec(4, 0); sl_gc_handle(&v); vec_elt(v, 0) = lsd_symsym; vec_elt(v, 1) = str_from_cstr(s->name); vec_elt(v, 2) = mk_rune(r); vec_elt(v, 3) = size_wrap(s->value); sl_free_gc_handles(1); return v; } 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(void) { int fd; long nsym; Map *symmap; fd = open(aout, OREAD); if(fd < 0) lerrorf(sl_errio, "could not open \"%s\"", aout); if(!crackhdr(fd, &fhdr)){ close(fd); lerrorf(sl_errio, "could not decode file header for \"%s\"", aout); } machbytype(fhdr.type); symmap = loadmap(nil, fd, &fhdr); if(symmap == nil){ close(fd); lerrorf(sl_errio, "could not load segments for \"%s\"", aout); } nsym = syminit(fd, &fhdr); if(nsym < 0){ close(fd); lerrorf(sl_errio, "could not initialize the symbol table for \"%s\"", aout); } 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); 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) lerrorf(sl_errio, "could not open \"%s\"", buf); freecore(); coremap = attachproc(pid, 0, fd, &fhdr); if(coremap == nil) lerrorf(sl_errio, "could not make coremap: %r"); } static int newproc(int *outp) { int pid, fd, p[2]; char buf[128], *argv[2]; argv[0] = aout; argv[1] = nil; if(pipe(p) < 0) lerrorf(sl_errio, "could not create a pipe"); pid = rfork(RFPROC|RFFDG|RFREND|RFNAMEG|RFNOTEG); switch(pid){ case -1: lerrorf(sl_errio, "could not fork"); case 0: 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; } static sl_v tracelist; static void trlist(Map *map, uvlong retpc, uvlong sp, Symbol *fn) { sl_v v; USED(map); v = alloc_vec(5, 0); sl_gc_handle(&v); vec_elt(v, 0) = lsd_framesym; vec_elt(v, 1) = mk_symbol(fn); vec_elt(v, 2) = mk_u64(retpc); vec_elt(v, 3) = mk_u64(sp); vec_elt(v, 4) = localslist(fn, sp); sl_free_gc_handles(1); tracelist = mk_cons(v, tracelist); } BUILTIN("lsd-ctrace", lsd_ctrace) { sl_v *a; uvlong pc, sp, res; argcount(nargs, 3); for(a = args; a < args+3; a++) if(sl_unlikely(!sl_isnum(*a))) type_error("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); lerrorf(sl_errio, "could not retrieve stack frame: %r"); } sl_free_gc_handles(1); return tracelist; } BUILTIN("lsd-cleanup", lsd_cleanup) { USED(args); argcount(nargs, 0); freecore(); return sl_void; } BUILTIN("lsd-load", lsd_load) { Reglist *r; sl_v v, registers; int pid, len; pid = -1; argcount(nargs, 1); if(sl_unlikely(!sl_isstr(args[0]) && !sl_isnum(args[0]))) type_error("str|num", args[0]); if(isfixnum(args[0])){ pid = numval(args[0]); snprint(aout, sizeof(aout), "/proc/%d/text", pid); }else{ len = cv_len(ptr(args[0])); if(len+1 > sizeof(aout)) lerrorf(sl_errio, "path too long"); memmove(aout, cvalue_data(args[0]), len); } load(); attach(pid); registers = sl_nil; v = sl_nil; sl_gc_handle(®isters); sl_gc_handle(&v); for(r = mach->reglist; r->rname != nil; r++){ v = alloc_vec(5, 0); vec_elt(v, 0) = lsd_regsym; vec_elt(v, 1) = str_from_cstr(r->rname); vec_elt(v, 2) = r->rflags == RINT ? lsd_gpregsym : lsd_fpregsym; vec_elt(v, 3) = size_wrap(r->roffs); switch(r->rformat){ default: vec_elt(v, 4) = sl_u32sym; break; case 'V': case 'W': case 'Y': case 'Z': vec_elt(v, 4) = sl_u64sym; break; } set(mk_sym(r->rname, true), v); registers = mk_cons(v, registers); } sl_free_gc_handles(2); v = alloc_vec(5, 0); sl_gc_handle(&v); vec_elt(v, 0) = fixnum(pid); vec_elt(v, 1) = registers; vec_elt(v, 2) = cvalue_from_ref(sl_strtype, machdata->bpinst, machdata->bpsize); vec_elt(v, 3) = symslist(textsym); vec_elt(v, 4) = symslist(globalsym); sl_free_gc_handles(1); return v; } BUILTIN("lsd-new", lsd_new) { sl_v v; int pid, p; USED(args); USED(nargs); pid = newproc(&p); if(proc_stdin != nil){ free(proc_stdin->loc.filename); 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; } BUILTIN("lsd-follow", lsd_follow) { int n; uvlong addr, f[10], *p; sl_v foll; argcount(nargs, 1); if(sl_unlikely(!sl_isnum(args[0]))) type_error("num", args[0]); addr = tosize(args[0]); n = (*machdata->foll)(coremap, addr, rget, f); if(n < 0) lerrorf(sl_errio, "follow(%ux): %r", addr); foll = sl_nil; sl_gc_handle(&foll); for(p = f; p < f+n; p++) foll = mk_cons(mk_u64(*p), foll); sl_free_gc_handles(1); return foll; } BUILTIN("lsd-das", lsd_das) { static char buf[512]; uvlong addr; argcount(nargs, 1); if(sl_unlikely(!sl_isnum(args[0]))) type_error("num", args[0]); addr = tosize(args[0]); if(machdata->das(coremap, addr, 'i', buf, sizeof(buf)) < 0) lerrorf(sl_errio, "could not disassemble at %ud", addr); return str_from_cstr(buf); } BUILTIN("lsd-instsize", lsd_instsize) { uvlong addr; int sz; argcount(nargs, 1); if(sl_unlikely(!sl_isnum(args[0]))) type_error("num", args[0]); addr = tosize(args[0]); sz = machdata->instsize(coremap, addr); if(sz < 0) lerrorf(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(nargs, 1); if(sl_unlikely(!sl_isnum(args[0]))) type_error("num", args[0]); addr = tosize(args[0]); if(!fileline(buf, sizeof(buf), addr)) lerrorf(sl_errio, "could not get locate source code line at %ud", addr); return str_from_cstr(buf); } BUILTIN("lsd-file2pc", lsd_file2pc) { static char buf[1024]; uvlong addr; int len, line; argcount(nargs, 2); if(sl_unlikely(!sl_isstr(args[0]))) type_error("str", args[0]); if(sl_unlikely(!isfixnum(args[1]))) type_error("num", args[1]); len = cv_len(ptr(args[0])); if(len+1 > sizeof(buf)) lerrorf(sl_errio, "path too long"); memmove(buf, cvalue_data(args[0]), len); buf[len] = '\0'; line = numval(args[1]); addr = file2pc(buf, line); if(addr == ~0) lerrorf(sl_errio, "could not find address of %s:%d", buf, line); return size_wrap(addr); }