mirror of https://github.com/pwndbg/pwndbg.git
Add capstone for loongarch64 (#2885)
* init loongarch64 capstone * loongarch64 fix resolving symbols Co-authored-by: OBarronCS <55004530+OBarronCS@users.noreply.github.com> * disasm display arch name in instruction repr * fix resolve target for `ALIAS_RET` instruction Co-authored-by: OBarronCS <55004530+OBarronCS@users.noreply.github.com> * fix reviewdog * rebase with dev branch * fix lint * fix lint * fix lint * fix typos --------- Co-authored-by: OBarronCS <55004530+OBarronCS@users.noreply.github.com>pull/2907/head
parent
d2efb84d6a
commit
75debdef36
@ -0,0 +1,99 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
|
||||
from capstone import * # noqa: F403
|
||||
from capstone.loongarch import * # noqa: F403
|
||||
from typing_extensions import override
|
||||
|
||||
import pwndbg.aglib.disasm.arch
|
||||
import pwndbg.lib.disasm.helpers as bit_math
|
||||
from pwndbg.aglib.disasm.instruction import InstructionCondition
|
||||
from pwndbg.aglib.disasm.instruction import PwndbgInstruction
|
||||
|
||||
# Emulator currently requires GDB, and we only use it here for type checking.
|
||||
if TYPE_CHECKING:
|
||||
from pwndbg.emu.emulator import Emulator
|
||||
|
||||
CONDITION_RESOLVERS: Dict[int, Callable[[List[int]], bool]] = {
|
||||
LOONGARCH_INS_BEQZ: lambda ops: ops[0] == 0,
|
||||
LOONGARCH_INS_BNEZ: lambda ops: ops[0] != 0,
|
||||
LOONGARCH_INS_BEQ: lambda ops: ops[0] == ops[1],
|
||||
LOONGARCH_INS_BNE: lambda ops: ops[0] != ops[1],
|
||||
LOONGARCH_INS_BGE: lambda ops: bit_math.to_signed(ops[0], pwndbg.aglib.arch.ptrsize * 8)
|
||||
>= bit_math.to_signed(ops[1], pwndbg.aglib.arch.ptrsize * 8),
|
||||
LOONGARCH_INS_BLT: lambda ops: bit_math.to_signed(ops[0], pwndbg.aglib.arch.ptrsize * 8)
|
||||
< bit_math.to_signed(ops[1], pwndbg.aglib.arch.ptrsize * 8),
|
||||
LOONGARCH_INS_BLTU: lambda ops: ops[0] < ops[1],
|
||||
LOONGARCH_INS_BGEU: lambda ops: ops[0] >= ops[1],
|
||||
}
|
||||
|
||||
|
||||
LOONGARCH_LOAD_INSTRUCTIONS: Dict[int, int] = {}
|
||||
|
||||
LOONGARCH_STORE_INSTRUCTIONS: Dict[int, int] = {}
|
||||
|
||||
LOONGARCH_BINARY_OPERATIONS: Dict[int, str] = {}
|
||||
|
||||
|
||||
# This class enhances 64-bit Loongarch
|
||||
class Loong64DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
|
||||
def __init__(self, architecture) -> None:
|
||||
super().__init__(architecture)
|
||||
|
||||
self.annotation_handlers: Dict[int, Callable[[PwndbgInstruction, Emulator], None]] = {}
|
||||
|
||||
@override
|
||||
def _condition(self, instruction: PwndbgInstruction, emu: Emulator) -> InstructionCondition:
|
||||
if len(instruction.operands) == 0:
|
||||
return InstructionCondition.UNDETERMINED
|
||||
|
||||
# Not using list comprehension because they run in a separate scope in which super() does not exist
|
||||
resolved_operands: List[int] = []
|
||||
for op in instruction.operands:
|
||||
resolved_operands.append(
|
||||
super()._resolve_used_value(op.before_value, instruction, op, emu)
|
||||
)
|
||||
|
||||
# If any of the relevent operands are None (we can't reason about them), quit.
|
||||
if any(value is None for value in resolved_operands[:-1]):
|
||||
# Note the [:-1]. Loongarch jump instructions have the target as the last operand
|
||||
# https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_beqz_bnez
|
||||
return InstructionCondition.UNDETERMINED
|
||||
|
||||
conditional = CONDITION_RESOLVERS.get(instruction.id, lambda *a: None)(resolved_operands)
|
||||
|
||||
if conditional is None:
|
||||
return InstructionCondition.UNDETERMINED
|
||||
|
||||
return InstructionCondition.TRUE if conditional else InstructionCondition.FALSE
|
||||
|
||||
@override
|
||||
def _resolve_target(self, instruction: PwndbgInstruction, emu: Emulator | None):
|
||||
if instruction.id == LOONGARCH_INS_ALIAS_RET:
|
||||
return self._read_register_name(instruction, "ra", emu)
|
||||
|
||||
# Manually compute target addresses for relative branches
|
||||
if instruction.id in (
|
||||
LOONGARCH_INS_B,
|
||||
LOONGARCH_INS_BL,
|
||||
LOONGARCH_INS_BEQ,
|
||||
LOONGARCH_INS_BNE,
|
||||
LOONGARCH_INS_BLT,
|
||||
LOONGARCH_INS_BGE,
|
||||
LOONGARCH_INS_BGEU,
|
||||
LOONGARCH_INS_BLTU,
|
||||
LOONGARCH_INS_BEQZ,
|
||||
LOONGARCH_INS_BNEZ,
|
||||
):
|
||||
# The relative offset is always the last operand
|
||||
return instruction.address + instruction.operands[-1].before_value
|
||||
|
||||
if instruction.id == LOONGARCH_INS_JIRL:
|
||||
if (offset_reg := instruction.operands[1].before_value) is not None:
|
||||
return offset_reg + (instruction.operands[2].before_value << 2)
|
||||
|
||||
return super()._resolve_target(instruction, emu)
|
||||
Loading…
Reference in new issue