class Metasm::Gui::DbgConsoleWidget

a widget that displays logs of the debugger, and a cli interface to the dbg

Attributes

cmd_help[RW]
cmd_history[RW]
commands[RW]
dbg[RW]
log[RW]
statusline[RW]

Public Instance Methods

add_log(l) click to toggle source
# File metasm/gui/debug.rb, line 1203
def add_log(l)
        @log << l.to_s
        @log.shift if log.length > @log_length
        redraw
end
click(x, y) click to toggle source
# File metasm/gui/debug.rb, line 520
def click(x, y)
        @caret_x = (x-1).to_i / @font_width - 1
        @caret_x = [[@caret_x, 0].max, @curline.length].min
        update_caret
end
cmd_dd(addr, dlen=nil, len=nil) click to toggle source

update the data window, or dump data to console if len given

# File metasm/gui/debug.rb, line 785
def cmd_dd(addr, dlen=nil, len=nil)
        if addr.kind_of? String
                s = addr.strip
                addr = solve_expr!(s) || @parent_widget.mem.curaddr
                if not s.empty?
                        s = s[1..-1] if s[0] == ,
                        len ||= solve_expr(s)
                end
        end

        if len
                while len > 0
                        data = @dbg.memory[addr, [len, 16].min]
                        le = (@dbg.cpu.endianness == :little)
                        data = '' if @dbg.memory.page_invalid?(addr)
                        case dlen
                        when nil; add_log "#{Expression[addr]}  #{data.unpack('C*').map { |c| '%02X' % c }.join(' ').ljust(2*16+15)}  #{data.tr("^\x20-\x7e", '.')}"
                        when 1;   add_log "#{Expression[addr]}  #{data.unpack('C*').map { |c| '%02X' % c }.join(' ')}"
                        when 2;   add_log "#{Expression[addr]}  #{data.unpack(le ? 'v*' : 'n*').map { |c| '%04X' % c }.join(' ')}"
                        when 4;   add_log "#{Expression[addr]}  #{data.unpack(le ? 'V*' : 'N*').map { |c| '%08X' % c }.join(' ')}"
                        when 8;   add_log "#{Expression[addr]}  #{data.unpack('Q*').map { |c| '%016X' % c }.join(' ')}"
                        end
                        addr += 16
                        len -= 16
                end
        else
                if dlen
                        @parent_widget.mem.view(:hex).data_size = dlen
                        @parent_widget.mem.view(:hex).resized
                        @parent_widget.mem.showview(:hex)
                end
                @parent_widget.mem.focus_addr(solve_expr(addr))
                @parent_widget.mem.gui_update
        end
end
doubleclick(x, y) click to toggle source
# File metasm/gui/debug.rb, line 526
def doubleclick(x, y)
        # TODO real copy/paste
        # for now, copy the line under the dblclick
        y -= height % @font_height
        y = y.to_i / @font_height
        hc = height / @font_height
        if y == hc - 1
                txt = @statusline
        elsif y == hc - 2
                txt = @curline
        else
                txt = @log.reverse[@log_offset + hc - y - 3].to_s
        end
        clipboard_copy(txt)
end
gui_update() click to toggle source
# File metasm/gui/debug.rb, line 1209
def gui_update
        redraw
end
handle_command() click to toggle source
# File metasm/gui/debug.rb, line 1176
def handle_command
        add_log(":#@curline")
        return if @curline == ''
        @cmd_history << @curline
        @cmd_history.shift if @cmd_history.length > @cmd_history_length
        @log_offset = 0
        cmd = @curline
        @curline = ''
        @caret_x = 0

        run_command(cmd)
