Hijack: Living on the Edge of (Ruby and) Rails, Part 4

Hijack can debug most any running Ruby process. Here's a hands-on introduction.

The previous three installments of this series looked at new features in Edge Rails and other very recent releases of the popular Web development framework. Tomorrow’s installment looks at some next-generation gems and next week’s regular column looks at nested forms, an addition sure to please every Rails developer, from newbie to master.

Today’s installment is something of a spur, because I had intended to write about a different topic. However, today’s topic is very clever, certainly on the edge—a first alpha—and useful nonetheless.

Debug Anything with Hijack

I’m a big fan of irb and the Ruby debugger, and use both to explore code and find and fix bugs in Ruby and Rails projects. For a Ruby script, install the ruby-debug gem and then invoke the script with the debugger, rdebug.

$ sudo gem install ruby-debug
Successfully installed ruby-debug-0.10.3
1 gem installed
Installing ri documentation for ruby-debug-0.10.3...
Installing RDoc documentation for ruby-debug-0.10.3...
$ which rdebug
$ rdebug some_script.rb

It’s also very easy to debug a Rails application: Sprinkle the statement…


… liberally throughout your code and invoke the server with…

$ ./script/server --debugger

Whenever your Rails application hits a debugger statement, ZAP!, the application suspends, presenting a prompt where you can poke and prod variables, instances, and classes, and step through statements. After you address the defect, either remove the debugger statements or omit the --debugger option. In the latter case, debugger statements are simply ignored (although the server reminds you of that with some vociferousness.)

Real world scenarios tend to be a little more challening. What happens when a bug appears after a certain period or occurs only intermittently? Short of divine intervention, your logs, the application database, and anecdotal evidence may be your only clues to the culprit.

But like Prometheus, who stole fire from Zeus and returned it to man, developer Ian Leitch has granted we mere mortals a little bit of omniscience. Leitch’s Hijack can attach to almost any running Ruby process, interrupt its execution, and let your peer in as if you were truly all-powerful. You can swap in code on-the-fly, too, to add a debugger call wherever you need it.

Hijack works with common scripts and can attach to the Mongrel daemon and Thin, too. However, it does not yet work with the Mongrel script (./script/server) included with every Rails project, nor with the Rails script runner. Leitch has plans to address these shortcomings in the near future. As he said in an email to me, “Hijack was little more than an experiment up until a few days ago when someone mentioned it on Twitter.”

As a demonstration, let’s attach to a small Rails application and use the available techniques to usurp execution and debug the code. The test machine is a MacBook running Mac OS X Leopard, Edge Rails, and the GNU Debugger, Apple version gdb-966.

Using Hijack with Debugger Statements

Using Hijack is simple. First, install it. Hijack adds a gem and a command-line utility called hijack.

$ gem sources -a http://gems.github.com
$ sudo gem install ileitch-hijack
$ which hijack

For this initial example, I’ve left a breakpoint in one of my Rails validators. Typically, mongrel_rails ignores such a statement. However, once I hijack the process, the application goes into limbo when it meanders across line 1.

def validate_novelty

  self.errors.add_to_base( 'This location is already defined' ) unless Location.
  find(:first, :conditions =>
    { :group_id => group.id, :room => room, :aisle => aisle, :bin => bin } ).nil?

To continue, install the ruby-debug gem (if you do not yet have it) and launch your application with mongrel_rails start.

$ sudo gem install ruby-debug
$ cd ~/Projects/warehouse
$ mongrel_rails start
** Starting Mongrel listening at
** Starting Rails with development environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no restart).
** Rails signals registered.  HUP => reload (without restart).  It might not work well.
** Mongrel 1.1.5 available at
** Use CTRL-C to stop.

Next, attach to the Mongrel process. Use ps or jobs to find its process ID and invoke Hijack.

$ ps ux | grep Mongrel
7563 s003  S+     0:04.37 /System/Library/Frameworks/Ruby.framework/
  Versions/1.8/usr/bin/ruby /usr/bin/mongrel_rails start
$ hijack 7563
=> Hijacked 7563 (/usr/bin/mongrel_rails) (ruby 1.8.6 [universal-darwin9.0])

When the Hijack prompt appears, type two commands: hijack_debug_mode followed by hijack_debug_start. (I omitted the former several times in preparing this post, with unpredictable results.)

>> hijack_debug_mode
=> true
>> hijack_debug_start

According to Leitch, the two commands break the hijacking process into two steps intentionally. The first command, hijack_debug_mode, requires ruby-debug and then stops by design so you can insert your breakpoint(s). The next command, hijack_debug_start, connects hijack to the application. (Specifically, hijack connects to a remote debugger which proxies for the application.) debugger calls fire only when the application is connected.

