예제 #1
0
class ValueEntry(Gtk.Frame):
    @require_gui_thread
    def __init__(self, title, text):
        Gtk.Frame.__init__(self)

        self.set_label(title)
        self.set_label_align(0.0, 0.0)

        self.box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
        self.box.set_margin_bottom(5)
        self.box.set_margin_left(2)
        self.text_entry = Gtk.Entry()
        self.text_entry.set_text(text)
        self.confirm_button = Gtk.Button(label="Set")

        self.get_style_context().add_class("value-entry")

        self.box.pack_start(self.text_entry, False, False, 0)
        self.box.pack_start(self.confirm_button, False, False, 5)
        self.add(self.box)
        self.show_all()

        self.confirm_button.connect("clicked",
                                    lambda btn: self._handle_confirm_click())

        self.on_value_entered = EventBroadcaster()

    @require_gui_thread
    def set_value(self, value):
        """
        @type value: str
        """
        self.text_entry.set_text(value)

    def _handle_confirm_click(self):
        value = self.text_entry.get_text()
        self.set_value("")

        self.on_value_entered.notify(value)
        self.hide()
예제 #2
0
class AddressInput(Gtk.Box):
    def __init__(self):
        Gtk.Box.__init__(self)

        self.set_orientation(Gtk.Orientation.VERTICAL)

        self.label_row = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)

        self.label = Gtk.Label().new("Hex address or expression")
        self.label_row.pack_start(self.label, False, False, 0)

        self.input_row = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)

        self.address_input = Gtk.Entry()
        self.address_input.set_editable(True)

        self.confirm_button = Gtk.Button()
        self.confirm_button.set_label("Load")

        self.input_row.pack_start(self.address_input, False, False, 0)
        self.input_row.pack_start(self.confirm_button, False, False, 0)

        self.pack_start(self.label_row, False, False, 2)
        self.pack_start(self.input_row, False, False, 0)

        self.set_margin_left(10)

        self.on_address_selected = EventBroadcaster()

        self.confirm_button.connect("clicked",
                                    lambda *x: self.on_address_selected.notify(
                                        self.address_input.get_text()))

    def set_enabled(self, value):
        """
        Sets whether the input should be enabled.
        @type value: bool
        """
        self.confirm_button.set_sensitive(value)
        self.address_input.set_sensitive(value)
