Class: Trepan::Core

Inherits:
Object
  • Object
show all
Includes:
Trace
Defined in:
app/core.rb

Overview

This class contains the Trepan core routines, such as an event processor which is responsible of handling what to do when an event is triggered.

See also ‘rdbgr’ the top-level Trepan class and command-line routine which ultimately will call this.

Constant Summary collapse

STEPPING_EVENT_MASK =

Synchronous events

LINE_EVENT_MASK     | CLASS_EVENT_MASK    | CALL_EVENT_MASK     |
RETURN_EVENT_MASK   | C_CALL_EVENT_MASK   | C_RETURN_EVENT_MASK |
INSN_EVENT_MASK     | BRKPT_EVENT_MASK    | YIELD_EVENT_MASK    |
LEAVE_EVENT_MASK    | SEND_EVENT_MASK
ASYNC_EVENT_MASK =
RAISE_EVENT_MASK    | VM_EVENT_MASK       | SWITCH_EVENT_MASK
CORE_DEFAULT_SETTINGS =
{
  :cmdproc_opts      => {},
  :debug_core_events => false,
  :hook_name         => :event_processor, # or :old_event_processor
  :step_count        => 0,                # Stop at next event
  :async_events      => ASYNC_EVENT_MASK,

  # Not sure what the "right" set really is. The below is just
  # a guess. Use "set events" or customize in ~/.trepanrc
  :step_events       =>  
#	(DEFAULT_EVENT_MASK | INSN_EVENT_MASK) &
	(DEFAULT_EVENT_MASK ) &
	~(C_CALL_EVENT_MASK | C_RETURN_EVENT_MASK | SEND_EVENT_MASK)
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(debugger, settings = {}) ⇒ Core

Returns a new instance of Core.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'app/core.rb', line 68

def initialize(debugger, settings={})
  @dbgr         = debugger
  @exception    = nil
  @mutex        = Mutex.new
  @settings     = CORE_DEFAULT_SETTINGS.merge(settings)

  @step_count   = @settings[:step_count]
  @step_events  = @settings[:step_events]
  @async_events = @settings[:async_events]
  @debug_events = @settings[:debug_core_events]

  hook_name     = @settings[:hook_name]
  @event_proc   = self.method(hook_name).to_proc
  @processor    = CmdProcessor.new(self, @settings[:cmdproc_opts])
  @unmaskable_events = %w(brkpt raise switch vm)
end

Instance Attribute Details

#async_eventsObject

Returns the value of attribute async_events.



16
17
18
# File 'app/core.rb', line 16

def async_events
  @async_events
end

#dbgrObject (readonly)

bitmask of asyncronous events - used all the time



18
19
20
# File 'app/core.rb', line 18

def dbgr
  @dbgr
end

#eventObject (readonly)

Returns the value of attribute event.



19
20
21
# File 'app/core.rb', line 19

def event
  @event
end

#event_procObject (readonly)

String - event which triggering event processor



21
22
23
# File 'app/core.rb', line 21

def event_proc
  @event_proc
end

#exceptionObject

Returns the value of attribute exception.



22
23
24
# File 'app/core.rb', line 22

def exception
  @exception
end

#frameObject (readonly)

Return exception to pass back. A ‘raise’ command can set this.



24
25
26
# File 'app/core.rb', line 24

def frame
  @frame
end

#hook_argObject (readonly)

‘arg’ passed from trace hook



25
26
27
# File 'app/core.rb', line 25

def hook_arg
  @hook_arg
end

#mutexObject

Returns the value of attribute mutex.



26
27
28
# File 'app/core.rb', line 26

def mutex
  @mutex
end

#processorObject

mutex to lock out other threads from entering debugger while we are in it.



28
29
30
# File 'app/core.rb', line 28

def processor
  @processor
end

#settingsObject (readonly)

Hash of things you can configure



29
30
31
# File 'app/core.rb', line 29

def settings
  @settings
end

#step_countObject

Returns the value of attribute step_count.



30
31
32
# File 'app/core.rb', line 30

def step_count
  @step_count
end

#step_eventsObject

Fixnum. Negative means no tracing, 0 means stop on next event, 1 means ignore one event. Step events gives the kind of things to count as a step.



34
35
36
# File 'app/core.rb', line 34

def step_events
  @step_events
end

#unmaskable_eventsObject

bitmask of events - used only when we are stepping



36
37
38
# File 'app/core.rb', line 36

def unmaskable_events
  @unmaskable_events
end

Instance Method Details

#debugger(prev_count = 0) ⇒ Object

Call this from inside the program you want to get a synchronous call to the debugger. set prev_count to the number of levels before the caller you want to skip.



162
163
164
165
166
167
168
169
# File 'app/core.rb', line 162

def debugger(prev_count=0)
  while @frame && @frame.type == 'IFUNC'
    @frame = @frame.prev
  end
  frame = RubyVM::Frame.current.prev(prev_count+1)
  @step_count = 0  # Make event processor stop
  event_processor('debugger-call', frame)
end

#event_processor(event, frame, arg = nil) ⇒ Object

A trace-hook processor with the interface a trace hook should have.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'app/core.rb', line 94

def event_processor(event, frame, arg=nil)

  return_exception = nil
  # FIXME: check for breakpoints or other unmaskable events. 
  # For now there are none.

  @mutex.synchronize do
    @frame = frame
    while @frame.type == 'IFUNC'
      @frame = @frame.prev
    end
    
    if @step_count > 0
      @step_count -= 1
      break
    elsif @step_count < 0 && ! @unmaskable_events.member?(event)
      break
    end

    @event    = event
    @hook_arg = arg
    
    ### debug:
    ### puts "#{frame.file[1]}:#{frame.source_location[0]}:in `#{frame.method}' #{event}" # if %w(line).member?(event)
    @processor.process_commands(@frame)
            
    # FIXME: There should be a Trace.event_mask which should return the first
    # mask that matches the given trace hook.
    if @step_count < 0
      # If we are continuing, no need to stop at stepping events.
      Trace.event_masks[0] &= ~STEPPING_EVENT_MASK 
    else
      # Set to trace only those events we are interested in.  
      
      # Don't step/trace into Ruby routines called from here in the code
      # below (e.g. "trace_hooks").
      step_count_save = step_count
      @step_count     = -1 
      
      unless @event_proc == dbgr.trace_filter.hook_proc
        dbgr.trace_filter.add_trace_func(@event_proc) 
        ## debug: p '+++1', @event_proc, dbgr.trace_filter.hook_proc
      end
      
      # FIXME: this doesn't work. Bug in rb-trace? 
      # Trace.event_masks[0] = @step_events | @async_events
      RubyVM::TraceHook::trace_hooks[0].event_mask = 
        @step_events | @async_events
      @step_count = step_count_save
    end
    
    # Nil out variables just in case...
    
    return_exception = @exception
    @frame = @event = @arg = @exception = nil
    
  end
  return return_exception 
end

#old_event_processor(event, file, line, id, bind, klass) ⇒ Object

A Ruby 1.8-style event processor. We don’t use file, line, id, bind.



155
156
157
# File 'app/core.rb', line 155

def old_event_processor(event, file, line, id, bind, klass)
  event_processor(event, RubyVM::Frame.current.prev)
end

#step_events_listObject



85
86
87
88
89
90
91
# File 'app/core.rb', line 85

def step_events_list
  if 0 == @step_events
    return nil
  else
    Trace.bitmask2events(@step_events).join(', ')
  end
end

#trace_var_processor(var_name, value) ⇒ Object

A trace-hook processor for ‘trace var’



172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'app/core.rb', line 172

def trace_var_processor(var_name, value)
  frame = RubyVM::Frame.current.prev(2)
  if 'CFUNC' == frame.type
    # Don't need the C call that got us here.
    prev = frame.prev
    frame = frame.prev if prev
  end

  # Stop future tracing into the debugger
  Thread.current.tracing = true  
  
  @step_count = 0  # Make event processor stop
  event_processor('trace-var', frame, [var_name, value])
end