At this point, you are connected and ready to debug. Whenever the application hits the breakpoint, Hijack drops to the debugger. Examine variables and look at backtraces as needed; when finished type continue to resume normal processing.

(rdb:20) p self
#<Location id: nil, group_id: 1, room: "sds", aisle: "dsds", bin: "dsdsd", created_at: nil, updated_at: nil>
(rdb:20) continue

Under the hood, Hijack uses the GNU Debugger, or gdb, to inject code that starts a Distributed Ruby (DRb) server. Once DRb is up and running, gdb is no longer needed and Hijack communicates directly with DRb. You must run Hijack on the same machine as the process being scrutinized; you must also run Hijack as the same user as the target process. Both limitations protect your processes from, well, being hijacked for nefarious purposes.

Hijack Running Code

In addition to affecting the execution of a running process, you can also change its code on-the-fly. You can replace both class methods and instance methods.

To replace code, start your server and hijack and type hijack_debug_mode. At the prompt, enter any code you want to “inject”. The general template to replace a class method is:

Klass.class_eval do
  class << self
    def some_class_method

class_eval evaluates the block within the context of the named class, here Klass. The meta-class class << self affects the class methods for Klass. Hence, you can override any class method simply be redefining it. Leitch provides this example.

Start your Rails application and start Hijack. Type hijack_debug_mode and then paste the following code at the prompt.

ActionController::Dispatcher.class_eval do
  class << self
    def dispatch_with_debugger(cgi, session_options, output)
      dispatch_without_debugger(cgi, session_options, output)

    alias_method :dispatch_without_debugger, :dispatch
    alias_method :dispatch, :dispatch_with_debugger

Now, if you point your browser to the application, it suspends execution within the dispatch method, which is a reasonable starting point to debug most anything.

The general template to replace instance methods looks like this:

Qlass.class_eval do
  def some_instance_method

Returning to my first example, if debugger wasn't already present, I could inject what I wanted with Hijack.

$ hijack 9377
=> Hijacked 9377 (/usr/bin/mongrel_rails) (ruby 1.8.6 [universal-darwin9.0])
>> hijack_debug_mode
=> true
>> Location.class_eval do
?>   def validate_novelty
>>     debugger
?>     self.errors.add_to_base( 'This location is already defined' ) unless Location.
?>       find(:first, :conditions => { :group_id => group.id, :room => room, :aisle => aisle, :bin => bin } ).nil?
>>   end
>> end
=> nil
>> hijack_debug_start

When I use the application to subsequently invoke the validator validate_novelty, Hijack drops to the debugger prompt.


Grand Theft Ruby

Hijack is in a nascent stage, but already has proven to be a very valuable tool. Expect lots of new features in the next release: pulling people from cars, shooting at cops, and outrunning John Law. Just kidding. This isn't Grand Theft Ruby. Still, the name is catchy.

My thanks to Ian Leitch for midnight tech support.

Happy tinkering.

Comments on "Hijack: Living on the Edge of (Ruby and) Rails, Part 4"

I was extremely pleased to locate this site.
Batman cartoon videos

I love this site – its so usefull and helpfull.|
nike free 5.0 trainer billige nike free run sko

Thanks a bunch! It a astonishing site!|
nike free 2015 nike free tr

Find out if dial up is available and cost.Motion sensitive controls are a significant stepping stone toward virtual reality in the home. That is why some people don’t watch or participate in sports such as football.However, officials were publicly reprimanded and an apology issued to Oklahoma because of a blown call that resulted in an Oklahoma loss. Another tip to consider may be the regularity that an oxygen compressor is usually to always be applied.
Wholesale Jerseys

Hijack: Living on the Edge of (Ruby and) Rails, Part 4 | Linux Magazine

Congrats!! Appreciate thus much information that is really not uninteresting and educational, this site!! Actually happy I discovered it!!
Dr wong hair transplant

Best Wishes!! Appreciate so much info that’s truly not uninteresting and informative, this website!! Actually pleased I discovered it!!
Pool marcite

Hi there, I log on to your blogs daily. Your writing style is awesome, keep doing what you’re doing!|
nike free joggesko nike free run 2 dame

Shop for NBA jerseys at the official NBA Store! We carry the widest variety of nba jerseys ads, and youth sizes. Keep checking back for the arrivals of the NBA Nike Jersey!

Congrats!! Enjoy this site, thus much information that is actually appealing and informative!! Actually pleased I came across it!!
Happy meal commercial

Leave a Reply