예제 #3
0
class ProgramRunner(object):
    def __init__(self, debugger, file, *args):
        self.debugger = debugger
        self.file = os.path.abspath(file)
        self.args = args
        self.parent_thread = None
        self.on_signal = EventBroadcaster()
        self.msg_queue = Queue.Queue()
        self.child_pid = None
        self.last_signal = None

    def run(self):
        assert not self.parent_thread

        self.parent_thread = threading.Thread(target=self._start_process)
        self.parent_thread.start()

    def exec_step_single(self):
        self._add_queue_command("step-single")

    def exec_continue(self):
        self._add_queue_command("continue")

    def exec_interrupt(self):
        try:
            os.kill(self.child_pid, signal.SIGUSR1)
            return True
        except:
            return False

    def exec_kill(self):
        try:
            os.kill(self.child_pid, signal.SIGKILL)
            return True
        except:
            return False

    def _add_queue_command(self, cmd):
        self.msg_queue.put(cmd)

    def _start_process(self):
        child_pid = os.fork()

        if child_pid:
            self.child_pid = child_pid
            self._parent()
        else:
            self._child()

    def _child(self):
        if ptrace.ptrace(ptrace.PTRACE_TRACEME) < 0:
            raise Exception()

        os.execl(self.file, self.file, *self.args)
        exit(0)

    def _parent(self):
        try:
            while True:
                pid, status = os.waitpid(self.child_pid, os.WNOHANG)

                if pid != 0:
                    self._handle_child_status(status)

                try:
                    command = self.msg_queue.get(True, 0.1)
                    self._handle_command(self.child_pid, status, command)
                except Queue.Empty:
                    pass
                except:
                    traceback.print_exc()
        except OSError:
            self.on_signal.notify(ProcessState.Exited)
        except ProcessExitException:
            pass
        except:
            traceback.print_exc()

        self.child_pid = None
        self.parent_thread = None

    def _handle_child_status(self, status):
        if os.WIFSTOPPED(status):
            self._on_stop(status)
        elif os.WIFEXITED(status):
            self.on_signal.notify(ProcessState.Exited, os.WTERMSIG(status),
                                  os.WEXITSTATUS(status))
            raise ProcessExitException()

    def _handle_command(self, pid, status, command):
        if command == "continue":
            self._do_continue(pid)
        elif command == "step-single":
            self._do_step_single(pid)

    def _on_stop(self, status):
        self.last_signal = os.WSTOPSIG(status)
        self.debugger.breakpoint_manager.set_breakpoints(self.child_pid)

        self.on_signal.notify(ProcessState.Stopped, self.last_signal)

    def _continue_after_breakpoint(self, exec_continue):
        pid = self.child_pid
        regs = ptrace.ptrace_getregs(pid)
        orig_address = regs.eip - 1
        if self.debugger.breakpoint_manager.has_breakpoint_for_address(
                orig_address):
            self.debugger.breakpoint_manager.restore_instruction(
                pid, orig_address)
            regs.eip -= 1
            assert ptrace.ptrace_setregs(pid, regs)
            self._do_step_single(pid)
            pid, status = os.waitpid(pid, 0)
            self.debugger.breakpoint_manager.set_breakpoints(pid)

            if exec_continue:
                self.exec_continue()
            else:
                self._handle_child_status(status)
            return True
        else:
            return False

    def _do_continue(self, pid):
        if self.last_signal == 5:  # sigtrap
            if self._continue_after_breakpoint(True):
                return

        ptrace.ptrace(ptrace.PTRACE_CONT, pid)

    def _do_step_single(self, pid):
        if self.last_signal == 5:  # sigtrap
            if self._continue_after_breakpoint(False):
                return

        ptrace.ptrace(ptrace.PTRACE_SINGLESTEP, pid)
예제 #4
0
class ToolbarManager(object):
    def __init__(self, toolbar_builder, debugger):
        signals = {
            "toolbar-run": lambda *x: self.run(),
            "toolbar-continue": lambda *x: self.cont(),
            "toolbar-stop": lambda *x: self.stop(),
            "toolbar-pause": lambda *x: self.pause(),
            "toolbar-step-over": lambda *x: self.step_over(),
            "toolbar-step-in": lambda *x: self.step_in(),
            "toolbar-step-out": lambda *x: self.step_out()
        }

        toolbar_builder.connect_signals(signals)

        self.toolbar_builder = toolbar_builder
        self.toolbar = toolbar_builder.get_object("toolbar")
        self.debugger = debugger
        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_debugger_state_changed.subscribe(
            self._handle_debugger_state_change)

        self.grp_halt_control = ["stop", "pause"]
        self.grp_step = ["continue", "step_over", "step_in", "step_out"]

        self.on_run_process = EventBroadcaster()

    @require_gui_thread
    def _get_items(self):
        return [
            self.toolbar.get_nth_item(i)
            for i in xrange(0, self.toolbar.get_n_items())
        ]

    def _state_exited(self):
        self._change_grp_state(self.grp_halt_control, False)
        self._change_grp_state(self.grp_step, False)
        self._change_state("run", True)

    def _state_stopped(self):
        self._change_grp_state(self.grp_halt_control, False)
        self._change_grp_state(self.grp_step, True)

        self._change_state("stop", True)

    def _state_running(self):
        self._change_grp_state(self.grp_halt_control, True)
        self._change_grp_state(self.grp_step, False)
        self._change_state("run", False)

    def _handle_process_state_change(self, state, event_data):
        if state == ProcessState.Exited:
            self._state_exited()
        elif state == ProcessState.Stopped:
            self._state_stopped()
        elif state == ProcessState.Running:
            self._state_running()

    def _handle_debugger_state_change(self, state, old_value):
        if (state.is_set(DebuggerState.BinaryLoaded)
                and not state.is_set(DebuggerState.Running)):
            self._change_state("run", True)
        else:
            self._change_state("run", False)

    def _change_state(self, item_name, sensitive=True):
        run_on_gui(self._change_state_ui, item_name, sensitive)

    def _change_grp_state(self, group, sensitive=True):
        for item in group:
            self._change_state(item, sensitive)

    @require_gui_thread
    def _change_state_ui(self, item_name, sensitive=True):
        item = self.toolbar_builder.get_object(item_name)
        item.set_sensitive(sensitive)

    def run(self):
        self.on_run_process.notify()

    def cont(self):
        self.debugger.exec_continue()

    def stop(self):
        self.debugger.quit_program()

    def pause(self):
        self.debugger.exec_pause()

    def step_over(self):
        self.debugger.exec_step_over()

    def step_in(self):
        self.debugger.exec_step_in()

    def step_out(self):
        self.debugger.exec_step_out()
