class Metasm::Gui::DisasmWidget

the main disassembler widget: this is a container for all the lower-level widgets that actually render the dasm state

Attributes

bg_color_callback[RW]
clones[RW]
dasm[R]
entrypoints[RW]
focus_changed_callback[RW]
gui_update_counter_max[RW]
keyboard_callback[RW]
keyboard_callback_ctrl[RW]
parent_widget[RW]
pos_history[RW]
pos_history_redo[RW]
session_file[RW]

Public Instance Methods

add_comment(addr) click to toggle source

add/change a comment @addr

# File metasm/gui/dasm_main.rb, line 262
def add_comment(addr)
        cmt = @dasm.comment[addr].to_a.join(' ')
        if di = @dasm.di_at(addr)
                cmt += di.comment.to_a.join(' ')
        end
        inputbox("new comment for #{Expression[addr]}", :text => cmt) { |c|
                c = c.split("\n")
                c = nil if c == []
                do_add_comment(addr, c)
                session_append "do_add_comment(#{addr.inspect}, #{c.inspect})"
                gui_update
        }
end
clone_window(*focus) click to toggle source

creates a new dasm window with the same disassembler object, focus it on addr#win

# File metasm/gui/dasm_main.rb, line 835
def clone_window(*focus)
        return if not popup = DasmWindow.new
        popup.display(@dasm, @entrypoints)
        w = popup.dasm_widget
        w.bg_color_callback = @bg_color_callback if bg_color_callback
        w.keyboard_callback = @keyboard_callback
        w.keyboard_callback_ctrl = @keyboard_callback_ctrl
        w.clones = @clones.concat w.clones
        w.focus_addr(*focus)
        popup
end
curaddr() click to toggle source

returns the address of the item under the cursor in current view

# File metasm/gui/dasm_main.rb, line 111
def curaddr
        curview.current_address
end
curobj() click to toggle source

returns the object under the cursor in current view (@dasm.decoded)

# File metasm/gui/dasm_main.rb, line 116
def curobj
        curview.respond_to?(:curobj) ? curview.curobj : @dasm.decoded[curaddr]
end
dasm=(d) click to toggle source

when updating @dasm, also update dasm for all views

# File metasm/gui/dasm_main.rb, line 71
def dasm=(d)
        @dasm = d
        view_indexes.each { |v|
                w = view(v)
                w.dasm = d if w.respond_to?(:'dasm=')
        }
end
decompile(addr) click to toggle source

(re)decompile

# File metasm/gui/dasm_main.rb, line 317
def decompile(addr)
        session_append "decompile(#{addr.inspect})"
        if @dasm.c_parser and var = @dasm.c_parser.toplevel.symbol[addr] and (var.type.kind_of? C::Function or @dasm.di_at(addr))
                @dasm.decompiler.redecompile(addr)
                view(:decompile).curfuncaddr = nil
        end
        focus_addr(addr, :decompile)
end
disassemble(addr) click to toggle source

disassemble from this point if points to a call, make it return

# File metasm/gui/dasm_main.rb, line 286
def disassemble(addr)
        session_append "disassemble(#{addr.inspect}) ; wait_disassemble_bg"
        if di = @dasm.di_at(addr) and di.opcode.props[:saveip]
                di.block.each_to_normal { |t|
                        t = @dasm.normalize t
                        next if not @dasm.decoded[t]
                        @dasm.function[t] ||= @dasm.function[:default] ? @dasm.function[:default].dup : DecodedFunction.new
                }
                di.block.add_to_subfuncret(di.next_addr)
                @dasm.addrs_todo << { :addr => di.next_addr, :from => addr, :from_subfuncret => true }
        elsif addr
                @entrypoints << addr
        end
        start_disassemble_bg
end
disassemble_fast(addr) click to toggle source

disassemble fast from this point (don't dasm subfunctions, don't backtrace)

# File metasm/gui/dasm_main.rb, line 303
def disassemble_fast(addr)
        @dasm.disassemble_fast(addr)
        session_append "dasm.disassemble_fast(#{addr.inspect})"
        gui_update
end
disassemble_fast_deep(addr) click to toggle source

