问题
I wanted to use DTrace to see "what syscalls are made by my shell script".
I made a very simple shell script, shell.sh
, and gave it execute privileges:
#!/bin/bash
grep 1 <<< 123
I cd
'd into its directory, and ran this simple DTrace script:
sudo dtrace -n 'syscall:::entry
/pid == $target/
{
@[probefunc] = count();
}' -c ./trace-me.sh
I get this error output:
dtrace: failed to execute ./trace-me.sh: unknown error
What happened here? I've run csrutil enable --without dtrace
. The DTrace script runs fine if I remove the -c
arg (and replace $target
with a pid).
Is this just another Mac gotcha? I'm running macOS Sierra 10.12.5 Beta.
回答1:
Thanks to the tip to which @l'L'l linked: I was able to work around this.
You'll need two shells.
In shell A (the shell we'll be inspecting):
# copy this shell's PID to clipboard (93827 for this example)
echo $$ | pbcopy
In shell B (the shell which will run DTrace), start tracing that PID:
sudo dtrace -n 'syscall:::entry
/progenyof($1) && pid != $1/
{
@[probefunc] = count();
}' 93827
We use progenyof() to ensure that we trace child processes of the shell. I've added && pid != $1
since for some reason progenyof(x)
seems to include x
.
Now back in shell A, run some code you'd like to inspect:
grep 1 <<< 123
Our DTrace program in shell B will successfully catch the child process launched in shell A.
There's a bit of noise to sift through. Maybe the shell launches a variety of children. Not sure how to be more selective.
It's educational to look at how dtruss implements -f
("follow children as they are forked")...
less "$(which dtruss)"
Relevant clauses are those using an OPT_follow &&
filter (indicates that -f
is enabled) or the self->child
variable (indicates that this thread is a child of the process specified in -p PID
).
It's also useful to know that ppid is a built-in variable which gives you the parent PID.
来源:https://stackoverflow.com/questions/44741836/failed-to-execute-script-sh-unknown-error