예제 #1
0
    def __init__(self, app, flags=None):
        super(QDebugPanel, self).__init__(flags)
        self.setDockOptions(QMainWindow.AnimatedDocks
                            | QMainWindow.AllowNestedDocks
                            | QMainWindow.AllowTabbedDocks)

        self.app = app
        self.q_settings = app.q_settings

        self.functions_list = DwarfListView()
        self.functions_list_model = QStandardItemModel(0, 1)
        self.functions_list_model.setHeaderData(0, Qt.Horizontal, '')
        self.functions_list.setModel(self.functions_list_model)
        self.functions_list.setHeaderHidden(True)
        self.functions_list.doubleClicked.connect(
            self._function_double_clicked)

        self.dock_functions_list = QDockWidget('Functions', self)
        self.dock_functions_list.setObjectName('functions')
        self.dock_functions_list.setWidget(self.functions_list)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_functions_list)
        self.resizeDocks([self.dock_functions_list], [100], Qt.Horizontal)
        self.app.debug_view_menu.addAction(
            self.dock_functions_list.toggleViewAction())

        screen_size = QtWidgets.QDesktopWidget().screenGeometry(-1)
        m_width = screen_size.width()

        self.memory_panel = HexEditor(self.app)
        self.memory_panel.debug_panel = self
        self.memory_panel.dataChanged.connect(self.on_memory_modified)

        self.disassembly_panel = DisassemblyView(self.app)
        self.disassembly_panel.debug_panel = self

        self.dock_memory_panel = QDockWidget('Memory', self)
        self.dock_memory_panel.setWidget(self.memory_panel)
        self.dock_memory_panel.setObjectName('memory')

        self.dock_disassembly_panel = QDockWidget('Disassembly', self)
        self.dock_disassembly_panel.setWidget(self.disassembly_panel)
        self.dock_disassembly_panel.setObjectName('disassembly')

        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_memory_panel,
                           Qt.Horizontal)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_disassembly_panel,
                           Qt.Horizontal)
        if m_width >= 1920:
            self.splitDockWidget(self.dock_memory_panel,
                                 self.dock_disassembly_panel, Qt.Horizontal)
        else:
            self.tabifyDockWidget(self.dock_memory_panel,
                                  self.dock_disassembly_panel)

        self.restoreUiState()
예제 #2
0
    def __init__(self, app, flags=None):
        super(QDebugPanel, self).__init__(flags)
        self.setDockOptions(QMainWindow.AnimatedDocks
                            | QMainWindow.AllowNestedDocks
                            | QMainWindow.AllowTabbedDocks)

        self.app = app
        self.q_settings = app.q_settings

        screen_size = QtWidgets.QDesktopWidget().screenGeometry(-1)
        m_width = screen_size.width()

        self.memory_panel = HexEditor(self.app)
        self.memory_panel.debug_panel = self
        self.memory_panel.dataChanged.connect(self.on_memory_modified)

        self.disassembly_panel = DisassemblyView(self.app)
        self.disassembly_panel.debug_panel = self

        self.dock_memory_panel = QDockWidget('Memory', self)
        self.dock_memory_panel.setWidget(self.memory_panel)
        self.dock_memory_panel.setObjectName('memory')

        self.dock_disassembly_panel = QDockWidget('Disassembly', self)
        self.dock_disassembly_panel.setWidget(self.disassembly_panel)
        self.dock_disassembly_panel.setObjectName('disassembly')

        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_memory_panel,
                           Qt.Horizontal)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_disassembly_panel,
                           Qt.Horizontal)
        if m_width >= 1920:
            self.splitDockWidget(self.dock_memory_panel,
                                 self.dock_disassembly_panel, Qt.Horizontal)
        else:
            self.tabifyDockWidget(self.dock_memory_panel,
                                  self.dock_disassembly_panel)

        self.restoreUiState()
