A couple of days ago Brendan was chatting with me on irc and we got to discussing such a beast. Mainly looking at something simple in the way of the python and perl providers that others have worked on.
Well, to make a long story short (ok it will be longer later), I've coded up something that appears to work against the nevada clone tree of a couple of days ago, and logged RFE 6591476 to track it.
I'll be putting the diffs up in the next day or so, but for a teaser, here is the documentation.
shprovider makes available probes that can be used to observe the behaviour of bourne shell scripts.
shprovider makes available the following probes:
Probe that fires on entry to a shell builtin command.
Probe that fires on return from a shell builtin command.
Probe that fires when the shell execs an external command.
Probe that fires on return from an external command.
Probe that fires on entry into a shell function.
Probe that fires on return from a shell function.
Probe that fires before commands on a particular line of code are executed.
Probe that fires when the shell forks a subshell.
Probe that fires on return from a forked subshell.
Probe that fires before any commands in a script are executed.
Probe that fires on script exit.
The argument types to the
shprovider are listed in the below table.
Probe args args args args builtin-entry,
char \* char \* int char \*\* builtin-return,
char \* char \* int line char \* int script-begin char \* script-end char \* int subshell-entry char \* pid_t subshell-return char \* int
arg0 in all probes is the script name.
entryprobes, and the
returnprobes, arg1 is the name of the function, builtin or program being called. arg2 and arg3 in these
entryprobes are the argument count and a pointer to the argument list. In these
returnprobes, arg2 is the return code from the function, builtin or program.
subshell-entry, arg1 is the pid of the forked subshell and in
subshell-returnprobes, arg1 is the return code from the subshell.
In the line probe, arg1 is the line number.
In the script-end probe, arg1 is the exit code of the script.
shprovider uses DTrace's stability mechanism to describe its stabilities, as shown in the following table. For more information on the stability mechanism see Chapter 39 of the Solaris Dynamic Tracing guide.
Element Name Class Data Class Dependancy Class Provider Unstable Unstable Common Module Private Private Unknown Function Private Private Unknown Name Unstable Unstable Common Arguments Unstable Unstable Common
The probes that gave me the most trouble were
line was tricky as
sh only does line numbers when it parses input. It has no concept of line numbers on execution, which is what we need.
So, I needed to add another structure element (
trenod, and every other struct that is cast over the top of it. In the first failed attempt, I set this to
standin->flin whenever we allocated a new one of these nodes, I set line to this value. The problem with this is that if the parser hits a newline, this number gets incremented before we actually set it, which means that the last command on every line has the line number of the following line. Not quite what I wanted.
What I ended up going with was the creation of another variable in the
fileblk structure (
comline) that I set just before
standin->flin is incremented. This looks like it works.
subshell-\* probes were not initially going to be a part of this, but an assumption I made about
execute() when coding the
exec-\* probes ended up causing the shell to coredump on me. It turns out that
com is properly defined when we fall through the switch to the
TFORK code, but if we go directly into the
TFORK case, it's something completely different (would you believe "1"?). So, I made the probe conditional on the node type. If it was a
TFORK, then we do a
subshell probe, otherwise we do an
exec probe. This also appears to work.
In the meanwhile, I've been sending Brendan
sh binaries and he's already started coding more tools for the DTrace Toolkit based on this provider, and I have to say that some of his ideas look pretty cool.