<commit_before>#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 <NAME>
#
#    Licence is LGPL, see LICENCE in the top-level directory

require 'metasm/gui/dasm_main'

module Metasm
module Gui

# TODO invalidate dbg.disassembler on selfmodifying code
class DbgWidget < ContainerVBoxWidget
	attr_accessor :dbg, :console, :regs, :code, :mem, :win
	attr_accessor :watchpoint
	attr_accessor :parent_widget, :keyboard_callback, :keyboard_callback_ctrl
	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
				'f88'
				# 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)
		@mem.focus_addr(0, :hex)
	end

	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

	def swapin_pid
		@mem.dasm = @dbg.disassembler
		@code.dasm = @dbg.disassembler
		swapin_tid
		gui_update
	end

	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

	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

	def pre_dbg_run
		@regs.pre_dbg_run
	end

	# TODO check_target always, incl when :stopped
	def post_dbg_run
		want_redraw = true
		return if @idle_checking ||= nil	# load only one bg proc
		@idle_checking = true
		Gui.idle_add {
			@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

	def wrap_run
		pre_dbg_run
		yield
		post_dbg_run
	end

	def dbg_continue(*a) wrap_run { @dbg.continue(*a) } end
	def dbg_singlestep(*a) wrap_run { @dbg.singlestep(*a) } end
	def dbg_stepover(*a) wrap_run { @dbg.stepover(*a) } end
	def dbg_stepout(*a) wrap_run { @dbg.stepout(*a) } end

	def redraw
		super
		@console.redraw
		@regs.gui_update
		@children.each { |c| c.redraw }
	end

	def gui_update
		@console.redraw
		@children.each { |c| c.gui_update }
	end

	def prompt_attach(caption='chose target')
		l = nil
		i = inputbox(caption) { |name|<commit_msg>gui/dbg: protect post_run stuff<commit_after>#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 <NAME>
#
#    Licence is LGPL, see LICENCE in the top-level directory

require 'metasm/gui/dasm_main'

module Metasm
module Gui

# TODO invalidate dbg.disassembler on selfmodifying code
class DbgWidget < ContainerVBoxWidget
	attr_accessor :dbg, :console, :regs, :code, :mem, :win
	attr_accessor :watchpoint
	attr_accessor :parent_widget, :keyboard_callback, :keyboard_callback_ctrl
	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
				'f88'
				# 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)
		@mem.focus_addr(0, :hex)
	end

	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

	def swapin_pid
		@mem.dasm = @dbg.disassembler
		@code.dasm = @dbg.disassembler
		swapin_tid
		gui_update
	end

	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

	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

	def pre_dbg_run
		@regs.pre_dbg_run
	end

	# TODO check_target always, incl when :stopped
	def post_dbg_run
		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

	def wrap_run
		pre_dbg_run
		yield
		post_dbg_run
	end

	def dbg_continue(*a) wrap_run { @dbg.continue(*a) } end
	def dbg_singlestep(*a) wrap_run { @dbg.singlestep(*a) } end
	def dbg_stepover(*a) wrap_run { @dbg.stepover(*a) } end
	def dbg_stepout(*a) wrap_run { @dbg.stepout(*a) } end

	def redraw
		super
		@console.redraw
		@regs.gui_update
		@children.each { |c| c.redraw }
	end

	def gui_update
		@console.redraw
		@children.each { |c| c.gui_update }
	end

	def prompt_attach(caption='chose target')
		l = nil
		i = inputbox(caption) { |name|
{'fraction_non_alphanumeric': 0.1099476439790576, 'fraction_numerical': 0.006544502617801047, 'mean_word_length': 3.7459627329192546, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2054083', 'n_tokens_mistral': 3232, 'n_tokens_neox': 2900, 'n_words': 695}