class Metasm::Gui::DbgWidget

TODO invalidate dbg.disassembler on selfmodifying code

Attributes

code[RW]
console[RW]
dbg[RW]
keyboard_callback[RW]
keyboard_callback_ctrl[RW]
mem[RW]
parent_widget[RW]
regs[RW]
watchpoint[RW]
win[RW]

Public Instance Methods

dbg_continue(*a) click to toggle source
# File metasm/gui/debug.rb, line 140
def dbg_continue(*a) wrap_run { @dbg.continue(*a) } end
dbg_singlestep(*a) click to toggle source
# File metasm/gui/debug.rb, line 141
def dbg_singlestep(*a) wrap_run { @dbg.singlestep(*a) } end
dbg_stepout(*a) click to toggle source
# File metasm/gui/debug.rb, line 143
def dbg_stepout(*a) wrap_run { @dbg.stepout(*a) } end
dbg_stepover(*a) click to toggle source
# File metasm/gui/debug.rb, line 142
def dbg_stepover(*a) wrap_run { @dbg.stepover(*a) } end
dragdropfile(f) click to toggle source
# File metasm/gui/debug.rb, line 207
def dragdropfile(f)
        case f
        when /\.(c|h|cpp)$/; @dbg.disassembler.parse_c_file(f)
        when /\.map$/; @dbg.load_map(f)
        when /\.rb$/; @dbg.load_plugin(f) ; @console.add_log "loaded plugin #{File.basename(f, '.rb')}"
        else messagebox("unsupported file extension #{f}")
        end
end
extend_contextmenu(tg, menu, addr=nil) click to toggle source
# File metasm/gui/debug.rb, line 216
def extend_contextmenu(tg, menu, addr=nil)
        if addr
                bm = tg.new_menu
                bl = @dbg.all_breakpoints(addr)
                if not bl.empty?
                        tg.addsubmenu(bm, '_clear breakpoint') { bl.each { |b| @dbg.del_bp(b) } }
                end
                tg.addsubmenu(bm, '_go here') { @dbg.bpx(addr, true) ; dbg_continue }
                tg.addsubmenu(bm, '_bpx') { @dbg.bpx(addr) }
                tg.addsubmenu(bm, 'bpm _read') { @dbg.hwbp(addr, :r, 1) }
                tg.addsubmenu(bm, 'bpm _write') { @dbg.hwbp(addr, :w, 1) }
                tg.addsubmenu(menu, '_bp', bm)
        end
        if @parent_widget.respond_to?(:extend_contextmenu)
                @parent_widget.extend_contextmenu(tg, menu, addr)
        end
end
gui_update() click to toggle source
# File metasm/gui/debug.rb, line 152
def gui_update
        @console.redraw
        @children.each { |c| c.gui_update }
end
initialize_widget(dbg) click to toggle source
# File metasm/gui/debug.rb, line 16
def initialize_widget(dbg)
        @dbg = dbg
        @keyboard_callback = {}
        @keyboard_callback_ctrl = {}
        @parent_widget = nil

        @regs = DbgRegWidget.new(dbg, self)
        @mem  = DisasmWidget.new(dbg.disassembler)
        @code = DisasmWidget.new(dbg.disassembler)    # after mem so that dasm.gui == @code
        @console = DbgConsoleWidget.new(dbg, self)
        @code.parent_widget = self
        @mem.parent_widget = self
        @dbg.disassembler.disassemble_fast(@dbg.pc)

        oldcb = @code.bg_color_callback
        @code.bg_color_callback = lambda { |a|
                if a == @dbg.pc
                        :red_bg
                        # TODO breakpoints & stuff
                elsif oldcb; oldcb[a]
                end
        }
        # TODO popup menu, set bp, goto here, show arg in memdump..

        @children = [@code, @mem, @regs]

        add @regs, 'expand' => false  # XXX
        add @mem
        add @code
        add @console

        @watchpoint = { @code => @dbg.register_pc }

        pc = @dbg.resolve_expr(@watchpoint[@code])
        graph = :graph if @dbg.disassembler.function_blocks(pc).to_a.length < 100
        @code.focus_addr(pc, graph, true)
        @mem.focus_addr(0, :hex, true)
end
keypress(key) click to toggle source
# File metasm/gui/debug.rb, line 73
def keypress(key)
        return true if @keyboard_callback[key] and @keyboard_callback[key][key]
        case key
        when :f5;  protect { dbg_continue }
        when :f10; protect { dbg_stepover }
        when :f11; protect { dbg_singlestep }
        when :f12; protect { dbg_stepout }
        when ?.; @console.grab_focus
        else return @parent_widget ? @parent_widget.keypress(key) : false
        end
        true
