Index: tools/llvm-mc-assemble-proto-fuzzer/CMakeLists.txt =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/CMakeLists.txt +++ tools/llvm-mc-assemble-proto-fuzzer/CMakeLists.txt @@ -23,7 +23,8 @@ add_definitions(-DGOOGLE_PROTOBUF_NO_RTTI) include_directories(${PROTOBUF_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) - protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS asm_proto.proto) + protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS proto-files/asm_proto.proto) + protobuf_generate_cpp(I_PROTO_SRCS I_PROTO_HDRS proto-files/rv32i_asm.proto) set(LLVM_OPTIONAL_SOURCES ${LLVM_OPTIONAL_SOURCES} ${PROTO_SRCS}) add_clang_library(mcASMProto ${PROTO_SRCS} @@ -33,10 +34,21 @@ ${PROTOBUF_LIBRARIES} ) + add_clang_library(mcRv32iASMProto + ${I_PROTO_SRCS} + ${I_PROTO_HDRS} + + LINK_LIBS + ${PROTOBUF_LIBRARIES} + ) + # Build and include libprotobuf-mutator include(ProtobufMutatorMC) include_directories(${ProtobufMutator_INCLUDE_DIRS}) + # Build the .proto files. + add_clang_subdirectory(proto-files) + # Build the protobuf->C++ translation library and driver. add_clang_subdirectory(proto-to-asm) @@ -48,6 +60,11 @@ ExampleMCProtoFuzzer.cpp ) + add_clang_executable(llvm-mc-assemble-proto-fuzzer-rv32i + ${DUMMY_MAIN} + ExampleMCProtoFuzzer.cpp + ) + set(COMMON_PROTO_FUZZ_LIBRARIES ${ProtobufMutator_LIBRARIES} ${PROTOBUF_LIBRARIES} @@ -62,6 +79,14 @@ mcProtoToASM ) + target_link_libraries(llvm-mc-assemble-proto-fuzzer-rv32i + PRIVATE + ${COMMON_PROTO_FUZZ_LIBRARIES} + mcRv32iASMProto + mcRv32iProtoToASM + ) + + endif() add_clang_subdirectory(handle-asm) Index: tools/llvm-mc-assemble-proto-fuzzer/README.txt =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/README.txt +++ tools/llvm-mc-assemble-proto-fuzzer/README.txt @@ -10,8 +10,8 @@ -DCMAKE_PREFIX_PATH=/path/to/install \ -DPBM_FUZZ_PATH=/full/path/to/protobuf/install \ -DPBM_REPO=file:///full/path/to/libprotobuf-mutator ../../llvm -$ ninja -v llvm-mc-assemble-proto-fuzzer llvm-mc-assemble-proto-to-asm - 2>&1 | tee log +$ ninja -v llvm-mc-assemble-proto-fuzzer llvm-mc-assemble-proto-to-asm \ + llvm-mc-assemble-proto-fuzzer-rv32i 2>&1 | tee log ------------------------------------------------------------------------------- Setting Up: @@ -31,7 +31,7 @@ $ python mcfuzz.py --corpus corpus --max-len 32 --runs 10 --triple riscv32 --out outputdir --objdump /full/path/to/riscv32-unknown-linux-gnu-objdump - --mattr +c + --mattr +c,+m Run the script with the --verbose flag if you would like to see the output of the fuzzer as it runs. @@ -63,3 +63,12 @@ The last part of the script runs a diff of all the .s and .objdump files, and prints out a summary of results (how many diffs passed and how many failed). + +------------------------------------------------------------------------------- +Notes: +------------------------------------------------------------------------------- +The fuzzer currently supports all the instructions in the RV32I ISA, except +for the following instructions: FENCE, FENCE.I, ECALL, EBREAK, CSRRW, CSRRS, +CSRRC, CSRRWI, CSRRSI, and CSRRCI. Currently, running the Python script will +result in some failures as instructions are given aliases by the golden +disassembler, and therefore the diff fails. Index: tools/llvm-mc-assemble-proto-fuzzer/asm_proto.proto =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/asm_proto.proto +++ /dev/null @@ -1,61 +0,0 @@ -//===-- asm_proto.proto - Protobuf description of ASM ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file describes a subset of ASM as a protobuf. It is used to -/// more easily find interesting inputs for fuzzing llvm mc layer. -/// -//===----------------------------------------------------------------------===// - -syntax = "proto2"; - -message Register { - enum RegName { - X0 = 1; X1 = 2; X2 = 3; X3 = 4; X4 = 5; X5 = 6; X6 = 7; X7 = 8; X8 = 9; - X9 = 10; X10 = 11; X11 = 12; X12 = 13; X13 = 14; X14 = 15; X15 = 16; - X16 = 17; X17 = 18; X18 = 19; X19 = 20; X20 = 21; X21 = 22; X22 = 23; - X23 = 24; X24 = 25; X25 = 26; X26 = 27; X27 = 28; X28 = 29; X29 = 30; - X30 = 31; X31 = 32; - }; - required RegName name = 1; -} - -message ITypeOpcode { - enum Op { - ADD = 1; SUB = 2; - }; - required Op op = 1; -} - -message ITypeOperands { - required Register operand1 = 1; - required Register operand2 = 2; - required Register operand3 = 3; -} - -message ITypeStatement { - required ITypeOpcode opcode = 1; - required ITypeOperands operands = 2; -} - -message AsmStatement { - oneof asmstatement_oneof { - ITypeStatement statement = 2; - } -} - -message AsmStatementSeq { - repeated AsmStatement statements = 1; -} - -message Assembly { - required AsmStatementSeq asmStatements = 1; -} - -package mc_proto_fuzzer; Index: tools/llvm-mc-assemble-proto-fuzzer/mcfuzz.py =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/mcfuzz.py +++ tools/llvm-mc-assemble-proto-fuzzer/mcfuzz.py @@ -45,8 +45,9 @@ args = parser.parse_args() # Step 1: Invoke fuzzer to generate a corpus. -cmd = 'llvm-mc-assemble-proto-fuzzer {corpus} -triple={triple} -mattr={mattr}' \ - + ' -filetype={filetype} -fuzzer-args -runs={runs} -max_len={max_len}' +cmd = 'llvm-mc-assemble-proto-fuzzer-rv32i {corpus} -triple={triple} ' \ + '-mattr={mattr}' + ' -filetype={filetype} -fuzzer-args -runs={runs} ' \ + '-max_len={max_len}' cmd = cmd.format(corpus=args.corpus, triple=args.triple, mattr=args.mattr, \ filetype=args.filetype, runs=args.runs, max_len=args.max_len) fuzz_command = shlex.split(cmd) @@ -78,7 +79,7 @@ filename_prefix = args.out + "/" + filename # Step 2: Run proto-to-asm on corpus file to generate .s file. - proto_to_asm_command = ["llvm-mc-assemble-proto-to-asm", \ + proto_to_asm_command = ["llvm-mc-assemble-proto-to-asm-rv32i", \ args.corpus + "/" + filename, "-riscv-no-aliases=" + str(args.NoAliases)] asm_file = open(filename_prefix + ".s", "w+r") @@ -90,8 +91,9 @@ asm_err)) # Step 3: Generate .o files in the outputdir. - cmd = 'llvm-mc-assemble-proto-fuzzer {corpus}/{file} -triple={triple}' \ - + ' -mattr={mattr} -out={out} -filetype=obj -fuzzer-args -runs=1' + cmd = 'llvm-mc-assemble-proto-fuzzer-rv32i {corpus}/{file} ' \ + + '-triple={triple} -mattr={mattr} -out={out} ' \ + + '-filetype=obj -fuzzer-args -runs=1' cmd = cmd.format(corpus=args.corpus, file=filename, triple=args.triple, \ mattr=args.mattr, out=args.out) obj_files_command = shlex.split(cmd) Index: tools/llvm-mc-assemble-proto-fuzzer/proto-files/asm_proto.proto =================================================================== --- /dev/null +++ tools/llvm-mc-assemble-proto-fuzzer/proto-files/asm_proto.proto @@ -0,0 +1,63 @@ +//===-- asm_proto.proto - Protobuf description of ASM ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes a subset of ASM as a protobuf. It is used to +/// more easily find interesting inputs for fuzzing llvm mc layer. +/// +//===----------------------------------------------------------------------===// + +syntax = "proto2"; + +message Register { + enum RegName { + X0 = 1; X1 = 2; X2 = 3; X3 = 4; X4 = 5; + X5 = 6; X6 = 7; X7 = 8; X8 = 9; X9 = 10; + X10 = 11; X11 = 12; X12 = 13; X13 = 14; X14 = 15; + X15 = 16; X16 = 17; X17 = 18; X18 = 19; X19 = 20; + X20 = 21; X21 = 22; X22 = 23; X23 = 24; X24 = 25; + X25 = 26; X26 = 27; X27 = 28; X28 = 29; X29 = 30; + X30 = 31; X31 = 32; + }; + required RegName name = 1; +} + +message RTypeOpcode { + enum Op { + ADD = 1; SUB = 2; + }; + required Op op = 1; +} + +message RTypeOperands { + required Register operand1 = 1; + required Register operand2 = 2; + required Register operand3 = 3; +} + +message RTypeStatement { + required RTypeOpcode opcode = 1; + required RTypeOperands operands = 2; +} + +message AsmStatement { + oneof asmstatement_oneof { + RTypeStatement statement = 2; + } +} + +message AsmStatementSeq { + repeated AsmStatement statements = 1; +} + +message Assembly { + required AsmStatementSeq asmStatements = 1; +} + +package mc_proto_fuzzer; Index: tools/llvm-mc-assemble-proto-fuzzer/proto-files/rv32i_asm.proto =================================================================== --- /dev/null +++ tools/llvm-mc-assemble-proto-fuzzer/proto-files/rv32i_asm.proto @@ -0,0 +1,202 @@ +//===-- rv32i_asm.proto - Protobuf description of ASM ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes a subset of ASM (RV32I) as a protobuf. It is used to +/// more easily find interesting inputs for fuzzing the llvm mc layer. +/// +//===----------------------------------------------------------------------===// + +syntax = "proto2"; + +message ITypeShiftImmediate { + required uint32 imm = 1; +} + +message ITypeImmediate { + required sint32 imm = 1; +} + +message STypeImmediate { + required sint32 imm = 1; +} + +message BTypeImmediate { + required sint32 imm = 1; +} + +message UTypeImmediate { + required uint32 imm = 1; +} + +message JTypeImmediate { + required sint32 imm = 1; +} + +message Register { + enum RegName { + X0 = 0; X1 = 1; X2 = 2; X3 = 3; X4 = 4; + X5 = 5; X6 = 6; X7 = 7; X8 = 8; X9 = 9; + X10 = 10; X11 = 11; X12 = 12; X13 = 13; X14 = 14; + X15 = 15; X16 = 16; X17 = 17; X18 = 18; X19 = 19; + X20 = 20; X21 = 21; X22 = 22; X23 = 23; X24 = 24; + X25 = 25; X26 = 26; X27 = 27; X28 = 28; X29 = 29; + X30 = 30; X31 = 31; + }; + required RegName name = 1; +} + +message RTypeOpcode { + enum Op { + ADD = 0; SUB = 1; SLL = 2; SLT = 3; SLTU = 4; + XOR = 5; SRL = 6; SRA = 7; OR = 8; AND = 9; + }; + required Op op = 1; +} + +message RTypeOperands { + required Register operand1 = 1; + required Register operand2 = 2; + required Register operand3 = 3; +} + +message RTypeStatement { + required RTypeOpcode opcode = 1; + required RTypeOperands operands = 2; +} + +message ITypeOpcode { + enum Op { + ADDI = 0; SLTI = 1; ANDI = 2; ORI = 3; XORI = 4; + SLTIU = 5; JALR = 6; + }; + required Op op = 1; +} + +message ITypeOperands { + required Register operand1 = 1; + required Register operand2 = 2; + required ITypeImmediate operand3 = 3; +} + +message ITypeStatement { + required ITypeOpcode opcode = 1; + required ITypeOperands operands = 2; +} + +message ITypeShiftOpcode { + enum Op { + SRAI = 0; SRLI = 1; SLLI = 2; + }; + required Op op = 1; +} + +message ITypeShiftOperands { + required Register operand1 = 1; + required Register operand2 = 2; + required ITypeShiftImmediate operand3 = 3; +} + +message ITypeShiftStatement { + required ITypeShiftOpcode opcode = 1; + required ITypeShiftOperands operands = 2; +} + +message STypeOpcode { + enum Op { + SW = 0; SH = 1; SB = 2; + }; + required Op op = 1; +} + +message STypeOperands { + required Register operand1 = 1; + required STypeImmediate operand2 = 2; + required Register operand3 = 3; +} + +message STypeStatement { + required STypeOpcode opcode = 1; + required STypeOperands operands = 2; +} + +message BTypeOpcode { + enum Op { + BEQ = 0; BNE = 1; BGE = 2; BLT = 3; BGEU = 4; + BLTU = 5; + }; + required Op op = 1; +} + +message BTypeOperands { + required Register operand1 = 1; + required Register operand2 = 2; + required BTypeImmediate operand3 = 3; +} + +message BTypeStatement { + required BTypeOpcode opcode = 1; + required BTypeOperands operands = 2; +} + +message UTypeOpcode { + enum Op { + LUI = 0; AUIPC = 1; + }; + required Op op = 1; +} + +message UTypeOperands { + required Register operand1 = 1; + required UTypeImmediate operand2 = 2; +} + +message UTypeStatement { + required UTypeOpcode opcode = 1; + required UTypeOperands operands = 2; +} + +message JTypeOpcode { + enum Op { + JAL = 0; + }; + required Op op = 1; +} + +message JTypeOperands { + required Register operand1 = 1; + required JTypeImmediate operand2 = 2; +} + +message JTypeStatement { + required JTypeOpcode opcode = 1; + required JTypeOperands operands = 2; +} + +message AsmStatement { + oneof asmstatement_oneof { + RTypeStatement statement1 = 1; + ITypeStatement statement2 = 2; + ITypeShiftStatement statement3 = 3; + STypeStatement statement4 = 4; + BTypeStatement statement5 = 5; + UTypeStatement statement6 = 6; + JTypeStatement statement7 = 7; + } +} + +message AsmStatementSeq { + repeated AsmStatement statements = 1; +} + +message Assembly { + required AsmStatementSeq asmStatements = 1; +} + +package mc_proto_fuzzer; Index: tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/CMakeLists.txt =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/CMakeLists.txt +++ tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/CMakeLists.txt @@ -2,13 +2,22 @@ set(CMAKE_CXX_FLAGS ${CXX_FLAGS_NOFUZZ}) # Needed by LLVM's CMake checks because this file defines multiple targets. -set(LLVM_OPTIONAL_SOURCES proto_to_asm.cpp proto_to_asm_main.cpp) +set(LLVM_OPTIONAL_SOURCES proto_to_asm.cpp proto_to_asm_main.cpp + proto_to_asm_rv32i.cpp) add_clang_library(mcProtoToASM proto_to_asm.cpp DEPENDS mcASMProto LINK_LIBS mcASMProto ${PROTOBUF_LIBRARIES} ) +add_clang_library(mcRv32iProtoToASM proto_to_asm_rv32i.cpp + DEPENDS mcRv32iASMProto + LINK_LIBS mcRv32iASMProto ${PROTOBUF_LIBRARIES} + ) + add_clang_executable(llvm-mc-assemble-proto-to-asm proto_to_asm_main.cpp) +add_clang_executable(llvm-mc-assemble-proto-to-asm-rv32i proto_to_asm_main.cpp) target_link_libraries(llvm-mc-assemble-proto-to-asm PRIVATE mcProtoToASM) +target_link_libraries(llvm-mc-assemble-proto-to-asm-rv32i + PRIVATE mcRv32iProtoToASM) Index: tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm.h =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm.h +++ tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm.h @@ -11,8 +11,6 @@ // //===----------------------------------------------------------------------===// -#include -#include #include namespace mc_proto_fuzzer { Index: tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm.cpp =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm.cpp +++ tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm.cpp @@ -20,18 +20,19 @@ namespace mc_proto_fuzzer { static bool NoAliases = false; + std::ostream &operator<<(std::ostream &OS, const Register &X) { switch (X.name()) { - case Register::X0: OS << "x0"; break; - case Register::X1: OS << "x1"; break; - case Register::X2: OS << "x2"; break; - case Register::X3: OS << "x3"; break; - case Register::X4: OS << "x4"; break; - case Register::X5: OS << "x5"; break; - case Register::X6: OS << "x6"; break; - case Register::X7: OS << "x7"; break; - case Register::X8: OS << "x8"; break; - case Register::X9: OS << "x9"; break; + case Register::X0: OS << "x0"; break; + case Register::X1: OS << "x1"; break; + case Register::X2: OS << "x2"; break; + case Register::X3: OS << "x3"; break; + case Register::X4: OS << "x4"; break; + case Register::X5: OS << "x5"; break; + case Register::X6: OS << "x6"; break; + case Register::X7: OS << "x7"; break; + case Register::X8: OS << "x8"; break; + case Register::X9: OS << "x9"; break; case Register::X10: OS << "x10"; break; case Register::X11: OS << "x11"; break; case Register::X12: OS << "x12"; break; @@ -57,27 +58,27 @@ } return OS; } -std::ostream &operator<<(std::ostream &OS, const ITypeOpcode &X) { +std::ostream &operator<<(std::ostream &OS, const RTypeOpcode &X) { switch (X.op()) { - case ITypeOpcode_Op_ADD: OS << "add"; break; - case ITypeOpcode_Op_SUB: OS << "sub"; break; + case RTypeOpcode_Op_ADD: OS << "add"; break; + case RTypeOpcode_Op_SUB: OS << "sub"; break; } return OS; } -std::ostream &operator<<(std::ostream &OS, const ITypeOperands &X) { +std::ostream &operator<<(std::ostream &OS, const RTypeOperands &X) { OS << X.operand1(); OS << "," << X.operand2(); OS << "," << X.operand3(); return OS; } -std::ostream &operator<<(std::ostream &OS, const ITypeStatement &X) { +std::ostream &operator<<(std::ostream &OS, const RTypeStatement &X) { OS << "\t" << X.opcode() << "\t"; OS << X.operands() << "\n"; return OS; } std::ostream &operator<<(std::ostream &OS, const AsmStatement &X) { if (X.has_statement()) { - ITypeOperands ThreeOperands = X.statement().operands(); + RTypeOperands ThreeOperands = X.statement().operands(); Register Oper1 = ThreeOperands.operand1(); Register Oper2 = ThreeOperands.operand2(); Register Oper3 = ThreeOperands.operand3(); @@ -85,12 +86,8 @@ OS << X.statement(); return OS; } - if (X.statement().opcode().op() == ITypeOpcode_Op_ADD) { - OS << X.statement(); - return OS; - } - else if (X.statement().opcode().op() == - ITypeOpcode_Op_SUB) { + if (X.statement().opcode().op() == + RTypeOpcode_Op_SUB) { if (Oper2.name() == Register_RegName_X0) { OS << "\tneg\t" << Oper1 << "," << Oper3 << "\n"; return OS; @@ -98,7 +95,8 @@ OS << X.statement(); return OS; } - } + } else + return OS << X.statement(); } return OS; } Index: tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm_rv32i.cpp =================================================================== --- /dev/null +++ tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm_rv32i.cpp @@ -0,0 +1,293 @@ +//==-- proto_to_asm_rv32i.cpp - Protobuf-ASM 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 for the assembly +// language grammar for RV32I instruction set and assembly language +// instructions. +// +//===----------------------------------------------------------------------===// +#include "proto_to_asm.h" +#include "rv32i_asm.pb.h" + +#include +#include + +namespace mc_proto_fuzzer { + +static bool NoAliases = false; + +std::ostream &operator<<(std::ostream &OS, const ITypeShiftImmediate &X) { + // Limit immediate range to [0,31]. + return OS << X.imm() % 32; +} +std::ostream &operator<<(std::ostream &OS, const ITypeImmediate &X) { + // Limit immediate range to [-2048, 2047]. + return OS << X.imm() % 2048; +} +std::ostream &operator<<(std::ostream &OS, const STypeImmediate &X) { + // Limit immediate range to [-2048, 2047]. + return OS << X.imm() % 2048; +} +std::ostream &operator<<(std::ostream &OS, const BTypeImmediate &X) { + // Limit immediate range to [-2048, 2046], in multiples of 2. + return OS << ((X.imm() % 2048) / 2) * 2; +} +std::ostream &operator<<(std::ostream &OS, const UTypeImmediate &X) { + // Limit immediate range to [0, 1048575]. + return OS << X.imm() % 1048576; +} +std::ostream &operator<<(std::ostream &OS, const JTypeImmediate &X) { + // Limit immediate range to [-1048576, 1048574], in multiples of 2. + return OS << (((X.imm() % 1048576) / 2) * 2); +} +std::ostream &operator<<(std::ostream &OS, const Register &X) { + switch (X.name()) { + case Register::X0: OS << "x0"; break; + case Register::X1: OS << "x1"; break; + case Register::X2: OS << "x2"; break; + case Register::X3: OS << "x3"; break; + case Register::X4: OS << "x4"; break; + case Register::X5: OS << "x5"; break; + case Register::X6: OS << "x6"; break; + case Register::X7: OS << "x7"; break; + case Register::X8: OS << "x8"; break; + case Register::X9: OS << "x9"; break; + case Register::X10: OS << "x10"; break; + case Register::X11: OS << "x11"; break; + case Register::X12: OS << "x12"; break; + case Register::X13: OS << "x13"; break; + case Register::X14: OS << "x14"; break; + case Register::X15: OS << "x15"; break; + case Register::X16: OS << "x16"; break; + case Register::X17: OS << "x17"; break; + case Register::X18: OS << "x18"; break; + case Register::X19: OS << "x19"; break; + case Register::X20: OS << "x20"; break; + case Register::X21: OS << "x21"; break; + case Register::X22: OS << "x22"; break; + case Register::X23: OS << "x23"; break; + case Register::X24: OS << "x24"; break; + case Register::X25: OS << "x25"; break; + case Register::X26: OS << "x26"; break; + case Register::X27: OS << "x27"; break; + case Register::X28: OS << "x28"; break; + case Register::X29: OS << "x29"; break; + case Register::X30: OS << "x30"; break; + case Register::X31: OS << "x31"; break; + } + return OS; +} +std::ostream &operator<<(std::ostream &OS, const RTypeOpcode &X) { + switch (X.op()) { + case RTypeOpcode_Op_ADD: OS << "add"; break; + case RTypeOpcode_Op_SUB: OS << "sub"; break; + case RTypeOpcode_Op_SLL: OS << "sll"; break; + case RTypeOpcode_Op_SLT: OS << "slt"; break; + case RTypeOpcode_Op_SLTU: OS << "sltu"; break; + case RTypeOpcode_Op_XOR: OS << "xor"; break; + case RTypeOpcode_Op_SRL: OS << "srl"; break; + case RTypeOpcode_Op_SRA: OS << "sra"; break; + case RTypeOpcode_Op_OR: OS << "or"; break; + case RTypeOpcode_Op_AND: OS << "and"; break; + } + return OS; +} +std::ostream &operator<<(std::ostream &OS, const RTypeOperands &X) { + OS << X.operand1(); + OS << "," << X.operand2(); + OS << "," << X.operand3(); + return OS; +} +std::ostream &operator<<(std::ostream &OS, const RTypeStatement &X) { + OS << "\t" << X.opcode() << "\t"; + OS << X.operands() << "\n"; + return OS; +} +std::ostream &operator<<(std::ostream &OS, const ITypeShiftOpcode &X) { + switch (X.op()) { + case ITypeShiftOpcode_Op_SRAI: OS << "srai"; break; + case ITypeShiftOpcode_Op_SRLI: OS << "srli"; break; + case ITypeShiftOpcode_Op_SLLI: OS << "slli"; break; + } + return OS; +} +std::ostream &operator<<(std::ostream &OS, const ITypeShiftOperands &X) { + OS << X.operand1(); + OS << "," << X.operand2(); + OS << "," << X.operand3(); + return OS; +} +std::ostream &operator<<(std::ostream &OS, const ITypeShiftStatement &X) { + OS << "\t" << X.opcode() << "\t"; + OS << X.operands() << "\n"; + return OS; +} +std::ostream &operator<<(std::ostream &OS, const ITypeOpcode &X) { + switch (X.op()) { + case ITypeOpcode_Op_ADDI: OS << "addi"; break; + case ITypeOpcode_Op_SLTI: OS << "slti"; break; + case ITypeOpcode_Op_ANDI: OS << "andi"; break; + case ITypeOpcode_Op_ORI: OS << "ori"; break; + case ITypeOpcode_Op_XORI: OS << "xori"; break; + case ITypeOpcode_Op_SLTIU: OS << "sltiu"; break; + case ITypeOpcode_Op_JALR: OS << "jalr"; break; + } + return OS; +} +std::ostream &operator<<(std::ostream &OS, const ITypeOperands &X) { + OS << X.operand1(); + OS << "," << X.operand2(); + OS << "," << X.operand3(); + return OS; +} +std::ostream &operator<<(std::ostream &OS, const ITypeStatement &X) { + OS << "\t" << X.opcode() << "\t"; + OS << X.operands() << "\n"; + return OS; +} +std::ostream &operator<<(std::ostream &OS, const STypeOpcode &X) { + switch (X.op()) { + case STypeOpcode_Op_SW: OS << "sw"; break; + case STypeOpcode_Op_SH: OS << "sh"; break; + case STypeOpcode_Op_SB: OS << "sb"; break; + } + return OS; +} +std::ostream &operator<<(std::ostream &OS, const STypeOperands &X) { + OS << X.operand1(); + OS << "," << X.operand2(); + OS << "(" << X.operand3() << ")"; + return OS; +} +std::ostream &operator<<(std::ostream &OS, const STypeStatement &X) { + OS << "\t" << X.opcode() << "\t"; + OS << X.operands() << "\n"; + return OS; +} +std::ostream &operator<<(std::ostream &OS, const BTypeOpcode &X) { + switch (X.op()) { + case BTypeOpcode_Op_BEQ: OS << "beq"; break; + case BTypeOpcode_Op_BNE: OS << "bne"; break; + case BTypeOpcode_Op_BGE: OS << "bge"; break; + case BTypeOpcode_Op_BLT: OS << "blt"; break; + case BTypeOpcode_Op_BGEU: OS << "bgeu"; break; + case BTypeOpcode_Op_BLTU: OS << "bltu"; break; + } + return OS; +} +std::ostream &operator<<(std::ostream &OS, const BTypeOperands &X) { + OS << X.operand1(); + OS << "," << X.operand2(); + OS << "," << X.operand3(); + return OS; +} +std::ostream &operator<<(std::ostream &OS, const BTypeStatement &X) { + OS << "\t" << X.opcode() << "\t"; + OS << X.operands() << "\n"; + return OS; +} +std::ostream &operator<<(std::ostream &OS, const UTypeOpcode &X) { + switch (X.op()) { + case UTypeOpcode_Op_LUI: OS << "lui"; break; + case UTypeOpcode_Op_AUIPC: OS << "auipc"; break; + } + return OS; +} +std::ostream &operator<<(std::ostream &OS, const UTypeOperands &X) { + OS << X.operand1(); + OS << "," << X.operand2(); + return OS; +} +std::ostream &operator<<(std::ostream &OS, const UTypeStatement &X) { + OS << "\t" << X.opcode() << "\t"; + OS << X.operands() << "\n"; + return OS; +} +std::ostream &operator<<(std::ostream &OS, const JTypeOpcode &X) { + switch (X.op()) { + case JTypeOpcode_Op_JAL: OS << "jal"; break; + } + return OS; +} +std::ostream &operator<<(std::ostream &OS, const JTypeOperands &X) { + OS << X.operand1(); + OS << "," << X.operand2(); + return OS; +} +std::ostream &operator<<(std::ostream &OS, const JTypeStatement &X) { + OS << "\t" << X.opcode() << "\t"; + OS << X.operands() << "\n"; + return OS; +} +std::ostream &operator<<(std::ostream &OS, const AsmStatement &X) { + if (X.has_statement1()) { + RTypeOperands ThreeOperands = X.statement1().operands(); + Register Oper1 = ThreeOperands.operand1(); + Register Oper2 = ThreeOperands.operand2(); + Register Oper3 = ThreeOperands.operand3(); + if (NoAliases) { + OS << X.statement1(); + return OS; + } + if (X.statement1().opcode().op() == RTypeOpcode_Op_ADD) { + OS << X.statement1(); + return OS; + } + else if (X.statement1().opcode().op() == + RTypeOpcode_Op_SUB) { + if (Oper2.name() == Register_RegName_X0) { + OS << "\tneg\t" << Oper1 << "," << Oper3 << "\n"; + return OS; + } else { + OS << X.statement1(); + return OS; + } + } else { + return OS << X.statement1(); + } + } else if (X.has_statement2()) { + OS << X.statement2(); + } else if (X.has_statement3()) { + OS << X.statement3(); + } else if (X.has_statement4()) { + OS << X.statement4(); + } else if (X.has_statement5()) { + OS << X.statement5(); + } else if (X.has_statement6()) { + OS << X.statement6(); + } else if (X.has_statement7()) { + OS << X.statement7(); + } + + return OS; +} +std::ostream &operator<<(std::ostream &OS, const AsmStatementSeq &X) { + for (auto &ST : X.statements()) OS << ST; + return OS; +} +std::ostream &operator<<(std::ostream &OS, const Assembly &X) { + return OS << X.asmstatements(); +} + +// --------------------------------- + +std::string FunctionToString(const Assembly &Input) { + std::ostringstream OS; + OS << Input; + return OS.str(); +} +std::string ProtoToASM(const uint8_t *Data, size_t Size, bool Flag) { + Assembly Message; + NoAliases = Flag; + if (!Message.ParsePartialFromArray(Data, Size)) + return "#error invalid proto\n"; + return FunctionToString(Message); +} + +} // namespace mc_proto_fuzzer