Browse files

add --eval for evaluating simple ruby expressions in the target process

  • Loading branch information...
1 parent 1745444 commit a5f725d980961d8cfcd0108e40137e5efac5185b @tmm1 committed Feb 21, 2011
Showing with 65 additions and 7 deletions.
  1. +41 −7 bin/rbtrace
  2. +24 −0 ext/rbtrace.c
View
48 bin/rbtrace
@@ -214,6 +214,23 @@ class RBTracer
end
end
+ # Evaluate some ruby code.
+ #
+ # Returns the String result.
+ def eval(code)
+ if (err = valid_syntax?(code)) != true
+ raise ArgumentError, "#{err.class} for expression #{code.inspect}"
+ end
+
+ send_cmd(:eval, code)
+
+ if wait_for(10, 'for eval response'){ !!@eval_result }
+ @eval_result
+ else
+ STDERR.puts '*** timed out waiting for eval response'
+ end
+ end
+
# Turn on GC tracing.
#
# Returns nothing.
@@ -315,6 +332,11 @@ class RBTracer
end
end
+ def puts(arg=nil)
+ @printed_newline = true
+ arg ? @out.puts(arg) : @out.puts
+ end
+
private
# Process incoming events until either a timeout or a condition becomes true.
@@ -364,7 +386,7 @@ class RBTracer
def valid_syntax?(code)
begin
- eval("#{code}\nBEGIN {return true}", nil, 'rbtrace_expression', 0)
+ Kernel.eval("#{code}\nBEGIN {return true}", nil, 'rbtrace_expression', 0)
rescue Exception => e
e
end
@@ -375,11 +397,6 @@ class RBTracer
@out.print(arg)
end
- def puts(arg=nil)
- @printed_newline = true
- arg ? @out.puts(arg) : @out.puts
- end
-
def newline
puts unless @printed_newline
@printed_newline = true
@@ -430,6 +447,10 @@ class RBTracer
pid, = *cmd
@forked_pid = pid
+ when 'evaled'
+ res, = *cmd
+ @eval_result = res
+
when 'mid'
mid, name = *cmd
@methods[mid] = name
@@ -692,14 +713,19 @@ EOS
opt :fork,
"fork a copy of the process for debugging (so you can attach gdb.rb)"
+
+ opt :eval,
+ "evaluate a ruby expression in the process",
+ :type => String,
+ :short => '-e'
end
opts = Trollop.with_standard_exception_handling(parser) do
raise Trollop::HelpNeeded if ARGV.empty?
parser.parse(ARGV)
end
- unless %w[ fork slow firehose methods config gc ].find{ |n| opts[:"#{n}_given"] }
+ unless %w[ fork eval slow firehose methods config gc ].find{ |n| opts[:"#{n}_given"] }
$stderr.puts "Error: --slow, --gc, --firehose, --methods or --config required."
$stderr.puts "Try --help for help."
exit(-1)
@@ -798,6 +824,14 @@ EOS
if opts[:fork_given]
pid = tracer.fork
STDERR.puts "*** forked off a busy looping copy at #{pid} (make sure to kill -9 it when you're done)"
+
+ elsif opts[:eval_given]
+ code = opts[:eval]
+ res = tracer.eval(code)
+
+ tracer.puts ">> #{code}"
+ tracer.puts "=> #{res}"
+
else
tracer.out = output if output
tracer.prefix = ' ' * opts[:prefix]
View
24 ext/rbtrace.c
@@ -775,6 +775,9 @@ rbtrace__process_event(msgpack_object cmd)
static int last_tracer_id = -1; // hax
char query[BUF_SIZE];
+ char code[BUF_SIZE+150];
+ VALUE val = Qnil;
+
msgpack_object_array ary;
msgpack_object_raw str;
@@ -890,6 +893,27 @@ rbtrace__process_event(msgpack_object cmd)
if (outer != -1) {
waitpid(outer, NULL, 0);
}
+
+ } else if (0 == strncmp("eval", str.ptr, str.size)) {
+ if (ary.size != 2 ||
+ ary.ptr[1].type != MSGPACK_OBJECT_RAW)
+ return;
+
+ str = ary.ptr[1].via.raw;
+
+ strncpy(query, str.ptr, str.size);
+ query[str.size] = 0;
+
+ snprintf(code, BUF_SIZE+150, "(begin; %s; rescue Exception => e; e; end).inspect", query);
+ val = rb_eval_string_protect(code, 0);
+
+ if (TYPE(val) == T_STRING) {
+ rbtrace__send_event(1,
+ "evaled",
+ 's', RSTRING_PTR(val)
+ );
+ }
+
}
}

0 comments on commit a5f725d

Please sign in to comment.