Skip to main content

Crate imping_codegen

Crate imping_codegen 

Source
Expand description

Generates Rust bindings from imping IR.

Generator turns an imping_ir::Ir into formatted Rust source, one pub mod per IR module, and returns it as Bindings with any Warnings. The generated code depends only on imping-runtime.

§Examples

let ir = imping_ir::Ir::from_json_str(r#"{
    "format_version": { "major": 1, "minor": 0 },
    "modules": [{
        "name": "target.exe", "architecture": "x64",
        "image_base": "0x140000000", "timestamp": "0x64b8f2a1", "image_size": "0xa2b000",
        "types": [
            { "id": 0, "name": "float", "kind": "primitive", "primitive": "f32" },
            { "id": 1, "name": "Vector2", "kind": "struct", "size": 8, "align": 4,
              "fields": [
                { "name": "x", "type": 0, "offset": 0 },
                { "name": "y", "type": 0, "offset": 4 }
              ] }
        ]
    }]
}"#)?;

let bindings = imping_codegen::Generator::new().generate(&[("steam", &ir)])?;
assert!(bindings.source().contains("pub mod target"));
assert!(bindings.source().contains("pub struct Vector2"));
assert!(bindings.warnings().is_empty());

§Several builds

Each IR file describes one build of the target, and generate takes them all, each with a label such as steam_2021. One set of bindings then serves every build: types, functions and globals are matched by namespace and name, must agree on their layouts and signatures, and keep each build’s address. An item only some IRs have is generated too; on the other builds it’s found by another build’s byte pattern.

§Generated code

  • Each module gets a MODULE identity, a Build enum with a variant per label, an init() that checks the running build and returns which it is, and build().
  • Types, functions and globals go in one module per namespace (target::hw::cVec4 for the type Hw::cVec4).
  • Structs become #[repr(C)] with explicit padding, bitfield accessors and compile-time checks on size, alignment and every field offset; unions get the same checks.
  • A struct whose IR field is marked as its base class (a struct at offset 0) derefs to that base and implements imping_runtime::Inherits for it and the base’s own bases, so upcast() turns pointers into base pointers.
  • Enums become integer newtypes with associated constants, typedefs become type aliases, and opaque types become byte arrays or zero-sized markers.
  • Functions become an unsafe fn plus a module of the same name with the function’s address in each build (RVA_STEAM_2021), rva() for the loaded build, Signature, ptr() and hook(). A hook’s closure gets the function’s Original first; original.forward() safely makes the call the target was making. A parameter named like a static or enum type in its module gets a trailing _.
  • Functions tagged imping-safe get a safe fn whose pointer parameters are references, unless a parameter has no safe form (a Warning says so). The tag means the function is always fine to call with valid arguments and keeps none of its pointer arguments after returning.
  • Globals become imping_runtime::Global statics. Structs, unions and enums whose every bit pattern is valid implement imping_runtime::Plain, which makes their globals safe to read and write.

Structs§

Bindings
Generated Rust source plus the warnings raised while generating it.
BuildsDiffer
What two builds’ IRs disagree on; see Error::BuildsDiffer.
Generator
Generates Rust bindings from the Ir of one or more builds.

Enums§

Error
Why Generator::generate failed.
Warning
Something the generator skipped or simplified.