diff --git a/Pipfile b/Pipfile new file mode 100644 index 000000000..d61ea531d --- /dev/null +++ b/Pipfile @@ -0,0 +1,11 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +[requires] +python_version = "3.13" diff --git a/src/rust/iced-x86-py/Pipfile b/src/rust/iced-x86-py/Pipfile new file mode 100644 index 000000000..8bf491636 --- /dev/null +++ b/src/rust/iced-x86-py/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +build = "*" +setuptools-rust = "*" + +[dev-packages] + +[requires] +python_version = "3.13" diff --git a/src/rust/iced-x86-py/src/formatter.rs b/src/rust/iced-x86-py/src/formatter.rs index 5a2214eb1..48c147f0c 100644 --- a/src/rust/iced-x86-py/src/formatter.rs +++ b/src/rust/iced-x86-py/src/formatter.rs @@ -54,19 +54,49 @@ pub(crate) struct Formatter { unsafe impl Send for Formatter {} unsafe impl Sync for Formatter {} +struct SymbolResolverAdapter { + resolver: PyObject, +} + +impl SymbolResolverAdapter { + fn new(resolver: PyObject) -> SymbolResolverAdapter { + SymbolResolverAdapter { resolver } + } +} + +impl iced_x86::SymbolResolver for SymbolResolverAdapter { + fn symbol( + &mut self, _instruction: &iced_x86::Instruction, _operand: u32, _instruction_operand: Option, address: u64, _address_size: u32, + ) -> Option> { + let instr = Instruction { instr: *_instruction }; + Python::with_gil(|py| { + let sym: Option = + self.resolver.call1(py, (instr, _operand, _instruction_operand, address, _address_size)).unwrap().extract(py).unwrap(); + + if let Some(val) = sym { + Some(iced_x86::SymbolResult::with_string(address, val)) + } else { + None + } + }) + } +} + #[pymethods] impl Formatter { #[new] - #[pyo3(text_signature = "(syntax)")] - fn new(syntax: u32) -> PyResult { + #[pyo3(signature = (syntax, symbol_resolver = None))] + fn new(syntax: u32, symbol_resolver: Option) -> PyResult { + let resolver = symbol_resolver.map(|val| -> Box { Box::new(SymbolResolverAdapter::new(val)) }); + let formatter: Box = if syntax == FormatterSyntax::Gas as u32 { - Box::new(iced_x86::GasFormatter::new()) + Box::new(iced_x86::GasFormatter::with_options(resolver, None)) } else if syntax == FormatterSyntax::Intel as u32 { - Box::new(iced_x86::IntelFormatter::new()) + Box::new(iced_x86::IntelFormatter::with_options(resolver, None)) } else if syntax == FormatterSyntax::Masm as u32 { - Box::new(iced_x86::MasmFormatter::new()) + Box::new(iced_x86::MasmFormatter::with_options(resolver, None)) } else if syntax == FormatterSyntax::Nasm as u32 { - Box::new(iced_x86::NasmFormatter::new()) + Box::new(iced_x86::NasmFormatter::with_options(resolver, None)) } else { return Err(PyValueError::new_err("Invalid formatter syntax")); }; diff --git a/src/rust/iced-x86-py/src/iced_x86/_iced_x86_py.pyi b/src/rust/iced-x86-py/src/iced_x86/_iced_x86_py.pyi index 012397fce..61bca9216 100644 --- a/src/rust/iced-x86-py/src/iced_x86/_iced_x86_py.pyi +++ b/src/rust/iced-x86-py/src/iced_x86/_iced_x86_py.pyi @@ -996,7 +996,7 @@ class Formatter: assert disasm == "VCVTNE2PS2BF16 zmm2{k5}{z},zmm6,dword bcst [rax+4]" ``` """ - def __init__(self, syntax: FormatterSyntax) -> None: ... + def __init__(self, syntax: FormatterSyntax, symbol_resolver: Callable) -> None: ... def format(self, instruction: Instruction) -> str: """ Formats the whole instruction: prefixes, mnemonic, operands diff --git a/src/rust/iced-x86-py/tests/formatter_gas_test.py b/src/rust/iced-x86-py/tests/formatter_gas_test.py index 5f605767c..0174bc104 100644 --- a/src/rust/iced-x86-py/tests/formatter_gas_test.py +++ b/src/rust/iced-x86-py/tests/formatter_gas_test.py @@ -115,3 +115,19 @@ def test_format() -> None: assert formatter.format_u16(0x89AB) == "0x89AB" assert formatter.format_u32(0x89ABCDEF) == "0x89ABCDEF" assert formatter.format_u64(0xFEDCBA9876543210) == "0xFEDCBA9876543210" + +def test_format_with_symbol_resolver(): + def symbol_resolver(instr, op, instr_op, addr, addr_size): + if addr == 0x00: + return "foo" + elif addr == 0x0B: + return "boo" + else: + return None + + instr1, _, _, instr4, _, _, instr7 = list(Decoder(32, b"\xE8\x06\x00\x00\x00\x31\xDB\xF7\xE2\xEB\xF5\x83\xC0\x0E\xC3\x8D\x81\x0B\x00\x00\x00")) + formatter = Formatter(FORMATTER_SYNTAX, symbol_resolver) + + assert formatter.format(instr1) == "call boo" + assert formatter.format(instr4) == "jmp foo" + assert formatter.format(instr7) == "lea boo(%ecx),%eax" diff --git a/src/rust/iced-x86-py/tests/formatter_intel_test.py b/src/rust/iced-x86-py/tests/formatter_intel_test.py index 2c1bcdc67..1ff32c5a1 100644 --- a/src/rust/iced-x86-py/tests/formatter_intel_test.py +++ b/src/rust/iced-x86-py/tests/formatter_intel_test.py @@ -115,3 +115,19 @@ def test_format() -> None: assert formatter.format_u16(0x89AB) == "89ABh" assert formatter.format_u32(0x89ABCDEF) == "89ABCDEFh" assert formatter.format_u64(0xFEDCBA9876543210) == "0FEDCBA9876543210h" + +def test_format_with_symbol_resolver(): + def symbol_resolver(instr, op, instr_op, addr, addr_size): + if addr == 0x00: + return "foo" + elif addr == 0x0B: + return "boo" + else: + return None + + instr1, _, _, instr4, _, _, instr7 = list(Decoder(32, b"\xE8\x06\x00\x00\x00\x31\xDB\xF7\xE2\xEB\xF5\x83\xC0\x0E\xC3\x8D\x81\x0B\x00\x00\x00")) + formatter = Formatter(FORMATTER_SYNTAX, symbol_resolver) + + assert formatter.format(instr1) == "call boo" + assert formatter.format(instr4) == "jmp short foo" + assert formatter.format(instr7) == "lea eax,[ecx+boo]" diff --git a/src/rust/iced-x86-py/tests/formatter_masm_test.py b/src/rust/iced-x86-py/tests/formatter_masm_test.py index 703ac5e54..a90daf759 100644 --- a/src/rust/iced-x86-py/tests/formatter_masm_test.py +++ b/src/rust/iced-x86-py/tests/formatter_masm_test.py @@ -115,3 +115,19 @@ def test_format() -> None: assert formatter.format_u16(0x89AB) == "89ABh" assert formatter.format_u32(0x89ABCDEF) == "89ABCDEFh" assert formatter.format_u64(0xFEDCBA9876543210) == "0FEDCBA9876543210h" + +def test_format_with_symbol_resolver(): + def symbol_resolver(instr, op, instr_op, addr, addr_size): + if addr == 0x00: + return "foo" + elif addr == 0x0B: + return "boo" + else: + return None + + instr1, _, _, instr4, _, _, instr7 = list(Decoder(32, b"\xE8\x06\x00\x00\x00\x31\xDB\xF7\xE2\xEB\xF5\x83\xC0\x0E\xC3\x8D\x81\x0B\x00\x00\x00")) + formatter = Formatter(FORMATTER_SYNTAX, symbol_resolver) + + assert formatter.format(instr1) == "call boo" + assert formatter.format(instr4) == "jmp short foo" + assert formatter.format(instr7) == "lea eax,[ecx+boo]" diff --git a/src/rust/iced-x86-py/tests/formatter_nasm_test.py b/src/rust/iced-x86-py/tests/formatter_nasm_test.py index 18e4a3db8..13c2ab293 100644 --- a/src/rust/iced-x86-py/tests/formatter_nasm_test.py +++ b/src/rust/iced-x86-py/tests/formatter_nasm_test.py @@ -115,3 +115,19 @@ def test_format() -> None: assert formatter.format_u16(0x89AB) == "89ABh" assert formatter.format_u32(0x89ABCDEF) == "89ABCDEFh" assert formatter.format_u64(0xFEDCBA9876543210) == "0FEDCBA9876543210h" + +def test_format_with_symbol_resolver(): + def symbol_resolver(instr, op, instr_op, addr, addr_size): + if addr == 0x00: + return "foo" + elif addr == 0x0B: + return "boo" + else: + return None + + instr1, _, _, instr4, _, _, instr7 = list(Decoder(32, b"\xE8\x06\x00\x00\x00\x31\xDB\xF7\xE2\xEB\xF5\x83\xC0\x0E\xC3\x8D\x81\x0B\x00\x00\x00")) + formatter = Formatter(FORMATTER_SYNTAX, symbol_resolver) + + assert formatter.format(instr1) == "call boo" + assert formatter.format(instr4) == "jmp short foo" + assert formatter.format(instr7) == "lea eax,[ecx+boo]"