From 0a61c07d591273b76da21fb8386b669989da3707 Mon Sep 17 00:00:00 2001 From: rsc Date: Mon, 19 Apr 2004 18:18:37 +0000 Subject: acid files --- acid/truss | 283 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 acid/truss (limited to 'acid/truss') diff --git a/acid/truss b/acid/truss new file mode 100644 index 00000000..5c4731f1 --- /dev/null +++ b/acid/truss @@ -0,0 +1,283 @@ +// poor emulation of SVR5 truss command - traces system calls + +include(acidfile); + +_stoprunning = 0; + +defn stopped(pid) { + local l; + local pc; + pc = *PC; + if notes then { + if (notes[0]!="sys: breakpoint") then + { + print(pid,": ",trapreason(),"\t"); + print(fmt(pc,97),"\t",fmt(pc,105),"\n"); + print("Notes pending:\n"); + l = notes; + while l do + { + print("\t",head l,"\n"); + l = tail l; + } + _stoprunning = 1; + } + } +} + +defn _addressof(pattern) { + local s, l; + l = symbols; + pattern = "^\\$*"+pattern+"$"; + while l do + { + s = head l; + if regexp(pattern, s[0]) && ((s[1] == 'T') || (s[1] == 'L')) then + return s[2]; + l = tail l; + } + return 0; +} + +stopPC = {}; +readPC = {}; +fd2pathPC = {}; +errstrPC = {}; +awaitPC = {}; +_waitPC = {}; +_errstrPC = {}; +trusscalls = { + "sysr1", + "_errstr", + "bind", + "chdir", + "close", + "dup", + "alarm", + "exec", + "_exits", + "_fsession", + "fauth", + "_fstat", + "segbrk", + "_mount", + "open", + "_read", + "oseek", + "sleep", + "_stat", + "rfork", + "_write", + "pipe", + "create", + "fd2path", + "brk_", + "remove", + "_wstat", + "_fwstat", + "notify", + "noted", + "segattach", + "segdetach", + "segfree", + "segflush", + "rendezvous", + "unmount", + "_wait", + "seek", + "fversion", + "errstr", + "stat", + "fstat", + "wstat", + "fwstat", + "mount", + "await", + "pread", + "pwrite", + }; + +trussapecalls = { + "_SYSR1", + "__ERRSTR", + "_BIND", + "_CHDIR", + "_CLOSE", + "_DUP", + "_ALARM", + "_EXEC", + "_EXITS", + "__FSESSION", + "_FAUTH", + "__FSTAT", + "_SEGBRK", + "__MOUNT", + "_OPEN", + "__READ", + "_OSEEK", + "_SLEEP", + "__STAT", + "_RFORK", + "__WRITE", + "_PIPE", + "_CREATE", + "_FD2PATH", + "_BRK_", + "_REMOVE", + "__WSTAT", + "__FWSTAT", + "_NOTIFY", + "_NOTED", + "_SEGATTACH", + "_SEGDETACH", + "_SEGFREE", + "_SEGFLUSH", + "_RENDEZVOUS", + "_UNMOUNT", + "__WAIT", + "_SEEK", + "__NFVERSION", + "__NERRSTR", + "_STAT", + "__NFSTAT", + "__NWSTAT", + "__NFWSTAT", + "__NMOUNT", + "__NAWAIT", + "_PREAD", + "_PWRITE", + }; + +defn addressof(pattern) { + // translate to ape system calls if we have an ape binary + if _addressof("_EXITS") == 0 then + return _addressof(pattern); + return _addressof(trussapecalls[match(pattern, trusscalls)]); +} + +defn setuptruss() { + local lst, offset, name, addr; + + trussbpt = {}; + offset = trapoffset(); + lst = trusscalls; + while lst do + { + name = head lst; + lst = tail lst; + addr = addressof(name); + if addr then + { + bpset(addr+offset); + trussbpt = append trussbpt, (addr+offset); + // sometimes _exits is renamed $_exits + if(regexp("exits|exec", name)) then stopPC = append stopPC, (addr+offset); + if(regexp("read", name)) then readPC = append readPC, (addr+offset); + if(regexp("fd2path", name)) then fd2pathPC = append fd2pathPC, (addr+offset); + if(regexp("^\\$*await", name)) then awaitPC = append awaitPC, (addr+offset); + if(regexp("^\\$*errstr", name)) then errstrPC = append errstrPC, (addr+offset); + // compatibility hacks for old kernel + if(regexp("_wait", name)) then _waitPC = append _waitPC, (addr+offset); + if(regexp("_errstr", name)) then _errstrPC = append _errstrPC, (addr+offset); + } + } +} + +defn trussflush() { + stop(pid); // already stopped, but flushes output +} + +defn new() { + bplist = {}; + newproc(progargs); + bpset(follow(main)[0]); + cont(); + bpdel(*PC); + // clear the hang bit, which is left set by newproc, so programs we fork/exec don't hang + printto("/proc/"+itoa(pid)+"/ctl", "nohang"); +} + +defn truss() { + local pc, lst, offset, prevpc, pcspret, ret; + + offset = trapoffset(); + + stop(pid); + _stoprunning = 0; + setuptruss(); + pcspret = UPCSPRET(); + + while !_stoprunning do { + cont(); + if notes[0]!="sys: breakpoint" then { + cleantruss(); + return {}; + } + pc = *PC; + if match(*PC, stopPC)>=0 then { + print(pid,": ",trapreason(),"\t"); + print(fmt(pc,'a'),"\t",fmt(pc,'i'),"\n"); + cleantruss(); + return {}; + } + if match(*PC, trussbpt)>=0 then { + usyscall(); + trussflush(); + prevpc = *PC; + step(); + ret = eval pcspret[2]; + print("\treturn value: ", ret\D, "\n"); + if (ret>=0) && (match(prevpc, readPC)>=0) then { + print("\tdata: "); + printtextordata(*((eval pcspret[1])+4), ret); + print("\n"); + } + if (ret>=0) && (match(prevpc, fd2pathPC)>=0) then { + print("\tdata: \"", *(*((eval pcspret[1])+4)\s), "\"\n"); + } + if (ret>=0) && (match(prevpc, errstrPC)>=0) then { + print("\tdata: \"", *(*(eval pcspret[1])\s), "\"\n"); + } + if (ret>=0) && (match(prevpc, awaitPC)>=0) then { + print("\tdata: "); + printtextordata(*(eval pcspret[1]), ret); + print("\n"); + } + // compatibility hacks for old kernel: + if (ret>=0) && (match(prevpc, _waitPC)>=0) then { + print("\tdata: "); + printtextordata(*(eval pcspret[1]), 12+3*12+64); + print("\n"); + } + if (ret>=0) && (match(prevpc, _errstrPC)>=0) then { + print("\tdata: "); + printtextordata(*(eval pcspret[1]), 64); + print("\n"); + } + } + trussflush(); + } +} + +defn cleantruss() { + local lst, offset, addr; + + stop(pid); + offset = trapoffset(); + lst = trussbpt; + while lst do + { + addr = head lst; + lst = tail lst; + bpdel(addr); + } + trussbpt = {}; + **PC = @*PC; // repair current instruction +} + +defn untruss() { + cleantruss(); + start(pid); +} + +print("/sys/lib/acid/truss"); -- cgit v1.2.3