예제 #3
0
class QDebugPanel(QMainWindow):
    def __init__(self, app, flags=None):
        super(QDebugPanel, self).__init__(flags)
        self.setDockOptions(QMainWindow.AnimatedDocks
                            | QMainWindow.AllowNestedDocks
                            | QMainWindow.AllowTabbedDocks)

        self.app = app
        self.q_settings = app.q_settings

        screen_size = QtWidgets.QDesktopWidget().screenGeometry(-1)
        m_width = screen_size.width()

        self.memory_panel = HexEditor(self.app)
        self.memory_panel.debug_panel = self
        self.memory_panel.dataChanged.connect(self.on_memory_modified)

        self.disassembly_panel = DisassemblyView(self.app)
        self.disassembly_panel.debug_panel = self

        self.dock_memory_panel = QDockWidget('Memory', self)
        self.dock_memory_panel.setWidget(self.memory_panel)
        self.dock_memory_panel.setObjectName('memory')

        self.dock_disassembly_panel = QDockWidget('Disassembly', self)
        self.dock_disassembly_panel.setWidget(self.disassembly_panel)
        self.dock_disassembly_panel.setObjectName('disassembly')

        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_memory_panel,
                           Qt.Horizontal)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_disassembly_panel,
                           Qt.Horizontal)
        if m_width >= 1920:
            self.splitDockWidget(self.dock_memory_panel,
                                 self.dock_disassembly_panel, Qt.Horizontal)
        else:
            self.tabifyDockWidget(self.dock_memory_panel,
                                  self.dock_disassembly_panel)

        self.restoreUiState()

    def restoreUiState(self):
        ui_state = self.q_settings.value('dwarf_debug_ui_state')
        if ui_state:
            self.restoreGeometry(ui_state)
        window_state = self.q_settings.value('dwarf_debug_ui_window')
        if window_state:
            self.restoreState(window_state)

    def closeEvent(self, event):
        self.q_settings.setValue('dwarf_debug_ui_state', self.saveGeometry())
        self.q_settings.setValue('dwarf_debug_ui_window', self.saveState())

    def showEvent(self, event):
        main_width = self.size().width()
        new_widths = [main_width * .4, main_width * .5]
        self.resizeDocks([self.dock_memory_panel, self.dock_disassembly_panel],
                         new_widths, Qt.Horizontal)
        return super().showEvent(event)

    def update_functions(self, functions_list=None):
        if functions_list is None:
            functions_list = {}
        for module_info_base in self.app.dwarf.database.modules_info:
            module_info = self.app.dwarf.database.modules_info[
                module_info_base]
            if len(module_info.functions) > 0:
                for function in module_info.functions:
                    functions_list[function.name] = function.address

        for function_name in sorted(functions_list.keys()):
            function_addr = functions_list[function_name]

            function_name = function_name.replace('.', '_')
            if not self.app.bookmarks_panel.is_address_bookmarked(
                    function_addr):
                self.app.bookmarks_panel._create_bookmark(ptr=function_addr,
                                                          note=function_name)

    def on_context_setup(self):
        self.memory_panel.on_context_setup()

    def on_memory_modified(self, pos, length):
        data_pos = self.memory_panel.base + pos
        data = self.memory_panel.data[pos:pos + length]
        data = [data[0]]  # todo: strange js part

        if self.dwarf.dwarf_api('writeBytes', [data_pos, data]):
            pass
        else:
            utils.show_message_box('Failed to write Memory')

    def raise_memory_panel(self):
        self.dock_memory_panel.raise_()

    def raise_disassembly_panel(self):
        self.dock_disassembly_panel.raise_()

    def jump_to_address(self, address, view=DEBUG_VIEW_MEMORY):
        address = utils.parse_ptr(address)

        if view == DEBUG_VIEW_MEMORY:
            if self.memory_panel.number_of_lines() > 0:
                if self.is_address_in_view(view, address):
                    return
        elif view == DEBUG_VIEW_DISASSEMBLY:
            if self.disassembly_panel.number_of_lines() > 0:
                if self.is_address_in_view(view, address):
                    return

        self.app.show_progress('reading data...')
        self.app.dwarf.read_range_async(
            address, lambda base, data, offset: self._apply_data(
                base, data, offset, view=view))

    def _apply_data(self, base, data, offset, view=DEBUG_VIEW_MEMORY):
        self.app.hide_progress()

        self.update_functions()

        if view == DEBUG_VIEW_MEMORY:
            self.memory_panel.set_data(data, base=base, offset=offset)
            if not self.dock_memory_panel.isVisible():
                self.dock_memory_panel.show()
            self.raise_memory_panel()

            if self.disassembly_panel.number_of_lines() == 0:
                self.disassembly_panel.disasm(base, data, offset)
        elif view == DEBUG_VIEW_DISASSEMBLY:
            self.disassembly_panel.disasm(base, data, offset)
            if not self.dock_disassembly_panel.isVisible():
                self.dock_disassembly_panel.show()
            self.raise_disassembly_panel()

            if self.memory_panel.number_of_lines() == 0:
                self.memory_panel.set_data(data, base=base, offset=offset)

    def is_address_in_view(self, view, address):
        if view == DEBUG_VIEW_MEMORY:
            if self.memory_panel.data:
                ptr_exists = self.memory_panel.base <= address <= self.memory_panel.base + len(
                    self.memory_panel.data)
                if ptr_exists:
                    self.memory_panel.caret.position = address - self.memory_panel.base
                    return True
        elif view == DEBUG_VIEW_DISASSEMBLY:
            if self.disassembly_panel.visible_lines() > 0:
                line_index_for_address = self.disassembly_panel.get_line_for_address(
                    address)
                if line_index_for_address >= 0:
                    self.disassembly_panel.highlighted_line = line_index_for_address
                    self.disassembly_panel.verticalScrollBar().setValue(
                        line_index_for_address)
                    return True
        return False

    def on_cm_jump_to_address(self, view=DEBUG_VIEW_MEMORY):
        ptr, _ = InputDialog.input_pointer(self.app)
        if ptr > 0:
            self.jump_to_address(ptr, view=view)

    def dump_data(self, address, _len):
        def _dump(ptr, data):
            if data is not None:
                from PyQt5.QtWidgets import QFileDialog
                _file = QFileDialog.getSaveFileName(self.app)
                with open(_file[0], 'wb') as f:
                    f.write(data)

        self.app.dwarf.read_memory_async(address, _len, _dump)
