Re: [DynInst_API:] Proposal: Add System Call Events to ProcControlAPI


Date: Thu, 23 May 2013 13:47:13 -0500
From: Bill Williams <bill@xxxxxxxxxxx>
Subject: Re: [DynInst_API:] Proposal: Add System Call Events to ProcControlAPI
On 05/23/2013 11:50 AM, David Smith wrote:
On 05/20/2013 09:53 AM, Emily Jacobson wrote:
Hi all,

Sorry for taking so long to respond to this.

We’re proposing adding system call callbacks to ProcControlAPI. After
internal discussion, we're sending out this proposal for wider feedback.
What follows is an overview of this feature, as well as the proposed
ProcControlAPI interface. For this feature to be exposed in the
DyninstAPI interface, it must first be exposed via ProcControlAPI. We
expect the DyninstAPI interface will closely mirror this.

I've never used the ProcControlAPI interface, but I'll just assume the
DyninstAPI will look the same and go ahead.

... stuff deleted ...

*Proposed Interface:*


A new Event child class: EventSyscall.  An EventSyscall is triggered
when a thread, which was put in syscall-monitoring mode by
Thread::setSyscallMode, enters or exists a system call. The Thread will
remain in syscall-monitoring mode after completion of this event
(presuming it has not been explicitly disabled by
Thread::setSyscallMode). An EventSyscall may be associated with an
EventType of pre-syscall (system call entry) or post-syscall (system
call exit).

So, Thread::setSyscallMode turns on/off syscall monitoring. When on,
EventSyscall events get seen.

In my head when thinking about this, I would have figured syscall events
would follow more of the existing event handling mechanisms, like
registerThreadEventCallback(). But, perhaps this is the difference
between the ProcControlAPI and DyninstAPI?

Sort of, yes. The ProcControl method for registering callbacks is to register them for particular events and have each callback take an Event*. Dyninst then wraps this in this (older) style of one interface method per type of callback. So at the ProcControl level you'd register a callback handler for EventSyscall, but at the Dyninst level you'd do something like registerPreSyscallCallback/registerPostSyscallCallback.

However, tracing syscalls is expensive and we only want to enable it for the processes/threads that a user cares about. So, in keeping with our existing model of "all user callbacks are global", you'd register the callback and orthogonally enable/disable the syscall events being generated. We've internally discussed the pros and cons of allowing user callbacks to be registered at a finer scope, which would allow us to automatically enable/disable syscall tracing based on what a user tells us they need. Right now that's a large change that wouldn't necessarily provide a large benefit; thoughts?

Also: preferences on whether you'd get handed EventSyscalls or MachSyscalls plus some other data from a BPatch-level callback?

We’re proposing adding a class representation for system calls; we’re
currently calling this class MachSyscall. Also, in support of this
syscall representation, we’re proposing representing the cross-product
of various architecture, OS, and possibly version information in a
Platform class. In this context, this allows us to go from a syscall’s
mutatee-side ID to its name (and to its arguments, eventually). More
generally, it allows us to represent the platform of a mutatee, which
even with our current feature set is not necessarily the platform of the
mutator (e.g. 32-bit mutatees/64-bit mutators). As this is variable
based on the process, it needs to be a process-level piece of
information and can’t be baked in at compile time.

This interface could be expanded in the future to support argument types
and value information.

What I'd like to see minimally available when a syscall entry event
happens is the syscall number and raw arguments. On syscall exit I'd
like to see the syscall number and return value.

You'd get bonus points for letting me change the syscall return value
(for failure injection) and letting me change syscall argument values.

But, perhaps that just betrays the fact that I'm used to working in the
kernel. Just for reference's sake, here is the kernel API systemtap used
in the past (things have changed a bit for newer kernels using tracepoints):

<https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/asm-generic/syscall.h>

I'm sure you already know this, but argument handling is tricky and very
architecture dependent. On some platforms, all args are passed in
registers. On other platforms, the first N arguments are stored in
registers, and the rest on the stack. Be sure your interface is flexible
enough to handle both cases.

Once you get past the minimum information needed, comes a design
question. Who is responsible for *really* understanding the syscalls,
information like number of arguments and argument types? Is it dyninst
or the software built on top of dyninst? (I don't have an answer here,
just asking the question.)

In the case of systemtap, since we're trying to keep our interface
similar between our in-kernel and our userspace (dyninst) runtimes,
we'll most likely just provide raw values and let the user figure out
how to interpret the system call.

Interpreting all system calls could be a big job.

... stuff deleted ...

// Returns the platform-specific number for this system call

int num() const;


// Returns the name for this system call (e.g., “getpid”)

string name() const;

That's a useful feature, providing the syscall name. We've had a bug
open in systemtap for a long while asking for this feature, but no one
has found the time to implement it.



--
--bw

Bill Williams
Paradyn Project
bill@xxxxxxxxxxx
[← Prev in Thread] Current Thread [Next in Thread→]