Skip to content

Commit 79b09fa

Browse files
authored
asm: improve error output for fuzzer (#10474)
This adds additional printed information for other kinds of failures, e.g., when an instruction fails to disassembly or does not disassemble all the bytes.
1 parent 865d1bb commit 79b09fa

File tree

1 file changed

+26
-17
lines changed

1 file changed

+26
-17
lines changed

cranelift/assembler-x64/src/fuzz.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use capstone::{arch::x86, arch::BuildsCapstone, arch::BuildsCapstoneSyntax, Caps
1919
pub fn roundtrip(inst: &Inst<FuzzRegs>) {
2020
// Check that we can actually assemble this instruction.
2121
let assembled = assemble(inst);
22-
let expected = disassemble(&assembled);
22+
let expected = disassemble(&assembled, inst);
2323

2424
// Check that our pretty-printed output matches the known-good output. Trim
2525
// off the instruction offset first.
@@ -39,37 +39,46 @@ pub fn roundtrip(inst: &Inst<FuzzRegs>) {
3939
///
4040
/// This will skip any traps or label registrations, but this is fine for the
4141
/// single-instruction disassembly we're doing here.
42-
fn assemble(insn: &Inst<FuzzRegs>) -> Vec<u8> {
42+
fn assemble(inst: &Inst<FuzzRegs>) -> Vec<u8> {
4343
let mut buffer = Vec::new();
4444
let offsets: Vec<i32> = Vec::new();
45-
insn.encode(&mut buffer, &offsets);
45+
inst.encode(&mut buffer, &offsets);
4646
buffer
4747
}
4848

4949
/// Building a new `Capstone` each time is suboptimal (TODO).
50-
fn disassemble(assembled: &[u8]) -> String {
50+
fn disassemble(assembled: &[u8], original: &Inst<FuzzRegs>) -> String {
5151
let cs = Capstone::new()
5252
.x86()
5353
.mode(x86::ArchMode::Mode64)
5454
.syntax(x86::ArchSyntax::Att)
5555
.detail(true)
5656
.build()
5757
.expect("failed to create Capstone object");
58-
let insns = cs
58+
let insts = cs
5959
.disasm_all(assembled, 0x0)
6060
.expect("failed to disassemble");
61-
assert_eq!(insns.len(), 1, "not a single instruction: {assembled:02x?}");
62-
let insn = insns.first().expect("at least one instruction");
63-
assert_eq!(
64-
assembled.len(),
65-
insn.len(),
66-
"\ncranelift generated {} bytes: {assembled:02x?}\n\
67-
capstone generated {} bytes: {:02x?}",
68-
assembled.len(),
69-
insn.len(),
70-
insn.bytes(),
71-
);
72-
insn.to_string()
61+
62+
if insts.len() != 1 {
63+
println!("> {original}");
64+
println!(" debug: {original:x?}");
65+
println!(" assembled: {}", pretty_print_hexadecimal(&assembled));
66+
assert_eq!(insts.len(), 1, "not a single instruction");
67+
}
68+
69+
let inst = insts.first().expect("at least one instruction");
70+
if assembled.len() != inst.len() {
71+
println!("> {original}");
72+
println!(" debug: {original:x?}");
73+
println!(" assembled: {}", pretty_print_hexadecimal(&assembled));
74+
println!(
75+
" capstone-assembled: {}",
76+
pretty_print_hexadecimal(inst.bytes())
77+
);
78+
assert_eq!(assembled.len(), inst.len(), "extra bytes not disassembled");
79+
}
80+
81+
inst.to_string()
7382
}
7483

7584
fn pretty_print_hexadecimal(hex: &[u8]) -> String {

0 commit comments

Comments
 (0)