Search code examples
macosbsddtrace

Failed to execute script.sh: unknown error


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.


Solution

  • 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.