|  | // | 
|  | // pthread-specific access functions | 
|  | // avoid complicated libthread_db interface | 
|  | // | 
|  |  | 
|  | include("pthread-"+systype+"-"+objtype); | 
|  |  | 
|  | // pick apart system mcontext_t structures | 
|  | defn mcontext(m) | 
|  | { | 
|  | complex mcontext_t m; | 
|  |  | 
|  | if systype == "linux" then { | 
|  | m = m\X; | 
|  | return {"PC", m[14], "SP", m[7], "BP", m[6]}; | 
|  | } else if systype == "freebsd" then { | 
|  | return {"PC", m.mc_eip, "SP", m.mc_esp, "BP", m.mc_ebp}; | 
|  | } else | 
|  | error("do not know how to read mcontext_t on system "+systype); | 
|  | } | 
|  |  | 
|  | // | 
|  | // plan 9 thread library support | 
|  | // | 
|  | defn context(c) | 
|  | { | 
|  | c = (Context)c; | 
|  | return mcontext(c.uc.uc_mcontext); | 
|  | } | 
|  |  | 
|  | defn contextstk(c) | 
|  | { | 
|  | _stk(context(c), 0); | 
|  | } | 
|  |  | 
|  | defn contextlstk(c) | 
|  | { | 
|  | _stk(context(c), 1); | 
|  | } | 
|  |  | 
|  | defn altfmt(A){ | 
|  | local i, s, yes; | 
|  | complex Alt A; | 
|  |  | 
|  | s = "alt("; | 
|  | s = s + "tag(*" + itoa(A.tag, "%#x") + "=" + itoa(*A.tag, "%#x") + ") "; | 
|  | i = 0; | 
|  | yes = 0; | 
|  | while A.op != CHANEND && A.op != CHANNOBLK do{ | 
|  | if A.op != CHANNOP then{ | 
|  | if yes then s = s + " "; | 
|  | s = s + itoa(i, "%d"); | 
|  | s = s + ":"; | 
|  | if A.op == CHANSND then s = s + "send"; | 
|  | if A.op == CHANRCV then s = s + "recv"; | 
|  | s = s + "(channel("; | 
|  | s = s + itoa(A.c, "%#x"); | 
|  | s = s + "))"; | 
|  | yes = 1; | 
|  | } | 
|  | i = i + 1; | 
|  | A = (Alt)(A + sizeofAlt); | 
|  | } | 
|  | if A.op==CHANNOBLK then{ | 
|  | if yes then s = s + " "; | 
|  | s = s + "noblock"; | 
|  | } | 
|  | s = s + ")"; | 
|  | return s; | 
|  | } | 
|  |  | 
|  | defn alt(A){ | 
|  | print(altfmt(A), "\n"); | 
|  | } | 
|  |  | 
|  | defn channel(C) { | 
|  | complex Channel C; | 
|  | local i, p; | 
|  |  | 
|  | print("channel ", C\X, " // ", *(C.name\s)); | 
|  | if C.freed then { | 
|  | print(" (moribund)"); | 
|  | } | 
|  | print("\n"); | 
|  | print("\telemsize=", C.elemsize\D, " bufsize=", C.bufsize, "\n"); | 
|  | if C.bufsize then { | 
|  | print("\t", C.nbuf\D, " values in channel:\n"); | 
|  | print("\t"); | 
|  | p = C.buf+C.off*C.elemsize; | 
|  | loop 1,C.nbuf do { | 
|  | if C.elemsize==4 then { | 
|  | print(*p\X, " "); | 
|  | }else { | 
|  | print("data(", p\X, ") "); | 
|  | } | 
|  | p = p+C.elemsize; | 
|  | if p == C.buf+C.bufsize*C.elemsize then { | 
|  | p = C.buf; | 
|  | } | 
|  | } | 
|  | } | 
|  | print("\n"); | 
|  | print(" senders:\n"); | 
|  | _altarray(C.asend); | 
|  | print(" recvers:\n"); | 
|  | _altarray(C.arecv); | 
|  | } | 
|  |  | 
|  | defn _altarray(aa) | 
|  | { | 
|  | local i, a, t; | 
|  |  | 
|  | i = 0; | 
|  | aa = (_Altarray)aa; | 
|  | while i < aa.n do { | 
|  | a = (Alt)aa.a[i]; | 
|  | print("\t"+threadstkline(a.thread)+"\n"); | 
|  | i++; | 
|  | } | 
|  | } | 
|  |  | 
|  | defn fnname(a){ | 
|  | local sym, s; | 
|  |  | 
|  | s = symbols; | 
|  | while s do { | 
|  | sym = head s; | 
|  | if sym[2] == a then | 
|  | return sym[0]; | 
|  | s = tail s; | 
|  | } | 
|  | return itoa(a, "%#x"); | 
|  | } | 
|  |  | 
|  | stkignorelist = {}; | 
|  | defn stkignore(s){ | 
|  | append stkignorelist, s; | 
|  | } | 
|  |  | 
|  | defn threadstkline(T){ | 
|  | local stk, frame, pc, pc0, file, s, sym, i, stop, P, mainpid; | 
|  |  | 
|  | T = (_Thread)T; | 
|  | P = (Proc)T.proc; | 
|  | if P.thread == T then { | 
|  | mainpid = pid; | 
|  | setproc(pthread2tid(P.osprocid)); | 
|  | stk = strace({}); | 
|  | setproc(mainpid); | 
|  | } else | 
|  | stk = strace(context(T.context)); | 
|  |  | 
|  | stop = 0; | 
|  | while stk && !stop do { | 
|  | frame = head stk; | 
|  | stk = tail stk; | 
|  | pc = frame[2]; | 
|  | pc0 = frame[0]; | 
|  | file = pcfile(pc); | 
|  | if !regexp("plan9/src/lib9/", file) | 
|  | && !regexp("plan9/src/libthread/", file) | 
|  | && file != "?file?" | 
|  | && match(file, stkignore)==-1 then | 
|  | stop = 1; | 
|  | } | 
|  | file = pcfile(pc); | 
|  | s = file+":"+itoa(pcline(pc), "%d"); | 
|  | if pc0 != 0 then | 
|  | s = s + " "+fnname(pc0); | 
|  | return s; | 
|  | } | 
|  |  | 
|  | defn threadfmt(T){ | 
|  | complex _Thread T; | 
|  | local P, s, name; | 
|  |  | 
|  | P = (Proc)T.proc; | 
|  | s = "t=(_Thread)"+itoa(T, "%#-10x")+" // "; | 
|  |  | 
|  | if P.thread == T then | 
|  | s = s + "Running    "; | 
|  | else | 
|  | s = s + "Sleeping   "; | 
|  | s = s + threadstkline(T); | 
|  |  | 
|  | name = T+392;	// T+offsetof(_Thread, name); | 
|  | if *(name\b) != 0 then | 
|  | s = s + " ["+*(name\s)+"]"; | 
|  | return s; | 
|  | } | 
|  |  | 
|  | defn thread(T){ | 
|  | print(threadfmt(T), "\n"); | 
|  | } | 
|  |  | 
|  | defn procthreads(P){ | 
|  | complex Proc P; | 
|  | local T; | 
|  |  | 
|  | T = (_Thread)P.allthreads.$head; | 
|  | while T != 0 do{ | 
|  | print("\t"); | 
|  | thread(T); | 
|  | T = (_Thread)T.allnext; | 
|  | } | 
|  | } | 
|  |  | 
|  | defn prociter(x) { | 
|  | local P; | 
|  |  | 
|  | P = (Proc)*_threadprocs; | 
|  | while P != 0 do{ | 
|  | if P != (Proc)*_threadprocs then print("\n"); | 
|  | proc(P); | 
|  | if x == 1 then | 
|  | procthreads(P); | 
|  | if x == 2 then | 
|  | threadstks(P); | 
|  | P = (Proc)P.next; | 
|  | } | 
|  | } | 
|  |  | 
|  | defn procs() { | 
|  | prociter(0); | 
|  | } | 
|  |  | 
|  | defn threads() { | 
|  | prociter(1); | 
|  | } | 
|  |  | 
|  | defn stacks() { | 
|  | prociter(2); | 
|  | } | 
|  |  | 
|  | threadstkignore = { | 
|  | "plan9/src/libthread/", | 
|  | "plan9/src/lib9/", | 
|  | "plan9/src/lib9/(fmt|utf)/", | 
|  | }; | 
|  | defn threadstks(P){ | 
|  | complex Proc P; | 
|  | local T,  mainpid, pref, ign; | 
|  |  | 
|  | pref = stkprefix; | 
|  | stkprefix = pref+"\t\t"; | 
|  | ign = stkignore; | 
|  | stkignore = threadstkignore; | 
|  | T = (_Thread)P.allthreads.$head; | 
|  | while T != 0 do{ | 
|  | print("\t"); | 
|  | thread(T); | 
|  | threadstk(T); | 
|  | T = (_Thread)T.allnext; | 
|  | print("\n"); | 
|  | } | 
|  | stkprefix = pref; | 
|  | stkignore = ign; | 
|  | } | 
|  |  | 
|  | defn proc(P){ | 
|  | complex Proc P; | 
|  |  | 
|  | print("p=(Proc)", itoa(P, "%#-10x"), "  // pthread ", P.osprocid\X, " pid ", pthread2tid(P.osprocid)\D, " "); | 
|  | if P.thread==0 then | 
|  | print(" Sched"); | 
|  | else | 
|  | print(" Running"); | 
|  | print("\n"); | 
|  | } | 
|  |  | 
|  | defn threadlstk(T){ | 
|  | complex _Thread T; | 
|  | local P, mainpid; | 
|  |  | 
|  | P = (Proc)T.proc; | 
|  | mainpid = pid; | 
|  | setproc(pthread2tid(P.osprocid)); | 
|  |  | 
|  | if P.thread == T then | 
|  | lstk(); | 
|  | else | 
|  | contextlstk(T.context); | 
|  | setproc(mainpid); | 
|  | } | 
|  |  | 
|  | defn threadstk(T){ | 
|  | complex _Thread T; | 
|  | local P, mainpid; | 
|  |  | 
|  | P = (Proc)T.proc; | 
|  | mainpid = pid; | 
|  | setproc(pthread2tid(P.osprocid)); | 
|  |  | 
|  | if P.thread == T then | 
|  | stk(); | 
|  | else | 
|  | contextstk(T.context); | 
|  |  | 
|  | setproc(mainpid); | 
|  | } | 
|  |  | 
|  | print(acidfile); |