Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Various changes

  • Loading branch information...
commit 083f19a86d51611a65c9a625d5503045624610e3 1 parent e526ca5
@FooBarWidget authored
View
0  bin/crash-watch 100644 → 100755
File mode changed
View
62 lib/crash_watch/gdb_controller.rb
@@ -2,12 +2,13 @@ module CrashWatch
class GdbController
class ExitInfo
- attr_reader :exit_code, :signal, :backtrace
+ attr_reader :exit_code, :signal, :backtrace, :snapshot
- def initialize(exit_code, signal, backtrace)
+ def initialize(exit_code, signal, backtrace, snapshot)
@exit_code = exit_code
@signal = signal
@backtrace = backtrace
+ @snapshot = snapshot
end
def signaled?
@@ -67,11 +68,50 @@ def attach(pid)
return result !~ /(No such process|Unable to access task)/
end
+ def call(code)
+ result = execute("call #{code}")
+ result =~ /= (.*)$/
+ return $1
+ end
+
+ def ruby_backtrace
+ filename = "/tmp/gdb-capture.#{@pid}.txt"
+
+ orig_stdout_fd_copy = call("(int) dup(1)")
+ new_stdout = call(%Q{(void *) fopen("#{filename}", "w")})
+ new_stdout_fd = call("(int) fileno(#{new_stdout})")
+ call("(int) dup2(#{new_stdout_fd}, 1)")
+
+ # Let's hope stdout is set to line buffered or unbuffered mode...
+ call("(void) rb_backtrace()")
+
+ call("(int) dup2(#{orig_stdout_fd_copy}, 1)")
+ call("(int) fclose(#{new_stdout})")
+ call("(int) close(#{orig_stdout_fd_copy})")
+
+ if File.exist?(filename)
+ result = File.read(filename)
+ result.strip!
+ if result.empty?
+ return nil
+ else
+ return result
+ end
+ else
+ return nil
+ end
+ ensure
+ if filename
+ File.unlink(filename) rescue nil
+ end
+ end
+
def wait_until_exit
execute("break _exit")
signal = nil
backtraces = nil
+ snapshot = nil
while true
result = execute("continue")
@@ -81,6 +121,7 @@ def wait_until_exit
if backtraces.empty?
backtraces = execute("bt full").strip
end
+ snapshot = yield(self) if block_given?
# Maybe the process will ignore this signal, so save
# current status, continue, and check whether the
# process exits later.
@@ -88,29 +129,30 @@ def wait_until_exit
if $1 == signal
# Looks like the signal we trapped earlier
# caused an exit.
- return ExitInfo.new(nil, signal, backtraces)
+ return ExitInfo.new(nil, signal, backtraces, snapshot)
else
- return ExitInfo.new(nil, signal, nil)
+ return ExitInfo.new(nil, signal, nil, snapshot)
end
elsif result =~ /^Breakpoint .*? _exit /
backtraces = execute("thread apply all bt full").strip
if backtraces.empty?
backtraces = execute("bt full").strip
end
+ snapshot = yield(self) if block_given?
result = execute("continue")
if result =~ /^Program exited with code (\d+)\.$/
- return ExitInfo.new($1.to_i, nil, backtraces)
+ return ExitInfo.new($1.to_i, nil, backtraces, snapshot)
elsif result =~ /^Program exited normally/
- return ExitInfo.new(0, nil, backtraces)
+ return ExitInfo.new(0, nil, backtraces, snapshot)
else
- return ExitInfo.new(nil, nil, backtraces)
+ return ExitInfo.new(nil, nil, backtraces, snapshot)
end
elsif result =~ /^Program exited with code (\d+)\.$/
- return ExitInfo.new($1.to_i, nil, nil)
+ return ExitInfo.new($1.to_i, nil, nil, nil)
elsif result =~ /^Program exited normally/
- return ExitInfo.new(0, nil, nil)
+ return ExitInfo.new(0, nil, nil, nil)
else
- return ExitInfo.new(nil, nil, nil)
+ return ExitInfo.new(nil, nil, nil, nil)
end
end
end
View
50 test/gdb_controller_spec.rb
@@ -11,6 +11,25 @@
after :each do
@gdb.close
+ if @process
+ Process.kill('KILL', @process.pid)
+ @process.close
+ end
+ end
+
+ def run_script_and_wait(code, snapshot_callback = nil, &block)
+ @process = IO.popen(%Q{ruby -e '#{code}'}, 'w')
+ @gdb.attach(@process.pid)
+ thread = Thread.new do
+ sleep 0.1
+ if block
+ block.call
+ end
+ @process.write("\n")
+ end
+ exit_info = @gdb.wait_until_exit(&snapshot_callback)
+ thread.join
+ return exit_info
end
describe "#execute" do
@@ -24,14 +43,6 @@
@process = IO.popen("sleep 9999", "w")
end
- after :each do
- if @process
- @gdb.close
- Process.kill('KILL', @process.pid)
- @process.close
- end
- end
-
it "returns true if attaching worked" do
@gdb.attach(@process.pid).should be_true
end
@@ -44,29 +55,6 @@
end
describe "#wait_until_exit" do
- after :each do
- if @process
- @gdb.close
- Process.kill('KILL', @process.pid)
- @process.close
- end
- end
-
- def run_script_and_wait(code, &block)
- @process = IO.popen(%Q{ruby -e '#{code}'}, 'w')
- @gdb.attach(@process.pid)
- thread = Thread.new do
- sleep 0.1
- if block
- block.call
- end
- @process.write("\n")
- end
- exit_info = @gdb.wait_until_exit
- thread.join
- return exit_info
- end
-
it "returns the expected information if the process exited normally" do
exit_info = run_script_and_wait('STDIN.readline')
exit_info.exit_code.should == 0
Please sign in to comment.
Something went wrong with that request. Please try again.