blob: 11092fe843bd53a32f514f5cd1fb1f9c9a07109a [file] [log] [blame]
require 'common/Logger'
require 'dbgp/DbgpThread'
require 'dbgp/ThreadEventHandler'
require 'dbgp/Utils'
require 'debugger/DebugEventHandler'
module XoredDebugger
class ThreadManager
include ThreadEventHandler
include DebugEventHandler
include Logger
include XoredDebuggerUtils
attr_reader :debugger
attr_reader :capture_manager
attr_reader :source_manager
def initialize(debugger)
begin
@debugger = debugger
@debugger.handler = self
@capture_manager = CaptureManager.new(self)
@source_manager = SourceManager.instance
Thread.set_event_handler(self)
# fake started event for main thread
started()
rescue Exception
Thread.set_event_handler(nil)
end
end
def terminate(excpt = nil)
log('Terminating thread manager')
begin
Thread.list.each do |thread|
dbgp_thread = thread[ :dbgp_thread_wrapper ]
dbgp_thread.exited(nil) unless dbgp_thread.nil? || Thread.main == thread
end
print_exception(excpt) unless excpt.nil? || excpt.is_a?(SystemExit)
@capture_manager.terminate
exited(excpt)
ensure
Thread.set_event_handler(nil)
end
end
def get_dbgp_thread(thread)
thread[ :dbgp_thread_wrapper ]
end
def started()
if (@debugger.is_debug_thread?(Thread.current))
return
end
log('Application thread started')
thread = Thread.current
thread[ :dbgp_thread_wrapper ] = DbgpThread.new(thread, self)
# suspending current context, till wrapper initialized
@debugger.current_context.suspend
end
def exited(excpt)
if (@debugger.is_debug_thread?(Thread.current))
return
end
log('Application thread exited')
logException(excpt, 'at exited()') unless excpt.nil?
dbgp_thread = Thread.current[ :dbgp_thread_wrapper ]
Thread.current[ :dbgp_thread_wrapper ] = nil
dbgp_thread.exited(excpt) unless dbgp_thread.nil?
end
def at_breakpoint(context)
log('at_breakpoint')
dbgp_thread = Thread.current[ :dbgp_thread_wrapper ]
dbgp_thread.at_breakpoint(context) unless dbgp_thread.nil?
end
def at_catchpoint(context, excpt)
log('at_catchpoint: ' + excpt.class.name)
dbgp_thread = Thread.current[ :dbgp_thread_wrapper ]
dbgp_thread.at_catchpoint(context, excpt) unless dbgp_thread.nil?
end
def at_line(context, file, line)
log('at_line: ' + file + ':' + line.to_s)
if (in_debugger_code?(context))
log('stepover debugger code')
context.suspend unless context.status == AbstractContext::BREAK
context.step_over()
else
dbgp_thread = Thread.current[ :dbgp_thread_wrapper ]
dbgp_thread.at_line(context, file, line) unless dbgp_thread.nil?
end
end
def in_debugger_code?(context)
# Don't debug debugger :)
depth = get_stack_depth(context)
if (depth == 0)
return true
end
depth.times { |index|
sf = context.stack_frame(index)
file = sf.file
method = sf.method.to_s
if (method.index('XoredDebugger::') == 0 || !file.index(@debugger.get_debugger_id).nil?)
return true
end
}
false
end
# TODO: Why this is not printed by VM
def print_exception(ex)
message = ex.backtrace.delete_if { |s| s.index(@debugger.get_debugger_id) != nil }
message[0] += ': ' + ex.message + ' (' + ex.class.name + ')'
message.each_index {
|i| message[i] = (i==0 ? message[i] : "\t from " + message[i])
}
$stderr.write( message.join("\n")+"\n" )
end
end
end