forked from AFLplusplus/LibAFL
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build_linux.rs
189 lines (156 loc) · 6.65 KB
/
build_linux.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
use std::{
env, fs,
path::{Path, PathBuf},
process::Command,
};
use libafl_qemu_build::maybe_generate_stub_bindings;
static LIBAFL_QEMU_RUNTIME_TEST: &str = r#"
#include <stdio.h>
#include "libafl_qemu.h"
void __libafl_qemu_testfile() {}
"#;
#[allow(clippy::too_many_lines)]
pub fn build() {
// Note: Unique features are checked in libafl_qemu_sys
println!(r#"cargo::rustc-check-cfg=cfg(emulation_mode, values("usermode", "systemmode"))"#);
println!(
r#"cargo::rustc-check-cfg=cfg(cpu_target, values("arm", "aarch64", "hexagon", "i386", "mips", "ppc", "x86_64"))"#
);
let emulation_mode = if cfg!(feature = "usermode") {
"usermode".to_string()
} else if cfg!(feature = "systemmode") {
"systemmode".to_string()
} else {
env::var("EMULATION_MODE").unwrap_or_else(|_| "usermode".to_string())
};
let src_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let src_dir = PathBuf::from(src_dir);
let out_dir = env::var("OUT_DIR").unwrap();
let out_dir = PathBuf::from(&out_dir);
let mut target_dir = out_dir.clone();
target_dir.pop();
target_dir.pop();
target_dir.pop();
let include_dir = target_dir.join("include");
let qemu_asan_guest = cfg!(all(feature = "build_libgasan", not(feature = "hexagon")));
let qemu_asan = cfg!(all(feature = "build_libqasan", not(feature = "hexagon")));
let libafl_qemu_hdr_name = "libafl_qemu.h";
let libafl_qemu_arch_hdr_name = "libafl_qemu_arch.h";
let libafl_qemu_defs_hdr_name = "libafl_qemu_defs.h";
let libafl_qemu_impl_hdr_name = "libafl_qemu_impl.h";
let libafl_runtime_dir = src_dir.join("runtime");
let libafl_qemu_hdr = libafl_runtime_dir.join(libafl_qemu_hdr_name);
let libafl_qemu_arch_hdr = libafl_runtime_dir.join(libafl_qemu_arch_hdr_name);
let libafl_qemu_defs_hdr = libafl_runtime_dir.join(libafl_qemu_defs_hdr_name);
let libafl_qemu_impl_hdr = libafl_runtime_dir.join(libafl_qemu_impl_hdr_name);
let libafl_runtime_testfile = out_dir.join("runtime_test.c");
fs::write(&libafl_runtime_testfile, LIBAFL_QEMU_RUNTIME_TEST).expect("Could not write runtime test file");
let mut runtime_test_cc_compiler = cc::Build::new();
runtime_test_cc_compiler.cpp(false)
.include(&libafl_runtime_dir)
.file(&libafl_runtime_testfile);
runtime_test_cc_compiler.try_compile("runtime_test").unwrap();
let runtime_bindings_file = out_dir.join("libafl_qemu_bindings.rs");
let stub_runtime_bindings_file = src_dir.join("runtime/libafl_qemu_stub_bindings.rs");
println!("cargo::rustc-check-cfg=cfg(emulation_mode, values(\"usermode\", \"systemmode\"))");
println!("cargo:rustc-cfg=emulation_mode=\"{emulation_mode}\"");
println!("cargo:rerun-if-env-changed=EMULATION_MODE");
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=build_linux.rs");
println!("cargo:rerun-if-changed={}", libafl_runtime_dir.display());
let cpu_target = if cfg!(feature = "x86_64") {
"x86_64".to_string()
} else if cfg!(feature = "arm") {
"arm".to_string()
} else if cfg!(feature = "aarch64") {
"aarch64".to_string()
} else if cfg!(feature = "i386") {
"i386".to_string()
} else if cfg!(feature = "mips") {
"mips".to_string()
} else if cfg!(feature = "ppc") {
"ppc".to_string()
} else if cfg!(feature = "hexagon") {
"hexagon".to_string()
} else {
env::var("CPU_TARGET").unwrap_or_else(|_| "x86_64".to_string())
};
println!("cargo:rerun-if-env-changed=CPU_TARGET");
println!("cargo:rustc-cfg=cpu_target=\"{cpu_target}\"");
println!("cargo::rustc-check-cfg=cfg(cpu_target, values(\"x86_64\", \"arm\", \"aarch64\", \"i386\", \"mips\", \"ppc\", \"hexagon\"))");
let cross_cc = if (emulation_mode == "usermode") && (qemu_asan || qemu_asan_guest) {
// TODO try to autodetect a cross compiler with the arch name (e.g. aarch64-linux-gnu-gcc)
let cross_cc = env::var("CROSS_CC").unwrap_or_else(|_| {
println!("cargo:warning=CROSS_CC is not set, default to cc (things can go wrong if the selected cpu target ({cpu_target}) is not the host arch ({}))", env::consts::ARCH);
"cc".to_owned()
});
println!("cargo:rerun-if-env-changed=CROSS_CC");
cross_cc
} else {
String::new()
};
if env::var("DOCS_RS").is_ok() || cfg!(feature = "clippy") {
fs::copy(&stub_runtime_bindings_file, &runtime_bindings_file)
.expect("Could not copy stub bindings file");
return; // only build when we're not generating docs
}
fs::create_dir_all(&include_dir).expect("Could not create include dir");
fs::copy(
libafl_qemu_hdr.clone(),
include_dir.join(libafl_qemu_hdr_name),
)
.expect("Could not copy libafl_qemu.h to out directory.");
fs::copy(
libafl_qemu_arch_hdr.clone(),
include_dir.join(libafl_qemu_arch_hdr_name),
)
.expect("Could not copy libafl_qemu_arch.h to out directory.");
fs::copy(
libafl_qemu_defs_hdr.clone(),
include_dir.join(libafl_qemu_defs_hdr_name),
)
.expect("Could not copy libafl_qemu_defs.h to out directory.");
fs::copy(
libafl_qemu_impl_hdr.clone(),
include_dir.join(libafl_qemu_impl_hdr_name),
)
.expect("Could not copy libafl_qemu_impl.h to out directory.");
bindgen::Builder::default()
.derive_debug(true)
.derive_default(true)
.impl_debug(true)
.generate_comments(true)
.default_enum_style(bindgen::EnumVariation::NewType {
is_global: true,
is_bitfield: true,
})
.header(libafl_qemu_hdr.display().to_string())
.generate()
.expect("Exit bindings generation failed.")
.write_to_file(&runtime_bindings_file)
.expect("Could not write bindings.");
maybe_generate_stub_bindings(
&cpu_target,
&emulation_mode,
stub_runtime_bindings_file.as_path(),
runtime_bindings_file.as_path()
);
if (emulation_mode == "usermode") && (qemu_asan || qemu_asan_guest) {
let qasan_dir = Path::new("libqasan");
let qasan_dir = fs::canonicalize(qasan_dir).unwrap();
println!("cargo:rerun-if-changed={}", qasan_dir.display());
let mut make = Command::new("make");
if cfg!(debug_assertions) {
make.env("CFLAGS", "-DDEBUG=1");
}
assert!(make
.current_dir(&out_dir)
.env("CC", &cross_cc)
.env("OUT_DIR", &target_dir)
.arg("-C")
.arg(&qasan_dir)
.status()
.expect("make failed")
.success());
}
}