Terminology ----------- tracee = the task being probed/traced tracer = the task that probes/traces the tracee Each tracer can trace at most one tracee. To monitor multiple tracees concurrently, spawn multiple tracer threads. Multiple tracers can trace the same tracee. User API Data Structures ------------------------ enum uprobe_event { UPEV_BKPT, // probepoint UPEV_FUNCRET, // return probe UPEV_EXIT, /* * TODO: Add other utrace-supported events: * CLONE, VFORK_DONE, EXEC, DEATH, SYSCALL_ENTRY, SYSCALL_EXIT, * SIGNAL, SIGNAL_*. */ }; struct uprobe { unsigned long id; // user-specified ID enum uprobe_event event; // event type pid_t who; // pid unsigned long where; // virtual address for UPEV_BKPT // or UPEV_FUNCRET const char *khandler; // If non-null, run khandler // without notifying tracer. }; User API Overview ----------------- int uprobe_register(const struct uprobe *u); Register interest in a specified type of event. This is how probepoints are registered. int uprobe_unregister(pid_d pid, unsigned long id); Unregister interest in a specified probepoint or other event, or all events for specified tracee. int uprobe_poll(struct uprobe *u, int timeout); Block until any of the previously registered events happens in the tracee (u->who). int uprobe_detach(pid_t pid); Unregister interest in all events associated with the specifed tracee. int uprobe_run_khandler(const char *khandler, struct uprobe *u, void *data); Run a kernel-mode handler, possibly exchanging data between user and kernel space. API Specs --------- int uprobe_register(const struct uprobe *u); -------------------------------------------- The tracer process registers an interest in the specified event. If event == UPEV_BKPT, we set a probepoint for process who at virtual address where. Caller sets id (which may be a pointer or integer) for future reference. When the specified event happens, uprobes does exactly one of the following: a) If khandler is specified, uprobes calls that kernel handler, passing it a pointer to the kernel equivalent of the uprobe object. uprobes then continues execution of process who (e.g., in the case of a breakpoint, doing the necessary single-step and such). khandler must have been previously registered by a call to the (new) kernel function register_khandler(), described elsewhere (soon). b) If khandler is null, and the tracer process is running uprobe_poll() for process who, uprobe_poll() returns. c) Otherwise, uprobes just continues execution of process who. Note that uprobe_poll() will not catch events previously specified by uprobe_register() that happen before the uprobe_poll() call. If there are multiple tracer processes for the same tracee, their ID "namespaces" (i.e., numberspaces) are considered distinct. int uprobe_unregister(pid_t pid, unsigned long id); ---------------------------------------------- Unregisters the tracer's interest in the event with the specified id on the specified tracee. We need to support the tracer calling uprobe_unregister() for the event he's currently handling. uprobe_unregister(pid, UPID_ALL) unregisters all of this tracer's uprobes for the specified tracee. int uprobe_poll(struct uprobe *u, int timeout); ----------------------------------------------- If process u->who is stopped, allow it to continue.* Then sleep until an event of interest happens in process u->who, or until timeout ms have passed, whichever comes first. On timeout, return 0. If an event happens, uprobes returns 1 and fills in the uprobe object with the values that were specified when that uprobe was registered. *If a tracer registers n uprobes for the same tracee and address, he'll have to call uprobe_poll() n times to be notified of all of them. The tracee won't continue until all n notifications have been delivered (or cancelled by uprobe_unregister() or uprobe_detach()). int uprobe_run_khandler(const char *khandler, struct uprobe *u, void *data); ---------------------------------------------------------------------------- Run the kernel-mode handler whose name is khandler, passing it the pointers u and data. The named khandler must have been previously registered by a call to the (new) kernel function register_khandler() (see above). The contents (if any) of *u and *data before the call are up to the caller; their contents on return are up to the khandler. It's up to the tracer and the khandler to guarantee that the process, if any, specified by u->who is in a state where the khandler can act on it. Typically, the tracer will call uprobe_run_khandler() after uprobe_poll() returns, indicating that an event of interest has occurred.