예제 #5
0
class SourceEditor(GtkSource.View):
    @staticmethod
    def load_file(path):
        try:
            return open(path).read()
        except:
            return None

    def __init__(self, debugger, language="cpp"):
        """
        @type debugger: debugger.mi.MiDebugger
        @type language: str
        """
        self.buffer = GtkSource.Buffer()
        super(SourceEditor, self).__init__(buffer=self.get_buffer())

        self.debugger = debugger

        self.start_undoable()

        self.set_language(language)
        self.get_buffer().set_highlight_syntax(True)
        self.get_buffer().set_highlight_matching_brackets(True)
        self.set_editable(False)

        self.gutter_renderer = BreakpointRenderer(
            self, paths.get_resource("img/circle.png"),
            paths.get_resource("img/arrow.png"))
        gutter = self.get_gutter(Gtk.TextWindowType.LEFT)
        gutter.insert(self.gutter_renderer, 0)

        self.stop_undoable()

        self.set_show_line_numbers(True)
        self.set_highlight_current_line(True)
        self.set_show_right_margin(True)
        self.set_right_margin_position(80)

        self.file = None
        self.on_breakpoint_changed = EventBroadcaster()

        self.exec_line = None
        self.bp_lines = set()

        self.analyser = SourceAnalyzer()
        self.connect("motion-notify-event",
                     lambda widget, event: self._handle_mouse_move(event))
        self.connect("button-press-event",
                     lambda widget, event: self._handle_mouse_click(event))
        self.on_symbol_hover = EventBroadcaster()

        self.debugger.breakpoint_manager.on_breakpoint_changed.subscribe(
            self._handle_model_breakpoint_change)
        self.breakpoint_lines = []

    def _handle_model_breakpoint_change(self, breakpoint):
        """
        @type breakpoint: debugee.Breakpoint
        """
        self._refresh_breakpoints()

    def _refresh_breakpoints(self):
        lines = []

        if (self.file
                and self.debugger.state.is_set(DebuggerState.BinaryLoaded)
                and self.debugger.process_state != ProcessState.Running):
            for bp in self.debugger.breakpoint_manager.get_breakpoints():
                if os.path.abspath(bp.location) == os.path.abspath(self.file):
                    lines.append(bp.line - 1)

        self.breakpoint_lines = lines

    def _handle_mouse_move(self, event):
        x, y = self.window_to_buffer_coords(Gtk.TextWindowType.TEXT, event.x,
                                            event.y)
        iter = self.get_iter_at_location(x, y)
        line = iter.get_line() + 1
        column = iter.get_line_offset() + 1
        symbol = self.analyser.get_symbol_name(line, column)

        if symbol is not None:
            self.on_symbol_hover.notify(self, symbol)

    def _handle_mouse_click(self, event):
        if (event.type == Gdk.EventType.BUTTON_PRESS
                and self.get_window(Gtk.TextWindowType.LEFT) == event.window):
            x, y = self.window_to_buffer_coords(Gtk.TextWindowType.LEFT,
                                                event.x, event.y)
            iter = self.get_iter_at_location(x, y)

            if self.debugger.state.is_set(DebuggerState.BinaryLoaded):
                self.toggle_breakpoint(iter.get_line())

    def get_buffer(self):
        return self.buffer

    def get_file(self):
        return self.file

    def get_breakpoint_lines(self):
        return self.breakpoint_lines

    @require_gui_thread
    def toggle_breakpoint(self, line):
        self.debugger.breakpoint_manager.toggle_breakpoint(self.file, line + 1)

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def set_language(self, key):
        manager = GtkSource.LanguageManager()
        language = manager.get_language(key)

        self.start_undoable()
        self.get_buffer().set_language(language)
        self.stop_undoable()

    @require_gui_thread
    def start_undoable(self):
        self.get_buffer().begin_not_undoable_action()

    @require_gui_thread
    def stop_undoable(self):
        self.get_buffer().end_not_undoable_action()

    @require_gui_thread
    def set_content_from_file(self, path):
        content = SourceEditor.load_file(path)

        if content:
            self.file = path
            self.start_undoable()
            self.get_buffer().set_text(content)
            self.stop_undoable()
            self.analyser.set_file(path)
            self._refresh_breakpoints()
            self.gutter_renderer.queue_draw()  # show existing breakpoints

    @require_gui_thread
    def get_cursor_iter(self):
        cursor_rectangle = self.get_cursor_locations(None)[0]
        return self.get_iter_at_location(cursor_rectangle.x,
                                         cursor_rectangle.y)

    @require_gui_thread
    def get_current_column(self):
        return self.get_cursor_iter().get_line_offset()

    @require_gui_thread
    def get_current_line(self):
        return self.get_cursor_iter().get_line()

    @require_gui_thread
    def get_line_iters(self, line_number):
        start_line = self.get_buffer().get_iter_at_line(line_number)
        end_line = start_line.copy()
        end_line.forward_to_line_end()
        return (start_line, end_line)

    @require_gui_thread
    def set_exec_line(self, line_number):
        self.unset_exec_line()
        line_iters = self.get_line_iters(line_number)
        self.scroll_to_iter(line_iters[0], 0.0, True, 0.5, 0.5)
        self.exec_line = line_number

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def unset_exec_line(self):
        self.exec_line = None

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def undo(self):
        if self.get_buffer().can_undo():
            self.get_buffer().undo()
            return True
        else:
            return False

    @require_gui_thread
    def redo(self):
        if self.get_buffer().can_redo():
            self.get_buffer().redo()
            return True
        else:
            return False
