123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- // poor emulation of SVR5 truss command - traces system calls
- include("/sys/lib/acid/syscall");
- _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");
|