Index: tools/clang-fuzzer/CMakeLists.txt =================================================================== --- tools/clang-fuzzer/CMakeLists.txt +++ tools/clang-fuzzer/CMakeLists.txt @@ -49,6 +49,9 @@ # Build the protobuf->C++ translation library and driver. add_clang_subdirectory(proto-to-cxx) + + # Build the protobuf->LLVM IR translation library and driver. + add_clang_subdirectory(proto-to-llvm) # Build the fuzzer initialization library. add_clang_subdirectory(fuzzer-initialize) Index: tools/clang-fuzzer/cxx_loop_proto.proto =================================================================== --- tools/clang-fuzzer/cxx_loop_proto.proto +++ tools/clang-fuzzer/cxx_loop_proto.proto @@ -37,17 +37,15 @@ PLUS = 0; MINUS = 1; MUL = 2; - DIV = 3; - MOD = 4; - XOR = 5; - AND = 6; - OR = 7; - EQ = 8; - NE = 9; - LE = 10; - GE = 11; - LT = 12; - GT = 13; + XOR = 3; + AND = 4; + OR = 5; + EQ = 6; + NE = 7; + LE = 8; + GE = 9; + LT = 10; + GT = 11; }; required Op op = 1; required Rvalue left = 2; @@ -67,12 +65,6 @@ required Rvalue rvalue = 2; } -message IfElse { - required Rvalue cond = 1; - required StatementSeq if_body = 2; - required StatementSeq else_body = 3; -} - message Statement { required AssignmentStatement assignment = 1; } Index: tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp =================================================================== --- tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp +++ tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp @@ -67,12 +67,6 @@ case BinaryOp::MUL: os << "*"; break; - case BinaryOp::DIV: - os << "/"; - break; - case BinaryOp::MOD: - os << "%"; - break; case BinaryOp::XOR: os << "^"; break; @@ -106,11 +100,6 @@ std::ostream &operator<<(std::ostream &os, const AssignmentStatement &x) { return os << x.varref() << "=" << x.rvalue() << ";\n"; } -std::ostream &operator<<(std::ostream &os, const IfElse &x) { - return os << "if (" << x.cond() << "){\n" - << x.if_body() << "} else { \n" - << x.else_body() << "}\n"; -} std::ostream &operator<<(std::ostream &os, const Statement &x) { return os << x.assignment(); } Index: tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx_main.cpp =================================================================== --- tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx_main.cpp +++ tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx_main.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -// This is a copy and will be updated later to introduce changes #include #include Index: tools/clang-fuzzer/proto-to-llvm/CMakeLists.txt =================================================================== --- /dev/null +++ tools/clang-fuzzer/proto-to-llvm/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD}) +set(CMAKE_CXX_FLAGS ${CXX_FLAGS_NOFUZZ}) + +# Needed by LLVM's CMake checks because this file defines multiple targets. +set(LLVM_OPTIONAL_SOURCES loop_proto_to_llvm.cpp loop_proto_to_llvm_main.cpp) + +add_clang_library(clangLoopProtoToLLVM loop_proto_to_llvm.cpp + DEPENDS clangCXXLoopProto + LINK_LIBS clangCXXLoopProto ${PROTOBUF_LIBRARIES} + ) + +add_clang_executable(clang-loop-proto-to-llvm loop_proto_to_llvm_main.cpp) + +target_link_libraries(clang-loop-proto-to-llvm PRIVATE clangLoopProtoToLLVM) Index: tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.h =================================================================== --- /dev/null +++ tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.h @@ -0,0 +1,23 @@ +//==-- loop_proto_to_llvm.h - Protobuf-C++ conversion ----------------------------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines functions for converting between protobufs and LLVM IR. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +namespace clang_fuzzer { +class LoopFunction; + +std::string LoopFunctionToLLVMString(const LoopFunction &input); +std::string LoopProtoToLLVM(const uint8_t *data, size_t size); +} Index: tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp =================================================================== --- /dev/null +++ tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp @@ -0,0 +1,179 @@ +//==-- loop_proto_to_llvm.cpp - Protobuf-C++ conversion +//---------------------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements functions for converting between protobufs and LLVM IR. +// +// +//===----------------------------------------------------------------------===// + +#include "loop_proto_to_llvm.h" +#include "cxx_loop_proto.pb.h" + +// The following is needed to convert protos in human-readable form +#include + +#include +#include + +namespace clang_fuzzer { + +// Forward decls +std::pair BinopToString(const BinaryOp &x); +std::pair StateSeqToString(const StatementSeq &x); + +// Counter variable to generate new LLVM IR variable names and wrapper function +int ctr = 0; +std::string get_var() { + ctr++; + return "%var" + std::to_string(ctr); +} + +// Proto to LLVM. + +std::pair ConstToString(const Const &x) { + std::string alloca_var = get_var(); + std::string load_var = get_var(); + std::string val = std::to_string(x.val()); + std::string insns = alloca_var + " = alloca i32\n" + + "store i32 " + val + ", i32* " + alloca_var + "\n" + + load_var + " = load i32, i32* " + alloca_var + "\n"; + return std::make_pair(insns, load_var); +} +std::pair VarRefToString(const VarRef &x) { + std::string arr; + switch(x.arr()) { + case VarRef::ARR_A: + arr = "%a"; + break; + case VarRef::ARR_B: + arr = "%b"; + break; + case VarRef::ARR_C: + arr = "%c"; + break; + } + std::string ptr_var = get_var(); + std::string insn = ptr_var + " = getelementptr i32, i32* " + arr + ", i64 %ct\n"; + return std::make_pair(insn, ptr_var); +} +std::pair RvalueToString(const Rvalue &x) { + if(x.has_cons()) + return ConstToString(x.cons()); + if(x.has_binop()) + return BinopToString(x.binop()); + if(x.has_varref()) { + std::pair var_ref = VarRefToString(x.varref()); + std::string val_var = get_var(); + std::string insns = var_ref.first + + val_var + " = load i32, i32* " + var_ref.second + "\n"; + return std::make_pair(insns, val_var); + } +} +std::pair BinopToString(const BinaryOp &x) { + std::pair left = RvalueToString(x.left()); + std::pair right = RvalueToString(x.right()); + std::string op; + switch (x.op()) { + case BinaryOp::PLUS: + op = "add"; + break; + case BinaryOp::MINUS: + op = "sub"; + break; + case BinaryOp::MUL: + op = "mul"; + break; + case BinaryOp::XOR: + op = "xor"; + break; + case BinaryOp::AND: + op = "and"; + break; + case BinaryOp::OR: + op = "or"; + break; + // Support for Boolean operators will be added later + case BinaryOp::EQ: + op = "add"; + break; + case BinaryOp::NE: + op = "add"; + break; + case BinaryOp::LE: + op = "add"; + break; + case BinaryOp::GE: + op = "add"; + break; + case BinaryOp::LT: + op = "add"; + break; + case BinaryOp::GT: + op = "add"; + break; + } + std::string val_var = get_var(); + std::string insns = left.first + + right.first + + val_var + " = " + op + " i32 " + left.second + + ", i32 " + right.second + "\n"; + return std::make_pair(insns, val_var); +} +std::string AssignmentStatementToString(const AssignmentStatement &x) { + std::pair ref = VarRefToString(x.varref()); + std::pair rv = RvalueToString(x.rvalue()); + std::string insns = rv.first + + ref.first + + "store i32 " + rv.second + ", i32* " + ref.second + "\n"; + return insns; +} +std::string StatementToString(const Statement &x) { + return AssignmentStatementToString(x.assignment()); +} +std::ostream &operator<<(std::ostream &os, const StatementSeq &x) { + for (auto &st : x.statements()) { + std::string statement = StatementToString(st); + os << statement; + } + return os; +} +std::ostream &operator<<(std::ostream &os, const LoopFunction &x) { + return os << "define void @foo(i32* %a, i32* %b, i32* noalias %c, i64 %s) {\n" + << "%i = alloca i64\n" + << "store i64 0, i64* %i\n" + << "br label %loop\n\n" + << "loop:\n" + << "%ct = load i64, i64* %i\n" + << "%comp = icmp eq i64 %ct, %s\n" + << "br i1 %comp, label %endloop, label %body\n\n" + << "body:\n" + << x.statements() + << "%z = add i64 1, %ct\n" + << "store i64 %z, i64* %i\n" + << "br label %loop\n\n" + << "endloop:\n" + << "ret void\n}\n"; +} + +// --------------------------------- + +std::string LoopFunctionToLLVMString(const LoopFunction &input) { + std::ostringstream os; + os << input; + return os.str(); +} +std::string LoopProtoToLLVM(const uint8_t *data, size_t size) { + LoopFunction message; + if (!message.ParsePartialFromArray(data, size)) + return "#error invalid proto\n"; + return LoopFunctionToLLVMString(message); +} + +} // namespace clang_fuzzer Index: tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm_main.cpp =================================================================== --- tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm_main.cpp +++ tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm_main.cpp @@ -1,4 +1,4 @@ -//==-- loop_proto_to_cxx_main.cpp - Driver for protobuf-C++ conversion -----==// +//==-- loop_proto_to_llvm_main.cpp - Driver for protobuf-LLVM conversion----==// // // The LLVM Compiler Infrastructure // @@ -7,26 +7,25 @@ // //===----------------------------------------------------------------------===// // -// Implements a simple driver to print a C++ program from a protobuf with loops. +// Implements a simple driver to print a LLVM program from a protobuf with loops // //===----------------------------------------------------------------------===// -// This is a copy and will be updated later to introduce changes #include #include #include #include -#include "proto_to_cxx.h" +#include "loop_proto_to_llvm.h" int main(int argc, char **argv) { for (int i = 1; i < argc; i++) { std::fstream in(argv[i]); std::string str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - std::cout << "// " << argv[i] << std::endl; - std::cout << clang_fuzzer::LoopProtoToCxx( + std::cout << ";; " << argv[i] << std::endl; + std::cout << clang_fuzzer::LoopProtoToLLVM( reinterpret_cast(str.data()), str.size()); } }