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]
|
[lib]
|
||||||
name = "fuzzbench"
|
name = "fuzzbench"
|
||||||
crate-type = ["staticlib"]
|
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;
|
use std::env;
|
||||||
|
|
||||||
fn main() {
|
pub fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let mut dir = env::current_exe().unwrap();
|
let mut dir = env::current_exe().unwrap();
|
||||||
@ -15,20 +15,18 @@ fn main() {
|
|||||||
|
|
||||||
dir.pop();
|
dir.pop();
|
||||||
|
|
||||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
let mut cc = ClangWrapper::new();
|
||||||
|
|
||||||
if let Some(code) = cc
|
if let Some(code) = cc
|
||||||
.is_cpp(is_cpp)
|
.cpp(is_cpp)
|
||||||
.from_args(&args)
|
|
||||||
.unwrap()
|
|
||||||
.link_staticlib(&dir, "fuzzbench".into())
|
|
||||||
.unwrap()
|
|
||||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp".into())
|
|
||||||
.unwrap()
|
|
||||||
// silence the compiler wrapper output, needed for some configure scripts.
|
// 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()
|
.run()
|
||||||
.unwrap()
|
.expect("Failed to run the wrapped compiler".into())
|
||||||
{
|
{
|
||||||
std::process::exit(code);
|
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;
|
use std::env;
|
||||||
|
|
||||||
fn main() {
|
pub fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let mut dir = env::current_exe().unwrap();
|
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();
|
dir.pop();
|
||||||
|
|
||||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
let mut cc = ClangWrapper::new();
|
||||||
cc.is_cpp(false)
|
if let Some(code) = cc
|
||||||
|
.cpp(is_cpp)
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence(true)
|
||||||
.from_args(&args)
|
.from_args(&args)
|
||||||
.unwrap()
|
.expect("Failed to parse the command line".into())
|
||||||
.link_staticlib(&dir, "generic_inmemory".into())
|
.link_staticlib(&dir, "generic_inmemory")
|
||||||
.unwrap()
|
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp")
|
||||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp".into())
|
.add_pass(LLVMPasses::CmpLogRtn)
|
||||||
.unwrap();
|
.run()
|
||||||
cc.run().unwrap();
|
.expect("Failed to run the wrapped compiler".into())
|
||||||
|
{
|
||||||
|
std::process::exit(code);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("LibAFL CC: No Arguments given");
|
panic!("LibAFL CC: No Arguments given");
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,5 @@
|
|||||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
pub mod libafl_cc;
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
libafl_cc::main()
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,34 @@
|
|||||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
fn main() {
|
pub fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let mut dir = env::current_exe().unwrap();
|
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();
|
dir.pop();
|
||||||
|
|
||||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
let mut cc = ClangWrapper::new();
|
||||||
cc.is_cpp(false)
|
if let Some(code) = cc
|
||||||
|
.cpp(is_cpp)
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence(true)
|
||||||
.from_args(&args)
|
.from_args(&args)
|
||||||
.unwrap()
|
.expect("Failed to parse the command line".into())
|
||||||
.link_staticlib(&dir, "libfuzzer_libmozjpeg".into())
|
.link_staticlib(&dir, "libfuzzer_libmozjpeg")
|
||||||
.unwrap()
|
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp")
|
||||||
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp".into())
|
.run()
|
||||||
.unwrap();
|
.expect("Failed to run the wrapped compiler".into())
|
||||||
cc.run().unwrap();
|
{
|
||||||
|
std::process::exit(code);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("LibAFL CC: No Arguments given");
|
panic!("LibAFL CC: No Arguments given");
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,5 @@
|
|||||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
pub mod libafl_cc;
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
libafl_cc::main()
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,34 @@
|
|||||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
fn main() {
|
pub fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let mut dir = env::current_exe().unwrap();
|
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();
|
dir.pop();
|
||||||
|
|
||||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
let mut cc = ClangWrapper::new();
|
||||||
cc.is_cpp(false)
|
if let Some(code) = cc
|
||||||
|
.cpp(is_cpp)
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence(true)
|
||||||
.from_args(&args)
|
.from_args(&args)
|
||||||
.unwrap()
|
.expect("Failed to parse the command line".into())
|
||||||
.link_staticlib(&dir, "libfuzzer_libpng".into())
|
.link_staticlib(&dir, "libfuzzer_libpng")
|
||||||
.unwrap()
|
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
.run()
|
||||||
.unwrap();
|
.expect("Failed to run the wrapped compiler".into())
|
||||||
cc.run().unwrap();
|
{
|
||||||
|
std::process::exit(code);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("LibAFL CC: No Arguments given");
|
panic!("LibAFL CC: No Arguments given");
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,5 @@
|
|||||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
pub mod libafl_cc;
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
libafl_cc::main()
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,34 @@
|
|||||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
fn main() {
|
pub fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let mut dir = env::current_exe().unwrap();
|
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();
|
dir.pop();
|
||||||
|
|
||||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
let mut cc = ClangWrapper::new();
|
||||||
cc.is_cpp(false)
|
if let Some(code) = cc
|
||||||
|
.cpp(is_cpp)
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence(true)
|
||||||
.from_args(&args)
|
.from_args(&args)
|
||||||
.unwrap()
|
.expect("Failed to parse the command line".into())
|
||||||
.link_staticlib(&dir, "libfuzzer_libpng".into())
|
.link_staticlib(&dir, "libfuzzer_libpng")
|
||||||
.unwrap()
|
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
.run()
|
||||||
.unwrap();
|
.expect("Failed to run the wrapped compiler".into())
|
||||||
cc.run().unwrap();
|
{
|
||||||
|
std::process::exit(code);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("LibAFL CC: No Arguments given");
|
panic!("LibAFL CC: No Arguments given");
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,5 @@
|
|||||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
pub mod libafl_cc;
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
libafl_cc::main()
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,34 @@
|
|||||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
fn main() {
|
pub fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let mut dir = env::current_exe().unwrap();
|
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();
|
dir.pop();
|
||||||
|
|
||||||
let mut cc = ClangWrapper::new("clang", "clang++");
|
let mut cc = ClangWrapper::new();
|
||||||
cc.is_cpp(false)
|
if let Some(code) = cc
|
||||||
|
.cpp(is_cpp)
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence(true)
|
||||||
.from_args(&args)
|
.from_args(&args)
|
||||||
.unwrap()
|
.expect("Failed to parse the command line".into())
|
||||||
.link_staticlib(&dir, "libfuzzer_libpng".into())
|
.link_staticlib(&dir, "libfuzzer_libpng")
|
||||||
.unwrap()
|
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
.run()
|
||||||
.unwrap();
|
.expect("Failed to run the wrapped compiler".into())
|
||||||
cc.run().unwrap();
|
{
|
||||||
|
std::process::exit(code);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("LibAFL CC: No Arguments given");
|
panic!("LibAFL CC: No Arguments given");
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,5 @@
|
|||||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
pub mod libafl_cc;
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
libafl_cc::main()
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,4 +12,7 @@ edition = "2018"
|
|||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# 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]
|
[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`
|
//! 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
|
/// `LibAFL` CC Error Type
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -31,19 +34,62 @@ pub const LIB_PREFIX: &str = "lib";
|
|||||||
/// Wrap a compiler hijacking its arguments
|
/// Wrap a compiler hijacking its arguments
|
||||||
pub trait CompilerWrapper {
|
pub trait CompilerWrapper {
|
||||||
/// Set the wrapper arguments parsing a command line set of arguments
|
/// 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
|
/// 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
|
/// 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
|
/// 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
|
/// 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
|
/// Command to run the compiler
|
||||||
fn command(&mut self) -> Result<Vec<String>, Error>;
|
fn command(&mut self) -> Result<Vec<String>, Error>;
|
||||||
@ -52,9 +98,9 @@ pub trait CompilerWrapper {
|
|||||||
fn is_linking(&self) -> bool;
|
fn is_linking(&self) -> bool;
|
||||||
|
|
||||||
/// Silences `libafl_cc` output
|
/// 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;
|
fn is_silent(&self) -> bool;
|
||||||
|
|
||||||
/// Run the compiler
|
/// Run the compiler
|
||||||
@ -79,202 +125,3 @@ pub trait CompilerWrapper {
|
|||||||
Ok(status.code())
|
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 crate libafl_targets;
|
||||||
extern "C" {
|
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 {
|
pub struct CmpLogRuntime {
|
||||||
@ -31,7 +31,7 @@ impl CmpLogRuntime {
|
|||||||
k &= (CMPLOG_MAP_W as u64) - 1;
|
k &= (CMPLOG_MAP_W as u64) - 1;
|
||||||
|
|
||||||
unsafe {
|
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")]
|
#[cfg(feature = "sancov_cmplog")]
|
||||||
{
|
{
|
||||||
sancov_cmp.define("SANCOV_CMPLOG", "1");
|
sancov_cmp.define("SANCOV_CMPLOG", "1");
|
||||||
println!("cargo:rerun-if-changed=src/cmplog.h");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sancov_cmp
|
sancov_cmp
|
||||||
@ -84,6 +83,15 @@ pub const CMPLOG_MAP_H: usize = {};
|
|||||||
.compile("libfuzzer_compatibility");
|
.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:rustc-link-search=native={}", &out_dir);
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
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
|
#define CMPLOG_MAP_H 32
|
||||||
#endif
|
#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_INS 0
|
||||||
#define CMPLOG_KIND_RTN 1
|
#define CMPLOG_KIND_RTN 1
|
||||||
|
|
||||||
@ -24,19 +28,31 @@ typedef struct CmpLogOperands {
|
|||||||
uint64_t v1;
|
uint64_t v1;
|
||||||
} CmpLogOperands;
|
} CmpLogOperands;
|
||||||
|
|
||||||
|
typedef struct CmpLogRoutine {
|
||||||
|
uint8_t v0[CMPLOG_RTN_LEN];
|
||||||
|
uint8_t v1[CMPLOG_RTN_LEN];
|
||||||
|
} CmpLogRoutine;
|
||||||
|
|
||||||
typedef struct CmpLogMap {
|
typedef struct CmpLogMap {
|
||||||
CmpLogHeader headers[CMPLOG_MAP_W];
|
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;
|
} CmpLogMap;
|
||||||
|
|
||||||
extern CmpLogMap libafl_cmplog_map;
|
extern CmpLogMap libafl_cmplog_map;
|
||||||
|
|
||||||
extern uint8_t libafl_cmplog_enabled;
|
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;
|
if (!libafl_cmplog_enabled) return;
|
||||||
|
|
||||||
uint16_t hits;
|
uint16_t hits;
|
||||||
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) {
|
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) {
|
||||||
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;
|
hits &= CMPLOG_MAP_H - 1;
|
||||||
libafl_cmplog_map.operands[k][hits].v0 = arg1;
|
libafl_cmplog_map.vals.operands[k][hits].v0 = arg1;
|
||||||
libafl_cmplog_map.operands[k][hits].v1 = arg2;
|
libafl_cmplog_map.vals.operands[k][hits].v1 = arg2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,10 +20,21 @@
|
|||||||
_a > _b ? _a : _b; \
|
_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
|
#else
|
||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#define MEMCPY memcpy
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define STATIC_ASSERT(pred) switch(0){case 0:case pred:;}
|
||||||
|
|
||||||
#endif
|
#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) {
|
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||||
|
|
||||||
uintptr_t rt = RETADDR;
|
uintptr_t rt = RETADDR;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user