include("/sys/lib/acid/syscall"); // print various /proc filesdefn fd() { rc("cat /proc/"+itoa(pid)+"/fd");} defn segment() { rc("cat /proc/"+itoa(pid)+"/segment");} defn ns() { rc("cat /proc/"+itoa(pid)+"/ns");} defn qid(qid) { complex Qid qid; return itoa(qid.path\X)+"."+itoa(qid.vers\X);} defn path(p) { complex Path p; if p != 0 then { return *(p.s\s); } else return "<null>";} // print Image cache contentsIHASHSIZE = 64; defn imagecacheline(h) { local d, p, q; while h != 0 do { complex Image h; d=(Dev)devtab[h.type]; p = "*closed*"; if h.c != 0 then p = path(h.c.path); q = h.qid; print (h\A, " ref=", h.ref, " pgref=", h.pgref, "\t#", d.dc\r, h.dev\D, " (", q.path, " ", q.vers\D, " ", q.type\X, ") ", p, "\n"); h = h.hash; }} defn imagecache() { local i; i=0; loop 1,IHASHSIZE do { imagecacheline(imagealloc.hash[i]); i = i+1; }} // dump channelsdefn chan(c) { local d, q; c = (Chan)c; d= (Dev)devtab[c.type]; q=c.qid; print("chan(", c\A, "): ref=", c.ref\D, " #", d.dc\r, c.dev\D, " (", q.path, " ", q.vers\D, " ", q.type\X, ")"); print(" fid=", c.fid\D, " iounit=", c.iounit\D); if c.ref != 0 then { print(" ", path(c.path), " mchan=", c.mchan\A); if c.mchan != 0 then { print(" ", path(c.mchan.path)); } } print("\n");} defn chans() { local c; c = (Chan)chanalloc.list; while c != 0 do { if c.ref != 0 then chan(c); c=(Chan)c.link; }} defn findchan(dev,type,path) { local c; c = (Chan)chanalloc.list; while c != 0 do { if c.ref != 0 then { if c.dev == dev && c.type == type && c.qid.path == path then return c; } c=(Chan)c.link; } return 0;} defn nchans() { local c, n; n = 0; c = (Chan)chanalloc.list; while c != 0 do { if c.ref != 0 then n++; c = (Chan)c.link; } return n;} defn activechanlist() { local l, n; l = {}; c = (Chan)chanalloc.list; while c != 0 do { if c.ref != 0 then l = append l,c; c = (Chan)c.link; } return l;} defn difflist(a, b) { local l, x; l = {}; while a != {} do { x = head a; if match(x, b) == -1 then l = append l, x; a = tail a; } return l;} _active_chan_list = {};defn newchans() { local l, new; l = activechanlist(); if _active_chan_list != {} then newerchans(_active_chan_list); _active_chan_list = l;} defn newerchans(oldlist){ local new; new = difflist(activechanlist(), oldlist); while new != {} do { chan(head new); new = tail new; }} // look for channels that refer to themselvesdefn badchans() { local bad, c, i, len, mtpt, p; c = (Chan)chanalloc.list; while c != 0 do { if c.ref != 0 then { bad = ""; p = (Path)c.path; if p != 0 then { path(p); mtpt = p.mtpt; len = p.mlen; i=0; loop 1,len do { if mtpt[i] == c then bad = bad+" mtpt self-ref"; i = i+1; } } if bad != "" then print("chan(", c\A, "):", bad, "\n"); } c = (Chan)c.link; }} NHASH=128;defn mntcache() { local i, m, c; i=0; loop 1,NHASH do { m = cache.hash[i]; while m != 0 do { complex Mntcache m; print(m\A, " dev ", m.dev\D, " type ", m.type, " qid (", m.qid.path, " ", m.qid.vers\D, ")\n"); c = findchan(m.dev, m.type, m.qid.path); if c != 0 then { print(" "); chan(c); } m = m.hash; } i = i+1; }} // manipulate processesdefn proctab(x) { return procalloc.tab[x];} defn proc(p) { complex Proc p; local s, i; if p.state != 0 && p.pid != 0 && p.text != 0 then { // 0 is Dead s = p.psstate; if s == 0 then { s = "kproc"; } else { s = *(s\s); } print(p\A, " ", p.pid, ": ", *(p.text\s), " ", *(p.user\s), " pc ", p.pc, " ", s, " (", *(statename[p.state]\s), ") ut ", p.time[0]\D, " st ", p.time[1]\D, " qpc ", p.qpc, "\n"); }} defn procenv(p) { complex Proc p; local i, e, v; e = p.egrp; complex Egrp e; i=0; loop 1,e.nent do { v = e.ent + i; i = i+sizeofEvalue; complex Evalue v; print(*(v.name\s), "="); printstringn(v.value, v.len); print("\n"); }}BY2PG=4096;KSTACK=4096;if objtype=="amd64" then { KSTACK=16*1024;}if objtype=="arm64" then { BY2PG=65536; KSTACK=8*1024;} defn procstksize(p) { complex Proc p; local top, sp; if p.state != 0 then { // 0 is Dead top = p.kstack+KSTACK; sp = *p.sched; print(top-sp\D, "\n"); }} defn procstk(p) { complex Proc p; local l, n; if p.state != 0 then { // 0 is Dead if p.mach == 0 then { l = p.sched; } else { n = p.nerrlab; if n == 0 then { return 0; } l = p.errlab + (n-1)*sizeofLabel; } complex Label l; if objtype=="386" || objtype=="amd64" then _stk(gotolabel, l.sp, linkreg(0), 0); else _stk(l.pc, l.sp, linkreg(0), 0); }} defn procs() { local i; i=0; loop 1,conf.nproc do { proc(proctab(i)); i = i+1; }} defn stacks() { local i, p; i=0; loop 1,conf.nproc do { p = (Proc)proctab(i); if p.state != 0 then { print("=========================================================\n"); proc(p); procstk(p); } i = i+1; }} defn stacksizes() { local i; i=0; loop 1,conf.nproc do { procstksize(proctab(i)); i = i+1; }} // segment-relateddefn procsegs(p) { complex Proc p; local i; i=0; loop 1,NSEG do { psegment(p.seg[i]); i = i+1; }} segtypes = { "text", "data", "bss", "stack", "shared", "physical", "shdata", "map" };defn psegment(s) { complex Segment s; if s != 0 then { print(s\A, " ", segtypes[s.type&SG_TYPE], " ", s.base, "-", s.top, " image ", s.image, "\n"); }} // find physical address for an address in a given processdefn procaddr(p, a) { complex Proc p; local i, s, r; r = 0; i=0; loop 1,NSEG do { s = p.seg[i]; if s != 0 then { complex Segment s; if s.base <= a && a < s.top then { r = segaddr(s, a); } } i = i+1; } return r;} // find an address in a given segmentdefn segaddr(s, a) { complex Segment s; local pte, pg; a = a - s.base; if s.map == 0 || s.mapsize < a/PTEMAPMEM then { return 0; } pte = s.map[a/PTEMAPMEM]; if pte == 0 then { return 0; } complex Pte pte; pg = pte.pages[(a%PTEMAPMEM)/BY2PG]; if pg == 0 then { return 0; } if pg & 1 then { // swapped out, return disk address return pg&~1; } complex Page pg; return (KZERO|(pg.pa+(a%BY2PG)))\A;} defn kzero() { return main - (main & 0x0FFFFFFF);} PTEMAPMEM = (1024*1024);PTEPERTAB = (PTEMAPMEM/BY2PG);defn up() { if objtype == "386" then { local mach; MACHADDR = KZERO+0x15000; mach = MACHADDR; complex Mach mach; return mach.externup; } if objtype == "amd64" then { local proc; proc = *R14; complex Proc proc; return proc; } if objtype == "arm64" then { local proc; proc = *R26; complex Proc proc; return proc; } print("up() not implemented for", objtype, "\n"); return -1;} defn intrcount() { local p, t, i, j; p = intrtimes\X; i=0; loop 1,256 do { t=0; j=0; loop 1,20 do { t = t+*p++; j=j+1; } if t != 0 then { print(itoa(i, "%5d"), " ", itoa(t, "%11d"), "\n"); } i=i+1; }} defn needacid(s){ print("\trc(\"cd /sys/src/9/", kdir, "; mk ", s, ".acid\")\n"); print("\tinclude(\"/sys/src/9/", kdir, "/", s, ".acid\")\n");} defn kinit() {if (map()[2]) != {} then { // map has more than two elements -> active proc kdir = "unknown"; KZERO = kzero(); if objtype == "386" then { map({"*data", KZERO, 0xffffffff, KZERO}); kdir="pc"; } if objtype == "amd64" then { map({"*data", KZERO, 0xffffffffffffffff, KZERO}); kdir="pc64"; } if (objtype == "mips" || objtype == "mips2") then { kdir = "ch"; } if objtype == "arm" then { kdir = "bcm"; } if objtype == "arm64" then { kdir = "bcm64"; } needacid("proc"); needacid("chan"); needacid("segment"); needacid("cache");}}
include("/sys/lib/acid/syscall");
// print various /proc files
defn fd() {
rc("cat /proc/"+itoa(pid)+"/fd");
}
defn segment() {
rc("cat /proc/"+itoa(pid)+"/segment");
}
defn ns() {
rc("cat /proc/"+itoa(pid)+"/ns");
}
defn qid(qid) {
complex Qid qid;
return itoa(qid.path\X)+"."+itoa(qid.vers\X);
}
defn path(p) {
complex Path p;
if p != 0 then {
return *(p.s\s);
} else
return "<null>";
}
// print Image cache contents
IHASHSIZE = 64;
defn imagecacheline(h) {
local d, p, q;
while h != 0 do {
complex Image h;
d=(Dev)devtab[h.type];
p = "*closed*";
if h.c != 0 then
p = path(h.c.path);
q = h.qid;
print (h\A, " ref=", h.ref, " pgref=", h.pgref, "\t#", d.dc\r, h.dev\D, " (",
q.path, " ", q.vers\D, " ", q.type\X, ") ", p, "\n");
h = h.hash;
}
}
defn imagecache() {
local i;
i=0; loop 1,IHASHSIZE do {
imagecacheline(imagealloc.hash[i]);
i = i+1;
}
}
// dump channels
defn chan(c) {
local d, q;
c = (Chan)c;
d= (Dev)devtab[c.type];
q=c.qid;
print("chan(", c\A, "): ref=", c.ref\D, " #", d.dc\r, c.dev\D, " (", q.path, " ", q.vers\D, " ", q.type\X, ")");
print(" fid=", c.fid\D, " iounit=", c.iounit\D);
if c.ref != 0 then {
print(" ", path(c.path), " mchan=", c.mchan\A);
if c.mchan != 0 then {
print(" ", path(c.mchan.path));
}
}
print("\n");
}
defn chans() {
local c;
c = (Chan)chanalloc.list;
while c != 0 do {
if c.ref != 0 then
chan(c);
c=(Chan)c.link;
}
}
defn findchan(dev,type,path) {
local c;
c = (Chan)chanalloc.list;
while c != 0 do {
if c.ref != 0 then {
if c.dev == dev && c.type == type && c.qid.path == path then
return c;
}
c=(Chan)c.link;
}
return 0;
}
defn nchans() {
local c, n;
n = 0;
c = (Chan)chanalloc.list;
while c != 0 do {
if c.ref != 0 then
n++;
c = (Chan)c.link;
}
return n;
}
defn activechanlist() {
local l, n;
l = {};
c = (Chan)chanalloc.list;
while c != 0 do {
if c.ref != 0 then
l = append l,c;
c = (Chan)c.link;
}
return l;
}
defn difflist(a, b) {
local l, x;
l = {};
while a != {} do {
x = head a;
if match(x, b) == -1 then
l = append l, x;
a = tail a;
}
return l;
}
_active_chan_list = {};
defn newchans() {
local l, new;
l = activechanlist();
if _active_chan_list != {} then
newerchans(_active_chan_list);
_active_chan_list = l;
}
defn newerchans(oldlist){
local new;
new = difflist(activechanlist(), oldlist);
while new != {} do {
chan(head new);
new = tail new;
}
}
// look for channels that refer to themselves
defn badchans() {
local bad, c, i, len, mtpt, p;
c = (Chan)chanalloc.list;
while c != 0 do {
if c.ref != 0 then {
bad = "";
p = (Path)c.path;
if p != 0 then {
path(p);
mtpt = p.mtpt;
len = p.mlen;
i=0; loop 1,len do {
if mtpt[i] == c then
bad = bad+" mtpt self-ref";
i = i+1;
}
}
if bad != "" then
print("chan(", c\A, "):", bad, "\n");
}
c = (Chan)c.link;
}
}
NHASH=128;
defn mntcache() {
local i, m, c;
i=0; loop 1,NHASH do {
m = cache.hash[i];
while m != 0 do {
complex Mntcache m;
print(m\A, " dev ", m.dev\D, " type ", m.type, " qid (",
m.qid.path, " ", m.qid.vers\D, ")\n");
c = findchan(m.dev, m.type, m.qid.path);
if c != 0 then {
print(" ");
chan(c);
}
m = m.hash;
}
i = i+1;
}
}
// manipulate processes
defn proctab(x) {
return procalloc.tab[x];
}
defn proc(p) {
complex Proc p;
local s, i;
if p.state != 0 && p.pid != 0 && p.text != 0 then { // 0 is Dead
s = p.psstate;
if s == 0 then {
s = "kproc";
} else {
s = *(s\s);
}
print(p\A, " ", p.pid, ": ", *(p.text\s), " ", *(p.user\s), " pc ", p.pc, " ", s, " (", *(statename[p.state]\s), ") ut ", p.time[0]\D, " st ", p.time[1]\D, " qpc ", p.qpc, "\n");
}
}
defn procenv(p) {
complex Proc p;
local i, e, v;
e = p.egrp;
complex Egrp e;
i=0; loop 1,e.nent do {
v = e.ent + i;
i = i+sizeofEvalue;
complex Evalue v;
print(*(v.name\s), "=");
printstringn(v.value, v.len);
print("\n");
}
}
BY2PG=4096;
KSTACK=4096;
if objtype=="amd64" then {
KSTACK=16*1024;
}
if objtype=="arm64" then {
BY2PG=65536;
KSTACK=8*1024;
}
defn procstksize(p) {
complex Proc p;
local top, sp;
if p.state != 0 then { // 0 is Dead
top = p.kstack+KSTACK;
sp = *p.sched;
print(top-sp\D, "\n");
}
}
defn procstk(p) {
complex Proc p;
local l, n;
if p.state != 0 then { // 0 is Dead
if p.mach == 0 then {
l = p.sched;
} else {
n = p.nerrlab;
if n == 0 then {
return 0;
}
l = p.errlab + (n-1)*sizeofLabel;
}
complex Label l;
if objtype=="386" || objtype=="amd64" then
_stk(gotolabel, l.sp, linkreg(0), 0);
else
_stk(l.pc, l.sp, linkreg(0), 0);
}
}
defn procs() {
local i;
i=0; loop 1,conf.nproc do {
proc(proctab(i));
i = i+1;
}
}
defn stacks() {
local i, p;
i=0; loop 1,conf.nproc do {
p = (Proc)proctab(i);
if p.state != 0 then {
print("=========================================================\n");
proc(p);
procstk(p);
}
i = i+1;
}
}
defn stacksizes() {
local i;
i=0; loop 1,conf.nproc do {
procstksize(proctab(i));
i = i+1;
}
}
// segment-related
defn procsegs(p) {
complex Proc p;
local i;
i=0; loop 1,NSEG do {
psegment(p.seg[i]);
i = i+1;
}
}
segtypes = { "text", "data", "bss", "stack", "shared", "physical", "shdata", "map" };
defn psegment(s) {
complex Segment s;
if s != 0 then {
print(s\A, " ", segtypes[s.type&SG_TYPE], " ", s.base, "-", s.top, " image ", s.image, "\n");
}
}
// find physical address for an address in a given process
defn procaddr(p, a) {
complex Proc p;
local i, s, r;
r = 0;
i=0; loop 1,NSEG do {
s = p.seg[i];
if s != 0 then {
complex Segment s;
if s.base <= a && a < s.top then {
r = segaddr(s, a);
}
}
i = i+1;
}
return r;
}
// find an address in a given segment
defn segaddr(s, a) {
complex Segment s;
local pte, pg;
a = a - s.base;
if s.map == 0 || s.mapsize < a/PTEMAPMEM then {
return 0;
}
pte = s.map[a/PTEMAPMEM];
if pte == 0 then {
return 0;
}
complex Pte pte;
pg = pte.pages[(a%PTEMAPMEM)/BY2PG];
if pg == 0 then {
return 0;
}
if pg & 1 then { // swapped out, return disk address
return pg&~1;
}
complex Page pg;
return (KZERO|(pg.pa+(a%BY2PG)))\A;
}
defn kzero() {
return main - (main & 0x0FFFFFFF);
}
PTEMAPMEM = (1024*1024);
PTEPERTAB = (PTEMAPMEM/BY2PG);
defn up() {
if objtype == "386" then {
local mach;
MACHADDR = KZERO+0x15000;
mach = MACHADDR;
complex Mach mach;
return mach.externup;
}
if objtype == "amd64" then {
local proc;
proc = *R14;
complex Proc proc;
return proc;
}
if objtype == "arm64" then {
local proc;
proc = *R26;
complex Proc proc;
return proc;
}
print("up() not implemented for", objtype, "\n");
return -1;
}
defn intrcount() {
local p, t, i, j;
p = intrtimes\X;
i=0; loop 1,256 do {
t=0;
j=0; loop 1,20 do {
t = t+*p++;
j=j+1;
}
if t != 0 then {
print(itoa(i, "%5d"), " ", itoa(t, "%11d"), "\n");
}
i=i+1;
}
}
defn needacid(s){
print("\trc(\"cd /sys/src/9/", kdir, "; mk ", s, ".acid\")\n");
print("\tinclude(\"/sys/src/9/", kdir, "/", s, ".acid\")\n");
}
defn kinit() {
if (map()[2]) != {} then { // map has more than two elements -> active proc
kdir = "unknown";
KZERO = kzero();
if objtype == "386" then {
map({"*data", KZERO, 0xffffffff, KZERO});
kdir="pc";
}
if objtype == "amd64" then {
map({"*data", KZERO, 0xffffffffffffffff, KZERO});
kdir="pc64";
}
if (objtype == "mips" || objtype == "mips2") then {
kdir = "ch";
}
if objtype == "arm" then {
kdir = "bcm";
}
if objtype == "arm64" then {
kdir = "bcm64";
}
needacid("proc");
needacid("chan");
needacid("segment");
needacid("cache");
}
}