예제 #6
0
class SourceEditor(GtkSource.View):
    @staticmethod
    def load_file(path):
        try:
            return open(path).read()
        except:
            return None

    def __init__(self, debugger, language="cpp"):
        """
        @type debugger: debugger.mi.MiDebugger
        @type language: str
        """
        self.buffer = GtkSource.Buffer()
        super(SourceEditor, self).__init__(buffer=self.get_buffer())

        self.debugger = debugger

        self.start_undoable()

        self.set_language(language)
        self.get_buffer().set_highlight_syntax(True)
        self.get_buffer().set_highlight_matching_brackets(True)
        self.set_editable(False)

        self.gutter_renderer = BreakpointRenderer(self,
                                                  paths.get_resource(
                                                      "img/circle.png"),
                                                  paths.get_resource(
                                                      "img/arrow.png"))
        gutter = self.get_gutter(Gtk.TextWindowType.LEFT)
        gutter.insert(self.gutter_renderer, 0)

        self.stop_undoable()

        self.set_show_line_numbers(True)
        self.set_highlight_current_line(True)
        self.set_show_right_margin(True)
        self.set_right_margin_position(80)

        self.file = None
        self.on_breakpoint_changed = EventBroadcaster()

        self.exec_line = None
        self.bp_lines = set()

        self.analyser = SourceAnalyzer()
        self.connect("motion-notify-event",
                     lambda widget, event: self._handle_mouse_move(event))
        self.connect("button-press-event",
                     lambda widget, event: self._handle_mouse_click(event))
        self.on_symbol_hover = EventBroadcaster()

        self.debugger.breakpoint_manager.on_breakpoint_changed.subscribe(
            self._handle_model_breakpoint_change)
        self.breakpoint_lines = []

    def _handle_model_breakpoint_change(self, breakpoint):
        """
        @type breakpoint: debugee.Breakpoint
        """
        self._refresh_breakpoints()

    def _refresh_breakpoints(self):
        lines = []

        if (self.file and
                self.debugger.state.is_set(DebuggerState.BinaryLoaded) and
                self.debugger.process_state != ProcessState.Running):
            for bp in self.debugger.breakpoint_manager.get_breakpoints():
                if os.path.abspath(bp.location) == os.path.abspath(self.file):
                    lines.append(bp.line - 1)

        self.breakpoint_lines = lines

    def _handle_mouse_move(self, event):
        x, y = self.window_to_buffer_coords(Gtk.TextWindowType.TEXT,
                                            event.x,
                                            event.y)
        iter = self.get_iter_at_location(x, y)
        line = iter.get_line() + 1
        column = iter.get_line_offset() + 1
        symbol = self.analyser.get_symbol_name(line, column)

        if symbol is not None:
            self.on_symbol_hover.notify(self, symbol)

    def _handle_mouse_click(self, event):
        if (event.type == Gdk.EventType.BUTTON_PRESS and
                self.get_window(Gtk.TextWindowType.LEFT) == event.window):
            x, y = self.window_to_buffer_coords(Gtk.TextWindowType.LEFT,
                                                event.x,
                                                event.y)
            iter = self.get_iter_at_location(x, y)

            if self.debugger.state.is_set(DebuggerState.BinaryLoaded):
                self.toggle_breakpoint(iter.get_line())

    def get_buffer(self):
        return self.buffer

    def get_file(self):
        return self.file

    def get_breakpoint_lines(self):
        return self.breakpoint_lines

    @require_gui_thread
    def toggle_breakpoint(self, line):
        self.debugger.breakpoint_manager.toggle_breakpoint(self.file, line + 1)

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def set_language(self, key):
        manager = GtkSource.LanguageManager()
        language = manager.get_language(key)

        self.start_undoable()
        self.get_buffer().set_language(language)
        self.stop_undoable()

    @require_gui_thread
    def start_undoable(self):
        self.get_buffer().begin_not_undoable_action()

    @require_gui_thread
    def stop_undoable(self):
        self.get_buffer().end_not_undoable_action()

    @require_gui_thread
    def set_content_from_file(self, path):
        content = SourceEditor.load_file(path)

        if content:
            self.file = path
            self.start_undoable()
            self.get_buffer().set_text(content)
            self.stop_undoable()
            self.analyser.set_file(path)
            self._refresh_breakpoints()
            self.gutter_renderer.queue_draw()  # show existing breakpoints

    @require_gui_thread
    def get_cursor_iter(self):
        cursor_rectangle = self.get_cursor_locations(None)[0]
        return self.get_iter_at_location(cursor_rectangle.x,
                                         cursor_rectangle.y)

    @require_gui_thread
    def get_current_column(self):
        return self.get_cursor_iter().get_line_offset()

    @require_gui_thread
    def get_current_line(self):
        return self.get_cursor_iter().get_line()

    @require_gui_thread
    def get_line_iters(self, line_number):
        start_line = self.get_buffer().get_iter_at_line(line_number)
        end_line = start_line.copy()
        end_line.forward_to_line_end()
        return (start_line, end_line)

    @require_gui_thread
    def set_exec_line(self, line_number):
        self.unset_exec_line()
        line_iters = self.get_line_iters(line_number)
        self.scroll_to_iter(line_iters[0], 0.0, True, 0.5, 0.5)
        self.exec_line = line_number

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def unset_exec_line(self):
        self.exec_line = None

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def undo(self):
        if self.get_buffer().can_undo():
            self.get_buffer().undo()
            return True
        else:
            return False

    @require_gui_thread
    def redo(self):
        if self.get_buffer().can_redo():
            self.get_buffer().redo()
            return True
        else:
            return False
