From 9dfa9b79a2295e4c7c45c5e1c08a7eac4d827708 Mon Sep 17 00:00:00 2001 From: ucgJhe Date: Sat, 12 Nov 2022 23:29:43 +0800 Subject: [PATCH 1/4] fix MCU stepping --- qiling/debugger/qdb/arch/arch_arm.py | 13 ++++++--- qiling/debugger/qdb/qdb.py | 34 ++++-------------------- qiling/debugger/qdb/render/render.py | 8 +++--- qiling/debugger/qdb/render/render_arm.py | 1 + 4 files changed, 20 insertions(+), 36 deletions(-) diff --git a/qiling/debugger/qdb/arch/arch_arm.py b/qiling/debugger/qdb/arch/arch_arm.py index 1e24eef19..ed2e797c4 100644 --- a/qiling/debugger/qdb/arch/arch_arm.py +++ b/qiling/debugger/qdb/arch/arch_arm.py @@ -10,16 +10,21 @@ class ArchARM(Arch): def __init__(self): super().__init__() - - @property - def regs(self): - return ( + self._regs = ( "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", ) + @property + def regs(self): + return self._regs + + @regs.setter + def regs(self, regs): + self._regs += regs + @property def regs_need_swapped(self): return { diff --git a/qiling/debugger/qdb/qdb.py b/qiling/debugger/qdb/qdb.py index e4351d0ff..4914af6ed 100644 --- a/qiling/debugger/qdb/qdb.py +++ b/qiling/debugger/qdb/qdb.py @@ -82,11 +82,7 @@ def bp_handler(ql, address, size, bp_list): self.cur_addr = self.ql.loader.entry_point - if self.ql.arch.type == QL_ARCH.CORTEX_M: - self._run() - - else: - self.init_state = self.ql.save() + self.init_state = self.ql.save() if self._script: run_qdb_script(self, self._script) @@ -118,23 +114,6 @@ def _run(self, address: int = 0, end: int = 0, count: int = 0) -> None: if not address: address = self.cur_addr - if self.ql.arch.type == QL_ARCH.CORTEX_M and self.ql.count != 0: - - while self.ql.count: - - if (bp := self.bp_list.pop(self.cur_addr, None)): - if isinstance(bp, TempBreakpoint): - self.del_breakpoint(bp) - else: - qdb_print(QDB_MSG.INFO, f"hit breakpoint at 0x{self.cur_addr:08x}") - - break - - self.ql.arch.step() - self.ql.count -= 1 - - return - if getattr(self.ql.arch, 'is_thumb', False): address |= 1 @@ -227,13 +206,10 @@ def do_step_in(self, *args) -> Optional[bool]: if prophecy.where is True: return True - if self.ql.arch == QL_ARCH.CORTEX_M: - self.ql.arch.step() - else: - step = 1 - # make sure follow branching - if prophecy.going is True and self.ql.arch.type == QL_ARCH.MIPS: - step += 1 + step = 1 + # make sure follow branching + if prophecy.going is True and self.ql.arch.type == QL_ARCH.MIPS: + step += 1 self._run(count=step) self.do_context() diff --git a/qiling/debugger/qdb/render/render.py b/qiling/debugger/qdb/render/render.py index 3d5e67d6f..4ce64fa1c 100644 --- a/qiling/debugger/qdb/render/render.py +++ b/qiling/debugger/qdb/render/render.py @@ -51,6 +51,7 @@ def wrapper(*args, **kwargs): def __init__(self): self.regs_a_row = 4 self.stack_num = 10 + self.disasm_num = 0x10 self.color = color def reg_diff(self, cur_regs, saved_reg_dump): @@ -206,13 +207,14 @@ def context_asm(self) -> None: lines = {} past_list = [] - from_addr = self.cur_addr - 0x10 - to_addr = self.cur_addr + 0x10 + from_addr = self.cur_addr - self.disasm_num + to_addr = self.cur_addr + self.disasm_num cur_addr = from_addr while cur_addr != to_addr: insn = self.disasm(cur_addr) - cur_addr += self.arch_insn_size + # cur_addr += self.arch_insn_size + cur_addr += insn.size if not insn: continue past_list.append(insn) diff --git a/qiling/debugger/qdb/render/render_arm.py b/qiling/debugger/qdb/render/render_arm.py index db462b96f..7209be2c6 100644 --- a/qiling/debugger/qdb/render/render_arm.py +++ b/qiling/debugger/qdb/render/render_arm.py @@ -16,6 +16,7 @@ class ContextRenderARM(ContextRender, ArchARM): def __init__(self, ql, predictor): super().__init__(ql, predictor) ArchARM.__init__(self) + self.disasm_num = 8 @staticmethod def print_mode_info(bits): From 01e31336ce92eb4e45faf011c102459c03b20565 Mon Sep 17 00:00:00 2001 From: ucgJhe Date: Mon, 28 Nov 2022 11:06:07 +0800 Subject: [PATCH 2/4] revert addition of cpsr for cortex_m --- qiling/arch/cortex_m_const.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qiling/arch/cortex_m_const.py b/qiling/arch/cortex_m_const.py index 7f3d2eb49..8f915163d 100644 --- a/qiling/arch/cortex_m_const.py +++ b/qiling/arch/cortex_m_const.py @@ -31,7 +31,6 @@ "apsr": UC_ARM_REG_APSR, "ipsr": UC_ARM_REG_IPSR, "epsr": UC_ARM_REG_EPSR, - "cpsr": UC_ARM_REG_CPSR, "primask": UC_ARM_REG_PRIMASK, "faultmask": UC_ARM_REG_FAULTMASK, "basepri": UC_ARM_REG_BASEPRI, From c0c1f1cd3450b27328f1c1e71cb4b25658a11a67 Mon Sep 17 00:00:00 2001 From: ucgJhe Date: Tue, 7 Feb 2023 10:31:53 +0800 Subject: [PATCH 3/4] show invalid instruction now --- qiling/debugger/qdb/context.py | 8 ++++---- qiling/debugger/qdb/misc.py | 15 +++++++++++++++ qiling/debugger/qdb/render/render.py | 6 ++---- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/qiling/debugger/qdb/context.py b/qiling/debugger/qdb/context.py index a3c71ef86..e4400f4b4 100644 --- a/qiling/debugger/qdb/context.py +++ b/qiling/debugger/qdb/context.py @@ -10,7 +10,7 @@ from capstone import CsInsn -from .misc import read_int +from .misc import read_int, InvalidInsn class Context: """ @@ -48,9 +48,9 @@ def disasm(self, address: int, detail: bool = False) -> Optional[CsInsn]: md = self.ql.arch.disassembler md.detail = detail - if (addr := self.read_insn(address)): - return next(md.disasm(addr, address), None) - return None + if (bytes_read := self.read_insn(address)): + return next(md.disasm(bytes_read, address), InvalidInsn(bytes_read, address)) + return InvalidInsn(bytes_read, address) def try_read(self, address: int, size: int) -> Optional[bytes]: """ diff --git a/qiling/debugger/qdb/misc.py b/qiling/debugger/qdb/misc.py index d9bf67362..a3cf29e1a 100644 --- a/qiling/debugger/qdb/misc.py +++ b/qiling/debugger/qdb/misc.py @@ -5,6 +5,8 @@ from typing import AnyStr, Callable, Optional +from dataclasses import dataclass + import ast def check_and_eval(line: str): @@ -25,6 +27,19 @@ def generic_visit(self, node): return eval(line) +@dataclass +class InvalidInsn: + """ + class for displaying invalid instruction + """ + bytes: bytes + address: bytes + mnemonic: str = 'invalid' + op_str: str = '' + + def __post_init__(self): + self.size = len(self.bytes) + class Breakpoint: """ diff --git a/qiling/debugger/qdb/render/render.py b/qiling/debugger/qdb/render/render.py index 4ce64fa1c..aa7a6022d 100644 --- a/qiling/debugger/qdb/render/render.py +++ b/qiling/debugger/qdb/render/render.py @@ -157,6 +157,7 @@ def print_asm(self, insn: CsInsn, to_jump: bool = False) -> None: """ opcode = "".join(f"{b:02x}" for b in insn.bytes) + trace_line = f"0x{insn.address:08x} │ {opcode:15s} {insn.mnemonic:10} {insn.op_str:35s}" cursor = "►" if self.cur_addr == insn.address else " " @@ -211,12 +212,9 @@ def context_asm(self) -> None: to_addr = self.cur_addr + self.disasm_num cur_addr = from_addr - while cur_addr != to_addr: + while cur_addr <= to_addr: insn = self.disasm(cur_addr) - # cur_addr += self.arch_insn_size cur_addr += insn.size - if not insn: - continue past_list.append(insn) bk_list = [] From e771912677ce7d164bf8cb89319c4d0588ab66c3 Mon Sep 17 00:00:00 2001 From: ucgJhe Date: Tue, 7 Feb 2023 10:33:29 +0800 Subject: [PATCH 4/4] pause at program exit point, now step command accepts argument --- qiling/debugger/qdb/qdb.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/qiling/debugger/qdb/qdb.py b/qiling/debugger/qdb/qdb.py index 0d1d1fbf6..7606cf3bc 100644 --- a/qiling/debugger/qdb/qdb.py +++ b/qiling/debugger/qdb/qdb.py @@ -78,7 +78,7 @@ def bp_handler(ql, address, size, bp_list): if self.ql.os.type == QL_OS.BLOB: self.ql.loader.entry_point = self.ql.loader.load_address - elif init_hook and self.ql.loader.entry_point != init_hook: + elif init_hook and self.ql.loader.entry_point != int(init_hook, 0): self.do_breakpoint(init_hook) self.cur_addr = self.ql.loader.entry_point @@ -116,7 +116,7 @@ def _run(self, address: int = 0, end: int = 0, count: int = 0) -> None: address = self.cur_addr if getattr(self.ql.arch, 'is_thumb', False): - address |= 1 + address |= 0b1 # assume we're running PE if on Windows if self.ql.os.type == QL_OS.WINDOWS: @@ -157,6 +157,7 @@ def inner(self, *args, **kwargs): qdb_print(QDB_MSG.ERROR, "The program is not being run.") else: func(self, *args, **kwargs) + return inner def parseline(self, line: str) -> Tuple[Optional[str], Optional[str], str]: @@ -213,17 +214,19 @@ def do_run(self, *args) -> None: @SnapshotManager.snapshot @save_reg_dump @check_ql_alive - def do_step_in(self, *args) -> Optional[bool]: + def do_step_in(self, step: str = '', *args) -> Optional[bool]: """ execute one instruction at a time, will enter subroutine """ - prophecy = self.predictor.predict() if prophecy.where is True: - return True + qdb_print(QDB_MSG.INFO, 'program exited due to code end hitted') + self.do_context() + return False + + step = 1 if step == '' else int(step) - step = 1 # make sure follow branching if prophecy.going is True and self.ql.arch.type == QL_ARCH.MIPS: step += 1 @@ -574,7 +577,6 @@ def do_EOF(self, *args) -> None: if input(f"{color.RED}[!] Are you sure about saying good bye ~ ? [Y/n]{color.END} ").strip() == "Y": self.do_quit() - do_r = do_run do_s = do_step_in do_n = do_step_over