|  | 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 cname(c) { | 
|  | complex Cname c; | 
|  | if c != 0 then { | 
|  | return *(c.s\s); | 
|  | } else | 
|  | return "<null>"; | 
|  | } | 
|  |  | 
|  | // print Image cache contents | 
|  | // requires include("/sys/src/9/xxx/segment.acid") | 
|  | IHASHSIZE = 64; | 
|  | defn imagecacheline(h) { | 
|  | while h != 0 do { | 
|  | complex Image h; | 
|  | print (h\X, " ", qid(h.qid), " type ", h.type\D, " ref ", h.ref, " next ", h.next\X, " ", cname(h.c.name), "\n"); | 
|  | h = h.hash; | 
|  | } | 
|  | } | 
|  |  | 
|  | defn imagecache() { | 
|  | local i; | 
|  |  | 
|  | i=0; loop 1,IHASHSIZE do { | 
|  | imagecacheline(imagealloc.free[i]); | 
|  | i = i+1; | 
|  | } | 
|  | } | 
|  |  | 
|  | // dump channels | 
|  | defn chan(c) { | 
|  | local d, q; | 
|  |  | 
|  | c = (Chan)c; | 
|  | d=(Dev)(*(devtab+4*c.type)); | 
|  | q=c.qid; | 
|  | print(c\X, " 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(" ", cname(c.name), " mchan=", c.mchan\X); | 
|  | if c.mchan != 0 then { | 
|  | print(" ", cname(c.mchan.name)); | 
|  | } | 
|  | } | 
|  | print("\n"); | 
|  | } | 
|  |  | 
|  | defn chans() { | 
|  | local c; | 
|  |  | 
|  | c = (Chan)chanalloc.list; | 
|  | while c != 0 do { | 
|  | chan(c); | 
|  | c=(Chan)c.link; | 
|  | } | 
|  | } | 
|  |  | 
|  | // manipulate processes | 
|  | defn proctab(x) { | 
|  | return procalloc.arena+sizeofProc*x; | 
|  | } | 
|  |  | 
|  | defn proc(p) { | 
|  | complex Proc p; | 
|  | local s, i; | 
|  |  | 
|  | if p.state != 0 then {	// 0 is Dead | 
|  | s = p.psstate; | 
|  | if s == 0 then { | 
|  | s = "kproc"; | 
|  | } else { | 
|  | s = *(s\s); | 
|  | } | 
|  | print(p\X, " ", p.pid, ": ", *(p.text\s), " ", *(p.user\s), " pc ", p.pc\X, " ", s, " (", *(statename[p.state]\s), ") ut ", p.time[0]\D, " st ", p.time[1]\D, " qpc ", p.qpc\X, "\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | defn procenv(p) { | 
|  | complex Proc p; | 
|  | local e, v; | 
|  |  | 
|  | e = p.egrp; | 
|  | complex Egrp e; | 
|  | v = e.entries; | 
|  | while v != 0 do { | 
|  | complex Evalue v; | 
|  | print(*(v.name\s), "="); | 
|  | printstringn(v.value, v.len); | 
|  | print("\n"); | 
|  | v = v.link; | 
|  | } | 
|  | } | 
|  |  | 
|  | KSTACK=4096; | 
|  |  | 
|  | 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; | 
|  |  | 
|  | if p.state != 0 then {	// 0 is Dead | 
|  | l = p.sched; | 
|  | if objtype=="386" then | 
|  | _stk(gotolabel, *l, linkreg(0), 0); | 
|  | else | 
|  | _stk(*(l+4), *l, 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\X, " ", segtypes[s.type&SG_TYPE], " ", s.base\X, "-", s.top\X, " image ", s.image\X, "\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 (0x80000000|(pg.pa+(a%BY2PG)))\X; | 
|  | } | 
|  |  | 
|  | // PC only | 
|  | MACHADDR = 0x80004000; | 
|  | PTEMAPMEM = (1024*1024); | 
|  | BY2PG = 4096; | 
|  | PTEPERTAB = (PTEMAPMEM/BY2PG); | 
|  | defn up() { | 
|  | local mach; | 
|  |  | 
|  | mach = MACHADDR; | 
|  | complex Mach mach; | 
|  | return mach.externup; | 
|  | } | 
|  |  | 
|  | defn intrcount() { | 
|  | local p, pp, t, i, j; | 
|  |  | 
|  | p = intrtimes; | 
|  | i=0; | 
|  | loop 1,256 do { | 
|  | pp = p[i]; | 
|  | i=i+1; | 
|  | if pp != 0 then { | 
|  | j=0; | 
|  | t=0; | 
|  | loop 1,1000 do { | 
|  | t = t+pp[j]; | 
|  | j=j+1; | 
|  | } | 
|  | print(itoa(i, "%5d"), " ", itoa(t, "%11d"), "\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | print(acidfile); | 
|  |  | 
|  | defn needacid(s){ | 
|  | print("\trc(\"cd /sys/src/9/", kdir, "; mk ", s, ".acid\")\n"); | 
|  | print("\tinclude(\"/sys/src/9/", kdir, "/", s, ".acid\")\n"); | 
|  | } | 
|  |  | 
|  | if (map()[2]) != {} then {	// map has more than two elements -> active proc | 
|  | kdir = "unknown"; | 
|  |  | 
|  | if objtype == "386" then { | 
|  | map({"*data", 0x80000000, 0xffffffff, 0x80000000}); | 
|  | kdir="pc"; | 
|  | } | 
|  | if (objtype == "mips" || objtype == "mips2") then { | 
|  | kdir = "ch"; | 
|  | } | 
|  | if objtype == "alpha" then { | 
|  | map({"*data", 0x80000000, 0xffffffff, 0x80000000}); | 
|  | kdir = "alpha"; | 
|  | } | 
|  | needacid("proc"); | 
|  | } | 
|  |  |