Llvm passes (#185)
* enable llvm passes in libafl_cc * cmplog rtn pass in fuzzbench fuzzer * improve libafl_cc * silence fuzzbench compiler wrapper * instrumentation and runtime for rtn cmplog * fix test * fix test * fuck clippy * remove anon union in CmpLogMap * windows.h * remove libafl_targets_cmplog_wrapper * no inline linking * adapt fuzzers/
This commit is contained in:
parent
37f641f79b
commit
5b54f0f068
@ -31,14 +31,3 @@ nix = "0.20.0"
|
||||
[lib]
|
||||
name = "fuzzbench"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[[bin]]
|
||||
# For c binaries
|
||||
name = "libafl_cc"
|
||||
path = "src/bin/libafl_cc.rs"
|
||||
|
||||
[[bin]]
|
||||
# For cpp binaries
|
||||
name = "libafl_cxx"
|
||||
path = "src/bin/libafl_cc.rs"
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
pub fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
@ -15,20 +15,18 @@ fn main() {
|
||||
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
|
||||
let mut cc = ClangWrapper::new();
|
||||
if let Some(code) = cc
|
||||
.is_cpp(is_cpp)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "fuzzbench".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp".into())
|
||||
.unwrap()
|
||||
.cpp(is_cpp)
|
||||
// silence the compiler wrapper output, needed for some configure scripts.
|
||||
.silence()
|
||||
.silence(true)
|
||||
.from_args(&args)
|
||||
.expect("Failed to parse the command line".into())
|
||||
.link_staticlib(&dir, "fuzzbench")
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp")
|
||||
.add_pass(LLVMPasses::CmpLogRtn)
|
||||
.run()
|
||||
.unwrap()
|
||||
.expect("Failed to run the wrapped compiler".into())
|
||||
{
|
||||
std::process::exit(code);
|
||||
}
|
||||
|
5
fuzzers/fuzzbench/src/bin/libafl_cxx.rs
Normal file
5
fuzzers/fuzzbench/src/bin/libafl_cxx.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub mod libafl_cc;
|
||||
|
||||
fn main() {
|
||||
libafl_cc::main()
|
||||
}
|
@ -1,21 +1,35 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
pub fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||
"cc" => false,
|
||||
"++" | "pp" | "xx" => true,
|
||||
_ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir),
|
||||
};
|
||||
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(false)
|
||||
let mut cc = ClangWrapper::new();
|
||||
if let Some(code) = cc
|
||||
.cpp(is_cpp)
|
||||
// silence the compiler wrapper output, needed for some configure scripts.
|
||||
.silence(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "generic_inmemory".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
.expect("Failed to parse the command line".into())
|
||||
.link_staticlib(&dir, "generic_inmemory")
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp")
|
||||
.add_pass(LLVMPasses::CmpLogRtn)
|
||||
.run()
|
||||
.expect("Failed to run the wrapped compiler".into())
|
||||
{
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
|
@ -1,22 +1,5 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use std::env;
|
||||
pub mod libafl_cc;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "generic_inmemory".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
libafl_cc::main()
|
||||
}
|
||||
|
@ -1,21 +1,34 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
pub fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||
"cc" => false,
|
||||
"++" | "pp" | "xx" => true,
|
||||
_ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir),
|
||||
};
|
||||
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(false)
|
||||
let mut cc = ClangWrapper::new();
|
||||
if let Some(code) = cc
|
||||
.cpp(is_cpp)
|
||||
// silence the compiler wrapper output, needed for some configure scripts.
|
||||
.silence(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "libfuzzer_libmozjpeg".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
.expect("Failed to parse the command line".into())
|
||||
.link_staticlib(&dir, "libfuzzer_libmozjpeg")
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp")
|
||||
.run()
|
||||
.expect("Failed to run the wrapped compiler".into())
|
||||
{
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
|
@ -1,22 +1,5 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use std::env;
|
||||
pub mod libafl_cc;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "libfuzzer_libmozjpeg".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
libafl_cc::main()
|
||||
}
|
||||
|
@ -1,21 +1,34 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
pub fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||
"cc" => false,
|
||||
"++" | "pp" | "xx" => true,
|
||||
_ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir),
|
||||
};
|
||||
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(false)
|
||||
let mut cc = ClangWrapper::new();
|
||||
if let Some(code) = cc
|
||||
.cpp(is_cpp)
|
||||
// silence the compiler wrapper output, needed for some configure scripts.
|
||||
.silence(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "libfuzzer_libpng".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
.expect("Failed to parse the command line".into())
|
||||
.link_staticlib(&dir, "libfuzzer_libpng")
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||
.run()
|
||||
.expect("Failed to run the wrapped compiler".into())
|
||||
{
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
|
@ -1,22 +1,5 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use std::env;
|
||||
pub mod libafl_cc;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "libfuzzer_libpng".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
libafl_cc::main()
|
||||
}
|
||||
|
@ -1,21 +1,34 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
pub fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||
"cc" => false,
|
||||
"++" | "pp" | "xx" => true,
|
||||
_ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir),
|
||||
};
|
||||
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(false)
|
||||
let mut cc = ClangWrapper::new();
|
||||
if let Some(code) = cc
|
||||
.cpp(is_cpp)
|
||||
// silence the compiler wrapper output, needed for some configure scripts.
|
||||
.silence(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "libfuzzer_libpng".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
.expect("Failed to parse the command line".into())
|
||||
.link_staticlib(&dir, "libfuzzer_libpng")
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||
.run()
|
||||
.expect("Failed to run the wrapped compiler".into())
|
||||
{
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
|
@ -1,22 +1,5 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use std::env;
|
||||
pub mod libafl_cc;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "libfuzzer_libpng".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
libafl_cc::main()
|
||||
}
|
||||
|
@ -1,21 +1,34 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
pub fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||
"cc" => false,
|
||||
"++" | "pp" | "xx" => true,
|
||||
_ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir),
|
||||
};
|
||||
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(false)
|
||||
let mut cc = ClangWrapper::new();
|
||||
if let Some(code) = cc
|
||||
.cpp(is_cpp)
|
||||
// silence the compiler wrapper output, needed for some configure scripts.
|
||||
.silence(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "libfuzzer_libpng".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
.expect("Failed to parse the command line".into())
|
||||
.link_staticlib(&dir, "libfuzzer_libpng")
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||
.run()
|
||||
.expect("Failed to run the wrapped compiler".into())
|
||||
{
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
|
@ -1,22 +1,5 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
use std::env;
|
||||
pub mod libafl_cc;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||
cc.is_cpp(true)
|
||||
.from_args(&args)
|
||||
.unwrap()
|
||||
.link_staticlib(&dir, "libfuzzer_libpng".into())
|
||||
.unwrap()
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
||||
.unwrap();
|
||||
cc.run().unwrap();
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
libafl_cc::main()
|
||||
}
|
||||
|
@ -12,4 +12,7 @@ edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
cc = { version = "1.0", features = ["parallel"] }
|
||||
|
||||
[dependencies]
|
||||
|
74
libafl_cc/build.rs
Normal file
74
libafl_cc/build.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use std::{env, fs::File, io::Write, path::Path, process::Command, str};
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let out_dir = Path::new(&out_dir);
|
||||
let src_dir = Path::new("src");
|
||||
|
||||
let dest_path = Path::new(&out_dir).join("clang_constants.rs");
|
||||
let mut clang_constants_file = File::create(&dest_path).expect("Could not create file");
|
||||
|
||||
let llvm_config = env::var("LLVM_CONFIG").unwrap_or_else(|_| "llvm-config".into());
|
||||
if let Ok(output) = Command::new(&llvm_config).args(&["--bindir"]).output() {
|
||||
let llvm_bindir = Path::new(
|
||||
str::from_utf8(&output.stdout)
|
||||
.expect("Invalid llvm-config output")
|
||||
.trim(),
|
||||
);
|
||||
|
||||
write!(
|
||||
&mut clang_constants_file,
|
||||
"// These constants are autogenerated by build.rs
|
||||
|
||||
pub const CLANG_PATH: &str = {:?};
|
||||
pub const CLANGXX_PATH: &str = {:?};
|
||||
",
|
||||
llvm_bindir.join("clang"),
|
||||
llvm_bindir.join("clang++")
|
||||
)
|
||||
.expect("Could not write file");
|
||||
|
||||
println!("cargo:rerun-if-changed=src/cmplog-routines-pass.cc");
|
||||
|
||||
let output = Command::new(&llvm_config)
|
||||
.args(&["--cxxflags"])
|
||||
.output()
|
||||
.expect("Failed to execute llvm-config");
|
||||
let cxxflags = str::from_utf8(&output.stdout).expect("Invalid llvm-config output");
|
||||
|
||||
let output = Command::new(&llvm_config)
|
||||
.args(&["--ldflags"])
|
||||
.output()
|
||||
.expect("Failed to execute llvm-config");
|
||||
let ldflags = str::from_utf8(&output.stdout).expect("Invalid llvm-config output");
|
||||
|
||||
let cxxflags: Vec<&str> = cxxflags.trim().split_whitespace().collect();
|
||||
let ldflags: Vec<&str> = ldflags.trim().split_whitespace().collect();
|
||||
|
||||
let _ = Command::new(llvm_bindir.join("clang++"))
|
||||
.args(&cxxflags)
|
||||
.arg(src_dir.join("cmplog-routines-pass.cc"))
|
||||
.args(&ldflags)
|
||||
.args(&["-fPIC", "-shared", "-o"])
|
||||
.arg(out_dir.join("cmplog-routines-pass.so"))
|
||||
.status()
|
||||
.expect("Failed to compile cmplog-routines-pass.cc");
|
||||
} else {
|
||||
write!(
|
||||
&mut clang_constants_file,
|
||||
"// These constants are autogenerated by build.rs
|
||||
|
||||
pub const CLANG_PATH: &str = \"clang\";
|
||||
pub const CLANGXX_PATH: &str = \"clang++\";
|
||||
"
|
||||
)
|
||||
.expect("Could not write file");
|
||||
|
||||
println!(
|
||||
"cargo:warning=Failed to locate the LLVM path using {}, we will not build LLVM passes",
|
||||
llvm_config
|
||||
);
|
||||
}
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
284
libafl_cc/src/clang.rs
Normal file
284
libafl_cc/src/clang.rs
Normal file
@ -0,0 +1,284 @@
|
||||
//! LLVM compiler Wrapper from `LibAFL`
|
||||
|
||||
use std::{
|
||||
convert::Into,
|
||||
path::{Path, PathBuf},
|
||||
string::String,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use crate::{CompilerWrapper, Error, LIB_EXT, LIB_PREFIX};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/clang_constants.rs"));
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub enum LLVMPasses {
|
||||
//CmpLogIns,
|
||||
CmpLogRtn,
|
||||
}
|
||||
|
||||
impl LLVMPasses {
|
||||
#[must_use]
|
||||
pub fn path(&self) -> PathBuf {
|
||||
match self {
|
||||
LLVMPasses::CmpLogRtn => PathBuf::from(env!("OUT_DIR")).join("cmplog-routines-pass.so"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrap Clang
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct ClangWrapper {
|
||||
is_silent: bool,
|
||||
optimize: bool,
|
||||
wrapped_cc: String,
|
||||
wrapped_cxx: String,
|
||||
|
||||
name: String,
|
||||
is_cpp: bool,
|
||||
linking: bool,
|
||||
x_set: bool,
|
||||
bit_mode: u32,
|
||||
|
||||
from_args_called: bool,
|
||||
base_args: Vec<String>,
|
||||
cc_args: Vec<String>,
|
||||
link_args: Vec<String>,
|
||||
passes: Vec<LLVMPasses>,
|
||||
}
|
||||
|
||||
#[allow(clippy::match_same_arms)] // for the linking = false wip for "shared"
|
||||
impl CompilerWrapper for ClangWrapper {
|
||||
fn from_args<S>(&mut self, args: &[S]) -> Result<&'_ mut Self, Error>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
let mut new_args: Vec<String> = vec![];
|
||||
if args.is_empty() {
|
||||
return Err(Error::InvalidArguments(
|
||||
"The number of arguments cannot be 0".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if self.from_args_called {
|
||||
return Err(Error::Unknown(
|
||||
"CompilerWrapper::from_args cannot be called twice on the same instance"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
self.from_args_called = true;
|
||||
|
||||
if args.len() == 1 {
|
||||
return Err(Error::InvalidArguments(
|
||||
"LibAFL Compiler wrapper - no commands specified. Use me as compiler.".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
self.name = args[0].as_ref().to_string();
|
||||
// Detect C++ compiler looking at the wrapper name
|
||||
self.is_cpp = self.is_cpp || self.name.ends_with("++");
|
||||
|
||||
// Sancov flag
|
||||
// new_args.push("-fsanitize-coverage=trace-pc-guard".into());
|
||||
|
||||
let mut linking = true;
|
||||
// Detect stray -v calls from ./configure scripts.
|
||||
if args.len() > 1 && args[1].as_ref() == "-v" {
|
||||
linking = false;
|
||||
}
|
||||
|
||||
for arg in &args[1..] {
|
||||
match arg.as_ref() {
|
||||
"-x" => self.x_set = true,
|
||||
"-m32" => self.bit_mode = 32,
|
||||
"-m64" => self.bit_mode = 64,
|
||||
"-c" | "-S" | "-E" => linking = false,
|
||||
"-shared" => linking = false, // TODO dynamic list?
|
||||
"-Wl,-z,defs" | "-Wl,--no-undefined" => continue,
|
||||
_ => (),
|
||||
};
|
||||
new_args.push(arg.as_ref().to_string());
|
||||
}
|
||||
self.linking = linking;
|
||||
|
||||
if self.optimize {
|
||||
new_args.push("-g".into());
|
||||
new_args.push("-O3".into());
|
||||
new_args.push("-funroll-loops".into());
|
||||
}
|
||||
|
||||
// Fuzzing define common among tools
|
||||
new_args.push("-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1".into());
|
||||
|
||||
// Libraries needed by libafl on Windows
|
||||
#[cfg(windows)]
|
||||
if linking {
|
||||
new_args.push("-lws2_32".into());
|
||||
new_args.push("-lBcrypt".into());
|
||||
new_args.push("-lAdvapi32".into());
|
||||
}
|
||||
|
||||
self.base_args = new_args;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn add_arg<S>(&mut self, arg: S) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
self.base_args.push(arg.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
fn add_cc_arg<S>(&mut self, arg: S) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
self.cc_args.push(arg.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
fn add_link_arg<S>(&mut self, arg: S) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
self.link_args.push(arg.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
fn link_staticlib<S>(&mut self, dir: &Path, name: S) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
if cfg!(any(target_os = "macos", target_os = "ios")) {
|
||||
//self.add_link_arg("-force_load".into())?;
|
||||
} else {
|
||||
self.add_link_arg("-Wl,--whole-archive");
|
||||
}
|
||||
self.add_link_arg(
|
||||
dir.join(format!("{}{}.{}", LIB_PREFIX, name.as_ref(), LIB_EXT))
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap(),
|
||||
);
|
||||
if cfg!(any(target_os = "macos", target_os = "ios")) {
|
||||
self
|
||||
} else {
|
||||
self.add_link_arg("-Wl,-no-whole-archive")
|
||||
}
|
||||
}
|
||||
|
||||
fn command(&mut self) -> Result<Vec<String>, Error> {
|
||||
let mut args = vec![];
|
||||
if self.is_cpp {
|
||||
args.push(self.wrapped_cxx.clone());
|
||||
} else {
|
||||
args.push(self.wrapped_cc.clone());
|
||||
}
|
||||
args.extend_from_slice(self.base_args.as_slice());
|
||||
for pass in &self.passes {
|
||||
args.push("-Xclang".into());
|
||||
args.push("-load".into());
|
||||
args.push("-Xclang".into());
|
||||
args.push(pass.path().into_os_string().into_string().unwrap());
|
||||
}
|
||||
if self.linking {
|
||||
if self.x_set {
|
||||
args.push("-x".into());
|
||||
args.push("none".into());
|
||||
}
|
||||
|
||||
args.extend_from_slice(self.link_args.as_slice());
|
||||
} else {
|
||||
args.extend_from_slice(self.cc_args.as_slice());
|
||||
}
|
||||
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
fn is_linking(&self) -> bool {
|
||||
self.linking
|
||||
}
|
||||
|
||||
fn silence(&mut self, value: bool) -> &'_ mut Self {
|
||||
self.is_silent = value;
|
||||
self
|
||||
}
|
||||
|
||||
fn is_silent(&self) -> bool {
|
||||
self.is_silent
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ClangWrapper {
|
||||
/// Create a new Clang Wrapper
|
||||
#[must_use]
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl ClangWrapper {
|
||||
/// Create a new Clang Wrapper
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
optimize: true,
|
||||
wrapped_cc: CLANG_PATH.into(),
|
||||
wrapped_cxx: CLANGXX_PATH.into(),
|
||||
name: "".into(),
|
||||
is_cpp: false,
|
||||
linking: false,
|
||||
x_set: false,
|
||||
bit_mode: 0,
|
||||
from_args_called: false,
|
||||
base_args: vec![],
|
||||
cc_args: vec![],
|
||||
link_args: vec![],
|
||||
passes: vec![],
|
||||
is_silent: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wrapped_cc(&mut self, cc: String) -> &'_ mut Self {
|
||||
self.wrapped_cc = cc;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn wrapped_cxx(&mut self, cxx: String) -> &'_ mut Self {
|
||||
self.wrapped_cxx = cxx;
|
||||
self
|
||||
}
|
||||
|
||||
/// Disable optimizations
|
||||
pub fn dont_optimize(&mut self) -> &'_ mut Self {
|
||||
self.optimize = false;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set cpp mode
|
||||
pub fn cpp(&mut self, value: bool) -> &'_ mut Self {
|
||||
self.is_cpp = value;
|
||||
self
|
||||
}
|
||||
|
||||
// Add LLVM pass
|
||||
pub fn add_pass(&mut self, pass: LLVMPasses) -> &'_ mut Self {
|
||||
self.passes.push(pass);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{ClangWrapper, CompilerWrapper};
|
||||
|
||||
#[test]
|
||||
fn test_clang_version() {
|
||||
ClangWrapper::new()
|
||||
.from_args(&["my-clang", "-v"])
|
||||
.unwrap()
|
||||
.run()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
469
libafl_cc/src/cmplog-routines-pass.cc
Normal file
469
libafl_cc/src/cmplog-routines-pass.cc
Normal file
@ -0,0 +1,469 @@
|
||||
/*
|
||||
american fuzzy lop++ - LLVM CmpLog instrumentation
|
||||
--------------------------------------------------
|
||||
|
||||
Written by Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sys/time.h>
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#else
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#define nullptr 0
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
/* Function that we never instrument or analyze */
|
||||
/* Note: this ignore check is also called in isInInstrumentList() */
|
||||
bool isIgnoreFunction(const llvm::Function *F) {
|
||||
|
||||
// Starting from "LLVMFuzzer" these are functions used in libfuzzer based
|
||||
// fuzzing campaign installations, e.g. oss-fuzz
|
||||
|
||||
static constexpr const char *ignoreList[] = {
|
||||
|
||||
"asan.",
|
||||
"llvm.",
|
||||
"sancov.",
|
||||
"__ubsan",
|
||||
"ign.",
|
||||
"__afl",
|
||||
"_fini",
|
||||
"__libc_",
|
||||
"__asan",
|
||||
"__msan",
|
||||
"__cmplog",
|
||||
"__sancov",
|
||||
"__san",
|
||||
"__cxx_",
|
||||
"__decide_deferred",
|
||||
"_GLOBAL",
|
||||
"_ZZN6__asan",
|
||||
"_ZZN6__lsan",
|
||||
"msan.",
|
||||
"LLVMFuzzerM",
|
||||
"LLVMFuzzerC",
|
||||
"LLVMFuzzerI",
|
||||
"maybe_duplicate_stderr",
|
||||
"discard_output",
|
||||
"close_stdout",
|
||||
"dup_and_close_stderr",
|
||||
"maybe_close_fd_mask",
|
||||
"ExecuteFilesOnyByOne"
|
||||
|
||||
};
|
||||
|
||||
for (auto const &ignoreListFunc : ignoreList) {
|
||||
|
||||
if (F->getName().startswith(ignoreListFunc)) { return true; }
|
||||
|
||||
}
|
||||
|
||||
static constexpr const char *ignoreSubstringList[] = {
|
||||
|
||||
"__asan", "__msan", "__ubsan", "__lsan",
|
||||
"__san", "__sanitize", "__cxx", "_GLOBAL__",
|
||||
"DebugCounter", "DwarfDebug", "DebugLoc"
|
||||
|
||||
};
|
||||
|
||||
for (auto const &ignoreListFunc : ignoreSubstringList) {
|
||||
|
||||
// hexcoder: F->getName().contains() not avaiilable in llvm 3.8.0
|
||||
if (StringRef::npos != F->getName().find(ignoreListFunc)) { return true; }
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
class CmpLogRoutines : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
CmpLogRoutines() : ModulePass(ID) {}
|
||||
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 4
|
||||
const char *getPassName() const override {
|
||||
|
||||
#else
|
||||
StringRef getPassName() const override {
|
||||
|
||||
#endif
|
||||
return "cmplog routines";
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
bool hookRtns(Module &M);
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
char CmpLogRoutines::ID = 0;
|
||||
|
||||
bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
|
||||
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC;
|
||||
LLVMContext & C = M.getContext();
|
||||
|
||||
Type *VoidTy = Type::getVoidTy(C);
|
||||
// PointerType *VoidPtrTy = PointerType::get(VoidTy, 0);
|
||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||
PointerType *i8PtrTy = PointerType::get(Int8Ty, 0);
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c = M.getOrInsertFunction("__cmplog_rtn_hook", VoidTy, i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogHookFn = cast<Function>(c);
|
||||
#else
|
||||
FunctionCallee cmplogHookFn = c;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c1 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_stdstring",
|
||||
VoidTy, i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogLlvmStdStd = cast<Function>(c1);
|
||||
#else
|
||||
FunctionCallee cmplogLlvmStdStd = c1;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c2 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_cstring", VoidTy,
|
||||
i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogLlvmStdC = cast<Function>(c2);
|
||||
#else
|
||||
FunctionCallee cmplogLlvmStdC = c2;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c3 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_stdstring", VoidTy,
|
||||
i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogGccStdStd = cast<Function>(c3);
|
||||
#else
|
||||
FunctionCallee cmplogGccStdStd = c3;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c4 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_cstring", VoidTy,
|
||||
i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogGccStdC = cast<Function>(c4);
|
||||
#else
|
||||
FunctionCallee cmplogGccStdC = c4;
|
||||
#endif
|
||||
|
||||
/* iterate over all functions, bbs and instruction and add suitable calls */
|
||||
for (auto &F : M) {
|
||||
|
||||
if (!isIgnoreFunction(&F)) continue;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
|
||||
Function *Callee = callInst->getCalledFunction();
|
||||
if (!Callee) continue;
|
||||
if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
|
||||
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
|
||||
bool isPtrRtn = FT->getNumParams() >= 2 &&
|
||||
!FT->getReturnType()->isVoidTy() &&
|
||||
FT->getParamType(0) == FT->getParamType(1) &&
|
||||
FT->getParamType(0)->isPointerTy();
|
||||
|
||||
bool isGccStdStringStdString =
|
||||
Callee->getName().find("__is_charIT_EE7__value") !=
|
||||
std::string::npos &&
|
||||
Callee->getName().find(
|
||||
"St7__cxx1112basic_stringIS2_St11char_traits") !=
|
||||
std::string::npos &&
|
||||
FT->getNumParams() >= 2 &&
|
||||
FT->getParamType(0) == FT->getParamType(1) &&
|
||||
FT->getParamType(0)->isPointerTy();
|
||||
|
||||
bool isGccStdStringCString =
|
||||
Callee->getName().find(
|
||||
"St7__cxx1112basic_stringIcSt11char_"
|
||||
"traitsIcESaIcEE7compareEPK") != std::string::npos &&
|
||||
FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() &&
|
||||
FT->getParamType(1)->isPointerTy();
|
||||
|
||||
bool isLlvmStdStringStdString =
|
||||
Callee->getName().find("_ZNSt3__1eqI") != std::string::npos &&
|
||||
Callee->getName().find("_12basic_stringI") != std::string::npos &&
|
||||
Callee->getName().find("_11char_traits") != std::string::npos &&
|
||||
FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() &&
|
||||
FT->getParamType(1)->isPointerTy();
|
||||
|
||||
bool isLlvmStdStringCString =
|
||||
Callee->getName().find("_ZNSt3__1eqI") != std::string::npos &&
|
||||
Callee->getName().find("_12basic_stringI") != std::string::npos &&
|
||||
FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() &&
|
||||
FT->getParamType(1)->isPointerTy();
|
||||
|
||||
/*
|
||||
{
|
||||
|
||||
fprintf(stderr, "F:%s C:%s argc:%u\n",
|
||||
F.getName().str().c_str(),
|
||||
Callee->getName().str().c_str(), FT->getNumParams());
|
||||
fprintf(stderr, "ptr0:%u ptr1:%u ptr2:%u\n",
|
||||
FT->getParamType(0)->isPointerTy(),
|
||||
FT->getParamType(1)->isPointerTy(),
|
||||
FT->getNumParams() > 2 ?
|
||||
FT->getParamType(2)->isPointerTy() : 22 );
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
if (isGccStdStringCString || isGccStdStringStdString ||
|
||||
isLlvmStdStringStdString || isLlvmStdStringCString) {
|
||||
|
||||
isPtrRtn = false;
|
||||
|
||||
}
|
||||
|
||||
if (isPtrRtn) { calls.push_back(callInst); }
|
||||
if (isGccStdStringStdString) { gccStdStd.push_back(callInst); }
|
||||
if (isGccStdStringCString) { gccStdC.push_back(callInst); }
|
||||
if (isLlvmStdStringStdString) { llvmStdStd.push_back(callInst); }
|
||||
if (isLlvmStdStringCString) { llvmStdC.push_back(callInst); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!calls.size() && !gccStdStd.size() && !gccStdC.size() &&
|
||||
!llvmStdStd.size() && !llvmStdC.size())
|
||||
return false;
|
||||
|
||||
for (auto &callInst : calls) {
|
||||
|
||||
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
|
||||
|
||||
IRBuilder<> IRB(callInst->getParent());
|
||||
IRB.SetInsertPoint(callInst);
|
||||
|
||||
std::vector<Value *> args;
|
||||
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
args.push_back(v1Pcasted);
|
||||
args.push_back(v2Pcasted);
|
||||
|
||||
IRB.CreateCall(cmplogHookFn, args);
|
||||
|
||||
// errs() << callInst->getCalledFunction()->getName() << "\n";
|
||||
|
||||
}
|
||||
|
||||
for (auto &callInst : gccStdStd) {
|
||||
|
||||
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
|
||||
|
||||
IRBuilder<> IRB(callInst->getParent());
|
||||
IRB.SetInsertPoint(callInst);
|
||||
|
||||
std::vector<Value *> args;
|
||||
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
args.push_back(v1Pcasted);
|
||||
args.push_back(v2Pcasted);
|
||||
|
||||
IRB.CreateCall(cmplogGccStdStd, args);
|
||||
|
||||
// errs() << callInst->getCalledFunction()->getName() << "\n";
|
||||
|
||||
}
|
||||
|
||||
for (auto &callInst : gccStdC) {
|
||||
|
||||
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
|
||||
|
||||
IRBuilder<> IRB(callInst->getParent());
|
||||
IRB.SetInsertPoint(callInst);
|
||||
|
||||
std::vector<Value *> args;
|
||||
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
args.push_back(v1Pcasted);
|
||||
args.push_back(v2Pcasted);
|
||||
|
||||
IRB.CreateCall(cmplogGccStdC, args);
|
||||
|
||||
// errs() << callInst->getCalledFunction()->getName() << "\n";
|
||||
|
||||
}
|
||||
|
||||
for (auto &callInst : llvmStdStd) {
|
||||
|
||||
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
|
||||
|
||||
IRBuilder<> IRB(callInst->getParent());
|
||||
IRB.SetInsertPoint(callInst);
|
||||
|
||||
std::vector<Value *> args;
|
||||
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
args.push_back(v1Pcasted);
|
||||
args.push_back(v2Pcasted);
|
||||
|
||||
IRB.CreateCall(cmplogLlvmStdStd, args);
|
||||
|
||||
// errs() << callInst->getCalledFunction()->getName() << "\n";
|
||||
|
||||
}
|
||||
|
||||
for (auto &callInst : llvmStdC) {
|
||||
|
||||
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
|
||||
|
||||
IRBuilder<> IRB(callInst->getParent());
|
||||
IRB.SetInsertPoint(callInst);
|
||||
|
||||
std::vector<Value *> args;
|
||||
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
args.push_back(v1Pcasted);
|
||||
args.push_back(v2Pcasted);
|
||||
|
||||
IRB.CreateCall(cmplogLlvmStdC, args);
|
||||
|
||||
// errs() << callInst->getCalledFunction()->getName() << "\n";
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool CmpLogRoutines::runOnModule(Module &M) {
|
||||
|
||||
hookRtns(M);
|
||||
verifyModule(M);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static void registerCmpLogRoutinesPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
auto p = new CmpLogRoutines();
|
||||
PM.add(p);
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterCmpLogRoutinesPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerCmpLogRoutinesPass);
|
||||
|
||||
static RegisterStandardPasses RegisterCmpLogRoutinesPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogRoutinesPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterCmpLogRoutinesPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerCmpLogRoutinesPass);
|
||||
#endif
|
||||
|
@ -1,6 +1,9 @@
|
||||
//! Compiler Wrapper from `LibAFL`
|
||||
|
||||
use std::{path::Path, process::Command, string::String, vec::Vec};
|
||||
use std::{convert::Into, path::Path, process::Command, string::String, vec::Vec};
|
||||
|
||||
pub mod clang;
|
||||
pub use clang::{ClangWrapper, LLVMPasses};
|
||||
|
||||
/// `LibAFL` CC Error Type
|
||||
#[derive(Debug)]
|
||||
@ -31,19 +34,62 @@ pub const LIB_PREFIX: &str = "lib";
|
||||
/// Wrap a compiler hijacking its arguments
|
||||
pub trait CompilerWrapper {
|
||||
/// Set the wrapper arguments parsing a command line set of arguments
|
||||
fn from_args(&mut self, args: &[String]) -> Result<&'_ mut Self, Error>;
|
||||
fn from_args<S>(&mut self, args: &[S]) -> Result<&'_ mut Self, Error>
|
||||
where
|
||||
S: AsRef<str>;
|
||||
|
||||
/// Add a compiler argument
|
||||
fn add_arg(&mut self, arg: String) -> Result<&'_ mut Self, Error>;
|
||||
fn add_arg<S>(&mut self, arg: S) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>;
|
||||
|
||||
/// Add a compiler argument only when compiling
|
||||
fn add_cc_arg(&mut self, arg: String) -> Result<&'_ mut Self, Error>;
|
||||
fn add_cc_arg<S>(&mut self, arg: S) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>;
|
||||
|
||||
/// Add a compiler argument only when linking
|
||||
fn add_link_arg(&mut self, arg: String) -> Result<&'_ mut Self, Error>;
|
||||
fn add_link_arg<S>(&mut self, arg: S) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>;
|
||||
|
||||
/// Add compiler arguments
|
||||
fn add_args<S>(&mut self, args: &[S]) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
for arg in args {
|
||||
self.add_arg(arg);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Add compiler arguments only when compiling
|
||||
fn add_cc_args<S>(&mut self, args: &[S]) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
for arg in args {
|
||||
self.add_cc_arg(arg);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Add compiler arguments only when linking
|
||||
fn add_link_args<S>(&mut self, args: &[S]) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
for arg in args {
|
||||
self.add_link_arg(arg);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Link static C lib
|
||||
fn link_staticlib(&mut self, dir: &Path, name: String) -> Result<&'_ mut Self, Error>;
|
||||
fn link_staticlib<S>(&mut self, dir: &Path, name: S) -> &'_ mut Self
|
||||
where
|
||||
S: AsRef<str>;
|
||||
|
||||
/// Command to run the compiler
|
||||
fn command(&mut self) -> Result<Vec<String>, Error>;
|
||||
@ -52,9 +98,9 @@ pub trait CompilerWrapper {
|
||||
fn is_linking(&self) -> bool;
|
||||
|
||||
/// Silences `libafl_cc` output
|
||||
fn silence(&mut self) -> &'_ mut Self;
|
||||
fn silence(&mut self, value: bool) -> &'_ mut Self;
|
||||
|
||||
/// Returns `true` if `silence` was called
|
||||
/// Returns `true` if `silence` was called with `true`
|
||||
fn is_silent(&self) -> bool;
|
||||
|
||||
/// Run the compiler
|
||||
@ -79,202 +125,3 @@ pub trait CompilerWrapper {
|
||||
Ok(status.code())
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrap Clang
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct ClangWrapper {
|
||||
is_silent: bool,
|
||||
optimize: bool,
|
||||
wrapped_cc: String,
|
||||
wrapped_cxx: String,
|
||||
|
||||
name: String,
|
||||
is_cpp: bool,
|
||||
linking: bool,
|
||||
x_set: bool,
|
||||
bit_mode: u32,
|
||||
|
||||
base_args: Vec<String>,
|
||||
cc_args: Vec<String>,
|
||||
link_args: Vec<String>,
|
||||
}
|
||||
|
||||
#[allow(clippy::match_same_arms)] // for the linking = false wip for "shared"
|
||||
impl CompilerWrapper for ClangWrapper {
|
||||
fn from_args<'a>(&'a mut self, args: &[String]) -> Result<&'a mut Self, Error> {
|
||||
let mut new_args = vec![];
|
||||
if args.is_empty() {
|
||||
return Err(Error::InvalidArguments(
|
||||
"The number of arguments cannot be 0".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if args.len() == 1 {
|
||||
return Err(Error::InvalidArguments(
|
||||
"LibAFL Compiler wrapper - no commands specified. Use me as compiler.".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
self.name = args[0].clone();
|
||||
// Detect C++ compiler looking at the wrapper name
|
||||
self.is_cpp = self.is_cpp || self.name.ends_with("++");
|
||||
|
||||
// Sancov flag
|
||||
// new_args.push("-fsanitize-coverage=trace-pc-guard".into());
|
||||
|
||||
let mut linking = true;
|
||||
// Detect stray -v calls from ./configure scripts.
|
||||
if args.len() > 1 && args[1] == "-v" {
|
||||
linking = false;
|
||||
}
|
||||
|
||||
for arg in &args[1..] {
|
||||
match arg.as_str() {
|
||||
"-x" => self.x_set = true,
|
||||
"-m32" => self.bit_mode = 32,
|
||||
"-m64" => self.bit_mode = 64,
|
||||
"-c" | "-S" | "-E" => linking = false,
|
||||
"-shared" => linking = false, // TODO dynamic list?
|
||||
"-Wl,-z,defs" | "-Wl,--no-undefined" => continue,
|
||||
_ => (),
|
||||
};
|
||||
new_args.push(arg.clone());
|
||||
}
|
||||
self.linking = linking;
|
||||
|
||||
if self.optimize {
|
||||
new_args.push("-g".into());
|
||||
new_args.push("-O3".into());
|
||||
new_args.push("-funroll-loops".into());
|
||||
}
|
||||
|
||||
// Fuzzing define common among tools
|
||||
new_args.push("-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1".into());
|
||||
|
||||
// Libraries needed by libafl on Windows
|
||||
#[cfg(windows)]
|
||||
if linking {
|
||||
new_args.push("-lws2_32".into());
|
||||
new_args.push("-lBcrypt".into());
|
||||
new_args.push("-lAdvapi32".into());
|
||||
}
|
||||
|
||||
self.base_args = new_args;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn add_arg(&mut self, arg: String) -> Result<&'_ mut Self, Error> {
|
||||
self.base_args.push(arg);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn add_cc_arg(&mut self, arg: String) -> Result<&'_ mut Self, Error> {
|
||||
self.cc_args.push(arg);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn add_link_arg(&mut self, arg: String) -> Result<&'_ mut Self, Error> {
|
||||
self.link_args.push(arg);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn link_staticlib(&mut self, dir: &Path, name: String) -> Result<&'_ mut Self, Error> {
|
||||
if cfg!(any(target_os = "macos", target_os = "ios")) {
|
||||
//self.add_link_arg("-force_load".into())?;
|
||||
} else {
|
||||
self.add_link_arg("-Wl,--whole-archive".into())?;
|
||||
}
|
||||
self.add_link_arg(
|
||||
dir.join(format!("{}{}.{}", LIB_PREFIX, name, LIB_EXT))
|
||||
.display()
|
||||
.to_string(),
|
||||
)?;
|
||||
if cfg!(any(target_os = "macos", target_os = "ios")) {
|
||||
Ok(self)
|
||||
} else {
|
||||
self.add_link_arg("-Wl,-no-whole-archive".into())
|
||||
}
|
||||
}
|
||||
|
||||
fn command(&mut self) -> Result<Vec<String>, Error> {
|
||||
let mut args = vec![];
|
||||
if self.is_cpp {
|
||||
args.push(self.wrapped_cxx.clone());
|
||||
} else {
|
||||
args.push(self.wrapped_cc.clone());
|
||||
}
|
||||
args.extend_from_slice(self.base_args.as_slice());
|
||||
if self.linking {
|
||||
if self.x_set {
|
||||
args.push("-x".into());
|
||||
args.push("none".into());
|
||||
}
|
||||
|
||||
args.extend_from_slice(self.link_args.as_slice());
|
||||
} else {
|
||||
args.extend_from_slice(self.cc_args.as_slice());
|
||||
}
|
||||
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
fn is_linking(&self) -> bool {
|
||||
self.linking
|
||||
}
|
||||
|
||||
fn silence(&mut self) -> &'_ mut Self {
|
||||
self.is_silent = true;
|
||||
self
|
||||
}
|
||||
|
||||
fn is_silent(&self) -> bool {
|
||||
self.is_silent
|
||||
}
|
||||
}
|
||||
|
||||
impl ClangWrapper {
|
||||
/// Create a new Clang Wrapper
|
||||
#[must_use]
|
||||
pub fn new(wrapped_cc: &str, wrapped_cxx: &str) -> Self {
|
||||
Self {
|
||||
optimize: true,
|
||||
wrapped_cc: wrapped_cc.into(),
|
||||
wrapped_cxx: wrapped_cxx.into(),
|
||||
name: "".into(),
|
||||
is_cpp: false,
|
||||
linking: false,
|
||||
x_set: false,
|
||||
bit_mode: 0,
|
||||
base_args: vec![],
|
||||
cc_args: vec![],
|
||||
link_args: vec![],
|
||||
is_silent: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Disable optimizations
|
||||
pub fn dont_optimize(&mut self) -> &'_ mut Self {
|
||||
self.optimize = false;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set cpp mode
|
||||
pub fn is_cpp(&mut self, value: bool) -> &'_ mut Self {
|
||||
self.is_cpp = value;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{ClangWrapper, CompilerWrapper};
|
||||
|
||||
#[test]
|
||||
fn test_clang_version() {
|
||||
ClangWrapper::new("clang", "clang++")
|
||||
.from_args(&["my-clang".into(), "-v".into()])
|
||||
.unwrap()
|
||||
.run()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use std::ffi::c_void;
|
||||
|
||||
extern crate libafl_targets;
|
||||
extern "C" {
|
||||
pub fn libafl_targets_cmplog_wrapper(k: u64, shape: u8, arg1: u64, arg2: u64);
|
||||
pub fn __libafl_targets_cmplog_instructions(k: u64, shape: u8, arg1: u64, arg2: u64);
|
||||
}
|
||||
|
||||
pub struct CmpLogRuntime {
|
||||
@ -31,7 +31,7 @@ impl CmpLogRuntime {
|
||||
k &= (CMPLOG_MAP_W as u64) - 1;
|
||||
|
||||
unsafe {
|
||||
libafl_targets_cmplog_wrapper(k, 8, op1, op2);
|
||||
__libafl_targets_cmplog_instructions(k, 8, op1, op2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,6 @@ pub const CMPLOG_MAP_H: usize = {};
|
||||
#[cfg(feature = "sancov_cmplog")]
|
||||
{
|
||||
sancov_cmp.define("SANCOV_CMPLOG", "1");
|
||||
println!("cargo:rerun-if-changed=src/cmplog.h");
|
||||
}
|
||||
|
||||
sancov_cmp
|
||||
@ -84,6 +83,15 @@ pub const CMPLOG_MAP_H: usize = {};
|
||||
.compile("libfuzzer_compatibility");
|
||||
}
|
||||
|
||||
println!("cargo:rerun-if-changed=src/cmplog.h");
|
||||
println!("cargo:rerun-if-changed=src/cmplog.c");
|
||||
|
||||
cc::Build::new()
|
||||
.define("CMPLOG_MAP_W", Some(&*format!("{}", cmplog_map_w)))
|
||||
.define("CMPLOG_MAP_H", Some(&*format!("{}", cmplog_map_h)))
|
||||
.file(_src_dir.join("cmplog.c"))
|
||||
.compile("cmplog");
|
||||
|
||||
println!("cargo:rustc-link-search=native={}", &out_dir);
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
207
libafl_targets/src/cmplog.c
Normal file
207
libafl_targets/src/cmplog.c
Normal file
@ -0,0 +1,207 @@
|
||||
// From AFL++'s afl-compiler-rt.c
|
||||
|
||||
#define CMPLOG_MODULE
|
||||
#include "common.h"
|
||||
#include "cmplog.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
void *__libafl_asan_region_is_poisoned(void *beg, size_t size) {
|
||||
|
||||
(void)beg;
|
||||
(void)size;
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
#pragma comment(linker, "/alternatename:__asan_region_is_poisoned=__libafl_asan_region_is_poisoned")
|
||||
|
||||
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static int dummy_fd[2] = {2, 2};
|
||||
static int dymmy_initialized = 0;
|
||||
|
||||
__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size) {
|
||||
|
||||
(void)beg;
|
||||
(void)size;
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void __libafl_targets_cmplog_instructions(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) {
|
||||
|
||||
STATIC_ASSERT(sizeof(libafl_cmplog_map.vals.operands) == sizeof(libafl_cmplog_map.vals.routines));
|
||||
|
||||
__libafl_targets_cmplog(k, shape, arg1, arg2);
|
||||
|
||||
}
|
||||
|
||||
// POSIX shenanigan to see if an area is mapped.
|
||||
// If it is mapped as X-only, we have a problem, so maybe we should add a check
|
||||
// to avoid to call it on .text addresses
|
||||
static long area_is_valid(void *ptr, size_t len) {
|
||||
|
||||
if (!ptr || __asan_region_is_poisoned(ptr, len)) return 0;
|
||||
|
||||
long valid_len;
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (IsBadReadPtr(ptr, len)) return 0;
|
||||
valid_len = (long)len;
|
||||
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
if (!dymmy_initialized) {
|
||||
if ((dummy_fd[1] = open("/dev/null", O_WRONLY)) < 0) {
|
||||
if (pipe(dummy_fd) < 0)
|
||||
dummy_fd[1] = 1;
|
||||
}
|
||||
dymmy_initialized = 1;
|
||||
}
|
||||
|
||||
valid_len = syscall(SYS_write, dummy_fd[1], ptr, len);
|
||||
|
||||
if (valid_len <= 0 || valid_len > (long)len) return 0;
|
||||
#endif
|
||||
|
||||
// even if the write succeed this can be a false positive if we cross
|
||||
// a page boundary. who knows why.
|
||||
|
||||
char *p = (char *)ptr;
|
||||
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
#else
|
||||
long page_size = 4096; // Yolo
|
||||
#endif
|
||||
char *page = (char *)((uintptr_t)p & ~(page_size - 1)) + page_size;
|
||||
|
||||
if (page > p + len) {
|
||||
// no, not crossing a page boundary
|
||||
return valid_len;
|
||||
} else {
|
||||
// yes it crosses a boundary, hence we can only return the length of
|
||||
// rest of the first page, we cannot detect if the next page is valid
|
||||
// or not, neither by SYS_write nor msync() :-(
|
||||
return (long)(page - p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __libafl_targets_cmplog_routines(uintptr_t k, uint8_t *ptr1, uint8_t *ptr2) {
|
||||
|
||||
if (!libafl_cmplog_enabled) return;
|
||||
|
||||
int l1, l2;
|
||||
if ((l1 = area_is_valid(ptr1, CMPLOG_RTN_LEN)) <= 0 ||
|
||||
(l2 = area_is_valid(ptr2, CMPLOG_RTN_LEN)) <= 0)
|
||||
return;
|
||||
int len = MIN(l1, l2);
|
||||
|
||||
uint32_t hits;
|
||||
|
||||
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_RTN) {
|
||||
libafl_cmplog_map.headers[k].kind = CMPLOG_KIND_RTN;
|
||||
libafl_cmplog_map.headers[k].hits = 1;
|
||||
libafl_cmplog_map.headers[k].shape = len - 1;
|
||||
hits = 0;
|
||||
} else {
|
||||
hits = libafl_cmplog_map.headers[k].hits++;
|
||||
if (libafl_cmplog_map.headers[k].shape < len)
|
||||
libafl_cmplog_map.headers[k].shape = len - 1;
|
||||
}
|
||||
|
||||
hits &= CMPLOG_MAP_RTN_H - 1;
|
||||
MEMCPY(libafl_cmplog_map.vals.routines[k][hits].v0, ptr1, len);
|
||||
MEMCPY(libafl_cmplog_map.vals.routines[k][hits].v1, ptr2, len);
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_rtn_hook(uint8_t *ptr1, uint8_t *ptr2) {
|
||||
|
||||
uintptr_t k = RETADDR;
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMPLOG_MAP_W - 1;
|
||||
|
||||
__libafl_targets_cmplog_routines(k, ptr1, ptr2);
|
||||
|
||||
}
|
||||
|
||||
// gcc libstdc++
|
||||
// _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareEPKc
|
||||
static uint8_t *get_gcc_stdstring(uint8_t *string) {
|
||||
|
||||
uint32_t *len = (uint32_t *)(string + 8);
|
||||
|
||||
if (*len < 16) { // in structure
|
||||
return (string + 16);
|
||||
} else { // in memory
|
||||
uint8_t **ptr = (uint8_t **)string;
|
||||
return (*ptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// llvm libc++ _ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocator
|
||||
// IcEEE7compareEmmPKcm
|
||||
static uint8_t *get_llvm_stdstring(uint8_t *string) {
|
||||
|
||||
// length is in: if ((string[0] & 1) == 0) uint8_t len = (string[0] >> 1);
|
||||
// or: if (string[0] & 1) uint32_t *len = (uint32_t *) (string + 8);
|
||||
|
||||
if (string[0] & 1) { // in memory
|
||||
uint8_t **ptr = (uint8_t **)(string + 16);
|
||||
return (*ptr);
|
||||
} else { // in structure
|
||||
return (string + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_rtn_gcc_stdstring_cstring(uint8_t *stdstring, uint8_t *cstring) {
|
||||
|
||||
if (!libafl_cmplog_enabled) return;
|
||||
if (area_is_valid(stdstring, 32) <= 0)
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_gcc_stdstring(stdstring), cstring);
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_rtn_gcc_stdstring_stdstring(uint8_t *stdstring1, uint8_t *stdstring2) {
|
||||
|
||||
if (!libafl_cmplog_enabled) return;
|
||||
if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0)
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_gcc_stdstring(stdstring1),
|
||||
get_gcc_stdstring(stdstring2));
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_rtn_llvm_stdstring_cstring(uint8_t *stdstring, uint8_t *cstring) {
|
||||
|
||||
if (!libafl_cmplog_enabled) return;
|
||||
if (area_is_valid(stdstring, 32) <= 0)
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_llvm_stdstring(stdstring), cstring);
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_rtn_llvm_stdstring_stdstring(uint8_t *stdstring1, uint8_t *stdstring2) {
|
||||
|
||||
if (!libafl_cmplog_enabled) return;
|
||||
if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0)
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_llvm_stdstring(stdstring1),
|
||||
get_llvm_stdstring(stdstring2));
|
||||
|
||||
}
|
@ -10,6 +10,10 @@
|
||||
#define CMPLOG_MAP_H 32
|
||||
#endif
|
||||
|
||||
#define CMPLOG_RTN_LEN 32
|
||||
|
||||
#define CMPLOG_MAP_RTN_H ((CMPLOG_MAP_H * sizeof(CmpLogOperands)) / sizeof(CmpLogRoutine))
|
||||
|
||||
#define CMPLOG_KIND_INS 0
|
||||
#define CMPLOG_KIND_RTN 1
|
||||
|
||||
@ -24,19 +28,31 @@ typedef struct CmpLogOperands {
|
||||
uint64_t v1;
|
||||
} CmpLogOperands;
|
||||
|
||||
typedef struct CmpLogRoutine {
|
||||
uint8_t v0[CMPLOG_RTN_LEN];
|
||||
uint8_t v1[CMPLOG_RTN_LEN];
|
||||
} CmpLogRoutine;
|
||||
|
||||
typedef struct CmpLogMap {
|
||||
CmpLogHeader headers[CMPLOG_MAP_W];
|
||||
CmpLogOperands operands[CMPLOG_MAP_W][CMPLOG_MAP_H];
|
||||
union {
|
||||
CmpLogOperands operands[CMPLOG_MAP_W][CMPLOG_MAP_H];
|
||||
CmpLogRoutine routines[CMPLOG_MAP_W][CMPLOG_MAP_RTN_H];
|
||||
} vals;
|
||||
} CmpLogMap;
|
||||
|
||||
extern CmpLogMap libafl_cmplog_map;
|
||||
|
||||
extern uint8_t libafl_cmplog_enabled;
|
||||
|
||||
static void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) {
|
||||
void __libafl_targets_cmplog_instructions(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2);
|
||||
|
||||
void __libafl_targets_cmplog_routines(uintptr_t k, uint8_t *ptr1, uint8_t *ptr2);
|
||||
|
||||
static inline void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) {
|
||||
|
||||
if (!libafl_cmplog_enabled) return;
|
||||
|
||||
|
||||
uint16_t hits;
|
||||
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) {
|
||||
libafl_cmplog_map.headers[k].kind = CMPLOG_KIND_INS;
|
||||
@ -51,8 +67,8 @@ static void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, u
|
||||
}
|
||||
|
||||
hits &= CMPLOG_MAP_H - 1;
|
||||
libafl_cmplog_map.operands[k][hits].v0 = arg1;
|
||||
libafl_cmplog_map.operands[k][hits].v1 = arg2;
|
||||
libafl_cmplog_map.vals.operands[k][hits].v0 = arg1;
|
||||
libafl_cmplog_map.vals.operands[k][hits].v1 = arg2;
|
||||
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,21 @@
|
||||
_a > _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
#define MIN(a, b) \
|
||||
({ \
|
||||
\
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a < _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
#define MEMCPY __builtin_memcpy
|
||||
#else
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MEMCPY memcpy
|
||||
#endif
|
||||
|
||||
|
||||
#define STATIC_ASSERT(pred) switch(0){case 0:case pred:;}
|
||||
|
||||
#endif
|
||||
|
@ -72,12 +72,6 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef SANCOV_CMPLOG
|
||||
void libafl_targets_cmplog_wrapper(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2){
|
||||
return __libafl_targets_cmplog(k, shape, arg1, arg2);
|
||||
}
|
||||
#endif
|
||||
|
||||
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
|
||||
uintptr_t rt = RETADDR;
|
||||
|
Loading…
x
Reference in New Issue
Block a user