Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]

[dev-packages]

[requires]
python_version = "3.13"
13 changes: 13 additions & 0 deletions src/rust/iced-x86-py/Pipfile
Original file line number Diff line number Diff line change
@@ -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"
42 changes: 36 additions & 6 deletions src/rust/iced-x86-py/src/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u32>, address: u64, _address_size: u32,
) -> Option<iced_x86::SymbolResult<'_>> {
let instr = Instruction { instr: *_instruction };
Python::with_gil(|py| {
let sym: Option<String> =
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<Self> {
#[pyo3(signature = (syntax, symbol_resolver = None))]
fn new(syntax: u32, symbol_resolver: Option<PyObject>) -> PyResult<Self> {
let resolver = symbol_resolver.map(|val| -> Box<dyn iced_x86::SymbolResolver> { Box::new(SymbolResolverAdapter::new(val)) });

let formatter: Box<dyn iced_x86::Formatter> = 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"));
};
Expand Down
2 changes: 1 addition & 1 deletion src/rust/iced-x86-py/src/iced_x86/_iced_x86_py.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions src/rust/iced-x86-py/tests/formatter_gas_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
16 changes: 16 additions & 0 deletions src/rust/iced-x86-py/tests/formatter_intel_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]"
16 changes: 16 additions & 0 deletions src/rust/iced-x86-py/tests/formatter_masm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]"
16 changes: 16 additions & 0 deletions src/rust/iced-x86-py/tests/formatter_nasm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]"