end
keypress_ctrl(key) click to toggle source
# File metasm/gui/debug.rb, line 86
def keypress_ctrl(key)
        return true if @keyboard_callback_ctrl[key] and @keyboard_callback_ctrl[key][key]
        case key
        when :f5;  protect { @dbg.pass_current_exception ; dbg.continue }
        else return @parent_widget ? @parent_widget.keypress_ctrl(key) : false
        end
        true
end
post_dbg_run() click to toggle source

TODO check_target always, incl when :stopped

# File metasm/gui/debug.rb, line 100
def post_dbg_run
        # focus currently stopped threads
        if @dbg.state == :running and tt = @dbg.tid_stuff.find { |tid, tstuff| tstuff[:state] != :running }
                @dbg.tid = tt[0]
        end

        want_redraw = true
        return if @idle_checking ||= nil      # load only one bg proc
        @idle_checking = true
        Gui.idle_add {
            protect {
                @dbg.check_target
                if @dbg.state == :running
                        redraw if want_redraw       # redraw once if the target is running (less flicker with singlestep)
                        want_redraw = false
                        sleep 0.01
                        next true
                end
                @idle_checking = false
                @dbg.dasm_invalidate
                @mem.gui_update
                @dbg.disassembler.sections.clear if @dbg.state == :dead
                @dbg.disassembler.disassemble_fast(@dbg.pc)
                @children.each { |c|
                        if wp = @watchpoint[c]
                                c.focus_addr @dbg.resolve_expr(wp), nil, true
                        end
                }
                redraw
                false
            }
        }
end
pre_dbg_run() click to toggle source
# File metasm/gui/debug.rb, line 95
def pre_dbg_run
        @regs.pre_dbg_run
end
prompt_attach(caption='choose target') click to toggle source
# File metasm/gui/debug.rb, line 157
def prompt_attach(caption='choose target')
        l = nil
        i = inputbox(caption) { |name|
                i = nil ; l.destroy if l and not l.destroyed?
                @dbg.attach(name)
        }

        # build process list in bg (exe name resolution takes a few seconds)
        list = [['pid', 'name']]
        list_pr = OS.current.list_processes
        Gui.idle_add {
                if pr = list_pr.shift
                        list << [pr.pid, pr.path] if pr.path
                        true
                elsif i
                        me = ::Process.pid.to_s
                        l = listwindow('running processes', list,
                                       :noshow => true,
                                       :color_callback => lambda { |le| [:grey, :palegrey] if le[0] == me }
                                      ) { |e|
                                              i.text = e[0]
                                              i.keypress(:enter) if l.destroyed?
                                      }
                                      l.x += l.width
                                      l.show
                                      false
                end
        } if not list_pr.empty?
end
prompt_createprocess(caption='choose path') click to toggle source
# File metasm/gui/debug.rb, line 187
def prompt_createprocess(caption='choose path')
        openfile(caption) { |path|
                path = '"' + path + '"' if @dbg.shortname == 'windbg' and path =~ /\s/
                inputbox('target args?', :text => path) { |pa|
                        @dbg.create_process(pa)
                }
        }
end
prompt_datawatch() click to toggle source
# File metasm/gui/debug.rb, line 196
def prompt_datawatch
        inputbox('data watch', :text => @watchpoint[@mem].to_s) { |e|
                case e
                when '', 'nil', 'none', 'delete'
                        @watchpoint.delete @mem
                else
                        @watchpoint[@mem] = @console.parse_expr(e)
                end
        }
end
redraw() click to toggle source
Calls superclass method
# File metasm/gui/debug.rb, line 145
def redraw
        super
        @console.redraw
        @regs.gui_update
        @children.each { |c| c.redraw }
end
swapin_pid() click to toggle source
# File metasm/gui/debug.rb, line 66
def swapin_pid
        @mem.dasm = @dbg.disassembler
        @code.dasm = @dbg.disassembler
        swapin_tid
        gui_update
end
swapin_tid() click to toggle source
# File metasm/gui/debug.rb, line 55
def swapin_tid
        @regs.swapin_tid
        @dbg.disassembler.disassemble_fast(@dbg.pc)
        @children.each { |c|
                if wp = @watchpoint[c]
                        c.focus_addr @dbg.resolve_expr(wp), nil, true
                end
        }
        redraw
end
wrap_run() { || ... } click to toggle source
# File metasm/gui/debug.rb, line 134
def wrap_run
        pre_dbg_run
        yield
        post_dbg_run
end