diff --git a/pwndbg/commands/context.py b/pwndbg/commands/context.py index 6f6d74d658..09e857c0c9 100644 --- a/pwndbg/commands/context.py +++ b/pwndbg/commands/context.py @@ -720,7 +720,8 @@ def context_backtrace(with_banner=True, target=sys.stdout, width=None): for i in range(backtrace_lines - 1): try: candidate = oldest_frame.older() - except gdb.MemoryError: + # We catch gdb.error in case of a `gdb.error: PC not saved` case + except (gdb.MemoryError, gdb.error): break if not candidate: diff --git a/pwndbg/disasm/__init__.py b/pwndbg/disasm/__init__.py index 86972d0fb1..9dae2c126c 100644 --- a/pwndbg/disasm/__init__.py +++ b/pwndbg/disasm/__init__.py @@ -117,8 +117,25 @@ def get_disassembler(pc): ) +class SimpleInstruction: + def __init__(self, address): + self.address = address + ins = gdb.newest_frame().architecture().disassemble(address)[0] + asm = ins["asm"].split(None, 1) + self.mnemonic = asm[0].strip() + self.op_str = asm[1].strip() if len(asm) > 1 else "" + self.size = ins["length"] + self.next = self.address + self.size + self.target = self.next + self.groups = [] + self.symbol = None + self.condition = False + + @pwndbg.memoize.reset_on_cont def get_one_instruction(address): + if pwndbg.arch.current not in CapstoneArch: + return SimpleInstruction(address) md = get_disassembler(address) size = VariableInstructionSizeMax.get(pwndbg.arch.current, 4) data = pwndbg.memory.read(address, size, partial=True) diff --git a/pwndbg/regs.py b/pwndbg/regs.py index a35327a93e..54223b6421 100644 --- a/pwndbg/regs.py +++ b/pwndbg/regs.py @@ -473,6 +473,124 @@ def __iter__(self): retval="v0", ) +# https://riscv.org/technical/specifications/ +# Volume 1, Unprivileged Spec v. 20191213 +# Chapter 25 - RISC-V Assembly Programmer’s Handbook +# x0 => zero (Hard-wired zero) +# x1 => ra (Return address) +# x2 => sp (Stack pointer) +# x3 => gp (Global pointer) +# x4 => tp (Thread pointer) +# x5 => t0 (Temporary/alternate link register) +# x6–7 => t1–2 (Temporaries) +# x8 => s0/fp (Saved register/frame pointer) +# x9 => s1 (Saved register) +# x10-11 => a0–1 (Function arguments/return values) +# x12–17 => a2–7 (Function arguments) +# x18–27 => s2–11 (Saved registers) +# x28–31 => t3–6 (Temporaries) +# f0–7 => ft0–7 (FP temporaries) +# f8–9 => fs0–1 (FP saved registers) +# f10–11 => fa0–1 (FP arguments/return values) +# f12–17 => fa2–7 (FP arguments) +# f18–27 => fs2–11 (FP saved registers) +# f28–31 => ft8–11 (FP temporaries) +riscv = RegisterSet( + pc="pc", + frame="fp", + stack="sp", + retaddr="ra", + gpr=( + "ra", + "gp", + "tp", + "t0", + "t1", + "t2", + "fp", + "s1", + "a0", + "a1", + "a2", + "a3", + "a4", + "a5", + "a6", + "a7", + "s2", + "s3", + "s4", + "s5", + "s6", + "s7", + "s8", + "s9", + "s10", + "s11", + "t3", + "t4", + "t5", + "t6", + "ft0", + "ft1", + "ft2", + "ft3", + "ft4", + "ft5", + "ft6", + "ft7", + "fs0", + "fs1", + "fa0", + "fa1", + "fa2", + "fa3", + "fa4", + "fa5", + "fa6", + "fa7", + "fs2", + "fs3", + "fs4", + "fs5", + "fs6", + "fs7", + "fs8", + "fs9", + "fs10", + "fs11", + "ft8", + "ft9", + "ft10", + "ft11", + ), + retval=( + "a0", + "a1", + "fa0", + "fa1", + ), + args=( + "a0", + "a1", + "a2", + "a3", + "a4", + "a5", + "a6", + "a7", + "fa0", + "fa1", + "fa2", + "fa3", + "fa4", + "fa5", + "fa6", + "fa7", + ), +) + + arch_to_regs = { "i386": i386, "i8086": i386, @@ -483,6 +601,7 @@ def __iter__(self): "armcm": armcm, "aarch64": aarch64, "powerpc": powerpc, + "riscv:rv64": riscv, }