예제 #4
0
    def __init__(self, plugin, *__args):
        super().__init__(*__args)

        self.plugin = plugin
        self.app = plugin.app
        self.emulator = plugin.emulator
        self.until_address = 0

        self._uc_user_arch = None
        self._uc_user_mode = None
        self._cs_user_arch = None
        self._cs_user_mode = None

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)

        self._toolbar_container = QHBoxLayout()
        self._toolbar = QToolBar()
        self._toolbar.addAction('Start', self.handle_start)
        self._toolbar.addAction('Step', self.handle_step)
        self._toolbar.addAction('Step next call', self.handle_step_next_call)
        self._toolbar.addAction('Stop', self.handle_stop)
        self._toolbar.addAction('Clear', self.handle_clear)
        self._toolbar.addAction('Options', self.handle_options)
        self._toolbar_container.addWidget(self._toolbar)

        selection_layout = QHBoxLayout()
        selection_layout.setAlignment(Qt.AlignRight)
        self.cpu_selection = QComboBox(self)
        index = 0
        for v in unicorn_const.__dict__:
            if 'UC_ARCH_' in v:
                item = '_'.join(v.split('_')[2:]).lower()
                if self.app.dwarf.arch == item:
                    index = self.cpu_selection.count()
                elif self.app.dwarf.arch == 'x64' and item == 'x86' or self.app.dwarf == 'ia32' and item == 'x86':
                    index = self.cpu_selection.count()

                self.cpu_selection.addItem(item, unicorn_const.__dict__[v])

        self.cpu_selection.activated[str].connect(self._on_cpu_selection)
        self.cpu_selection.setCurrentIndex(index)
        self.mode_selection = QComboBox(self)
        index = 0
        for v in unicorn_const.__dict__:
            if 'UC_MODE_' in v:
                item = '_'.join(v.split('_')[2:]).lower()
                if self.app.dwarf.arch == item:
                    index = self.mode_selection.count()
                elif (self.app.dwarf.arch == 'x64'
                      or self.app.dwarf.arch == 'arm64') and item == '64':
                    index = self.mode_selection.count()
                elif self.app.dwarf.arch == 'ia32' and item == '32':
                    index = self.mode_selection.count()

                self.mode_selection.addItem(item, unicorn_const.__dict__[v])
        self.mode_selection.activated[str].connect(self._on_mode_selection)
        self.mode_selection.setCurrentIndex(index)
        selection_layout.addWidget(self.cpu_selection)
        selection_layout.addWidget(self.mode_selection)
        self._toolbar_container.addLayout(selection_layout)

        layout.addLayout(self._toolbar_container)

        self.tabs = QTabWidget()
        self.assembly = DisassemblyView(self.app)
        self.assembly.display_jumps = False
        self.assembly.follow_jumps = False
        #self.memory_table = HexEditor(self.app)
        #self.memory_table._read_only = True
        self.tabs.addTab(self.assembly, 'Code')
        #self.tabs.addTab(self.memory_table, 'Memory')

        layout.addWidget(self.tabs)

        self.ranges_list = DwarfListView(self.app)
        self.ranges_list.doubleClicked.connect(self.ranges_item_double_clicked)
        self._ranges_model = QStandardItemModel(0, 2)
        self._ranges_model.setHeaderData(0, Qt.Horizontal, 'Memory')
        self._ranges_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._ranges_model.setHeaderData(1, Qt.Horizontal, 'Size')
        self.ranges_list.setModel(self._ranges_model)
        self.tabs.addTab(self.ranges_list, 'Ranges')

        self._access_list = DwarfListView(self.app)
        self._access_list.doubleClicked.connect(
            self.access_item_double_clicked)
        self._access_model = QStandardItemModel(0, 3)
        self._access_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self._access_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._access_model.setHeaderData(1, Qt.Horizontal, 'Access')
        self._access_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._access_model.setHeaderData(2, Qt.Horizontal, 'Value')
        self._access_list.setModel(self._access_model)
        self.tabs.addTab(self._access_list, 'Access')

        layout.setSpacing(0)
        self.setLayout(layout)

        self.console = plugin.console

        self.emulator.onEmulatorSetup.connect(self.on_emulator_setup)
        self.emulator.onEmulatorStart.connect(self.on_emulator_start)
        self.emulator.onEmulatorStop.connect(self.on_emulator_stop)
        # self.emulator.onEmulatorStep.connect(self.on_emulator_step)
        self.emulator.onEmulatorHook.connect(self.on_emulator_hook)
        self.emulator.onEmulatorMemoryHook.connect(
            self.on_emulator_memory_hook)
        self.emulator.onEmulatorMemoryRangeMapped.connect(
            self.on_emulator_memory_range_mapped)
        self.emulator.onEmulatorLog.connect(self.on_emulator_log)

        self._require_register_result = None
        self._last_instruction_address = 0
