714 lines
11 KiB
Plaintext
714 lines
11 KiB
Plaintext
// 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");
|