#include "inc/priv.h"#include <draw.h>#include <bio.h>#include <ctype.h>#include <mach.h>#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; voidlsd_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_vmk_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 uvlongrget(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_vmk_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_vsymslist(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_vlocalslist(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 voidload(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 voidfreecore(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 voidattach(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);} voidwindow(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 intnewproc(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_vnew(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 voidtrlist(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);}
#include "inc/priv.h"
#include <draw.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#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);
}