Search code examples
rubyipctrace

Ruby - set_trace_func on forked processes


I'd like to achieve the following:

Build a Ruby command line utility that registers some set_trace_func events, then invokes whatever ruby-executable argument you pass to it (say rspec). The registered events then carry over to the command invoked.

Pseudo code of myutility:

set_trace_func() # Set some events here

exec(ARGV.join(' ')) # Execute argument passed

Then call as myutility rspec.

My objective here is to actually register trace points on arbitrary commands (as long as they are using ruby shims).

Things I have tried:

  1. exec Does not work, for obvious reasons (it replaces the process entirely).
  2. popen, system, backticks. These start an independent process.

I can use some form of IPC, but that assumes control over the command I am invoking with my utility. This is not the case; I'd like to accept arbitrary Ruby-executable arguments.

Is this possible? One thing I have not looked at closely is drb, but that too assumes some interference with outside arguments.


Solution

  • You can inject some code into ruby process by adding arguments to ruby interpreter, so your utility can be split in two parts - runner and payload. Payload is just another script, it registers for set_trace_func etc. upon require, and runner inject the former into target script like so:

    exec('/usr/bin/env', 'ruby', '-r', payload_full_filename, *ARGV)
    

    This will make ruby to require your payload into process first and then proceed with running target script itself (payload will run even if target script cannot compile)