2 releases

0.1.1 May 22, 2024
0.1.0 May 21, 2024

#727 in Algorithms


Used in jingle

MIT license

4.5MB
107K SLoC

C++ 105K SLoC // 0.2% comments Rust 2.5K SLoC // 0.0% comments

jingle_sleigh: A Rust FFI Layer around Ghidra's SLEIGH

sleigh is the code translator at the heart of ghidra's excellent decompiler. sleigh converts instruction bytes into sequences of PCODE, an intermediate representation of processor semantics on an idealized machine.

License

sleigh, like the rest of ghidra is licensed APACHE 2, and you can find the original license reproduced here. jingle makes no modifications to the existing code in sleigh, but instead adds code outside it for FFI purposes. While the sleigh source is not distributed in this repo (and is instead pulled in through a submodule), I am including the license as distribution through crates.io would require vendoring the sleigh sources into the crate for distribution.

Why do this?

This is hardly the first time someone has written a rust FFI around sleigh. However, I wanted to have control over the FFI since I had particular requirements for jingle and figured "what's one more?"

How do I use this?

This library provides only the rust binding around sleigh, you will need to provide your own architecture definition for sleigh to parse. The easiest way to do this is to install ghidra, open a file of the given architecture, and then point jingle_sleigh towards that ghidra installation. More enterprising users can run the sleigh compiler themselves.

I would have preferred to allow compiling slaspecs in this library, but there are some difficulties linking in those parts of sleigh because much of the logic for parsing architectures exists in a file that also has a main and of course no linker likes dealing with multiple mains.

But anyway, here's an example of usage yanked from the tests:

    #[test]
    fn get_one() {
        let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3];
        let ctx_builder =
            SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap();
        let ctx = ctx_builder
            .set_image(Image::from(mov_eax_0.as_slice()))
            .build("x86:LE:64:default")
            .unwrap();
        let instr = ctx.read(0, 1).last().unwrap();
        assert_eq!(instr.length, 5);
        assert!(instr.disassembly.mnemonic.eq("MOV"));
        assert!(!instr.ops.is_empty());
        varnode!(&ctx, #0:4).unwrap();
        let _op = PcodeOperation::Copy {
            input: varnode!(&ctx, #0:4).unwrap(),
            output: varnode!(&ctx, "register"[0]:4).unwrap(),
        };
        assert!(matches!(&instr.ops[0], _op))
    }

Dependencies

~1.7–4MB
~69K SLoC