end
init_commands() click to toggle source
# File metasm/gui/debug.rb, line 821
def init_commands
        @commands = {}
        @cmd_help = {}
        p = @parent_widget
        new_command('help') { add_log @commands.keys.sort.join(' ') } # TODO help <subject>
        new_command('d', 'focus data window on an address') { |arg| cmd_dd(arg) }
        new_command('db', 'dump/focus bytes in data window')  { |arg| cmd_dd(arg, 1) }
        new_command('dw', 'dump/focus words in data window')  { |arg| cmd_dd(arg, 2) }
        new_command('dd', 'dump/focus dwords in data window') { |arg| cmd_dd(arg, 4) }
        new_command('dq', 'dump/focus qwords in data window') { |arg| cmd_dd(arg, 8) }
        new_command('dc', 'focus C struct in data window: <name> <addr>') { |arg|
                name, addr = arg.strip.split(/\s+/, 2)
                addr = (addr ? solve_expr(addr) : @parent_widget.mem.curaddr)
                @parent_widget.mem.focus_addr(addr, :cstruct, false, name)
        }
        new_command('dC', 'dump C struct: dC <name> <addr>') { |arg|
                name, addr = arg.strip.split(/\s+/, 2)
                addr = (addr ? solve_expr(addr) : @parent_widget.mem.curaddr)
                if st = @dbg.disassembler.c_parser.decode_c_struct(name, @dbg.memory, addr)
                        add_log st.to_s.gsub("\t", '  ')
                end
        }
        new_command('u', 'focus code window on an address') { |arg| p.code.focus_addr(solve_expr(arg)) }
        new_command('.', 'focus code window on current address') { p.code.focus_addr(solve_expr(@dbg.register_pc.to_s)) }
        new_command('wc', 'set code window height') { |arg|
                if arg == ''
                        p.code.curview.grab_focus
                else
                        p.resize_child(p.code, width, arg.to_i*@font_height)
                end
        }
        new_command('wd', 'set data window height') { |arg|
                if arg == ''
                        p.mem.curview.grab_focus
                else
                        p.resize_child(p.mem, width, arg.to_i*@font_height)
                end
        }
        new_command('wp', 'set console window height') { |arg|
                if arg == ''
                        grab_focus
                else
                        p.resize_child(self, width, arg.to_i*@font_height)
                end
        }
        new_command('width', 'set window width (chars)') { |arg|
                if a = solve_expr(arg); p.win.width = a*@font_width
                else add_log "width #{p.win.width/@font_width}"
                end
        }
        new_command('height', 'set window height (chars)') { |arg|
                if a = solve_expr(arg); p.win.height = a*@font_height
                else add_log "height #{p.win.height/@font_height}"
                end
        }
        new_command('continue', 'run', 'let the target run until something occurs') { p.dbg_continue }
        new_command('stepinto', 'singlestep', 'run a single instruction of the target') { p.dbg_singlestep }
        new_command('stepover', 'run a single instruction of the target, do not enter into subfunctions') { p.dbg_stepover }
        new_command('stepout', 'stepover until getting out of the current function') { p.dbg_stepout }
        new_command('bpx', 'set a breakpoint') { |arg|
                arg =~ /^(.*?)( once)?(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/
                e, o, c, a = $1, $2, ($3 || $5), $4
                o = o ? true : false
                cd = parse_expr(c) if c
                cb = lambda { a.split(';').each { |aaa| run_command(aaa) } } if a
                @dbg.bpx(solve_expr(e), o, cd, &cb)
        }
        new_command('hwbp', 'set a hardware breakpoint (hwbp 0x2345 w)') { |arg|
                arg =~ /^(.*?)( once)?( [rwx])?(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/
                e, o, t, c, a = $1, $2, $3, ($4 || $6), $5
                o = o ? true : false
                t = (t || 'x').strip.to_sym
                cd = parse_expr(c) if c
                cb = lambda { a.split(';').each { |aaa| run_command(aaa) } } if a
                @dbg.hwbp(solve_expr(e), t, 1, o, cd, &cb)
        }
        new_command('bpm', 'set a hardware memory breakpoint: bpm r 0x4800ff 16') { |arg|
                arg =~ /^(.*?)(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/
                e, c, a = $1, ($2 || $4), $3
                cd = parse_expr(c) if c
                cb = lambda { a.split(';').each { |aaa| run_command(aaa) } } if a
                raise 'bad syntax: bpm r|w|x addr [len]' unless e =~ /^([rwx]) (.*)/
                mode = $1.downcase.to_sym
                e = $2
                exp = solve_expr!(e)
                len = solve_expr(e) if e != ''
                len ||= 1
                @dbg.bpm(exp, mode, len, false, cd, &cb)
        }
        new_command('g', 'wait until target reaches the specified address') { |arg|
                arg =~ /^(.*?)(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/
                e, c, a = $1, ($2 || $4), $3
                cd = parse_expr(c) if c
                cb = lambda { a.split(';').each { |aaa| run_command(aaa) } } if a
                @dbg.bpx(solve_expr(e), true, cd, &cb) if arg
                p.dbg_continue
        }
        new_command('refresh', 'redraw', 'update', 'update the target memory/register cache') {
                @dbg.invalidate
                @dbg.dasm_invalidate
                p.gui_update
        }
        new_command('bl', 'list breakpoints') {
                @bl = []
                @dbg.all_breakpoints.each { |b|
                        add_log "#{@bl.length} #{@dbg.addrname!(b.address)} #{b.type} #{b.state}#{" if #{b.condition}" if b.condition}"
                        @bl << b
                }
        }
        new_command('bc', 'clear breakpoints') { |arg|
                @bl ||= @dbg.all_breakpoints
                if arg == '*'
                        @bl.each { |b| @dbg.del_bp(b) }
                else
                        next if not i = solve_expr(arg)
                        if b = @bl[i]
                                @dbg.del_bp(b)
                        end
                end
        }
        new_command('break', 'interrupt a running target') { |arg| @dbg.break ; p.post_dbg_run }
        new_command('kill', 'kill the target') { |arg| @dbg.kill(arg) ; p.post_dbg_run }
        new_command('detach', 'detach from the target') { @dbg.detach ; p.post_dbg_run }
        new_command('r', 'read/write the content of a register') { |arg|
                reg, val = arg.split(/\s+|\s*=\s*/, 2)
                if reg == 'fl'
                        @dbg.toggle_flag(val.to_sym)
                elsif not reg
                        @dbg.register_list.each { |r|
                                add_log "#{r} = #{Expression[@dbg.get_reg_value(r)]}"
                        }
                elsif not val
                        add_log "#{reg} = #{Expression[@dbg.get_reg_value(reg.to_sym)]}"
                else
                        @dbg.set_reg_value(reg.to_sym, solve_expr(val))
                end
                p.regs.gui_update
        }
        new_command('ma', 'memory_ascii', 'write memory (ascii) - ma <addr> foo bar') { |arg|
                next if not addr = solve_expr!(arg)
                data = arg.strip
                @dbg.memory[addr, data.length] = data
                @dbg.invalidate
                @dbg.dasm_invalidate
                p.gui_update
        }
        new_command('mx', 'memory_hex', 'write memory (hex) - mx <addr> 0011223344') { |arg|
                next if not addr = solve_expr!(arg)
                data = [arg.delete(' ')].pack('H*')
                @dbg.memory[addr, data.length] = data
                @dbg.invalidate
                @dbg.dasm_invalidate
                p.gui_update
        }
        new_command('?', 'display a value') { |arg|
                next if not v = solve_expr(arg)
                add_log "#{v} 0x#{v.to_s(16)} #{[v & 0xffff_ffff].pack('L').inspect} #{@dbg.addrname!(v)}"
        }
        new_command('exit', 'quit', 'quit the debugger interface') { p.win.destroy }
        new_command('ruby', 'execute arbitrary ruby code') { |arg|
                case ret = eval(arg)
                when nil, true, false, Symbol; add_log ret.inspect
                when String; add_log ret[0, 64].inspect
                when Integer, Expression; add_log Expression[ret].to_s
                else add_log "#<#{ret.class}>"
                end
        }
        new_command('loadsyms', 'load symbols from a mapped module') { |arg|
                if not arg.empty? and arg = (solve_expr(arg) rescue arg)
                        @dbg.loadsyms(arg)
                else
                        @dbg.loadallsyms { |a|
                                @statusline = "loading symbols from #{Expression[a]}"
                                redraw
                                Gui.main_iter
                        }
                end
                p.gui_update
        }
        new_command('scansyms', 'scan target memory for loaded modules') {
                if defined? @scan_addr and @scan_addr
                        add_log 'scanning @%08x' % @scan_addr
                        next
                end
                @scan_addr = 0
                Gui.idle_add {
                        if @scan_addr <= 0xffff_f000        # cpu.size?
                                protect { @dbg.loadsyms(@scan_addr) }
                                @scan_addr += 0x1000
                                true
                        else
                                add_log 'scansyms finished'
                                @scan_addr = nil
                                p.gui_update
                                nil
                        end
                }
        }
        new_command('symbol', 'display information on symbols') { |arg|
                arg = arg.to_s.downcase
                @dbg.symbols.map { |k, v| an = @dbg.addrname(k) ; [k, an] if an.downcase.include? arg }.compact.sort_by { |k, v| v.downcase }.each { |k, v|
                        add_log "#{Expression[k]} #{@dbg.addrname(k)}"
                }
        }
        new_command('maps', 'show file mappings from parsed modules') { |arg|
                want = arg.to_s.downcase
                want = nil if want == ''
                @dbg.modulemap.map { |n, (a_b, a_e)|
                        [a_b, "#{Expression[a_b]}-#{Expression[a_e]} #{n}"] if not want or n.downcase.include?(want)
                }.compact.sort.each { |s1, s2|
                        add_log s2
                }
        }
        new_command('rawmaps', 'show OS file mappings') { |arg|
                # XXX listwindow
                @dbg.mappings.sort.each { |a, l, *i|
                        foo = i*' '
                        next if arg.to_s != '' and foo !~ /#{arg}/
                        add_log "%08x %06x %s" % [a, l, i*' ']
                }
        }
        new_command('add_symbol', 'add a symbol name') { |arg|
                name, val = arg.to_s.split(/\s+/, 2)
                val = solve_expr(val)
                if val.kind_of? Integer
                        @dbg.symbols[val] = name
                        @dbg.disassembler.set_label_at(val, name)
                        p.gui_update
                end
        }
        new_command('bt', 'backtrace', 'stacktrace', 'bt [limit] - show a stack trace from current pc') { |arg|
                arg = solve_expr(arg) if arg
                arg = 500 if not arg.kind_of? ::Integer
                @dbg.stacktrace(arg) { |a, s| add_log "#{Expression[a]} #{s}" }
        }
        new_command('dasm', 'disassemble_fast', 'disassembles from an address') { |arg|
                addr = solve_expr(arg)
                dasm = @dbg.disassembler
                dasm.disassemble_fast(addr)
                dasm.function_blocks(addr).keys.sort.each { |a|
                        next if not di = dasm.di_at(a)
                        dasm.dump_block(di.block) { |l| add_log l }
                }
                p.gui_update
        }
        new_command('save_hist', 'save the command buffer to a file') { |arg|
                File.open(arg, 'w') { |fd| fd.puts @log }
        }

        new_command('watch', 'follow an expression in the data view (none to delete)') { |arg|
                if not arg
                        add_log p.watchpoint[p.mem].to_s
                elsif arg == 'nil' or arg == 'none' or arg == 'delete'
                        p.watchpoint.delete p.mem
                else
                        p.watchpoint[p.mem] = parse_expr(arg)
                end
        }

        new_command('list_pid', 'list pids currently debugged') { |arg|
                add_log @dbg.list_debug_pids.sort.map { |pp| pp == @dbg.pid ? "*#{pp}" : pp }.join(' ')
        }
        new_command('list_tid', 'list tids currently debugged') { |arg|
                add_log @dbg.list_debug_tids.sort.map { |tt| tt == @dbg.tid ? "*#{tt}" : tt }.join(' ')
        }

        new_command('list_processes', 'list processes available for debugging') { |arg|
                @dbg.list_processes.each { |pp|
                        add_log "#{pp.pid} #{pp.path}"
                }
        }
        new_command('list_threads', 'list thread ids of the current process') { |arg|
                @dbg.list_threads.each { |t|
                        stf = { :state => @dbg.state, :info => @dbg.info } if t == @dbg.tid
                        stf ||= @dbg.tid_stuff[t]
                        stf ||= {}
                        add_log "#{t} #{stf[:state]} #{stf[:info]}"
                }
        }

        new_command('pid', 'select a pid') { |arg|
                if pid = solve_expr(arg)
                        @dbg.pid = pid
                else
                        add_log "pid #{@dbg.pid}"
                end
        }
        new_command('tid', 'select a tid') { |arg|
                if tid = solve_expr(arg)
                        @dbg.tid = tid
                else
                        add_log "tid #{@dbg.tid} #{@dbg.state} #{@dbg.info}"
                end
        }

        new_command('exception_pass', 'pass the exception unhandled to the target on next continue') {
                @dbg.pass_current_exception
        }
        new_command('exception_handle', 'handle the exception, hide it from the target on next continue') {
                @dbg.pass_current_exception false
        }

        new_command('exception_pass_all', 'ignore all target exceptions') {
                @dbg.pass_all_exceptions = true
        }
        new_command('exception_handle_all', 'break on target exceptions') {
                @dbg.pass_all_exceptions = false
        }

        new_command('thread_events_break', 'break on thread creation/termination') {
                @dbg.ignore_newthread = false
                @dbg.ignore_endthread = false
        }
        new_command('thread_events_ignore', 'ignore thread creation/termination') {
                @dbg.ignore_newthread = true
                @dbg.ignore_endthread = true
        }

        new_command('trace_children', 'trace children of debuggee (0|1)') { |arg|
                arg = case arg.to_s.strip.downcase
                when '0', 'no', 'false'; false
                else true
                end
                add_log "trace children #{arg ? 'active' : 'inactive'}"
                # update the flag for future debugee
                @dbg.trace_children = arg
                # change current debugee setting if supported
                @dbg.do_trace_children if @dbg.respond_to?(:do_trace_children)
        }

        new_command('attach', 'attach to a running process') { |arg|
                if pr = @dbg.list_processes.find { |pp| pp.path.to_s.downcase.include?(arg.downcase) }
                        pid = pr.pid
                else
                        pid = solve_expr(arg)
                end
                @dbg.attach(pid)
        }
        new_command('create_process', 'create a new process and debug it') { |arg|
                @dbg.create_process(arg)
        }

        new_command('plugin', 'load', 'load a debugger plugin') { |arg|
                @dbg.load_plugin arg
                add_log "loaded plugin #{File.basename(arg, '.rb')}"
        }


        @dbg.ui_command_setup(self) if @dbg.respond_to? :ui_command_setup
end
initialize_visible() click to toggle source
# File metasm/gui/debug.rb, line 507
def initialize_visible
        grab_focus
        gui_update
end
initialize_widget(dbg, parent_widget) click to toggle source
# File metasm/gui/debug.rb, line 485
def initialize_widget(dbg, parent_widget)
        @dbg = dbg
        @parent_widget = parent_widget
        @dbg.gui = self

        @log = []
        @log_length = 4000
        @log_offset = 0
        @curline = ''
        @statusline = 'type \help\ for help'
        @cmd_history = ['']
        @cmd_history_length = 200     # number of past commands to remember
        @cmd_histptr = nil

        @dbg.set_log_proc { |l| add_log l }

        @default_color_association = ColorTheme.merge :log => :palegrey, :curline => :white, :caret => :yellow,
                :background => :black, :status => :black, :status_bg => '088'

        init_commands
end
keyboard_callback() click to toggle source
# File metasm/gui/debug.rb, line 1173
def keyboard_callback; @parent_widget.keyboard_callback end
keyboard_callback_ctrl() click to toggle source
# File metasm/gui/debug.rb, line 1174
def keyboard_callback_ctrl; @parent_widget.keyboard_callback_ctrl end
keypress(key) click to toggle source
# File metasm/gui/debug.rb, line 616
def keypress(key)
        case key
        when :left
                if @caret_x > 0
                        @caret_x -= 1
                        update_caret
                end
        when :right
                if @caret_x < @curline.length
                        @caret_x += 1
                        update_caret
                end
        when :up
                if not @cmd_histptr
                        if @curline != ''
                                @cmd_history << @curline
                                @cmd_histptr = 2
                        else
                                @cmd_histptr = 1
                        end
                else
                        @cmd_histptr += 1
                        @cmd_histptr = 1 if @cmd_histptr > @cmd_history.length
                end
                @curline = @cmd_history[-@cmd_histptr].dup
                @caret_x = @curline.length
                update_status_cmd
                redraw

        when :down
                if not @cmd_histptr
                        @cmd_history << @curline if @curline != ''
                        @cmd_histptr = @cmd_history.length
                else
                        @cmd_histptr -= 1
                        @cmd_histptr = @cmd_history.length if @cmd_histptr < 1
                end
                @curline = @cmd_history[-@cmd_histptr].dup
                @caret_x = @curline.length
                update_status_cmd
                redraw

        when :home
                @caret_x = 0
                update_caret
        when :end
                @caret_x = @curline.length
                update_caret

        when :pgup
                @log_offset += height/@font_height - 3
                redraw
        when :pgdown
                @log_offset -= height/@font_height - 3
                redraw

        when :tab
                # autocomplete
                if @caret_x > 0 and not @curline[0, @caret_x].index(\ ) and st = @curline[0, @caret_x] and not @commands[st]
                        keys = @commands.keys.find_all { |k| k[0, st.length] == st }
                        while st.length < keys.first.to_s.length and keys.all? { |k| k[0, st.length+1] == keys.first[0, st.length+1] }
                                st << keys.first[st.length]
                                @curline[@caret_x, 0] = st[-1, 1]
                                @caret_x += 1
                        end
                        update_status_cmd
                        redraw
                end

        when :enter
                @cmd_histptr = nil
                handle_command
                update_status_cmd
        when :esc
        when :delete
                if @caret_x < @curline.length
                        @curline[@caret_x, 1] = ''
                        update_status_cmd
                        redraw
                end
        when :backspace
                if @caret_x > 0
                        @caret_x -= 1
                        @curline[@caret_x, 1] = ''
                        update_status_cmd
                        redraw
                end

        when :insert
                if keyboard_state(:shift)
                        txt = clipboard_paste.to_s
                        @curline[@caret_x, 0] = txt
                        @caret_x += txt.length
                        update_status_cmd
                        redraw
                end

        when Symbol; return false     # avoid :shift cannot coerce to Int warning
        when \x20..\x7e
                @curline[@caret_x, 0] = key.chr
                @caret_x += 1
                update_status_cmd
                redraw

        else return false
        end
        true
end
keypress_ctrl(key) click to toggle source
# File metasm/gui/debug.rb, line 725
def keypress_ctrl(key)
        case key
        when v
                txt = clipboard_paste.to_s
                @curline[@caret_x, 0] = txt
                @caret_x += txt.length
                update_status_cmd
                redraw
        else return false
        end
        true
end
mouse_wheel(dir, x, y) click to toggle source
# File metasm/gui/debug.rb, line 557
def mouse_wheel(dir, x, y)
        case dir
        when :up; @log_offset += 3
        when :down; @log_offset -= 3
        end
        redraw
end
new_command(*cmd, &b) click to toggle source
# File metasm/gui/debug.rb, line 752
def new_command(*cmd, &b)
        hlp = cmd.pop if cmd.last.include? ' '
        cmd.each { |c|
                @cmd_help[c] = hlp || 'nodoc'
                @commands[c] = lambda { |*a| protect { b.call(*a) } }
        }
end
paint() click to toggle source
# File metasm/gui/debug.rb, line 565
def paint
        y = height

        render = lambda { |str, color|
                draw_string_color(color, 1, y, str)
                y -= @font_height
        }

        w_w = width

        y -= @font_height
        draw_rectangle_color(:status_bg, 0, y, w_w, @font_height)
        str = "#{@dbg.pid}:#{@dbg.tid} #{@dbg.state} #{@dbg.info}"
        draw_string_color(:status, w_w-str.length*@font_width-1, y, str)
        draw_string_color(:status, 1+@font_width, y, @statusline)
        y -= @font_height

        w_w_c = w_w/@font_width
        @caret_y = y
        if @caret_x < w_w_c-1
                render[':' + @curline, :curline]
        else
                render['~' + @curline[@caret_x-w_w_c+2, w_w_c], :curline]
        end

        l_nr = -1
        lastline = nil
        @log_offset = 0 if @log_offset < 0
        @log.reverse.each { |l|
                l.scan(/.{1,#{w_w/@font_width}}/).reverse_each { |l_|
                        lastline = l_
                        l_nr += 1
                        next if l_nr < @log_offset
                        render[l_, :log]
                }
                break if y < 0
        }
        if lastline and l_nr < @log_offset
                render[lastline, :log]
                @log_offset = l_nr-1
        end

        if focus?
                cx = [@caret_x+1, w_w_c-1].min*@font_width+1
                cy = @caret_y
                draw_line_color(:caret, cx, cy, cx, cy+@font_height-1)
        end

        @oldcaret_x = @caret_x
end
parse_expr(arg) click to toggle source

arg str -> expr value, with special codeptr/dataptr = code/data.curaddr

# File metasm/gui/debug.rb, line 761
def parse_expr(arg)
        parse_expr!(arg.dup)
end
parse_expr!(arg) click to toggle source
# File metasm/gui/debug.rb, line 765
def parse_expr!(arg)
        @dbg.parse_expr!(arg) { |e|
                case e.downcase
                when 'code_addr', 'codeptr'; @parent_widget.code.curaddr
                when 'data_addr', 'dataptr'; @parent_widget.mem.curaddr
                end
        }
end
rightclick(x, y) click to toggle source

copy/paste word under cursor (paste when on last line)

# File metasm/gui/debug.rb, line 543
def rightclick(x, y)
        y -= height % @font_height
        y = y.to_i / @font_height
        hc = height / @font_height
        x /= @font_width
        if y >= hc - 2
                keypress_ctrl v
        else
                txt = @log.reverse[@log_offset + hc - y - 3].to_s
                word = txt[0...x].to_s[/\w*$/] << txt[x..-1].to_s[/^\w*/]
                clipboard_copy(word)
        end
end
run_command(cmd) click to toggle source
# File metasm/gui/debug.rb, line 1189
def run_command(cmd)
        cmd = cmd.sub(/^\s+/, '')
        cn = cmd.split.first
        if not @commands[cn]
                a = @commands.keys.find_all { |k| k[0, cn.length] == cn }
                cn = a.first if a.length == 1
        end
        if pc = @commands[cn]
                pc[cmd.split(/\s+/, 2)[1].to_s]
        else
                add_log 'unknown command'
        end
end
solve_expr(arg) click to toggle source
# File metasm/gui/debug.rb, line 774
def solve_expr(arg)
        return arg if arg.kind_of? Integer
        solve_expr!(arg.dup)
end
solve_expr!(arg) click to toggle source
# File metasm/gui/debug.rb, line 779
def solve_expr!(arg)
        return if not e = parse_expr!(arg)
        @dbg.resolve_expr(e)
end
swapin_pid() click to toggle source
# File metasm/gui/debug.rb, line 516
def swapin_pid
        @parent_widget.swapin_pid
end
swapin_tid() click to toggle source
# File metasm/gui/debug.rb, line 512
def swapin_tid
        @parent_widget.swapin_tid
end
update_caret() click to toggle source

hint that the caret moved

# File metasm/gui/debug.rb, line 1214
def update_caret
        return if @oldcaret_x == @caret_x
        w_w = width - @font_width
        x1 = (@oldcaret_x+1) * @font_width + 1
        x2 = (@caret_x+1) * @font_width + 1
        y = @caret_y

        if x1 > w_w or x2 > w_w
                invalidate(0, y, 100000, @font_height)
        else
                invalidate(x1-1, y, 2, @font_height)
                invalidate(x2-1, y, 2, @font_height)
        end

        @oldcaret_x = @caret_x
end
update_status_cmd() click to toggle source
# File metasm/gui/debug.rb, line 738
def update_status_cmd
        st = @curline.split.first
        if @commands[st]
                @statusline = "#{st}: #{@cmd_help[st]}"
        else
                keys = @commands.keys.find_all { |k| k[0, st.length] == st } if st
                if keys and not keys.empty?
                        @statusline = keys.sort.join(' ')
                else
                        @statusline = 'type \help\ for help'
                end
        end
end
wrap_run(&b) click to toggle source
# File metasm/gui/debug.rb, line 1172
def wrap_run(&b) @parent_widget.wrap_run(&b) end