plan9fox/sys/lib/acid/port
2017-06-12 19:30:56 +00:00

713 lines
11 KiB
Text

// portable acid for all architectures
defn pfl(addr)
{
print(pcfile(addr), ":", pcline(addr), "\n");
}
defn
notestk(addr)
{
local pc, sp;
complex Ureg addr;
pc = addr.pc\A;
sp = addr.sp\A;
print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " ");
pfl(pc);
_stk(pc, sp, linkreg(addr), 1);
}
defn
notelstk(addr)
{
local pc, sp;
complex Ureg addr;
pc = addr.pc\A;
sp = addr.sp\A;
print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " ");
pfl(pc);
_stk(pc, sp, linkreg(addr), 1);
}
defn params(param)
{
while param do {
sym = head param;
print(sym[0], "=", itoa(sym[1], "%ux"));
param = tail param;
if param then
print (",");
}
}
stkprefix = "";
stkignore = {};
stkend = 0;
defn locals(l)
{
local sym;
while l do {
sym = head l;
print(stkprefix, "\t", sym[0], "=", itoa(sym[1], "%ux"), "\n");
l = tail l;
}
}
defn _stkign(file)
{
s = stkignore;
while s do {
if regexp(head s, file) then
return 1;
s = tail s;
}
return 0;
}
// print a stack trace
//
// in a run of leading frames in files matched by regexps in stkignore,
// only print the last one.
defn _stk(pc, sp, link, dolocals)
{
local stk, ign, last, lastpc;
stk = strace(pc, sp, link);
if stkignore then
ign = 1;
else
ign = 0;
last = stk;
lastpc = pc;
while stk do {
if ign then {
if !_stkign(pcfile(pc)) then {
ign = 0;
stk = last;
pc = lastpc;
}
}
frame = head stk;
if !ign then {
print(stkprefix, fmt(frame[0], 'a'), "(");
params(frame[2]);
print(")+", itoa(pc-frame[0], "%ux"), " ");
pfl(pc);
if dolocals then
locals(frame[3]);
}
last = stk;
lastpc = pc;
stk = tail stk;
pc = frame[1];
}
print(stkprefix, fmt(pc, 'a'), " ");
pfl(pc);
}
defn findsrc(file)
{
local lst, src;
if file[0] == '/' then {
src = file(file);
if src != {} then {
srcfiles = append srcfiles, file;
srctext = append srctext, src;
return src;
}
return {};
}
lst = srcpath;
while head lst do {
src = file(head lst+file);
if src != {} then {
srcfiles = append srcfiles, file;
srctext = append srctext, src;
return src;
}
lst = tail lst;
}
}
defn line(addr)
{
local src, file;
file = pcfile(addr);
src = match(file, srcfiles);
if src >= 0 then
src = srctext[src];
else
src = findsrc(file);
if src == {} then {
print("no source for ", file, "\n");
return {};
}
line = pcline(addr)-1;
print(file, ":", line+1, ":", src[line], "\n");
}
defn addsrcdir(dir)
{
dir = dir+"/";
if match(dir, srcpath) >= 0 then {
print("already in srcpath\n");
return {};
}
srcpath = {dir}+srcpath;
}
defn source()
{
local l;
l = srcpath;
while l do {
print(head l, "\n");
l = tail l;
}
l = srcfiles;
while l do {
print("\t", head l, "\n");
l = tail l;
}
}
defn Bsrc(addr)
{
local lst;
lst = srcpath;
file = pcfile(addr);
if file[0] == '/' && access(file) then {
rc("B "+file+":"+itoa(pcline(addr)));
return {};
}
while head lst do {
name = head lst+file;
if access(name) then {
rc("B "+name+":"+itoa(pcline(addr)));
return {};
}
lst = tail lst;
}
print("no source for ", file, "\n");
}
defn srcline(addr)
{
local text, cline, line, file, src;
file = pcfile(addr);
src = match(file,srcfiles);
if (src>=0) then
src = srctext[src];
else
src = findsrc(file);
if (src=={}) then
{
return "(no source)";
}
return src[pcline(addr)-1];
}
defn src(addr)
{
local src, file, line, cline, text;
file = pcfile(addr);
src = match(file, srcfiles);
if src >= 0 then
src = srctext[src];
else
src = findsrc(file);
if src == {} then {
print("no source for ", file, "\n");
return {};
}
cline = pcline(addr)-1;
print(file, ":", cline+1, "\n");
line = cline-5;
loop 0,10 do {
if line >= 0 then {
text = src[line];
if text == {} then
return {};
if line == cline then
print(">");
else
print(" ");
print(line+1, "\t", text, "\n");
}
line = line+1;
}
}
defn step() // single step the process
{
local lst, lpl, addr, bput;
bput = 0;
if match(*PC, bplist) >= 0 then { // Sitting on a breakpoint
bput = fmt(*PC, bpfmt);
*bput = @bput;
}
wpupdate(0);
lst = follow(*PC);
lpl = lst;
while lpl do { // place break points
*(head lpl) = bpinst;
lpl = tail lpl;
}
startstop(pid); // do the step
while lst do { // remove the breakpoints
addr = fmt(head lst, bpfmt);
*addr = @addr;
lst = tail lst;
}
if bput != 0 then
*bput = bpinst;
}
defn bpset(addr) // set a breakpoint
{
if status(pid) != "Stopped" then {
print("Waiting...\n");
stop(pid);
}
if match(addr, bplist) >= 0 then
print("breakpoint already set at ", fmt(addr, 'a'), "\n");
else {
*fmt(addr, bpfmt) = bpinst;
bplist = append bplist, addr;
}
}
defn bptab() // print a table of breakpoints
{
local lst, addr;
lst = bplist;
while lst do {
addr = head lst;
print("\t", fmt(addr, 'A'), " ", fmt(addr, 'a'), " ", fmt(addr, 'i'), "\n");
lst = tail lst;
}
}
defn bpdel(addr) // delete a breakpoint
{
local n, pc, nbplist;
n = match(addr, bplist);
if n < 0 then {
print("no breakpoint at ", fmt(addr, 'a'), "\n");
return {};
}
addr = fmt(addr, bpfmt);
*addr = @addr;
nbplist = {}; // delete from list
while bplist do {
pc = head bplist;
if pc != addr then
nbplist = append nbplist, pc;
bplist = tail bplist;
}
bplist = nbplist; // delete from memory
}
defn wpflush() // copy wplist to /proc/$pid/watchpt
{
local s, lst, el;
lst = wplist;
s = "";
while lst do {
el = head lst;
s = s + (el[0] + " " + itoa(el[1]) + " " + itoa(el[2]) + "\n");
lst = tail lst;
}
lst = proclist;
while lst do {
if access("/proc/"+itoa(head lst)+"/watchpt") then
printto("/proc/"+itoa(head lst)+"/watchpt", s);
lst = tail lst;
}
}
defn wpset(type, addr, len) // set a watchpoint
{
local lst;
if status(pid) != "Stopped" then {
print("Waiting...\n");
stop(pid);
}
if !regexp("^[rwx\\-]+$", type) then {
print("invalid type\n");
return {};
}
lst = proclist;
while lst do {
if rc("echo '"+type+" "+itoa(addr)+" "+itoa(len)+"' >> /proc/"+itoa(head lst)+"/watchpt") != "" then
return {};
lst = tail lst;
}
wplist = append wplist, {type, addr, len, {}};
}
defn wptab() // print a table of watchpoints
{
local lst, el;
lst = wplist;
while lst do {
el = head lst;
print("\t", el[0], " ", fmt(el[1], 'A'), " ", fmt(el[1], 'a'), " ", fmt(el[2], 'd'), "\n");
lst = tail lst;
}
}
defn wpdel(addr)
{
local lst, el, found, nwplist;
lst = wplist;
found = 0;
nwplist = {};
while lst do {
el = head lst;
if el[1] == addr then
found = 1;
else
nwplist = append nwplist, el;
lst = tail lst;
}
if found == 0 then {
print("no watchpoint at ", fmt(addr, 'a'), "\n");
return {};
}
wplist = nwplist;
wpflush();
}
defn bytes(b)
{
local s;
s = "";
while b do {
s = s + itoa(head b, "%#.2x ");
b = tail b;
}
return s;
}
defn wpupdate(ch) // update remembered values
{
local el, nwplist, mem, lst, i;
lst = wplist;
nwplist = {};
while lst do {
el = head lst;
i = 0;
mem = {};
while i < el[2] do {
mem = append mem, *((el[1] + i)\b);
i = i + 1;
}
if ch && el[3] != {} && el[3] != mem then {
print("\t", fmt(el[1], 'a'), "\twas ", bytes(el[3]), "\n");
print("\t", fmt(el[1], 'a'), "\tis ", bytes(mem), "\n");
}
nwplist = append nwplist, {el[0], el[1], el[2], mem};
lst = tail lst;
}
wplist = nwplist;
}
defn wpprocess() // trapped at watchpoint
{
local pts;
local el;
pts = getfields(getfields(notes[0], " ", 1)[2], ",", 1);
while pts do {
el = head pts;
el = wplist[atoi(el)];
if el != {} then {
print("\ttriggered ", el[0], " watchpoint at ", fmt(el[1], 'a'), " (", fmt(el[1], 'A'), ")\n");
}
pts = tail pts;
}
wpupdate(1);
}
defn cont() // continue execution
{
local addr;
addr = fmt(*PC, bpfmt);
if match(addr, bplist) >= 0 then { // Sitting on a breakpoint
*addr = @addr;
step(); // Step over
*addr = bpinst;
}
wpupdate(0);
startstop(pid); // Run
}
defn stopped(pid) // called from acid when a process changes state
{
pstop(pid); // stub so this is easy to replace
}
defn procs() // print status of processes
{
local c, lst, cpid;
cpid = pid;
lst = proclist;
while lst do {
np = head lst;
setproc(np);
if np == cpid then
c = '>';
else
c = ' ';
print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), " setproc(", np, ")\n");
lst = tail lst;
}
pid = cpid;
if pid != 0 then
setproc(pid);
}
_asmlines = 30;
defn asm(addr)
{
local bound;
bound = fnbound(addr);
addr = fmt(addr, 'i');
loop 1,_asmlines do {
print(fmt(addr, 'a'), " ", fmt(addr, 'A'));
print("\t", @addr++, "\n");
if bound != {} && addr > bound[1] then {
lasmaddr = addr;
return {};
}
}
lasmaddr = addr;
}
defn casm()
{
asm(lasmaddr);
}
defn win()
{
local npid, estr;
bplist = {};
wplist = {};
notes = {};
estr = "/sys/lib/acid/window '0 0 600 400' "+textfile;
if progargs != "" then
estr = estr+" "+progargs;
npid = rc(estr);
npid = atoi(npid);
if npid == 0 then
error("win failed to create process");
setproc(npid);
stopped(npid);
}
defn win2()
{
local npid, estr;
bplist = {};
wplist = {};
notes = {};
estr = "/sys/lib/acid/transcript '0 0 600 400' '100 100 700 500' "+textfile;
if progargs != "" then
estr = estr+" "+progargs;
npid = rc(estr);
npid = atoi(npid);
if npid == 0 then
error("win failed to create process");
setproc(npid);
stopped(npid);
}
defn new()
{
bplist = {};
wplist = {};
newproc(progargs);
// Dont miss the delay slot calls
bpset(follow(main)[0]);
cont();
bpdel(*PC);
}
defn stmnt() // step one statement
{
local line;
line = pcline(*PC);
while 1 do {
step();
if line != pcline(*PC) then {
src(*PC);
return {};
}
}
}
defn func() // step until we leave the current function
{
local bound, end, start, pc;
bound = fnbound(*PC);
if bound == {} then {
print("cannot locate text symbol\n");
return {};
}
pc = *PC;
start = bound[0];
end = bound[1];
while pc >= start && pc < end do {
step();
pc = *PC;
}
}
defn next()
{
local sp, bound;
sp = *SP;
bound = fnbound(*PC);
stmnt();
pc = *PC;
if pc >= bound[0] && pc < bound[1] then
return {};
while (pc < bound[0] || pc > bound[1]) && sp >= *SP do {
step();
pc = *PC;
}
src(*PC);
}
defn dump(addr, n, fmt)
{
// see definition of dump in acid manual: it does n+1 iterations
loop 0, n do {
print(fmt(addr, 'A'), ": ");
addr = mem(addr, fmt);
}
}
defn mem(addr, fmt)
{
local i, c, n;
i = 0;
while fmt[i] != 0 do {
c = fmt[i];
n = 0;
while '0' <= fmt[i] && fmt[i] <= '9' do {
n = 10*n + fmt[i]-'0';
i = i+1;
}
if n <= 0 then n = 1;
addr = fmt(addr, fmt[i]);
while n > 0 do {
print(*addr++, " ");
n = n-1;
}
i = i+1;
}
print("\n");
return addr;
}
defn symbols(pattern)
{
local l, s;
l = symbols;
while l do {
s = head l;
if regexp(pattern, s[0]) then
print(s[0], "\t", s[1], "\t", s[2], "\n");
l = tail l;
}
}
defn spsrch(len)
{
local addr, a, s, e;
addr = *SP;
s = origin & 0x7fffffff;
e = etext & 0x7fffffff;
loop 1, len do {
a = *addr++;
c = a & 0x7fffffff;
if c > s && c < e then {
print("src(", a, ")\n");
pfl(a);
}
}
}
defn procattach()
{
wpflush();
}
defn dying()
{
wplist = {};
wpflush();
}
progargs="";
print("/sys/lib/acid/port");