Skip to content

Commit 4f7df98

Browse files
committed
Support repr(packed) and repr(align) on structs/unions
1 parent 202b291 commit 4f7df98

File tree

1 file changed

+40
-2
lines changed
  • rust/binaryninja-derive/src

1 file changed

+40
-2
lines changed

rust/binaryninja-derive/src/lib.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,43 @@ use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt};
33
use quote::quote;
44
use syn::spanned::Spanned;
55
use syn::{
6-
parse_macro_input, Attribute, Data, DeriveInput, Fields, FieldsNamed, Ident, Path, Variant,
6+
parenthesized, parse_macro_input, token, Attribute, Data, DeriveInput, Fields, FieldsNamed,
7+
Ident, LitInt, Path, Variant,
78
};
89

910
type Result<T> = std::result::Result<T, Diagnostic>;
1011

1112
struct Repr {
1213
c: bool,
14+
packed: Option<usize>,
15+
align: Option<usize>,
1316
primitive: Option<(Path, bool)>,
1417
}
1518

1619
impl Repr {
1720
fn from_attrs(attrs: Vec<Attribute>) -> Result<Self> {
1821
let mut c = false;
22+
let mut packed = None;
23+
let mut align = None;
1924
let mut primitive = None;
2025
for attr in attrs {
2126
if attr.path().is_ident("repr") {
2227
attr.parse_nested_meta(|meta| {
2328
if let Some(ident) = meta.path.get_ident() {
2429
if ident == "C" {
2530
c = true;
31+
} else if ident == "packed" {
32+
if meta.input.peek(token::Paren) {
33+
let content;
34+
parenthesized!(content in meta.input);
35+
packed = Some(content.parse::<LitInt>()?.base10_parse()?);
36+
} else {
37+
packed = Some(1);
38+
}
39+
} else if ident == "align" {
40+
let content;
41+
parenthesized!(content in meta.input);
42+
align = Some(content.parse::<LitInt>()?.base10_parse()?);
2643
} else if ident_in_list(ident, ["u8", "u16", "u32", "u64"]) {
2744
primitive = Some((meta.path.clone(), false));
2845
} else if ident_in_list(ident, ["i8", "i16", "i32", "i64"]) {
@@ -39,7 +56,12 @@ impl Repr {
3956
}
4057
}
4158

42-
Ok(Self { c, primitive })
59+
Ok(Self {
60+
c,
61+
packed,
62+
align,
63+
primitive,
64+
})
4365
}
4466
}
4567

@@ -105,12 +127,17 @@ fn impl_abstract_struct_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Re
105127
}
106128

107129
let args = field_arguments(&name, fields);
130+
let packed = repr.packed.is_some();
131+
let alignment = repr.align.map(|align| quote! { .set_alignment(#align) });
108132
Ok(quote! {
109133
impl ::binaryninja::types::AbstractType for #name {
110134
fn resolve_type() -> ::binaryninja::rc::Ref<::binaryninja::types::Type> {
111135
::binaryninja::types::Type::structure(
112136
&::binaryninja::types::Structure::builder()
113137
#(.insert(#args))*
138+
.set_width(::std::mem::size_of::<#name>() as u64)
139+
.set_packed(#packed)
140+
#alignment
114141
.finalize()
115142
)
116143
}
@@ -124,6 +151,8 @@ fn impl_abstract_union_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Res
124151
}
125152

126153
let args = field_arguments(&name, fields);
154+
let packed = repr.packed.is_some();
155+
let alignment = repr.align.map(|align| quote! { .set_alignment(#align) });
127156
Ok(quote! {
128157
impl ::binaryninja::types::AbstractType for #name {
129158
fn resolve_type() -> ::binaryninja::rc::Ref<::binaryninja::types::Type> {
@@ -133,6 +162,9 @@ fn impl_abstract_union_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Res
133162
.set_structure_type(
134163
::binaryninja::types::StructureType::UnionStructureType
135164
)
165+
.set_width(::std::mem::size_of::<#name>() as u64)
166+
.set_packed(#packed)
167+
#alignment
136168
.finalize()
137169
)
138170
}
@@ -148,6 +180,12 @@ fn impl_abstract_enum_type(
148180
if repr.c {
149181
return Err(name.span().error("`repr(C)` enums are not supported"));
150182
}
183+
if repr.align.is_some() {
184+
// No way to set custom alignment for enums in Binja
185+
return Err(name
186+
.span()
187+
.error("`repr(align(...))` on enums is not supported"));
188+
}
151189

152190
let Some((primitive, signed)) = repr.primitive else {
153191
return Err(name

0 commit comments

Comments
 (0)