Skip to content

Commit 9a23a8e

Browse files
committed
Add testing example for AbstractType derive macro
1 parent c8aae0b commit 9a23a8e

File tree

5 files changed

+380
-0
lines changed

5 files changed

+380
-0
lines changed

rust/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pdb = { path = "./examples/pdb-ng/pdb-0.8.0-patched" }
2424

2525
[workspace]
2626
members = [
27+
"examples/abstract-type",
2728
"examples/basic_script",
2829
"examples/decompile",
2930
"examples/dwarf/dwarf_export",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "abstract-type"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
binaryninja = { path="../../", features = ["derive"] }

rust/examples/abstract-type/build.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use std::env;
2+
use std::fs::File;
3+
use std::io::BufReader;
4+
use std::path::PathBuf;
5+
6+
#[cfg(target_os = "macos")]
7+
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
8+
9+
#[cfg(target_os = "linux")]
10+
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
11+
12+
#[cfg(windows)]
13+
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
14+
15+
// Check last run location for path to BinaryNinja; Otherwise check the default install locations
16+
fn link_path() -> PathBuf {
17+
use std::io::prelude::*;
18+
19+
let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
20+
let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
21+
22+
File::open(lastrun)
23+
.and_then(|f| {
24+
let mut binja_path = String::new();
25+
let mut reader = BufReader::new(f);
26+
27+
reader.read_line(&mut binja_path)?;
28+
Ok(PathBuf::from(binja_path.trim()))
29+
})
30+
.unwrap_or_else(|_| {
31+
#[cfg(target_os = "macos")]
32+
return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
33+
34+
#[cfg(target_os = "linux")]
35+
return home.join("binaryninja");
36+
37+
#[cfg(windows)]
38+
return PathBuf::from(env::var("PROGRAMFILES").unwrap())
39+
.join("Vector35\\BinaryNinja\\");
40+
})
41+
}
42+
43+
fn main() {
44+
// Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
45+
let install_path = env::var("BINARYNINJADIR")
46+
.map(PathBuf::from)
47+
.unwrap_or_else(|_| link_path());
48+
49+
#[cfg(target_os = "linux")]
50+
println!(
51+
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
52+
install_path.to_str().unwrap(),
53+
install_path.to_str().unwrap(),
54+
);
55+
56+
#[cfg(target_os = "macos")]
57+
println!(
58+
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
59+
install_path.to_str().unwrap(),
60+
install_path.to_str().unwrap(),
61+
);
62+
63+
#[cfg(target_os = "windows")]
64+
{
65+
println!("cargo:rustc-link-lib=binaryninjacore");
66+
println!("cargo:rustc-link-search={}", install_path.to_str().unwrap());
67+
}
68+
}
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
use binaryninja::rc::Ref;
2+
use binaryninja::types::{AbstractType, EnumerationBuilder, StructureBuilder, StructureType, Type};
3+
4+
fn create_struct<F>(f: F) -> Ref<Type>
5+
where
6+
F: FnOnce(&StructureBuilder) -> &StructureBuilder,
7+
{
8+
Type::structure(&f(&StructureBuilder::new()).finalize())
9+
}
10+
11+
fn create_enum<F>(width: usize, signed: bool, f: F) -> Ref<Type>
12+
where
13+
F: FnOnce(&EnumerationBuilder) -> &EnumerationBuilder,
14+
{
15+
Type::enumeration(&f(&EnumerationBuilder::new()).finalize(), width, signed)
16+
}
17+
18+
fn primitive() {
19+
assert_eq!(u8::resolve_type(), Type::int(1, false));
20+
assert_eq!(u16::resolve_type(), Type::int(2, false));
21+
assert_eq!(u32::resolve_type(), Type::int(4, false));
22+
assert_eq!(u64::resolve_type(), Type::int(8, false));
23+
assert_eq!(u128::resolve_type(), Type::int(16, false));
24+
25+
assert_eq!(i8::resolve_type(), Type::int(1, true));
26+
assert_eq!(i16::resolve_type(), Type::int(2, true));
27+
assert_eq!(i32::resolve_type(), Type::int(4, true));
28+
assert_eq!(i64::resolve_type(), Type::int(8, true));
29+
assert_eq!(i128::resolve_type(), Type::int(16, true));
30+
31+
assert_eq!(f32::resolve_type(), Type::float(4));
32+
assert_eq!(f64::resolve_type(), Type::float(8));
33+
}
34+
35+
fn basic_struct() {
36+
#[derive(AbstractType)]
37+
#[repr(C)]
38+
struct A {
39+
first: u8,
40+
second: u32,
41+
third: u16,
42+
}
43+
44+
assert_eq!(
45+
A::resolve_type(),
46+
create_struct(|s| {
47+
s.with_members([
48+
(&Type::int(1, false), "first"),
49+
(&Type::int(4, false), "second"),
50+
(&Type::int(2, false), "third"),
51+
])
52+
})
53+
);
54+
}
55+
56+
fn packed_struct() {
57+
#[derive(AbstractType)]
58+
#[repr(C, packed)]
59+
struct A {
60+
first: u8,
61+
second: u32,
62+
third: u16,
63+
}
64+
65+
assert_eq!(
66+
A::resolve_type(),
67+
create_struct(|s| {
68+
s.set_packed(true).with_members([
69+
(&Type::int(1, false), "first"),
70+
(&Type::int(4, false), "second"),
71+
(&Type::int(2, false), "third"),
72+
])
73+
})
74+
);
75+
}
76+
77+
fn custom_alignment() {
78+
#[derive(AbstractType)]
79+
#[repr(C, align(16))]
80+
struct A {
81+
first: u8,
82+
second: u32,
83+
third: u16,
84+
}
85+
86+
assert_eq!(
87+
A::resolve_type(),
88+
create_struct(|s| {
89+
s.set_alignment(16).with_members([
90+
(&Type::int(1, false), "first"),
91+
(&Type::int(4, false), "second"),
92+
(&Type::int(2, false), "third"),
93+
])
94+
})
95+
);
96+
}
97+
98+
fn named_field() {
99+
#[derive(AbstractType)]
100+
#[repr(C)]
101+
struct A {
102+
first: u8,
103+
#[binja(named)]
104+
second: B,
105+
}
106+
107+
#[derive(AbstractType)]
108+
#[repr(C)]
109+
struct B {
110+
third: u16,
111+
}
112+
113+
assert_eq!(
114+
A::resolve_type(),
115+
create_struct(|s| {
116+
s.with_members([
117+
(&Type::int(1, false), "first"),
118+
(
119+
&Type::named_type_from_type("B", &B::resolve_type()),
120+
"second",
121+
),
122+
])
123+
})
124+
);
125+
assert_eq!(
126+
B::resolve_type(),
127+
create_struct(|s| { s.with_members([(&Type::int(2, false), "third")]) })
128+
);
129+
}
130+
131+
fn pointer_field() {
132+
#[derive(AbstractType)]
133+
#[repr(C)]
134+
#[binja(pointer_width = 4)]
135+
struct A {
136+
first: u8,
137+
second: *const u32,
138+
}
139+
140+
assert_eq!(
141+
A::resolve_type(),
142+
create_struct(|s| {
143+
s.with_members([
144+
(&Type::int(1, false), "first"),
145+
(
146+
&Type::pointer_of_width(&Type::int(4, false), 4, false, false, None),
147+
"second",
148+
),
149+
])
150+
})
151+
);
152+
}
153+
154+
fn nested_pointer_field() {
155+
#[derive(AbstractType)]
156+
#[repr(C)]
157+
struct A {
158+
first: u8,
159+
#[binja(named)]
160+
second: B,
161+
}
162+
163+
#[derive(AbstractType)]
164+
#[repr(C)]
165+
#[binja(pointer_width = 4)]
166+
struct B {
167+
third: u32,
168+
fourth: *const u16,
169+
}
170+
171+
assert_eq!(
172+
A::resolve_type(),
173+
create_struct(|s| {
174+
s.with_members([
175+
(&Type::int(1, false), "first"),
176+
(
177+
&Type::named_type_from_type("B", &B::resolve_type()),
178+
"second",
179+
),
180+
])
181+
})
182+
);
183+
assert_eq!(
184+
B::resolve_type(),
185+
create_struct(|s| {
186+
s.with_members([
187+
(&Type::int(4, false), "third"),
188+
(
189+
&Type::pointer_of_width(&Type::int(2, false), 4, false, false, None),
190+
"fourth",
191+
),
192+
])
193+
})
194+
);
195+
}
196+
197+
fn named_pointer_field() {
198+
#[derive(AbstractType)]
199+
#[repr(C)]
200+
#[binja(pointer_width = 4)]
201+
struct A {
202+
first: u8,
203+
#[binja(named)]
204+
second: *const B,
205+
}
206+
207+
#[derive(AbstractType)]
208+
#[repr(C)]
209+
struct B {
210+
third: u32,
211+
fourth: u16,
212+
}
213+
214+
assert_eq!(
215+
A::resolve_type(),
216+
create_struct(|s| {
217+
s.with_members([
218+
(&Type::int(1, false), "first"),
219+
(
220+
&Type::pointer_of_width(
221+
&Type::named_type_from_type("B", &B::resolve_type()),
222+
4,
223+
false,
224+
false,
225+
None,
226+
),
227+
"second",
228+
),
229+
])
230+
})
231+
);
232+
assert_eq!(
233+
B::resolve_type(),
234+
create_struct(|s| {
235+
s.with_members([
236+
(&Type::int(4, false), "third"),
237+
(&Type::int(2, false), "fourth"),
238+
])
239+
})
240+
)
241+
}
242+
243+
fn union() {
244+
#[derive(AbstractType)]
245+
#[repr(C)]
246+
union A {
247+
first: u32,
248+
second: [u16; 2],
249+
third: [u8; 4],
250+
}
251+
252+
assert_eq!(
253+
A::resolve_type(),
254+
create_struct(|s| {
255+
s.set_structure_type(StructureType::UnionStructureType)
256+
.with_members([
257+
(&Type::int(4, false), "first"),
258+
(&Type::array(&Type::int(2, false), 2), "second"),
259+
(&Type::array(&Type::int(1, false), 4), "third"),
260+
])
261+
})
262+
);
263+
}
264+
265+
fn enumeration() {
266+
#[derive(AbstractType)]
267+
#[repr(u32)]
268+
#[allow(dead_code)]
269+
enum Color {
270+
Red = 0xff0000,
271+
Green = 0x00ff00,
272+
Blue = 0x0000ff,
273+
}
274+
275+
assert_eq!(
276+
Color::resolve_type(),
277+
create_enum(4, false, |e| {
278+
e.insert("Red", 0xff0000)
279+
.insert("Green", 0x00ff00)
280+
.insert("Blue", 0x0000ff)
281+
})
282+
);
283+
}
284+
285+
fn main() {
286+
let _ = binaryninja::headless::Session::new();
287+
primitive();
288+
basic_struct();
289+
packed_struct();
290+
custom_alignment();
291+
named_field();
292+
pointer_field();
293+
nested_pointer_field();
294+
named_pointer_field();
295+
union();
296+
enumeration();
297+
}

0 commit comments

Comments
 (0)