Skip to content

Introduce a trait/derive macro for constructing Binja types out of Rust types #4545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from

Conversation

mkrasnitski
Copy link
Contributor

This work is not yet finished, but I'm opening a draft to get discussion going about design decisions. This PR introduces a trait BinaryNinjaType with the following definition:

pub trait BinaryNinjaType {
    fn binja_type() -> Ref<Type>;
}

Implementing this trait on a Rust type allows it to be converted into a Binja Type to be sent to a BinaryView. Accompanying the trait is a derive macro that allows automatic implementation of this trait for any Rust type, as long as it satisfies the following restrictions:

  • Structs/Unions must be marked repr(C). This is just a design decision aimed at making the trait's semantics more obvious. Unit structs and Tuple structs (with unnamed fields) are unsupported.
  • Enums must not be repr(C), and must instead be marked with a primitive type, e.g. repr(u8) or repr(u32). They must also be fieldless (all variants must not contain extra data), in other words C-style. Additionally, all variants must be assigned an explicit discriminant value.
    • All primitive integer types are allowed for representation, except for u128, i128, usize and isize.

Currently, several features are missing which I hope to implement, but they are non-trivial and therefore require a bit of discussion around design:

  • Pointers - The Type::pointer constructor requires an architecture and no others do.
  • repr(C) on Enums - The underlying representation (width) is ABI-dependant, which basically means arch-dependant in Binja terms. So, in order for the semantics to make sense, this needs to rely on an architecture, the same as pointers.
  • Named Types - Rather than having nested structs be inlined in the type definition, I'd like to be reference named types via an attribute on the field like #[name = "..."]. However, actually resolving this requires querying a BinaryView.

The following features are also currently missing but are more straightforward to implement:

  • repr(transparent) on Structs and Enums - This is valid if there is only a single non-zero-sized field/variant. However, the complication is that any number of additional zero-sized fields can live alongside it (such as PhantomData), and determining which of the fields is the one with non-zero size seems tricky.
  • repr(align) and repr(packed) - This would be nice to add, such that alignment and padding could be specified in Rust, but requires me reading up a bit more about how exactly these attributes work.

I would appreciate feedback and thoughts on addressing what's missing.

This trait allows the user to transform a Rust type definition into a
Binja `Type` object that can be applied to a Binary View. This is done
via the `BinaryNinjaType::binja_type` constructor.

TODO: Pointers, Enums, Unions, and named types
Only fixed-width (e.g. `repr(u8)`) enums without any nested fields are
allowed.

Things left TODO: Pointers, Named Types, `repr(transparent)`,
`repr(align)`, `repr(packed)`, and `repr(C)` on fieldless enums
@mkrasnitski
Copy link
Contributor Author

With regards to architecture-dependency, I think a possible solution involves having binja_type not return a Type, but instead an intermediate representation of the type that abstracts pointers, named types, etc. Then, a given BinaryView or Architecture could ingest this intermediate type, convert it to a Type internally by resolving pointer width and type names, and return it back.

In addition to the above, if it ends up turning out that a Binja Type can be cheaply converted into this intermediate type, then all the places where Binja expects a Type could be changed to expect this intermediate type instead, or even trait bounded on all types which can be turned into it (which would include anything that implements BinaryNinjaType, plus actual Type objects).

@mkrasnitski
Copy link
Contributor Author

Closing this for now as there's some roadblocks to this in its current state - will open a followup PR at some point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant