Autodetect llvm-config for QEMU bindings generation (#1610)
* Autodetect llvm-config for QEMU bindings generation * fix ci * Fix signal handlers without ucontext pointer * ci
This commit is contained in:
parent
bbb999f4d5
commit
31f4669794
6
.github/workflows/build_and_test.yml
vendored
6
.github/workflows/build_and_test.yml
vendored
@ -145,7 +145,7 @@ jobs:
|
||||
# Skipping `python` as it has to be built with the `maturin` tool
|
||||
# `agpl`, `nautilus` require nightly
|
||||
# `sancov_pcguard_edges` is tested seperately
|
||||
run: cargo hack check --each-feature --clean-per-run --exclude-features=prelude,agpl,nautilus,python,sancov_pcguard_edges,arm,aarch64,i386,be,systemmode --no-dev-deps
|
||||
run: LLVM_CONFIG=llvm-config-15 cargo hack check --each-feature --clean-per-run --exclude-features=prelude,agpl,nautilus,python,sancov_pcguard_edges,arm,aarch64,i386,be,systemmode --no-dev-deps
|
||||
- name: Check nightly features
|
||||
run: cargo +nightly check --features=agpl && cargo +nightly check --features=nautilus
|
||||
|
||||
@ -179,7 +179,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Run a maturin build
|
||||
run: LLVM_CONFIG_PATH=llvm-config-15 cd ./bindings/pylibafl && python3 -m venv .env && . .env/bin/activate && pip install --upgrade --force-reinstall . && ./test.sh
|
||||
run: export LLVM_CONFIG=llvm-config-15 && cd ./bindings/pylibafl && python3 -m venv .env && . .env/bin/activate && pip install --upgrade --force-reinstall . && ./test.sh
|
||||
- name: Run python test
|
||||
run: . ./bindings/pylibafl/.env/bin/activate && cd ./fuzzers/baby_fuzzer && python3 baby_fuzzer.py 2>&1 | grep "Bye"
|
||||
|
||||
@ -270,7 +270,7 @@ jobs:
|
||||
run: sudo ln -s /usr/include/asm-generic /usr/include/asm
|
||||
- name: Build and run example fuzzers (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: RUN_ON_CI=1 ./scripts/test_all_fuzzers.sh
|
||||
run: RUN_ON_CI=1 LLVM_CONFIG=llvm-config-15 ./scripts/test_all_fuzzers.sh
|
||||
- name: Build and run example fuzzers (macOS)
|
||||
if: runner.os == 'macOS' # use bash v4
|
||||
run: /usr/local/bin/bash -c 'RUN_ON_CI=1 ./scripts/test_all_fuzzers.sh'
|
||||
|
@ -68,7 +68,7 @@ pub struct ShutdownSignalData {
|
||||
/// Type for shutdown handler
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
pub type ShutdownFuncPtr =
|
||||
unsafe fn(Signal, &mut siginfo_t, &mut ucontext_t, data: &mut ShutdownSignalData);
|
||||
unsafe fn(Signal, &mut siginfo_t, Option<&mut ucontext_t>, data: &mut ShutdownSignalData);
|
||||
|
||||
/// Shutdown handler. `SigTerm`, `SigInterrupt`, `SigQuit` call this
|
||||
/// We can't handle SIGKILL in the signal handler, this means that you shouldn't kill your fuzzer with `kill -9` because then the shmem segments are never freed
|
||||
@ -80,7 +80,7 @@ pub type ShutdownFuncPtr =
|
||||
pub unsafe fn shutdown_handler<SP>(
|
||||
signal: Signal,
|
||||
_info: &mut siginfo_t,
|
||||
_context: &mut ucontext_t,
|
||||
_context: Option<&mut ucontext_t>,
|
||||
data: &ShutdownSignalData,
|
||||
) where
|
||||
SP: ShMemProvider,
|
||||
@ -106,7 +106,7 @@ pub unsafe fn shutdown_handler<SP>(
|
||||
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
impl Handler for ShutdownSignalData {
|
||||
fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: &mut ucontext_t) {
|
||||
fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: Option<&mut ucontext_t>) {
|
||||
unsafe {
|
||||
let data = &mut SHUTDOWN_SIGHANDLER_DATA;
|
||||
if !data.shutdown_handler.is_null() {
|
||||
|
@ -659,21 +659,30 @@ pub mod unix_signal_handler {
|
||||
state::{HasClientPerfMonitor, HasCorpus, HasSolutions},
|
||||
};
|
||||
|
||||
pub(crate) type HandlerFuncPtr =
|
||||
unsafe fn(Signal, &mut siginfo_t, &mut ucontext_t, data: &mut InProcessExecutorHandlerData);
|
||||
pub(crate) type HandlerFuncPtr = unsafe fn(
|
||||
Signal,
|
||||
&mut siginfo_t,
|
||||
Option<&mut ucontext_t>,
|
||||
data: &mut InProcessExecutorHandlerData,
|
||||
);
|
||||
|
||||
/// A handler that does nothing.
|
||||
/*pub fn nop_handler(
|
||||
_signal: Signal,
|
||||
_info: &mut siginfo_t,
|
||||
_context: &mut ucontext_t,
|
||||
_context: Option<&mut ucontext_t>,
|
||||
_data: &mut InProcessExecutorHandlerData,
|
||||
) {
|
||||
}*/
|
||||
|
||||
#[cfg(unix)]
|
||||
impl Handler for InProcessExecutorHandlerData {
|
||||
fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: &mut ucontext_t) {
|
||||
fn handle(
|
||||
&mut self,
|
||||
signal: Signal,
|
||||
info: &mut siginfo_t,
|
||||
context: Option<&mut ucontext_t>,
|
||||
) {
|
||||
unsafe {
|
||||
let data = &mut GLOBAL_STATE;
|
||||
let in_handler = data.set_in_handler(true);
|
||||
@ -759,7 +768,7 @@ pub mod unix_signal_handler {
|
||||
pub unsafe fn inproc_timeout_handler<E, EM, OF, Z>(
|
||||
_signal: Signal,
|
||||
_info: &mut siginfo_t,
|
||||
_context: &mut ucontext_t,
|
||||
_context: Option<&mut ucontext_t>,
|
||||
data: &mut InProcessExecutorHandlerData,
|
||||
) where
|
||||
E: HasObservers,
|
||||
@ -809,7 +818,7 @@ pub mod unix_signal_handler {
|
||||
pub unsafe fn inproc_crash_handler<E, EM, OF, Z>(
|
||||
signal: Signal,
|
||||
_info: &mut siginfo_t,
|
||||
_context: &mut ucontext_t,
|
||||
_context: Option<&mut ucontext_t>,
|
||||
data: &mut InProcessExecutorHandlerData,
|
||||
) where
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
@ -840,7 +849,12 @@ pub mod unix_signal_handler {
|
||||
{
|
||||
let mut writer = std::io::BufWriter::new(&mut bsod);
|
||||
writeln!(writer, "input: {:?}", input.generate_name(0)).unwrap();
|
||||
libafl_bolts::minibsod::generate_minibsod(&mut writer, signal, _info, _context)
|
||||
libafl_bolts::minibsod::generate_minibsod(
|
||||
&mut writer,
|
||||
signal,
|
||||
_info,
|
||||
_context.as_deref(),
|
||||
)
|
||||
.unwrap();
|
||||
writer.flush().unwrap();
|
||||
}
|
||||
@ -876,7 +890,7 @@ pub mod unix_signal_handler {
|
||||
&mut writer,
|
||||
signal,
|
||||
_info,
|
||||
_context,
|
||||
_context.as_deref(),
|
||||
)
|
||||
.unwrap();
|
||||
writer.flush().unwrap();
|
||||
@ -1322,8 +1336,12 @@ pub mod windows_exception_handler {
|
||||
|
||||
/// The signature of the crash handler function
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
pub(crate) type ForkHandlerFuncPtr =
|
||||
unsafe fn(Signal, &mut siginfo_t, &mut ucontext_t, data: &mut InProcessForkExecutorGlobalData);
|
||||
pub(crate) type ForkHandlerFuncPtr = unsafe fn(
|
||||
Signal,
|
||||
&mut siginfo_t,
|
||||
Option<&mut ucontext_t>,
|
||||
data: &mut InProcessForkExecutorGlobalData,
|
||||
);
|
||||
|
||||
/// The inmem fork executor's handlers.
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
@ -1463,7 +1481,7 @@ pub(crate) static mut FORK_EXECUTOR_GLOBAL_DATA: InProcessForkExecutorGlobalData
|
||||
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
impl Handler for InProcessForkExecutorGlobalData {
|
||||
fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: &mut ucontext_t) {
|
||||
fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: Option<&mut ucontext_t>) {
|
||||
match signal {
|
||||
Signal::SigUser2 | Signal::SigAlarm => unsafe {
|
||||
if !FORK_EXECUTOR_GLOBAL_DATA.timeout_handler.is_null() {
|
||||
@ -2076,7 +2094,7 @@ pub mod child_signal_handlers {
|
||||
pub(crate) unsafe fn child_crash_handler<E>(
|
||||
_signal: Signal,
|
||||
_info: &mut siginfo_t,
|
||||
_context: &mut ucontext_t,
|
||||
_context: Option<&mut ucontext_t>,
|
||||
data: &mut InProcessForkExecutorGlobalData,
|
||||
) where
|
||||
E: HasObservers,
|
||||
@ -2098,7 +2116,7 @@ pub mod child_signal_handlers {
|
||||
pub(crate) unsafe fn child_timeout_handler<E>(
|
||||
_signal: Signal,
|
||||
_info: &mut siginfo_t,
|
||||
_context: &mut ucontext_t,
|
||||
_context: Option<&mut ucontext_t>,
|
||||
data: &mut InProcessForkExecutorGlobalData,
|
||||
) where
|
||||
E: HasObservers,
|
||||
|
@ -1939,7 +1939,12 @@ pub struct LlmpShutdownSignalHandler {
|
||||
|
||||
#[cfg(unix)]
|
||||
impl Handler for LlmpShutdownSignalHandler {
|
||||
fn handle(&mut self, _signal: Signal, _info: &mut siginfo_t, _context: &mut ucontext_t) {
|
||||
fn handle(
|
||||
&mut self,
|
||||
_signal: Signal,
|
||||
_info: &mut siginfo_t,
|
||||
_context: Option<&mut ucontext_t>,
|
||||
) {
|
||||
unsafe {
|
||||
ptr::write_volatile(&mut self.shutting_down, true);
|
||||
}
|
||||
|
@ -837,12 +837,16 @@ pub fn generate_minibsod<W: Write>(
|
||||
writer: &mut BufWriter<W>,
|
||||
signal: Signal,
|
||||
_siginfo: &siginfo_t,
|
||||
ucontext: &ucontext_t,
|
||||
ucontext: Option<&ucontext_t>,
|
||||
) -> Result<(), std::io::Error> {
|
||||
writeln!(writer, "{:━^100}", " CRASH ")?;
|
||||
write_crash(writer, signal, ucontext)?;
|
||||
if let Some(uctx) = ucontext {
|
||||
write_crash(writer, signal, uctx)?;
|
||||
writeln!(writer, "{:━^100}", " REGISTERS ")?;
|
||||
dump_registers(writer, ucontext)?;
|
||||
dump_registers(writer, uctx)?;
|
||||
} else {
|
||||
writeln!(writer, "Received signal {}", signal)?;
|
||||
}
|
||||
writeln!(writer, "{:━^100}", " BACKTRACE ")?;
|
||||
writeln!(writer, "{:?}", backtrace::Backtrace::new())?;
|
||||
writeln!(writer, "{:━^100}", " MAPS ")?;
|
||||
|
@ -378,7 +378,7 @@ impl Display for Signal {
|
||||
#[cfg(feature = "alloc")]
|
||||
pub trait Handler {
|
||||
/// Handle a signal
|
||||
fn handle(&mut self, signal: Signal, info: &mut siginfo_t, _context: &mut ucontext_t);
|
||||
fn handle(&mut self, signal: Signal, info: &mut siginfo_t, _context: Option<&mut ucontext_t>);
|
||||
/// Return a list of signals to handle
|
||||
fn signals(&self) -> Vec<Signal>;
|
||||
}
|
||||
@ -425,7 +425,7 @@ unsafe fn handle_signal(sig: c_int, info: *mut siginfo_t, void: *mut c_void) {
|
||||
handler.handle(
|
||||
*signal,
|
||||
&mut ptr::read_unaligned(info),
|
||||
&mut ptr::read_unaligned(void as *mut ucontext_t),
|
||||
(void as *mut ucontext_t).as_mut(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,19 @@
|
||||
#![allow(clippy::missing_panics_doc)]
|
||||
use std::{
|
||||
fs,
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use which::which;
|
||||
|
||||
mod bindings;
|
||||
mod build;
|
||||
|
||||
pub use build::build;
|
||||
|
||||
const LLVM_VERSION_MAX: i32 = 33;
|
||||
|
||||
pub fn build_with_bindings(
|
||||
cpu_target: &str,
|
||||
is_big_endian: bool,
|
||||
@ -25,6 +30,73 @@ pub fn build_with_bindings(
|
||||
.expect("Faield to write to the bindings file");
|
||||
}
|
||||
|
||||
// For bindgen, the llvm version must be >= of the rust llvm version
|
||||
fn find_llvm_config() -> Result<String, String> {
|
||||
if let Ok(var) = env::var("LLVM_CONFIG") {
|
||||
return Ok(var);
|
||||
}
|
||||
|
||||
let rustc_llvm_ver = find_rustc_llvm_version().unwrap();
|
||||
for version in (rustc_llvm_ver..=LLVM_VERSION_MAX).rev() {
|
||||
let llvm_config_name: String = format!("llvm-config-{version}");
|
||||
if which(&llvm_config_name).is_ok() {
|
||||
return Ok(llvm_config_name);
|
||||
}
|
||||
}
|
||||
|
||||
if which("llvm-config").is_ok() {
|
||||
if let Some(ver) = find_llvm_version("llvm-config".to_owned()) {
|
||||
if ver >= rustc_llvm_ver {
|
||||
return Ok("llvm-config".to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err("could not find llvm-config".to_owned())
|
||||
}
|
||||
|
||||
fn exec_llvm_config(llvm_config: String, args: &[&str]) -> String {
|
||||
match Command::new(llvm_config).args(args).output() {
|
||||
Ok(output) => String::from_utf8(output.stdout)
|
||||
.expect("Unexpected llvm-config output")
|
||||
.trim()
|
||||
.to_string(),
|
||||
Err(e) => panic!("Could not execute llvm-config: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_llvm_version(llvm_config: String) -> Option<i32> {
|
||||
let output = exec_llvm_config(llvm_config, &["--version"]);
|
||||
if let Some(major) = output.split('.').collect::<Vec<&str>>().first() {
|
||||
if let Ok(res) = major.parse::<i32>() {
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn exec_rustc(args: &[&str]) -> String {
|
||||
let rustc = env::var("RUSTC").unwrap();
|
||||
match Command::new(rustc).args(args).output() {
|
||||
Ok(output) => String::from_utf8(output.stdout)
|
||||
.expect("Unexpected rustc output")
|
||||
.trim()
|
||||
.to_string(),
|
||||
Err(e) => panic!("Could not execute rustc: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_rustc_llvm_version() -> Option<i32> {
|
||||
let output = exec_rustc(&["--verbose", "--version"]);
|
||||
let ver = output.split(':').last().unwrap().trim();
|
||||
if let Some(major) = ver.split('.').collect::<Vec<&str>>().first() {
|
||||
if let Ok(res) = major.parse::<i32>() {
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
//linux-user_main.c.o libqemu-x86_64-linux-user.fa.p
|
||||
|
||||
fn qemu_bindgen_clang_args(
|
||||
@ -33,6 +105,11 @@ fn qemu_bindgen_clang_args(
|
||||
cpu_target: &str,
|
||||
is_usermode: bool,
|
||||
) -> Vec<String> {
|
||||
if env::var("LLVM_CONFIG_PATH").is_err() {
|
||||
let found = find_llvm_config().expect("Cannot find a suitable llvm-config, it must be a version equal or greater than the rustc LLVM version");
|
||||
env::set_var("LLVM_CONFIG_PATH", found);
|
||||
}
|
||||
|
||||
// load compile commands
|
||||
let compile_commands_string = &fs::read_to_string(build_dir.join("compile_commands.json"))
|
||||
.expect("failed to read compile commands");
|
||||
|
Loading…
x
Reference in New Issue
Block a user