Skip to content

Commit

Permalink
Small fixes for RISC-V (pwndbg#2172)
Browse files Browse the repository at this point in the history
* Fix i386-32 syscall name printing

pwndbg-git from AUR shows hexadecimal constants in masm syntax
(e.g. 80h) for some reason (as if the option CS_OPT_SYNTAX_MASM was set).
This commit makes syscall name printing work regardless of hex syntax.

* riscv: Fix AssertionError on "jalr ra, ra, 0x252"

When the PC was on this instruction, the pwndbg context would not be
printed due to this AssertionError.

* riscv: Fix AssertionError on "c.jalr a5"

According to the specification, "C.JALR expands to jalr x1, 0(rs1)".
  • Loading branch information
Ordoviz authored May 22, 2024
1 parent 213bc8b commit 2b9beef
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 18 deletions.
16 changes: 5 additions & 11 deletions pwndbg/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import pwndbg.chain
import pwndbg.constants
import pwndbg.disasm
import pwndbg.disasm.arch
import pwndbg.gdblib.arch
import pwndbg.gdblib.file
import pwndbg.gdblib.memory
Expand Down Expand Up @@ -71,7 +72,7 @@ def get_syscall_name(instruction: PwndbgInstruction) -> str | None:
if syscall_register in ("eax", "rax"):
mnemonic = instruction.mnemonic

is_32bit = mnemonic == "int" and instruction.op_str == "0x80"
is_32bit = mnemonic == "int" and instruction.operands[0].before_value == 0x80
if not (mnemonic == "syscall" or is_32bit):
return None

Expand All @@ -87,7 +88,7 @@ def get_syscall_name(instruction: PwndbgInstruction) -> str | None:
def get(instruction: PwndbgInstruction) -> List[Tuple[pwndbg.lib.functions.Argument, int]]:
"""
Returns an array containing the arguments to the current function,
if $pc is a 'call' or 'bl' type instruction.
if $pc is a 'call', 'bl', or 'jalr' type instruction.
Otherwise, returns None.
"""
Expand All @@ -105,19 +106,12 @@ def get(instruction: PwndbgInstruction) -> List[Tuple[pwndbg.lib.functions.Argum
except KeyError:
return []

# Not sure of any OS which allows multiple operands on
# a call instruction.
assert len(instruction.operands) == 1

target = instruction.operands[0].before_value
assistant = pwndbg.disasm.arch.DisassemblyAssistant.for_current_arch()
target = assistant.resolve_target(instruction, None, call=True)

if not target:
return []

if pwndbg.gdblib.arch.name in ["rv32", "rv64"]:
target += instruction.address
target &= pwndbg.gdblib.arch.ptrmask

name = pwndbg.gdblib.symbol.get(target)
if not name:
return []
Expand Down
8 changes: 4 additions & 4 deletions pwndbg/disasm/riscv.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@ def resolve_target(self, instruction: PwndbgInstruction, emu: Emulator | None, c

# Determine the target address of the indirect jump
if instruction.id in [RISCV_INS_JALR, RISCV_INS_C_JALR]:
target = (
instruction.op_find(CS_OP_REG, 1).before_value
+ instruction.op_find(CS_OP_IMM, 1).imm
) & ptrmask
target = instruction.op_find(CS_OP_REG, 1).before_value
if instruction.id == RISCV_INS_JALR:
target += instruction.op_find(CS_OP_IMM, 1).imm
target &= ptrmask
# Clear the lowest bit without knowing the register width
return target ^ (target & 1)

Expand Down
15 changes: 12 additions & 3 deletions tests/qemu-tests/tests/user/test_riscv64.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import re
import sys
import traceback

Expand All @@ -13,11 +12,21 @@
assert pwndbg.gdblib.symbol.address("main") == 0x4000000668
gdb.execute("continue")

gdb.execute("nextcall", to_string=True)
gdb.execute("stepuntilasm jalr")

# verify call argument are enriched
assembly = gdb.execute("nearpc", to_string=True)
assert re.search(r"s.*'Not enough args'", assembly), assembly
assert "'Not enough args'" in assembly

gdb.execute("stepuntilasm c.jalr")

# verify jump target is correct
assembly = gdb.execute("nearpc 0", to_string=True)
target = assembly.splitlines()[0].split()[-1]
gdb.execute("stepi")
assembly = gdb.execute("nearpc 0", to_string=True)
assert assembly.split()[2] == target, (assembly.split()[2], target)

except AssertionError:
traceback.print_exc(file=sys.stdout)
sys.exit(1)

0 comments on commit 2b9beef

Please sign in to comment.