diff --git a/qiling/debugger/gdb/gdb.py b/qiling/debugger/gdb/gdb.py index f6d6498d8..11d7cf7c0 100644 --- a/qiling/debugger/gdb/gdb.py +++ b/qiling/debugger/gdb/gdb.py @@ -184,6 +184,7 @@ def handle_qmark(subcmd: str) -> Reply: from unicorn.arm64_const import UC_ARM64_REG_X29 from unicorn.mips_const import UC_MIPS_REG_INVALID from unicorn.ppc_const import UC_PPC_REG_31 + from unicorn.riscv_const import UC_RISCV_REG_S0 arch_uc_bp = { QL_ARCH.X86 : UC_X86_REG_EBP, @@ -193,7 +194,9 @@ def handle_qmark(subcmd: str) -> Reply: QL_ARCH.MIPS : UC_MIPS_REG_INVALID, # skipped QL_ARCH.A8086 : UC_X86_REG_EBP, QL_ARCH.CORTEX_M : UC_ARM_REG_R11, - QL_ARCH.PPC : UC_PPC_REG_31 + QL_ARCH.PPC : UC_PPC_REG_31, + QL_ARCH.RISCV : UC_RISCV_REG_S0, + QL_ARCH.RISCV64 : UC_RISCV_REG_S0 }[self.ql.arch.type] def __get_reg_idx(ucreg: int) -> int: diff --git a/qiling/debugger/gdb/utils.py b/qiling/debugger/gdb/utils.py index 5e3b208bf..4a836d521 100644 --- a/qiling/debugger/gdb/utils.py +++ b/qiling/debugger/gdb/utils.py @@ -20,10 +20,12 @@ def __init__(self, ql: Qiling, entry_point: int, exit_point: int): self.exit_point = exit_point self.swbp = set() self.last_bp = None + self._need_flush_tb = False def __entry_point_hook(ql: Qiling): ql.hook_del(ep_hret) ql.hook_code(self.dbg_hook) + self._need_flush_tb = True ql.log.info(f'{PROMPT} stopped at entry point: {ql.arch.regs.arch_pc:#x}') ql.stop() @@ -32,6 +34,13 @@ def __entry_point_hook(ql: Qiling): # that hook will be used to set up the breakpoint handling hook ep_hret = ql.hook_address(__entry_point_hook, entry_point) + def flush_tb(self): + """Flush Unicorn translation blocks after GDB hook or breakpoint updates.""" + flush_tb = getattr(self.ql.uc, 'ctl_flush_tb', None) + + if flush_tb is not None: + flush_tb() + def dbg_hook(self, ql: Qiling, address: int, size: int): if getattr(ql.arch, 'is_thumb', False): address |= 1 @@ -56,6 +65,8 @@ def bp_insert(self, addr: int, size: int): for bp in targets: self.swbp.add(bp) + self._need_flush_tb = True + self.ql.log.info(f'{PROMPT} breakpoint added at {addr:#x}') return True @@ -69,6 +80,8 @@ def bp_remove(self, addr: int, size: int) -> bool: for bp in targets: self.swbp.remove(bp) + self._need_flush_tb = True + self.ql.log.info(f'{PROMPT} breakpoint removed from {addr:#x}') return True @@ -80,6 +93,10 @@ def resume_emu(self, address: Optional[int] = None, steps: int = 0): if getattr(self.ql.arch, 'is_thumb', False): address |= 0b1 + if self._need_flush_tb: + self.flush_tb() + self._need_flush_tb = False + op = f'stepping {steps} instructions' if steps else 'resuming' self.ql.log.info(f'{PROMPT} {op} from {address:#x}') diff --git a/qiling/debugger/gdb/xml/riscv/riscv-core.xml b/qiling/debugger/gdb/xml/riscv/riscv-core.xml new file mode 100644 index 000000000..76180b824 --- /dev/null +++ b/qiling/debugger/gdb/xml/riscv/riscv-core.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qiling/debugger/gdb/xml/riscv/riscv-fpu.xml b/qiling/debugger/gdb/xml/riscv/riscv-fpu.xml new file mode 100644 index 000000000..1e1838e99 --- /dev/null +++ b/qiling/debugger/gdb/xml/riscv/riscv-fpu.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qiling/debugger/gdb/xml/riscv/target.xml b/qiling/debugger/gdb/xml/riscv/target.xml new file mode 100644 index 000000000..1d0eb2b00 --- /dev/null +++ b/qiling/debugger/gdb/xml/riscv/target.xml @@ -0,0 +1,15 @@ + + + + + + riscv:rv32 + GNU/Linux + + + + diff --git a/qiling/debugger/gdb/xml/riscv64/riscv64-core.xml b/qiling/debugger/gdb/xml/riscv64/riscv64-core.xml new file mode 100644 index 000000000..61ec01e1d --- /dev/null +++ b/qiling/debugger/gdb/xml/riscv64/riscv64-core.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qiling/debugger/gdb/xml/riscv64/riscv64-fpu.xml b/qiling/debugger/gdb/xml/riscv64/riscv64-fpu.xml new file mode 100644 index 000000000..1e1838e99 --- /dev/null +++ b/qiling/debugger/gdb/xml/riscv64/riscv64-fpu.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qiling/debugger/gdb/xml/riscv64/target.xml b/qiling/debugger/gdb/xml/riscv64/target.xml new file mode 100644 index 000000000..3f51b9352 --- /dev/null +++ b/qiling/debugger/gdb/xml/riscv64/target.xml @@ -0,0 +1,15 @@ + + + + + + riscv:rv64 + GNU/Linux + + + + diff --git a/qiling/debugger/gdb/xmlregs.py b/qiling/debugger/gdb/xmlregs.py index 6bc2371f4..a84ec6700 100644 --- a/qiling/debugger/gdb/xmlregs.py +++ b/qiling/debugger/gdb/xmlregs.py @@ -42,6 +42,12 @@ reg_map as ppc_regs ) +from qiling.arch.riscv_const import ( + reg_csr_map as riscv_regs_csr, + reg_float_map as riscv_regs_float, + reg_map as riscv_regs +) + from qiling.const import QL_ARCH, QL_OS RegEntry = Tuple[Optional[int], int, int] @@ -147,7 +153,9 @@ def __load_regsmap(archtype: QL_ARCH, xmltree: ElementTree.ElementTree) -> Seque QL_ARCH.CORTEX_M: dict(**cortex_m_regs), QL_ARCH.ARM64: dict(**arm64_regs, **arm64_regs_v, **arm64_reg_map_fp), QL_ARCH.MIPS: dict(**mips_regs_gpr), - QL_ARCH.PPC: dict(**ppc_regs) + QL_ARCH.PPC: dict(**ppc_regs), + QL_ARCH.RISCV: dict(**riscv_regs, **riscv_regs_float, **riscv_regs_csr), + QL_ARCH.RISCV64: dict(**riscv_regs, **riscv_regs_float, **riscv_regs_csr) }[archtype] regsinfo = sorted(QlGdbFeatures.__walk_xml_regs(xmltree))