blob: 52be79cec0872aac72f0bbc4ae830ae2f64e56ac [file] [log] [blame]
###############################################################################
# Copyright (c) 2005, 2016 IBM Corporation and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0.
#
# SPDX-License-Identifier: EPL-2.0
#
###############################################################################
require 'monitor'
require 'common/Logger'
require 'debugger/AbstractContext'
require 'debugger/Exceptions'
module Kernel
def xored_debugger_current_method
caller[0] =~ /\d:in `([^']+)'/
$1
end
end
module XoredDebugger
class BasicContext < AbstractContext
include Logger
STOP_AT_ANY_DEPTH = -1
def initialize(thread)
@levels = []
@thread = thread
@suspended = false
@monitor = Monitor.new
@waitResumed = @monitor.new_cond
reset_stepping
end
def thread
@thread
end
def dead?
not @thread.alive?
end
def suspended?
@suspended
end
# Continuation Commands
def run()
if (@suspended)
@monitor.synchronize do
log('Requesting thread ' + @thread.object_id.to_s + ' to resume')
@suspended = false
@waitResumed.signal
end
else
raise OperationNotAvailableError
end
end
def step_into
@stepping = true
@stop_depth = STOP_AT_ANY_DEPTH
run
end
def step_over
@stepping = true
@stop_depth = stack_frames_num
run
end
def step_out
@stepping = true
@stop_depth = stack_frames_num - 1
run
end
def stop
begin
reset_stepping
run if @suspended
ensure
Kernel.exit!
end
nil
end
def suspend
if (!@suspended)
log('Requesting thread ' + @thread.object_id.to_s + ' to suspend')
@suspended = true
else
raise OperationNotAvailableError
end
end
# Evaluation
def eval(text, index)
frame = @levels[stack_frames_num - 1 - index]
if frame.nil?
log('frame ' + index.to_s + ' is nil ' + @levels.inspect)
return nil
end
binding = frame[ :binding ]
info = frame[ :info ]
Kernel.eval(text.to_s, binding, info.file, info.line)
end
# Stack depth
def stack_frames_num
@levels.length
end
# Stack level
def stack_frame(index)
frame = @levels[stack_frames_num - 1 - index]
return frame[ :info ]
end
# basic debugger specific methods
def stack_update(file, line, binding, label)
if (@levels.empty?)
stack_push(file, line, binding, label)
else
new_frame = {
:binding => binding,
:info => StackLevelInfo.new(file, line, label)
}
@levels[stack_frames_num - 1] = new_frame
end
end
def stack_push(file, line, binding, label)
frame = {
:binding => binding,
:info => StackLevelInfo.new(file, line, label)
}
@levels.push(frame)
end
def stack_pop
@levels.pop
if (@stepping && (@stop_depth >= stack_frames_num))
@stop_depth = STOP_AT_ANY_DEPTH
end
end
def check_suspended
if (Thread.current != @thread)
raise ThreadError, 'Context.check_suspended called from invalid thread'
end
@monitor.synchronize do
while (@suspended)
log('Suspending thread ' + @thread.object_id.to_s)
@waitResumed.wait
log('Resuming thread ' + @thread.object_id.to_s)
end
end
end
def check_stepping
depth = stack_frames_num
return (@stepping && (@stop_depth == STOP_AT_ANY_DEPTH || depth <= @stop_depth))
end
def reset_stepping
@stepping = false
@stop_depth = STOP_AT_ANY_DEPTH
end
end
end