예제 #5
0
class EmulatorPanel(QWidget):
    def __init__(self, plugin, *__args):
        super().__init__(*__args)

        self.plugin = plugin
        self.app = plugin.app
        self.emulator = plugin.emulator
        self.until_address = 0

        self._uc_user_arch = None
        self._uc_user_mode = None
        self._cs_user_arch = None
        self._cs_user_mode = None

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)

        self._toolbar_container = QHBoxLayout()
        self._toolbar = QToolBar()
        self._toolbar.addAction('Start', self.handle_start)
        self._toolbar.addAction('Step', self.handle_step)
        self._toolbar.addAction('Step next call', self.handle_step_next_call)
        self._toolbar.addAction('Stop', self.handle_stop)
        self._toolbar.addAction('Clear', self.handle_clear)
        self._toolbar.addAction('Options', self.handle_options)
        self._toolbar_container.addWidget(self._toolbar)

        selection_layout = QHBoxLayout()
        selection_layout.setAlignment(Qt.AlignRight)
        self.cpu_selection = QComboBox(self)
        index = 0
        for v in unicorn_const.__dict__:
            if 'UC_ARCH_' in v:
                item = '_'.join(v.split('_')[2:]).lower()
                if self.app.dwarf.arch == item:
                    index = self.cpu_selection.count()
                elif self.app.dwarf.arch == 'x64' and item == 'x86' or self.app.dwarf == 'ia32' and item == 'x86':
                    index = self.cpu_selection.count()

                self.cpu_selection.addItem(item, unicorn_const.__dict__[v])

        self.cpu_selection.activated[str].connect(self._on_cpu_selection)
        self.cpu_selection.setCurrentIndex(index)
        self.mode_selection = QComboBox(self)
        index = 0
        for v in unicorn_const.__dict__:
            if 'UC_MODE_' in v:
                item = '_'.join(v.split('_')[2:]).lower()
                if self.app.dwarf.arch == item:
                    index = self.mode_selection.count()
                elif (self.app.dwarf.arch == 'x64'
                      or self.app.dwarf.arch == 'arm64') and item == '64':
                    index = self.mode_selection.count()
                elif self.app.dwarf.arch == 'ia32' and item == '32':
                    index = self.mode_selection.count()

                self.mode_selection.addItem(item, unicorn_const.__dict__[v])
        self.mode_selection.activated[str].connect(self._on_mode_selection)
        self.mode_selection.setCurrentIndex(index)
        selection_layout.addWidget(self.cpu_selection)
        selection_layout.addWidget(self.mode_selection)
        self._toolbar_container.addLayout(selection_layout)

        layout.addLayout(self._toolbar_container)

        self.tabs = QTabWidget()
        self.assembly = DisassemblyView(self.app)
        self.assembly.display_jumps = False
        self.assembly.follow_jumps = False
        #self.memory_table = HexEditor(self.app)
        #self.memory_table._read_only = True
        self.tabs.addTab(self.assembly, 'Code')
        #self.tabs.addTab(self.memory_table, 'Memory')

        layout.addWidget(self.tabs)

        self.ranges_list = DwarfListView(self.app)
        self.ranges_list.doubleClicked.connect(self.ranges_item_double_clicked)
        self._ranges_model = QStandardItemModel(0, 2)
        self._ranges_model.setHeaderData(0, Qt.Horizontal, 'Memory')
        self._ranges_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._ranges_model.setHeaderData(1, Qt.Horizontal, 'Size')
        self.ranges_list.setModel(self._ranges_model)
        self.tabs.addTab(self.ranges_list, 'Ranges')

        self._access_list = DwarfListView(self.app)
        self._access_list.doubleClicked.connect(
            self.access_item_double_clicked)
        self._access_model = QStandardItemModel(0, 3)
        self._access_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self._access_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._access_model.setHeaderData(1, Qt.Horizontal, 'Access')
        self._access_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._access_model.setHeaderData(2, Qt.Horizontal, 'Value')
        self._access_list.setModel(self._access_model)
        self.tabs.addTab(self._access_list, 'Access')

        layout.setSpacing(0)
        self.setLayout(layout)

        self.console = plugin.console

        self.emulator.onEmulatorSetup.connect(self.on_emulator_setup)
        self.emulator.onEmulatorStart.connect(self.on_emulator_start)
        self.emulator.onEmulatorStop.connect(self.on_emulator_stop)
        # self.emulator.onEmulatorStep.connect(self.on_emulator_step)
        self.emulator.onEmulatorHook.connect(self.on_emulator_hook)
        self.emulator.onEmulatorMemoryHook.connect(
            self.on_emulator_memory_hook)
        self.emulator.onEmulatorMemoryRangeMapped.connect(
            self.on_emulator_memory_range_mapped)
        self.emulator.onEmulatorLog.connect(self.on_emulator_log)

        self._require_register_result = None
        self._last_instruction_address = 0

    def _on_cpu_selection(self, cpu):
        self._uc_user_arch = unicorn_const.__dict__['UC_ARCH_' + cpu.upper()]
        self._cs_user_arch = capstone.__dict__['CS_ARCH_' + cpu.upper()]
        self._uc_user_mode = unicorn_const.__dict__[
            'UC_MODE_' + self.mode_selection.itemText(
                self.mode_selection.currentIndex()).upper()]
        self._cs_user_mode = capstone.__dict__[
            'CS_MODE_' + self.mode_selection.itemText(
                self.mode_selection.currentIndex()).upper()]

    def _on_mode_selection(self, mode):
        self._uc_user_mode = unicorn_const.__dict__['UC_MODE_' + mode.upper()]
        self._cs_user_mode = capstone.__dict__['CS_MODE_' + mode.upper()]
        self._uc_user_arch = unicorn_const.__dict__[
            'UC_ARCH_' + self.cpu_selection.itemText(
                self.cpu_selection.currentIndex()).upper()]
        self._cs_user_arch = capstone.__dict__[
            'CS_ARCH_' + self.cpu_selection.itemText(
                self.cpu_selection.currentIndex()).upper()]

    def resizeEvent(self, event):
        self.ranges_list.setFixedHeight((self.height() / 100) * 25)
        self.ranges_list.setFixedWidth((self.width() / 100) * 30)
        self._access_list.setFixedHeight((self.height() / 100) * 25)
        return super().resizeEvent(event)

    def handle_clear(self):
        self.ranges_list.clear()
        self._access_list.clear()
        self.assembly._lines.clear()
        self.assembly.viewport().update()
        # self.memory_table.setRowCount(0)
        self.console.clear()
        self.emulator.clean()

    def handle_options(self):
        EmulatorConfigsDialog.show_dialog(self.app.dwarf)

    def handle_start(self):
        ph = ''
        if self.until_address > 0:
            ph = hex(self.until_address)
        address, inp = InputDialog.input_pointer(
            self.app, input_content=ph, hint='pointer to last instruction')
        if address > 0:
            self.until_address = address
            self.app.console_panel.show_console_tab('emulator')
            self.emulator.emulate(self.until_address,
                                  user_arch=self._uc_user_arch,
                                  user_mode=self._uc_user_mode,
                                  cs_arch=self._cs_user_arch,
                                  cs_mode=self._cs_user_mode)
            # if err > 0:
            #    self.until_address = 0
            #    self.console.log('cannot start emulator. err: %d' % err)
            #    return

    def handle_step(self):
        self.app.console_panel.show_console_tab('emulator')

        try:
            self.emulator.emulate(step_mode=STEP_MODE_SINGLE,
                                  user_arch=self._uc_user_arch,
                                  user_mode=self._uc_user_mode,
                                  cs_arch=self._cs_user_arch,
                                  cs_mode=self._cs_user_mode)
        except self.emulator.EmulatorAlreadyRunningError:
            self.console.log('Emulator already running')
        except self.emulator.EmulatorSetupFailedError as error:
            self.until_address = 0
            self.console.log(error)

    def handle_step_next_call(self):
        self.app.console_panel.show_console_tab('emulator')

        try:
            self.emulator.emulate(step_mode=STEP_MODE_FUNCTION,
                                  user_arch=self._uc_user_arch,
                                  user_mode=self._uc_user_mode,
                                  cs_arch=self._cs_user_arch,
                                  cs_mode=self._cs_user_mode)
        except self.emulator.EmulatorAlreadyRunningError:
            self.console.log('Emulator already running')
        except self.emulator.EmulatorSetupFailedError as error:
            self.until_address = 0
            self.console.log(error)

    def handle_stop(self):
        self.emulator.stop()

    def on_emulator_hook(self, instruction):
        # @PinkiePonkie why setting context here (which is triggered each instruction) and later, set it again
        # in emulator_stop? step = double hit in set_context, running emulation on more than 1 instruction
        # doesn't need spam of set_context
        # self.app.context_panel.set_context(0, 2, self.emulator.current_context)

        # check if the previous hook is waiting for a register result
        if self._require_register_result is not None:
            row = 1
            if len(self._require_register_result) == 1:
                res = 'jump = %s' % (hex(self._require_register_result[0]))
            else:
                res = '%s = %s' % (self._require_register_result[1],
                                   hex(
                                       self.emulator.uc.reg_read(
                                           self._require_register_result[0])))
            if len(self.assembly._lines) > 1:
                if self.assembly._lines[len(self.assembly._lines) -
                                        row] is None:
                    row = 2

                telescope = self.get_telescope(
                    self.emulator.uc.reg_read(
                        self._require_register_result[0]))
                if telescope is not None and telescope != 'None':
                    res += ' (' + telescope + ')'

                self.assembly._lines[len(self.assembly._lines) -
                                     row].string = res
                # invalidate
                self._require_register_result = None

        # check if the code jumped
        self._last_instruction_address = instruction.address

        self.assembly.add_instruction(instruction)

        # add empty line if jump
        if instruction.is_jump or instruction.is_call:
            self.assembly.add_instruction(None)
            self._require_register_result = [
                instruction.jump_address
                if instruction.is_jump else instruction.call_address
            ]
        else:
            # implicit regs read are notified later through mem access
            if len(instruction.regs_read) == 0:
                if len(instruction.operands) > 0:
                    for i in instruction.operands:
                        if i.type == capstone.CS_OP_REG:
                            self._require_register_result = [
                                i.value.reg,
                                instruction.reg_name(i.value.reg)
                            ]
                            break
        self.assembly.verticalScrollBar().setValue(len(self.assembly._lines))
        self.assembly.viewport().update()

        if instruction.is_call:
            range_ = Range.build_or_get(self.app.dwarf, instruction.address)
            if range_.base > instruction.call_address > range_.tail:
                if self.emulator.step_mode == STEP_MODE_NONE:
                    self.emulator.stop()
                action = JumpOutsideTheBoxDialog.show_dialog(self.app.dwarf)
                if action == 0:
                    # step to jump
                    if self.emulator.step_mode != STEP_MODE_NONE:
                        self.handle_step()
                    else:
                        self.emulator.emulate(self.until_address,
                                              user_arch=self._uc_user_arch,
                                              user_mode=self._uc_user_mode,
                                              cs_arch=self._cs_user_arch,
                                              cs_mode=self._cs_user_mode)
                if action == 1:
                    # step to next jump
                    if self.emulator.step_mode != STEP_MODE_NONE:
                        self.handle_step_next_jump()
                    else:
                        self.emulator.emulate(self.until_address,
                                              user_arch=self._uc_user_arch,
                                              user_mode=self._uc_user_mode,
                                              cs_arch=self._cs_user_arch,
                                              cs_mode=self._cs_user_mode)
                elif action == 2:
                    # hook lr
                    hook_addr = instruction.address + instruction.size
                    if instruction.thumb:
                        hook_addr += 1
                    self.app.dwarf.hook_native(input_=hex(hook_addr))

    def on_emulator_log(self, log):
        self.app.console_panel.show_console_tab('emulator')
        self.console.log(log)

    def on_emulator_memory_hook(self, data):
        uc, access, address, value = data
        _address = QStandardItem()
        if self.ranges_list.uppercase_hex:
            if self.app.dwarf.pointer_size > 4:
                str_frmt = '0x{0:016X}'.format(address)
            else:
                str_frmt = '0x{0:08X}'.format(address)
        else:
            if self.app.dwarf.pointer_size > 4:
                str_frmt = '0x{0:016x}'.format(address)
            else:
                str_frmt = '0x{0:08x}'.format(address)
        _address.setText(str_frmt)
        _address.setTextAlignment(Qt.AlignCenter)

        _access = QStandardItem()
        if access == UC_MEM_READ:
            _access.setText('READ')
        elif access == UC_MEM_WRITE:
            _access.setText('WRITE')
        elif access == UC_MEM_FETCH:
            _access.setText('FETCH')
        _access.setTextAlignment(Qt.AlignCenter)

        _value = QStandardItem()
        _value.setText(str(value))

        self._access_model.appendRow([_address, _access, _value])

        res = None
        row = 1
        if len(self.assembly._lines) > 1:
            if self.assembly._lines[len(self.assembly._lines) - row] is None:
                row = 2
            if access == UC_MEM_READ:
                if self._require_register_result is not None:
                    if len(self._require_register_result) > 1:
                        res = '%s = %s' % (self._require_register_result[1],
                                           hex(value))
            else:
                if self.assembly._lines[len(self.assembly._lines) -
                                        row].string:
                    res = '%s, %s = %s' % (self.assembly._lines[
                        len(self.assembly._lines) - row].string, hex(address),
                                           hex(value))
                else:
                    res = '%s = %s' % (hex(address), hex(value))
            if res is not None:
                telescope = self.get_telescope(value)
                if telescope is not None and telescope != 'None':
                    res += ' (' + telescope + ')'
                # invalidate
                self._require_register_result = None
                self.assembly._lines[len(self.assembly._lines) -
                                     row].string = res

    def get_telescope(self, address):
        try:
            size = self.app.dwarf.pointer_size
            telescope = self.emulator.uc.mem_read(address, size)
            try:
                for i in range(len(telescope)):
                    if int(telescope[i]) == 0x0 and i != 0:
                        st = telescope.decode('utf8')
                        return st
                st = telescope.decode('utf8')
                if len(st) != size:
                    return '0x%s' % telescope.hex()
                while True:
                    telescope = self.emulator.uc.mem_read(address + size, 1)
                    if int(telescope) == 0x0:
                        break
                    st += telescope.decode('utf8')
                    size += 1
                return st
            except:
                return '0x%s' % telescope.hex()
        except UcError as e:
            # read from js
            telescope = self.app.dwarf.dwarf_api('getAddressTs', address)
            if telescope is None:
                return None
            telescope = str(telescope[1]).replace('\n', ' ')
            if len(telescope) > 50:
                telescope = telescope[:50] + '...'
            return telescope

    def on_emulator_memory_range_mapped(self, data):
        address, size = data
        _address = QStandardItem()
        if self.ranges_list.uppercase_hex:
            if self.app.dwarf.pointer_size > 4:
                str_frmt = '0x{0:016X}'.format(address)
            else:
                str_frmt = '0x{0:08X}'.format(address)
        else:
            if self.app.dwarf.pointer_size > 4:
                str_frmt = '0x{0:016x}'.format(address)
            else:
                str_frmt = '0x{0:08x}'.format(address)
        _address.setText(str_frmt)
        _address.setTextAlignment(Qt.AlignCenter)
        _size = QStandardItem()
        _size.setText("{0:,d}".format(int(size)))
        self._ranges_model.appendRow([_address, _size])

    def on_emulator_setup(self, data):
        user_arch = data[0]
        user_mode = data[1]
        if user_arch is not None and user_mode is not None:
            index = self.cpu_selection.findData(user_arch)
            self.cpu_selection.setCurrentIndex(index)
            index = self.mode_selection.findData(user_mode)
            self.mode_selection.setCurrentIndex(index)

    def on_emulator_start(self):
        pass

    def on_emulator_stop(self):
        self.plugin.emulator_context_widget.set_context(
            0, self.emulator.current_context)

        # check if the previous hook is waiting for a register result
        if self._require_register_result is not None:
            row = 1
            if len(self._require_register_result) == 1:
                res = 'jump = %s' % (hex(self._require_register_result[0]))
            else:
                res = '%s = %s' % (self._require_register_result[1],
                                   hex(
                                       self.emulator.uc.reg_read(
                                           self._require_register_result[0])))
                telescope = self.get_telescope(
                    self.emulator.uc.reg_read(
                        self._require_register_result[0]))
                if telescope is not None and telescope != 'None':
                    res += ' (' + telescope + ')'

            if len(self.assembly._lines) > 1:
                if self.assembly._lines[len(self.assembly._lines) -
                                        row] is None:
                    row = 2
                self.assembly._lines[len(self.assembly._lines) -
                                     row].string = res
                # invalidate
                self._require_register_result = None

    def ranges_item_double_clicked(self, model_index):
        row = self._ranges_model.itemFromIndex(model_index).row()
        if row != -1:
            item = self._ranges_model.item(row, 0).text()
            #self.memory_table.read_memory(item)
            self.tabs.setCurrentIndex(1)

    def access_item_double_clicked(self, model_index):
        row = self._access_model.itemFromIndex(model_index).row()
        if row != -1:
            item = self._access_model.item(row, 0).text()
            #self.memory_table.read_memory(item)
            self.tabs.setCurrentIndex(1)