@@ -3,26 +3,43 @@ use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt};
3
3
use quote:: quote;
4
4
use syn:: spanned:: Spanned ;
5
5
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 ,
7
8
} ;
8
9
9
10
type Result < T > = std:: result:: Result < T , Diagnostic > ;
10
11
11
12
struct Repr {
12
13
c : bool ,
14
+ packed : Option < usize > ,
15
+ align : Option < usize > ,
13
16
primitive : Option < ( Path , bool ) > ,
14
17
}
15
18
16
19
impl Repr {
17
20
fn from_attrs ( attrs : Vec < Attribute > ) -> Result < Self > {
18
21
let mut c = false ;
22
+ let mut packed = None ;
23
+ let mut align = None ;
19
24
let mut primitive = None ;
20
25
for attr in attrs {
21
26
if attr. path ( ) . is_ident ( "repr" ) {
22
27
attr. parse_nested_meta ( |meta| {
23
28
if let Some ( ident) = meta. path . get_ident ( ) {
24
29
if ident == "C" {
25
30
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 ( ) ?) ;
26
43
} else if ident_in_list ( ident, [ "u8" , "u16" , "u32" , "u64" ] ) {
27
44
primitive = Some ( ( meta. path . clone ( ) , false ) ) ;
28
45
} else if ident_in_list ( ident, [ "i8" , "i16" , "i32" , "i64" ] ) {
@@ -39,7 +56,12 @@ impl Repr {
39
56
}
40
57
}
41
58
42
- Ok ( Self { c, primitive } )
59
+ Ok ( Self {
60
+ c,
61
+ packed,
62
+ align,
63
+ primitive,
64
+ } )
43
65
}
44
66
}
45
67
@@ -105,12 +127,17 @@ fn impl_abstract_struct_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Re
105
127
}
106
128
107
129
let args = field_arguments ( & name, fields) ;
130
+ let packed = repr. packed . is_some ( ) ;
131
+ let alignment = repr. align . map ( |align| quote ! { . set_alignment( #align) } ) ;
108
132
Ok ( quote ! {
109
133
impl :: binaryninja:: types:: AbstractType for #name {
110
134
fn resolve_type( ) -> :: binaryninja:: rc:: Ref <:: binaryninja:: types:: Type > {
111
135
:: binaryninja:: types:: Type :: structure(
112
136
& :: binaryninja:: types:: Structure :: builder( )
113
137
#( . insert( #args) ) *
138
+ . set_width( :: std:: mem:: size_of:: <#name>( ) as u64 )
139
+ . set_packed( #packed)
140
+ #alignment
114
141
. finalize( )
115
142
)
116
143
}
@@ -124,6 +151,8 @@ fn impl_abstract_union_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Res
124
151
}
125
152
126
153
let args = field_arguments ( & name, fields) ;
154
+ let packed = repr. packed . is_some ( ) ;
155
+ let alignment = repr. align . map ( |align| quote ! { . set_alignment( #align) } ) ;
127
156
Ok ( quote ! {
128
157
impl :: binaryninja:: types:: AbstractType for #name {
129
158
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
133
162
. set_structure_type(
134
163
:: binaryninja:: types:: StructureType :: UnionStructureType
135
164
)
165
+ . set_width( :: std:: mem:: size_of:: <#name>( ) as u64 )
166
+ . set_packed( #packed)
167
+ #alignment
136
168
. finalize( )
137
169
)
138
170
}
@@ -148,6 +180,12 @@ fn impl_abstract_enum_type(
148
180
if repr. c {
149
181
return Err ( name. span ( ) . error ( "`repr(C)` enums are not supported" ) ) ;
150
182
}
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
+ }
151
189
152
190
let Some ( ( primitive, signed) ) = repr. primitive else {
153
191
return Err ( name
0 commit comments