disassemble fast & deep from this point (don't backtrace, but still dasm subfuncs)

# File metasm/gui/dasm_main.rb, line 310
def disassemble_fast_deep(addr)
        @dasm.disassemble_fast_deep(addr)
        session_append "dasm.disassemble_fast_deep(#{addr.inspect})"
        gui_update
end
do_add_comment(addr, c) click to toggle source
# File metasm/gui/dasm_main.rb, line 276
def do_add_comment(addr, c)
        if di = @dasm.di_at(addr)
                di.comment = c
        else
                @dasm.comment[addr] = c
        end
end
do_gui_update() click to toggle source

ask the current view to update itself

# File metasm/gui/dasm_main.rb, line 232
def do_gui_update
        curview.gui_update if curview # invalidate all views ?
end
dragdropfile(f) click to toggle source
# File metasm/gui/dasm_main.rb, line 847
def dragdropfile(f)
        case f
        when /\.(c|h|cpp)$/; @dasm.parse_c_file(f)
        when /\.map$/; @dasm.load_map(f) ; gui_update
        when /\.rb$/; @dasm.load_plugin(f)
        else messagebox("unsupported file extension #{f}")
        end
end
extend_contextmenu(tg, menu, addr=nil) click to toggle source
# File metasm/gui/dasm_main.rb, line 862
def extend_contextmenu(tg, menu, addr=nil)
        if @parent_widget.respond_to?(:extend_contextmenu)
                @parent_widget.extend_contextmenu(tg, menu, addr)
        end
end
focus_addr(addr, viewidx=nil, quiet=false, *a) click to toggle source

display the specified address the display first searches in the current view if it cannot display the address, the listing, graph and decompile views are tried (in that order) the current focus address is saved in @pos_history (see focus_addr_back/redo) if quiet is false, a messagebox is popped if no view can display the address

# File metasm/gui/dasm_main.rb, line 175
def focus_addr(addr, viewidx=nil, quiet=false, *a)
        viewidx ||= curview_index || :listing
        return if not addr
        return if viewidx == curview_index and addr == curaddr and a.empty?
        oldpos = [curview_index, (curview.get_cursor_pos if curview)]
        views = [viewidx, oldpos[0]]
        views += [:listing, :graph, :decompile] & view_indexes
        if views.compact.uniq.find { |i|
                o_p = view(i).get_cursor_pos
                if (view(i).focus_addr(addr, *a) rescue nil)
                        view(i).gui_update if i != oldpos[0]
                        showview(i)
                        true
                else
                        view(i).set_cursor_pos o_p
                        a.clear
                        false
                end
        }
                @pos_history << oldpos if oldpos[0]  # ignore start focus_addr
                @pos_history_redo.clear
                session_append "@session_focus_addr = #{addr.inspect} ; @pos_history = #{@pos_history.inspect}"
                true
        else
                messagebox "Invalid address #{addr}" if not quiet
                if oldpos[0]
                        showview oldpos[0]
                        curview.set_cursor_pos oldpos[1]
                end
                false
        end
end
focus_addr_autocomplete(v, show_alt=true) click to toggle source

same as focus_addr, also understands partial label names if the partial part is ambiguous, show a listwindow with all matches (if show_alt)

# File metasm/gui/dasm_main.rb, line 558
def focus_addr_autocomplete(v, show_alt=true)
        if not focus_addr(v, nil, true)
                labels = @dasm.prog_binding.map { |k, vv|
                        [k, Expression[@dasm.normalize(vv)]] if k.downcase.include? v.downcase
                }.compact
                case labels.length
                when 0
                        ve = @dasm.normalize(Expression.parse(v))
                        focus_addr(v) if not focus_addr(ve, nil, true)
                when 1
                        focus_addr(labels[0][0])
                else
                        if labels.all? { |k, vv| vv == labels[0][1] }
                                focus_addr(labels[0][0])
                        elsif show_alt
                                labels.unshift ['name', 'addr']
                                listwindow("list of labels", labels) { |i| focus_addr i[1] }
                        end
                end
        end
end
focus_addr_back(val = @pos_history.pop) click to toggle source

focus on the last address seen before the last focus_addr

# File metasm/gui/dasm_main.rb, line 209
def focus_addr_back(val = @pos_history.pop)
        return if not val
        @pos_history_redo << [curview_index, curview.get_cursor_pos]
        showview val[0]
        curview.set_cursor_pos val[1]
        true
end
focus_addr_redo() click to toggle source

undo focus_addr_back

# File metasm/gui/dasm_main.rb, line 218
def focus_addr_redo
        if val = @pos_history_redo.pop
                @pos_history << [curview_index, curview.get_cursor_pos]
                showview val[0]
                curview.set_cursor_pos val[1]
        end
end
gui_update() click to toggle source

ask the current view to update itself and redraw (incl all cloned widgets)

# File metasm/gui/dasm_main.rb, line 227
def gui_update
        @clones.each { |c| c.do_gui_update }
end
initialize_widget(dasm, ep=[]) click to toggle source
# File metasm/gui/dasm_main.rb, line 38
def initialize_widget(dasm, ep=[])
        @dasm = dasm
        @dasm.gui = self
        ep = [ep] if not ep.kind_of? Array
        @entrypoints = ep
        @pos_history = []
        @pos_history_redo = []
        @keyboard_callback = {}
        @keyboard_callback_ctrl = {}
        @clones = [self]
        @parent_widget = nil
        @gui_update_counter_max = 100
        @dasm.callback_prebacktrace ||= lambda { Gui.main_iter }
        start_disassemble_bg

        addview :listing,   AsmListingWidget.new(@dasm, self)
        addview :graph,     GraphViewWidget.new(@dasm, self)
        addview :decompile, CdecompListingWidget.new(@dasm, self)
        addview :opcodes,   AsmOpcodeWidget.new(@dasm, self)
        addview :hex,       HexWidget.new(@dasm, self)
        addview :coverage,  CoverageWidget.new(@dasm, self)
        addview :funcgraph, FuncGraphViewWidget.new(@dasm, self)
        addview :cstruct,   CStructWidget.new(@dasm, self)

        view(:listing).grab_focus

        if ENV['METASM_DASM_PLUGINS']
                ENV['METASM_DASM_PLUGINS'].split(',').each { |p| @dasm.load_plugin p }
        end
end
inspect() click to toggle source
# File metasm/gui/dasm_main.rb, line 868
def inspect
        "<DisasmWidget @%x @dasm=#{dasm.inspect}>" % object_id
end
keep_focus_while() { || ... } click to toggle source

calls focus_addr(pre_yield_curaddr) after yield

# File metasm/gui/dasm_main.rb, line 242
def keep_focus_while
        addr = curaddr
        yield
        focus_addr curaddr if addr
end
keypress(key) click to toggle source
# File metasm/gui/dasm_main.rb, line 750
def keypress(key)
        return true if @keyboard_callback[key] and @keyboard_callback[key][key]
        case key
        when :enter; focus_addr curview.hl_word
        when :esc; focus_addr_back
        when ?/; inputbox('search word') { |w|
                        next unless curview.respond_to? :hl_word
                        next if w == ''
                        curview.hl_word = w
                        curview.hl_word_re = /(.*)(#{w})/
                        curview.redraw
                }
        when ?b; prompt_backtrace(curaddr)
        when ?c; disassemble(curaddr)
        when ?C; disassemble_fast(curaddr)
        when ?d; curobj.kind_of?(DecodedInstruction) ? toggle_expr_dec(curobj) : toggle_data(curaddr)
        when ?f; list_functions
        when ?g; prompt_goto
        when ?k; toggle_expr_str(curobj)
        when ?K; name_local_vars(curaddr)
        when ?l; list_labels
        when ?m; prompt_constant(curobj)
        when ?n; rename
        when ?o; toggle_expr_offset(curobj)
        when ?p; playpause_dasm
        when ?r; toggle_expr_char(curobj)
        when ?t; prompt_struct_ptr
        when ?v; $VERBOSE = ! $VERBOSE ; puts "#{'not ' if not $VERBOSE}verbose"      # toggle verbose flag
        when ?x; list_xrefs
        when ?;; add_comment(curaddr)

        when ?\ ; toggle_view(:listing)
        when :tab; toggle_view(:decompile)
        when ?j; curview.keypress(:down)
        #when ?k; curview.keypress(:up)
        else
                p key if $DEBUG
                return @parent_widget ? @parent_widget.keypress(key) : false
        end
        true
end
keypress_ctrl(key) click to toggle source
# File metasm/gui/dasm_main.rb, line 736
def keypress_ctrl(key)
        return true if @keyboard_callback_ctrl[key] and @keyboard_callback_ctrl[key][key]
        case key
        when :enter; focus_addr_redo
        when ?o; w = toplevel ; w.promptopen if w.respond_to? :promptopen
        when ?s; w = toplevel ; w.promptsave if w.respond_to? :promptsave
        when ?r; prompt_run_ruby
        when ?C; disassemble_fast_deep(curaddr)
        when ?f; prompt_search_decoded
        else return @parent_widget ? @parent_widget.keypress_ctrl(key) : false
        end
        true
end
list_bghilight(title, list, a={}, &b) click to toggle source

calls listwindow with the same argument, but also creates a new bg_color_callback that will color lines whose address is to be found in list in green the callback is put only for the duration of the listwindow, and is not reentrant.

# File metasm/gui/dasm_main.rb, line 251
def list_bghilight(title, list, a={}, &b)
        prev_colorcb = bg_color_callback
        addr_idx = a.delete(:bghilight_index) || 0
        hash = list[1..-1].inject({}) { |h, l| h.update Expression[l[addr_idx] || :unknown].reduce => true }
        @bg_color_callback = lambda { |addr| hash[addr] ? '0f0' : prev_colorcb ? prev_colorcb[addr] : nil }
        redraw
        popupend = lambda { @bg_color_callback = prev_colorcb ; redraw }
        listwindow(title, list, a.merge(:ondestroy => popupend), &b)
end
list_functions() click to toggle source
# File metasm/gui/dasm_main.rb, line 339
def list_functions
        list = [['name', 'addr']]
        @dasm.function.keys.each { |f|
                addr = @dasm.normalize(f)
                next if not @dasm.di_at(addr)
                list << [@dasm.get_label_at(addr), Expression[addr]]
        }
        title = "list of functions"
        listwindow(title, list) { |i| focus_addr i[1] }
end
list_labels() click to toggle source
# File metasm/gui/dasm_main.rb, line 350
def list_labels
        list = [['name', 'addr']]
        @dasm.prog_binding.each { |k, v|
                list << [k, Expression[@dasm.normalize(v)]]
        }
        listwindow("list of labels", list) { |i| focus_addr i[1] }
end
list_sections() click to toggle source
# File metasm/gui/dasm_main.rb, line 358
def list_sections
        list = [['addr', 'length', 'name', 'info']]
        @dasm.section_info.each { |n,a,l,i|
                list << [Expression[a], Expression[l], n, i]
        }
        listwindow("list of sections", list) { |i| focus_addr i[0] if i[0] != '0' or @dasm.get_section_at(0) }
end
list_strings() click to toggle source
# File metasm/gui/dasm_main.rb, line 366
def list_strings
        list = [['addr', 'string', 'length']]
        @dasm.strings_scan { |o, str|
                list << [Expression[o], str[0, 24].inspect, str.length]
        }
        listwindow("list of strings", list) { |i| focus_addr i[0] }
end
list_xrefs(addr=nil) click to toggle source
# File metasm/gui/dasm_main.rb, line 374
def list_xrefs(addr=nil)
        list = [['address', 'type', 'instr']]
        if not addr and pointed_localvar
                addr = curview.hl_word
                faddr = @dasm.find_function_start(curaddr)
                func = @dasm.function[faddr]
                if func and func.localvars_xrefs
                        stoff = func.localvars.index(addr)
                        func.localvars_xrefs[stoff].to_a.each { |a|
                                list << [Expression[a], '?']
                                if di = @dasm.di_at(a)
                                        list.last << di.instruction
                                end
                        }
                end
        else
                addr ||= pointed_addr
                @dasm.each_xref(addr) { |xr|
                        next if not xr.origin
                        list << [Expression[xr.origin], "#{xr.type}#{xr.len}"]
                        if di = @dasm.di_at(xr.origin)
                                list.last << di.instruction
                        end
                }
        end
        if list.length == 1
                messagebox "no xref to #{Expression[addr]}" if addr
        else
                listwindow("list of xrefs to #{Expression[addr]}", list) { |i| focus_addr(i[0], nil, true) }
        end
end
name_local_vars(a) click to toggle source
# File metasm/gui/dasm_main.rb, line 715
def name_local_vars(a)
        @dasm.name_local_vars(a)
        session_append "dasm.name_local_vars(#{a.inspect})"
        gui_update
end
normalize(addr) click to toggle source

parse an address and change it to a canonical address form supported formats: label names, or string with numerical value, incl hex (0x42 and 42h) if the string is full decimal, a check against mapped space is done to find if it is hexadecimal (eg 08048000)

# File metasm/gui/dasm_main.rb, line 144
def normalize(addr)
        case addr
        when ::String
                if @dasm.prog_binding[addr]
                        addr = @dasm.prog_binding[addr]
                elsif (?0..?9).include? addr[0] or (?a..?f).include? addr.downcase[0]
                        case addr
                        when /^0x/i
                        when /h$/i; addr = '0x' + addr[0...-1]
                        when /[a-f]/i; addr = '0x' + addr
                        when /^[0-9]+$/
                                addr = '0x' + addr if not @dasm.get_section_at(addr.to_i) and
                                                          @dasm.get_section_at(addr.to_i(16))
                        end
                        begin
                                addr = Integer(addr)
                        rescue ::ArgumentError
                                return
                        end
                else
                        return
                end
        end
        addr
end
playpause_dasm() click to toggle source

pause/play disassembler returns true if playing this empties @dasm.addrs_todo, the dasm may still continue to work if this msg is

handled during an instr decoding/backtrace (the backtrace may generate new addrs_todo)

addresses in addrs_todo pointing to existing decoded instructions are left to create a prettier graph

# File metasm/gui/dasm_main.rb, line 669
def playpause_dasm
        @dasm_pause ||= []
        if @dasm_pause.empty? and @dasm.addrs_todo.empty?
                true
        elsif @dasm_pause.empty?
                @dasm_pause = @dasm.addrs_todo.dup
                @dasm.addrs_todo.replace @dasm_pause.find_all { |a| @dasm.decoded[@dasm.normalize(a[:addr])] }
                @dasm_pause -= @dasm.addrs_todo
                puts "dasm paused (#{@dasm_pause.length})"
        else
                @dasm.addrs_todo.concat @dasm_pause
                @dasm_pause.clear
                puts "dasm restarted (#{@dasm.addrs_todo.length})"
                start_disassemble_bg
                true
        end
end
pointed_addr() click to toggle source

returns the address of the label under the cursor or the address of the line of the cursor

# File metasm/gui/dasm_main.rb, line 121
def pointed_addr
        hl = curview.hl_word
        if hl =~ /^[0-9].*h$/ and a = hl.to_i(16) and @dasm.get_section_at(a)
                return a
        end
        @dasm.prog_binding[hl] || curview.current_address
end
pointed_localvar(obj=curobj, hl=curview.hl_word) click to toggle source

returns the ExpressionString if the currently hilighted word is a :stackvar

# File metasm/gui/dasm_main.rb, line 130
def pointed_localvar(obj=curobj, hl=curview.hl_word)
        return if not obj.kind_of?(Renderable)
        localvar = nil
        obj.each_expr { |e|
                next unless e.kind_of?(ExpressionString)
                localvar = e if e.type == :stackvar and e.str == hl
        }
        localvar
end
prompt_backtrace(addr=curaddr) click to toggle source
# File metasm/gui/dasm_main.rb, line 413
def prompt_backtrace(addr=curaddr)
        inputbox('expression to backtrace', :text => curview.hl_word) { |e|
                expr = IndExpression.parse_string(e)
                bd = {}
                registers = (@dasm.cpu.dbg_register_list.map { |r| r.to_s } rescue [])
                expr.externals.grep(String).each { |w|
                        if registers.include? w.downcase
                                bd[w] = w.downcase.to_sym
                        end
                }
                expr = expr.bind(bd).reduce { |e_| e_.len ||= @dasm.cpu.size/8 if e_.kind_of? Indirection ; nil }

                log = []
                dasm.backtrace(expr, addr, :log => log)
                list = [['order', 'address', 'type', 'old value', 'value']]
                order = 0
                log.each { |t, *a|
                        order += 1
                        list << [('%03d' % order), Expression[a[-1]], t] rescue next
                        case t
                        when :start
                                list.last << a[0]
                        when :up
                                order -= 1
                                list.pop
                        when :di
                                list.last[-1] = "di #{@dasm.di_at(a[-1]).instruction rescue nil}"
                                list.last << a[1] << a[0]
                        when :func
                                list.last << a[1] << a[0]
                        when :found
                                list.pop
                                a[0].each { |e_| list << [('%03d' % (order += 1)), nil, :found, Expression[e_]] }
                        else
                                list.last << a[0] << a[1..-1].inspect
                        end
                }
                list_bghilight("backtrace #{expr} from #{Expression[addr]}", list, :bghilight_index => 1) { |i|
                        a = i[1].empty? ? i[3] : i[1]
                        focus_addr(a, nil, true)
                }
        }
end
prompt_c_struct(prompt, opts={}) { |name| ... } click to toggle source

prompts for a structure name, autocompletes to known structures, and/or display a listwindow with possible completions, yields the target structure name

# File metasm/gui/dasm_main.rb, line 505
def prompt_c_struct(prompt, opts={})
        inputbox(prompt, opts) { |st_name|
                stars = ''
                if opts[:allow_stars]
                        stars = st_name[/\**$/]
                        st_name[stars] = ''
                end

                # TODO propose typedef struct {} moo; too
                sh = @dasm.c_parser.toplevel.struct
                if sh[st_name].kind_of?(C::Union)
                        stn_list = [st_name]
                else
                        stn_list = sh.keys.grep(String).find_all { |k| sh[k].kind_of?(C::Union) }
                end

                if name = stn_list.find { |n| n == st_name } || stn_list.find { |n| n.downcase == st_name.downcase }
                        # single match
                        yield(name+stars)
                else
                        # try autocomplete
                        list = [['name']]
                        list += stn_list.sort.grep(/#{st_name}/i).map { |stn| [stn+stars] }
                        if list.length == 2
                                # single autocompletion
                                yield(list[1][0])
                        else
                                listwindow(prompt, list) { |ans|
                                        yield(ans[0])
                                }
                        end
                end
        }
end
prompt_constant(di=curobj) click to toggle source

prompt the contant to use in place of some numeric value

# File metasm/gui/dasm_main.rb, line 458
def prompt_constant(di=curobj)
        return if not di.kind_of?(DecodedInstruction)
        di.each_expr { |e|
                next unless e.kind_of?(Expression)
                if (e.lexpr.kind_of?(Integer) or e.lexpr.kind_of?(ExpressionString)) and
                                (!curview.hl_word or curview.hl_word == Expression[e.lexpr].to_s)
                        v = Expression[e.lexpr].reduce
                        lst = []
                        dasm.c_constants.each { |cn, cv, fm| lst << [cn, fm] if v == cv }
                        if not lst.empty?
                                default = Expression[v].to_s
                                lst << [default]
                                listwindow("constant for #{Expression[v]}", [['name', 'enum']] + lst) { |a|
                                        if a[0] == default
                                                e.lexpr = v
                                        else
                                                e.lexpr = ExpressionString.new(v, a[0], :constant)
                                        end
                                        session_append "if di = dasm.di_at(#{di.address.inspect}) ; di.each_expr { |e| e.lexpr = #{e.lexpr.inspect} if e.kind_of?(Expression) and e.lexpr and Expression[e.lexpr].reduce == #{v.inspect} } ; end"
                                        gui_update
                                }
                        end
                end
                if (e.rexpr.kind_of? Integer or e.rexpr.kind_of?(ExpressionString)) and
                                (!curview.hl_word or curview.hl_word == Expression[e.rexpr].to_s)
                        v = Expression[e.rexpr].reduce
                        lst = []
                        dasm.c_constants.each { |cn, cv, fm| lst << [cn, fm] if v == cv }
                        if not lst.empty?
                                default = Expression[v].to_s
                                lst << [default]
                                listwindow("constant for #{Expression[v]}", [['name', 'enum']] + lst) { |a|
                                        if a[0] == default
                                                e.rexpr = v
                                        else
                                                e.rexpr = ExpressionString.new(v, a[0], :constant)
                                        end
                                        session_append "if di = dasm.di_at(#{di.address.inspect}) ; di.each_expr { |e| e.rexpr = #{e.rexpr.inspect} if e.kind_of?(Expression) and e.rexpr and Expression[e.rexpr].reduce == #{v.inspect} } ; end"
                                        gui_update
                                }
                        end
                end
        }
end
prompt_goto() click to toggle source

jump to address

# File metasm/gui/dasm_main.rb, line 407
def prompt_goto
        inputbox('address to go', :text => Expression[curaddr]) { |v|
                focus_addr_autocomplete(v)
        }
end
prompt_parse_c_file() click to toggle source

parses a C header

# File metasm/gui/dasm_main.rb, line 581
def prompt_parse_c_file
        openfile('open C header') { |f|
                @dasm.parse_c_file(f) rescue messagebox("#{$!}\n#{$!.backtrace}")
        }
end
prompt_run_ruby() click to toggle source

run arbitrary ruby

# File metasm/gui/dasm_main.rb, line 588
def prompt_run_ruby
        inputbox('ruby code to eval()') { |c|
                messagebox eval(c).inspect[0, 512], 'eval'
                session_append "#eval #{c.inspect}"
        }
end
prompt_run_ruby_plugin() click to toggle source

run ruby plugin

# File metasm/gui/dasm_main.rb, line 596
def prompt_run_ruby_plugin
        openfile('ruby plugin') { |f| @dasm.load_plugin(f) }
end
prompt_search_decoded() click to toggle source

search for a regexp in dasm.decoded.to_s

# File metasm/gui/dasm_main.rb, line 601
def prompt_search_decoded
        inputbox('text to search in instrs (regex)', :text => curview.hl_word) { |pat|
                re = /#{pat}/i
                found = []
                @dasm.decoded.each { |k, v|
                        found << k if v.to_s =~ re
                }
                list = [['addr', 'str']] + found.map { |a| [Expression[a], @dasm.decoded[a].to_s] }
                list_bghilight("search result for /#{pat}/i", list) { |i| focus_addr i[0] }
        }
end
prompt_struct_ptr(reg=curview.hl_word, addr=curaddr) click to toggle source

prompt the struct to use for offset in a given instr

# File metasm/gui/dasm_main.rb, line 541
def prompt_struct_ptr(reg=curview.hl_word, addr=curaddr)
        return if not reg or not @dasm.cpu.register_symbols.find { |rs| rs.to_s == reg.to_s }
        reg = reg.to_sym

        di = @dasm.di_at(addr)
        return if not di.kind_of?(DecodedInstruction)

        prompt_c_struct("struct pointed by #{reg}", :allow_stars => true) { |st|
                # TODO store that info for the decompiler ?
                @dasm.trace_update_reg_structptr(addr, reg, st)
                session_append "dasm.trace_update_reg_structptr(#{addr.inspect}, #{reg.inspect}, #{st.inspect})"
                gui_update
        }
end
rebase(addr=nil) click to toggle source

calls the @dasm.rebase method to change the load base address of the current program

# File metasm/gui/dasm_main.rb, line 614
def rebase(addr=nil)
        if not addr
                inputbox('rebase address') { |a| rebase(Integer(a)) }
        else
                na = curaddr + dasm.rebase(addr)
                gui_update
                focus_addr na
        end
end
redraw() click to toggle source

redraw the window

# File metasm/gui/dasm_main.rb, line 237
def redraw
        curview.redraw
end
rename(what=nil) click to toggle source

prompts for a new name for what is under the cursor (or the current address)

# File metasm/gui/dasm_main.rb, line 625
def rename(what=nil)
        if not what and localvar = pointed_localvar
                addr = curaddr
                str = localvar.str.dup
                inputbox("new name for #{localvar}", :text => localvar.to_s) { |v|
                        if v =~ /^[a-z_][a-z0-9_]*$/i
                                localvar.str.replace v
                                session_append "pointed_localvar(dasm.decoded[#{addr.inspect}], #{str.inspect}).str.replace(#{v.inspect})"
                                gui_update
                        else messagebox("invalid local var name #{v.inspect}")
                        end
                }
                return
        end

        what ||= pointed_addr
        if @dasm.prog_binding[what] or old = @dasm.get_label_at(what)
                old ||= what
                inputbox("new name for #{old}", :text => old) { |v|
                        if v == ''
                                @dasm.del_label_at(what)
                                session_append "dasm.del_label_at(#{what.inspect})"
                        else
                                @dasm.rename_label(old, v)
                                session_append "dasm.rename_label(#{old.inspect}, #{v.inspect})"
                        end
                        gui_update
                }
        else
                inputbox("label name for #{Expression[what]}", :text => Expression[what]) { |v|
                        next if v == ''
                        @dasm.set_label_at(what, v)
                        @dasm.split_block(what)
                        session_append "dasm.set_label_at(#{what.inspect}, #{v.inspect}) ; dasm.split_block(#{what.inspect})"
                        gui_update
                }
        end
end
replay_session(filename) click to toggle source
# File metasm/gui/dasm_main.rb, line 797
def replay_session(filename)
        i = 0
        File.readlines(filename).each { |l|
                instance_eval l
                i += 1
        }
        focus_addr(@session_focus_addr) if @session_focus_addr
        puts "Session replay finished"
rescue ::Exception
        puts "Session replay: error on line #{i}: #{$!.class} #{$!}"
end
save_session(filename) click to toggle source
# File metasm/gui/dasm_main.rb, line 793
def save_session(filename)
        @session_file = filename
end
session_append(str) click to toggle source

append one line to the session file converts addresses to hex, deletes consecutive set_focus lines

# File metasm/gui/dasm_main.rb, line 811
def session_append(str)
        return if not session_file

        # convert decimal addrs to hex
        str = str.sub(/(\(|\[|= )(\d\d\d\d\d\d+)/) { $1 + ('0x%x' % $2.to_i) }

        @session_lastsz_setfocus ||= nil      # prevent warning
        if str =~ /^@session_focus_addr = / and @session_lastsz_setfocus
                # overwrite previous set_focus
                File.truncate(session_file, @session_lastsz_setfocus) if File.size(session_file) == @session_lastsz
                is_setfocus = true
        end

        File.open(session_file, 'a') { |fd| fd.puts str }

        @session_lastsz = File.size(session_file)
        @session_lastsz_setfocus = @session_lastsz if not is_setfocus

rescue
        @session_file = nil
        puts "Failed to save session, disabling (#{$!.class} #{$!})"
end
spawn_emudbg() click to toggle source
# File metasm/gui/dasm_main.rb, line 856
def spawn_emudbg
        edbg = EmuDebugger.new(@dasm)
        edbg.pc = curaddr
        DbgWindow.new(edbg)
end
start_disassemble_bg() click to toggle source

start an idle callback that will run one round of @dasm.disassemble_mainiter

# File metasm/gui/dasm_main.rb, line 80
def start_disassemble_bg
        return if @dasm.addrs_todo.empty? and @entrypoints.all? { |ep| @dasm.decoded[ep] }
        gui_update_counter = 0
        run = false
        Gui.idle_add {
                # metasm disassembler loop
                # update gui once in a while
                if run or not @entrypoints.empty? or not @dasm.addrs_todo.empty?
                        protect { run = @dasm.disassemble_mainiter(@entrypoints) }
                        gui_update_counter += 1
                        if gui_update_counter > @gui_update_counter_max
                                gui_update_counter = 0
                                gui_update
                        end
                        true
                else
                        gui_update
                        false
                end
        }
end
terminate() click to toggle source
# File metasm/gui/dasm_main.rb, line 106
def terminate
        @clones.delete self
end
toggle_data(addr) click to toggle source

change the format of displayed data under addr (byte, word, dword, qword) currently this is done using a fake empty xref

# File metasm/gui/dasm_main.rb, line 328
def toggle_data(addr)
        session_append "toggle_data(#{addr.inspect})"
        return if @dasm.decoded[addr] or not @dasm.get_section_at(addr)
        @dasm.add_xref(addr, Xref.new(nil, nil, 1)) if not @dasm.xrefs[addr]
        @dasm.each_xref(addr) { |x|
                x.len = {1 => 2, 2 => 4, 4 => 8}[x.len] || 1
                break
        }
        gui_update
end
toggle_expr_char(o) click to toggle source

toggles <41h> vs <'A'> display

# File metasm/gui/dasm_main.rb, line 688
def toggle_expr_char(o)
        @dasm.toggle_expr_char(o)
        session_append "dasm.toggle_expr_char(dasm.decoded[#{curaddr.inspect}])"
        gui_update
end
toggle_expr_dec(o) click to toggle source

toggle <10h> vs <16> display

# File metasm/gui/dasm_main.rb, line 695
def toggle_expr_dec(o)
        @dasm.toggle_expr_dec(o)
        session_append "dasm.toggle_expr_dec(dasm.decoded[#{curaddr.inspect}])"
        gui_update
end
toggle_expr_offset(o) click to toggle source

toggle <401000h> vs <'sub_fancyname'> in the current instr display

# File metasm/gui/dasm_main.rb, line 702
def toggle_expr_offset(o)
        @dasm.toggle_expr_offset(o)
        session_append "dasm.toggle_expr_offset(dasm.decoded[#{curaddr.inspect}])"
        gui_update
end
toggle_expr_str(o) click to toggle source

toggle constant/localvar names with raw value

# File metasm/gui/dasm_main.rb, line 709
def toggle_expr_str(o)
        @dasm.toggle_expr_str(o)
        session_append "dasm.toggle_expr_str(dasm.decoded[#{curaddr.inspect}])"
        gui_update
end
toggle_view(idx) click to toggle source
# File metasm/gui/dasm_main.rb, line 721
def toggle_view(idx)
        default = (idx == :graph ? :listing : :graph)
        # switch to idx ; if already in idx, use default
        focus_addr(curaddr, ((curview_index == idx) ? default : idx))
end
undefine_function(addr, incl_subfuncs = false) click to toggle source

undefines the whole function body

# File metasm/gui/dasm_main.rb, line 728
def undefine_function(addr, incl_subfuncs = false)
        list = []
        @dasm.each_function_block(addr, incl_subfuncs) { |b| list << b }
        list.each { |b| @dasm.undefine_from(b) }
        session_append "undefine_function(#{addr.inspect}, #{incl_subfuncs.inspect})"
        gui_update
end
wait_disassemble_bg() click to toggle source
# File metasm/gui/dasm_main.rb, line 102
def wait_disassemble_bg
        Gui.main_iter until @entrypoints.empty? and @dasm.addrs_todo.empty?
end