Permalink
Browse files

initial import

  • Loading branch information...
0 parents commit cf40396ed2d35e4df59cf6a154a1f0be7e320422 Joshua ben Jore committed Aug 12, 2009
Showing with 455 additions and 0 deletions.
  1. +27 −0 .autotest
  2. +6 −0 History.txt
  3. +13 −0 Manifest.txt
  4. +71 −0 README.txt
  5. +36 −0 Rakefile
  6. +74 −0 bin/trepan-backend
  7. +10 −0 ext/extconf.rb
  8. +50 −0 ext/reref.c
  9. +94 −0 lib/trepan.rb
  10. +26 −0 lib/trepan/exception.rb
  11. +21 −0 test/test_roundtrip.rb
  12. +13 −0 test/test_trepan_tool.rb
  13. +14 −0 test/test_value.rb
@@ -0,0 +1,27 @@
+require 'autotest/restart'
+
+# Autotest.add_hook :initialize do |at|
+# at.extra_files << "../some/external/dependency.rb"
+#
+# at.libs << ":../some/external"
+#
+# at.add_exception 'vendor'
+#
+# at.add_mapping(/dependency.rb/) do |f, _|
+# at.files_matching(/test_.*rb$/)
+# end
+#
+# %w(TestA TestB).each do |klass|
+# at.extra_class_map[klass] = "test/test_misc.rb"
+# end
+# end
+
+# Autotest.add_hook :run_command do |at|
+# system "rake build"
+# end
+
+# Local variables:
+# mode: ruby
+# End:
+#
+# vim: syntax=ruby
@@ -0,0 +1,6 @@
+=== 1.0.0 / 2009-08-12
+
+* 1 major enhancement
+
+ * Birthday!
+
@@ -0,0 +1,13 @@
+.autotest
+History.txt
+Manifest.txt
+README.txt
+Rakefile
+bin/trepan-backend
+ext/extconf.rb
+ext/reref.c
+lib/trepan.rb
+lib/trepan/exception.rb
+test/test_roundtrip.rb
+test/test_trepan_tool.rb
+test/test_value.rb
@@ -0,0 +1,71 @@
+= trepan
+
+* http://rubyforge.org/projects/trepan
+
+== DESCRIPTION:
+
+Trepan is a Kernel extension which augments Kernel#caller's results
+with the function's arguments at each level.
+
+== FEATURES/PROBLEMS:
+
+== SYNOPSIS:
+
+Regular Kernel#enhanced_caller:
+
+ require 'trepan'
+
+ def something(foo) enhanced_caller end
+ stack = something( 42 )
+ p stack.first.args # [ 42 ]
+
+Fancy Exception#backtrace:
+
+ require 'trepan/exception'
+ def something(foo) raise end
+ begin
+ something( 42 )
+ rescue Exception => e
+ p e.backtrace.first.args # [ 42 ]
+ end
+
+== REQUIREMENTS:
+
+Requires:
+
+* MRI Ruby 1.8 compiled with symbols
+* gdb
+* bash
+* make
+* a working C compiler
+
+== INSTALL:
+
+Install this gem like any other gem:
+
+ $ gem install trepan
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) 2009 Josh ben Jore
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,36 @@
+require 'rubygems'
+require 'hoe'
+require 'rbconfig'
+
+EXT = "ext/reref.#{Config::CONFIG['DLEXT']}"
+
+class Trepan
+ # !!!: Duplicated in lib/trepan.rb
+ VERSION = '1.0.0'
+end
+
+Hoe.spec 'trepan' do
+ | p |
+
+ # self.rubyforge_name = 'trepanx' # if different than 'trepan'
+
+ p.spec_extras[:extensions] = 'ext/extconf.rb'
+ p.clean_globs << EXT << 'ext/*.o' << 'ext/Makefile'
+
+ p.developer('Josh ben Jore', 'twists@gmail.com')
+end
+
+task :test => EXT
+
+file EXT => [ 'ext/extconf.rb', 'ext/reref.c' ] do
+ Dir.chdir( 'ext' ) do
+ ruby 'extconf.rb'
+ sh 'make'
+ end
+end
+
+# Local variables:
+# mode: ruby
+# End:
+#
+# vim: syntax=ruby
@@ -0,0 +1,74 @@
+#!/usr/bin/env ruby
+
+require 'expect'
+
+# TODO: use Getopt::Long
+# TODO: use Pod::Usage
+#
+pid = ARGV[0]
+cmd = "bash -c 'gdb --quiet --nw --nx --pid #{pid} 2>/dev/null'"
+
+# Attach to the other Ruby process with GDB and script the interaction
+# with Expect
+#
+IO.popen(cmd, 'r+') do
+ |gdb|
+
+ # Wait for start-up
+ #
+ gdb.expect( /\(gdb\)/ ) do
+
+ # Send for the backtrace
+ #
+ gdb.print( "backtrace\n" )
+ end
+
+ # Wait for the backtrace
+ #
+ gdb.expect( /\(gdb\)/ ) do
+ | bufa |
+
+ # Parse the backtrace to get the list of C pointers to the arguments.
+ #
+ buf = bufa.to_s
+ argv_pointers =
+ buf.scan( /rb_call .+?argc=(\d+).+?argv=(0x[[:xdigit:]]+)/ )
+
+ # Dereference each pointer to get the (VALUE) we can hand back to Ruby
+ #
+ argv_pointers.each_index do
+ | argv_index |
+ argc, argv = argv_pointers[ argv_index ]
+
+ # Capture all arguments
+ #
+ 1.upto( argc.to_i ) do
+ | nth |
+ nth_index = nth - 1
+
+ # Capture an argument
+ #
+ gdb.print( "print *( #{nth_index} + (VALUE*)#{argv} )\n" )
+ gdb.expect( /= [[:xdigit:]]+\n/ ) do
+ | p |
+ value = /= (\d+)/.match( p[0] )
+ puts "VALUE[#{argv_index}][#{nth_index}]=#{value[1]}"
+ end
+
+ # Ensure we got a prompt back
+ #
+ gdb.expect( /\(gdb\)/ )
+ end
+ end
+
+ # Shut down GDB and let the other process resume
+ #
+ gdb.print( "detach\nquit\n" )
+ end
+end
+
+# Local variables:
+# mode: ruby
+# End:
+#
+# vim: syntax=ruby
@@ -0,0 +1,10 @@
+#!/usr/bin/env ruby
+$preload = false
+require 'mkmf'
+create_makefile('reref')
+
+# Local variables:
+# mode: ruby
+# End:
+#
+# vim: syntax=ruby
@@ -0,0 +1,50 @@
+#include "ruby.h"
+
+extern VALUE rb_cObject;
+extern VALUE rb_cFixnum;
+
+/*
+ * call-seq:
+ * obj.__value__ => (VALUE*)obj
+ *
+ * Returns an object's C (VALUE) for use in correlating Ruby objects
+ * to C objects.
+ */
+VALUE
+rb___value__(ref)
+ VALUE ref;
+{
+ return 1 | (ref << 1);
+}
+
+/*
+ * call-seq:
+ * fixnum.__object__ => obj
+ *
+ * Dereferences a fixnum to produce Ruby object.
+ */
+VALUE
+rb___object__(ref)
+ VALUE ref;
+{
+ return (VALUE)NUM2INT(ref);
+}
+
+void
+Init_reref(void)
+{
+ rb_define_method(rb_cObject,"__value__",rb___value__, 0);
+ rb_define_method(rb_cFixnum,"__object__",rb___object__,0);
+}
+
+/*
+ * Local variables:
+ * mode: c
+ * c-indentation-style: bsd
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ *
+ * ex: set ts=8 sts=4 sw=4 noet:
+ */
@@ -0,0 +1,94 @@
+require 'rbconfig'
+require 'reref'
+
+module Kernel
+ def enhanced_caller
+ Trepan.enhanced_caller
+ end
+end
+
+module Trepan
+ # !!!: Duplicated in Rakefile
+ VERSION = '1.0.0'
+
+ # Construct the path to the ruby interpreter
+ #
+ RUBY = File.join(
+ Config::CONFIG['bindir'],
+ "#{Config::CONFIG['ruby_install_name']}#{Config::CONFIG['EXEEXT']}"
+ )
+
+ # Construct the path the trepan program
+ #
+ TREPAN = File.join( Config::CONFIG['bindir'], 'trepan-backend' )
+
+ # === Description
+ # TODO: description goes here
+ #
+ # === Returns
+ # TODO: description goes here
+ #
+ def enhanced_caller
+
+ # Disable GC for a moment so I won't suffer a bad pointer while
+ # I'm plucking objects right out of memory.
+ #
+ gc_was_disabled = GC.disable
+
+ # Open my own brain for inspection. This is going to produce a
+ # bunch of data like:
+ #
+ # VALUE[0][0] = 85
+ # VALUE[0][1] = ...
+ #
+ my_brain = `#{ruby} #{trepane_rb} #{$$}`
+
+
+ # Reach into our memory and pluck some objects out.
+ #
+ caller_argv = []
+ my_brain.scan( /VALUE\[(\d+)\]\[(\d+)\]=(\d+)/ ) do
+ | match |
+
+ caller_ix = match[0].to_i
+ argv_ix = match[1].to_i
+ pointer = match[2].to_i
+
+ caller_argv[caller_ix] ||= []
+ caller_argv[argv_ix] = pointer.__object__
+ end
+
+ # Re-enable GC if relevant because I've finished capturing
+ # everything
+ #
+ if gc_was_disabled
+ GC.enable
+ end
+
+ # The top level of caller_argv ought to have the Kernel.`...`
+ # function call so remove it.
+ #
+ stack = Kernel.caller
+ while caller_argv.length > stack.length
+ caller_argv.shift
+ end
+
+ # Make the enhanced caller results
+ #
+ stack.
+ zip( caller_argv )\
+ .collect do
+ | src, args |
+ {
+ :src => src,
+ :args => args
+ }
+ end
+ end
+end
+
+# Local variables:
+# mode: ruby
+# End:
+#
+# vim: syntax=ruby
Oops, something went wrong.

0 comments on commit cf40396

Please sign in to comment.