Skip to content

Commit 4ad1c3a

Browse files
committed
Support pointer fields (hardcoded to 64-bit width for now)
1 parent 08ffe5e commit 4ad1c3a

File tree

1 file changed

+61
-22
lines changed
  • rust/binaryninja-derive/src

1 file changed

+61
-22
lines changed

rust/binaryninja-derive/src/lib.rs

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,56 @@ use quote::quote;
44
use syn::spanned::Spanned;
55
use syn::{
66
parenthesized, parse_macro_input, token, Attribute, Data, DeriveInput, Field, Fields,
7-
FieldsNamed, Ident, LitInt, Path, Variant,
7+
FieldsNamed, Ident, LitInt, Path, Type, Variant,
88
};
99

1010
type Result<T> = std::result::Result<T, Diagnostic>;
1111

12+
struct AbstractField {
13+
ty: Type,
14+
ident: Ident,
15+
named: bool,
16+
pointer: bool,
17+
}
18+
19+
impl AbstractField {
20+
fn from_field(field: Field) -> Result<Self> {
21+
let Some(ident) = field.ident else {
22+
return Err(field.span().error("field must be named"));
23+
};
24+
let named = field.attrs.iter().any(|attr| attr.path().is_ident("named"));
25+
let (ty, pointer) = match field.ty {
26+
Type::Ptr(ty) => (*ty.elem, true),
27+
_ => (field.ty, false),
28+
};
29+
Ok(Self {
30+
ty,
31+
ident,
32+
named,
33+
pointer,
34+
})
35+
}
36+
37+
fn resolved_ty(&self) -> TokenStream {
38+
let ty = &self.ty;
39+
let mut resolved = quote! { <#ty as ::binaryninja::types::AbstractType>::resolve_type() };
40+
if self.named {
41+
resolved = quote! {
42+
::binaryninja::types::Type::named_type_from_type(
43+
stringify!(#ty),
44+
&#resolved
45+
)
46+
};
47+
}
48+
if self.pointer {
49+
resolved = quote! {
50+
::binaryninja::types::Type::pointer_of_width(&#resolved, 8, false, false, None)
51+
}
52+
}
53+
resolved
54+
}
55+
}
56+
1257
struct Repr {
1358
c: bool,
1459
packed: Option<usize>,
@@ -109,28 +154,12 @@ fn impl_abstract_type(ast: DeriveInput) -> Result<TokenStream> {
109154
}
110155
}
111156

112-
fn field_resolved_type(field: &Field) -> TokenStream {
113-
let ty = &field.ty;
114-
let resolved_ty = quote! { <#ty as ::binaryninja::types::AbstractType>::resolve_type() };
115-
if field.attrs.iter().any(|attr| attr.path().is_ident("named")) {
116-
quote! {
117-
::binaryninja::types::Type::named_type_from_type(
118-
stringify!(#ty),
119-
&#resolved_ty
120-
)
121-
}
122-
} else {
123-
resolved_ty
124-
}
125-
}
126-
127-
fn field_arguments(name: &Ident, fields: FieldsNamed) -> Vec<TokenStream> {
157+
fn field_arguments(name: &Ident, fields: &[AbstractField]) -> Vec<TokenStream> {
128158
fields
129-
.named
130159
.iter()
131160
.map(|field| {
132-
let ident = field.ident.as_ref().unwrap();
133-
let resolved_ty = field_resolved_type(field);
161+
let ident = &field.ident;
162+
let resolved_ty = field.resolved_ty();
134163
quote! {
135164
&#resolved_ty,
136165
stringify!(#ident),
@@ -148,7 +177,12 @@ fn impl_abstract_struct_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Re
148177
return Err(name.span().error("struct must be `repr(C)`"));
149178
}
150179

151-
let args = field_arguments(&name, fields);
180+
let fields = fields
181+
.named
182+
.into_iter()
183+
.map(AbstractField::from_field)
184+
.collect::<Result<Vec<_>>>()?;
185+
let args = field_arguments(&name, &fields);
152186
let packed = repr.packed.is_some();
153187
let alignment = repr.align.map(|align| quote! { .set_alignment(#align) });
154188
Ok(quote! {
@@ -172,7 +206,12 @@ fn impl_abstract_union_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Res
172206
return Err(name.span().error("union must be `repr(C)`"));
173207
}
174208

175-
let args = field_arguments(&name, fields);
209+
let fields = fields
210+
.named
211+
.into_iter()
212+
.map(AbstractField::from_field)
213+
.collect::<Result<Vec<_>>>()?;
214+
let args = field_arguments(&name, &fields);
176215
let packed = repr.packed.is_some();
177216
let alignment = repr.align.map(|align| quote! { .set_alignment(#align) });
178217
Ok(quote! {

0 commit comments

Comments
 (0)