| I am frequently asked to port strace to a given platform. Less |
| frequently I am asked how one would go about porting strace to a given |
| platform. :-) Since I have ported strace to a few platforms already I |
| have some advice to the would-be strace porter. |
| |
| The number one question is ``Does the native operating support a |
| concept which enables even the mere possibility of tracing?''. So far |
| I have seen two mechanisms which support system call tracing. They |
| are the SunOS originated feature of the PTRACE_SYSCALL argument to the |
| ptrace system call and the PIOCSENTRY/PIOCSEXIT ioctl for the /proc |
| filesystem under System V release 4 style Unix derived systems. There |
| may be others (surely a better one could be devised :-) but innovation |
| is a rare commodity so unless one of these is supported you may be |
| SOL. |
| |
| Therefore the first step is to try `man 2 ptrace' and `man 4 proc' to |
| see if there is even a glimmer of hope. Without assistance from the |
| operating system, system call tracing is a lost cause. If there is a |
| native system call tracing program (however pathetic it might be :-), |
| you may be able to use it to trace itself to determine what mechanism |
| it is using for tracing the system calls of another process. If the |
| interface is documented you should be a happy camper. Otherwise, |
| unless you can tolerate the thought of many thankless hours |
| single-stepping in a debugger with little or nothing to show for it, |
| you should consider other tasks to distract you from your friends, |
| family, education, job, spouse and/or significant other. |
| |
| If you have arrived here, your OS should have ptrace or proc or you |
| should have a high tolerance for pain. Then again, curious but |
| detached readers are invited to continue with little to risk but |
| boredom. If the mechanism is neither ptrace nor proc then examine how |
| it is intended to work and see how well it fits with what strace |
| already does. If it fits, fine, add a few more ifdefs. If there is a |
| gross mismatch, write a whole new event loop. |
| |
| At this point you are responsible for determining three things: how is |
| the specific system call communicated, how are system call arguments |
| handled, and how is errno handled. These things can usually be |
| resolved in a day or two using a decent assembly level debugger and |
| some educated guesswork. For example, set a breakpoint on `read'. |
| Then disassemble the code and see where the arguments go. Do they go |
| on the stack? Do they go into registers? Some combination of the |
| two? Find the point where the transition from user mode to kernel |
| mode is made. Can you identify the arguments at this point? When the |
| call returns where does errno go? Into a specific register? Into a |
| global variable? |
| |
| Next you need to determine how to decode numeric system call numbers |
| into system call names (syscallent.h), errno values into errno names |
| (errnoent.h) and ioctl values into ioctl names (ioctlent.h). Often |
| this fragile step can be accomplished by massaging system header files |
| with ad hoc shell scripts. Expect your scripts to break with every |
| dot rev of each OS release. |
| |
| Finally, once you have the basic framework in which system calls and |
| their arguments can be decoded, you must do the dirty work of decoding |
| every useful call. Some may be similar or identical to like-named |
| calls in other operating systems. Go ahead and tweak what is there |
| to achieve what you want. If there is more difference than similarity, |
| then just write your own version of it using one of the existing |
| implementations for ideas. |
| |
| The first order of decoding is the generation of suitable system call, |
| errno, ioctl and signal tables. Sample scripts are included to assist |
| with the generation of a first pass at these tables. |
| |
| Good luck and feel free to contact me before and/or during any major |
| project. |
| |
| Rick Sladkey <jrs@world.std.com> |