예제 #7
0
class ToolbarManager(object):
    def __init__(self, toolbar_builder, debugger):
        signals = {
            "toolbar-run": lambda *x: self.run(),
            "toolbar-continue": lambda *x: self.cont(),
            "toolbar-stop": lambda *x: self.stop(),
            "toolbar-pause": lambda *x: self.pause(),
            "toolbar-step-over": lambda *x: self.step_over(),
            "toolbar-step-in": lambda *x: self.step_in(),
            "toolbar-step-out": lambda *x: self.step_out()
        }

        toolbar_builder.connect_signals(signals)

        self.toolbar_builder = toolbar_builder
        self.toolbar = toolbar_builder.get_object("toolbar")
        self.debugger = debugger
        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_debugger_state_changed.subscribe(
            self._handle_debugger_state_change)

        self.grp_halt_control = ["stop", "pause"]
        self.grp_step = ["continue", "step_over", "step_in", "step_out"]

        self.on_run_process = EventBroadcaster()

    @require_gui_thread
    def _get_items(self):
        return [self.toolbar.get_nth_item(i)
                for i in xrange(0, self.toolbar.get_n_items())]

    def _state_exited(self):
        self._change_grp_state(self.grp_halt_control, False)
        self._change_grp_state(self.grp_step, False)
        self._change_state("run", True)

    def _state_stopped(self):
        self._change_grp_state(self.grp_halt_control, False)
        self._change_grp_state(self.grp_step, True)

        self._change_state("stop", True)

    def _state_running(self):
        self._change_grp_state(self.grp_halt_control, True)
        self._change_grp_state(self.grp_step, False)
        self._change_state("run", False)

    def _handle_process_state_change(self, state, event_data):
        if state == ProcessState.Exited:
            self._state_exited()
        elif state == ProcessState.Stopped:
            self._state_stopped()
        elif state == ProcessState.Running:
            self._state_running()

    def _handle_debugger_state_change(self, state, old_value):
        if (state.is_set(DebuggerState.BinaryLoaded) and
                not state.is_set(DebuggerState.Running)):
            self._change_state("run", True)
        else:
            self._change_state("run", False)

    def _change_state(self, item_name, sensitive=True):
        run_on_gui(self._change_state_ui, item_name, sensitive)

    def _change_grp_state(self, group, sensitive=True):
        for item in group:
            self._change_state(item, sensitive)

    @require_gui_thread
    def _change_state_ui(self, item_name, sensitive=True):
        item = self.toolbar_builder.get_object(item_name)
        item.set_sensitive(sensitive)

    def run(self):
        self.on_run_process.notify()

    def cont(self):
        self.debugger.exec_continue()

    def stop(self):
        self.debugger.quit_program()

    def pause(self):
        self.debugger.exec_pause()

    def step_over(self):
        self.debugger.exec_step_over()

    def step_in(self):
        self.debugger.exec_step_in()

    def step_out(self):
        self.debugger.exec_step_out()