Skip to content

Commit

Permalink
lifter: update tool commandline options and add flags for debug logs
Browse files Browse the repository at this point in the history
  • Loading branch information
kumarak committed Jan 30, 2025
1 parent 65b742b commit 05756da
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 57 deletions.
4 changes: 2 additions & 2 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ CheckOptions:
- key: 'readability-identifier-naming.EnumConstantCase'
value: 'UPPER_CASE'
- key: 'readability-identifier-naming.FunctionCase'
value: 'lower_case'
value: 'camelBack'
- key: 'readability-identifier-naming.GlobalConstantCase'
value: 'lower_case'
- key: 'readability-identifier-naming.GlobalConstantPointerCase'
value: 'lower_case'
- key: 'readability-identifier-naming.GlobalFunctionCase'
value: 'lower_case'
value: 'camelBack'
- key: 'readability-identifier-naming.GlobalPointerCase'
value: 'lower_case'
- key: 'readability-identifier-naming.GlobalVariableCase'
Expand Down
12 changes: 9 additions & 3 deletions include/patchestry/AST/ASTConsumer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <patchestry/AST/TypeBuilder.hpp>
#include <patchestry/Ghidra/JsonDeserialize.hpp>
#include <patchestry/Ghidra/PcodeOperations.hpp>
#include <patchestry/Util/Options.hpp>

namespace patchestry::ast {
using namespace patchestry::ghidra;
Expand All @@ -38,16 +39,20 @@ namespace patchestry::ast {
{
public:
explicit PcodeASTConsumer(
clang::CompilerInstance &ci, Program &prog, std::string &outfile
clang::CompilerInstance &ci, Program &prog, patchestry::Options &opts
)
: program(prog)
, ci(ci)
, outfile(outfile)
, options(opts)
, codegen(std::make_unique< CodeGenerator >(ci))
, type_builder(std::make_unique< TypeBuilder >(ci.getASTContext())) {}

void HandleTranslationUnit(clang::ASTContext &ctx) override;

const std::unordered_map< void *, std::string > &locations(void) const {
return location_map;
}

private:
void set_sema_context(clang::DeclContext *dc);

Expand All @@ -66,7 +71,8 @@ namespace patchestry::ast {
std::reference_wrapper< Program > program;
std::reference_wrapper< clang::CompilerInstance > ci;

std::string outfile;
const patchestry::Options &options;

std::unique_ptr< CodeGenerator > codegen;
std::unique_ptr< TypeBuilder > type_builder;

Expand Down
38 changes: 38 additions & 0 deletions include/patchestry/Util/Options.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2024, Trail of Bits, Inc.
*
* This source code is licensed in accordance with the terms specified in
* the LICENSE file found in the root directory of this source tree.
*/

#pragma once

#include <string>
#include <vector>

namespace patchestry {

enum class EmitMLIRType : int {
hl, // Vast High-level dialects
cir, // Clang IR dialects
};

struct Options
{
bool emit_mlir = false;
bool emit_tower = false;
bool emit_llvm = false;
bool emit_asm = false;
bool emit_obj = false;
bool verbose = false;

std::string output_file;
std::string input_file;

bool print_tu = false;

std::vector< std::string > pipelines = {};
EmitMLIRType mlir_type = EmitMLIRType::hl;
};

} // namespace patchestry
27 changes: 15 additions & 12 deletions lib/patchestry/AST/ASTConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <patchestry/Ghidra/JsonDeserialize.hpp>
#include <patchestry/Ghidra/Pcode.hpp>
#include <patchestry/Ghidra/PcodeOperations.hpp>
#include <patchestry/Util/Log.hpp>

namespace patchestry::ast {

Expand All @@ -51,19 +52,21 @@ namespace patchestry::ast {
);
}

std::error_code ec;
auto out =
std::make_unique< llvm::raw_fd_ostream >(outfile, ec, llvm::sys::fs::OF_Text);

llvm::errs() << "Print AST dump\n";
ctx.getTranslationUnitDecl()->dumpColor();

ctx.getTranslationUnitDecl()->print(
*llvm::dyn_cast< llvm::raw_ostream >(out), ctx.getPrintingPolicy(), 0
);
if (options.print_tu) {
#ifdef ENABLE_DEBUG
ctx.getTranslationUnitDecl()->dumpColor();
#endif
std::error_code ec;
auto out = std::make_unique< llvm::raw_fd_ostream >(
options.output_file + ".c", ec, llvm::sys::fs::OF_Text
);
ctx.getTranslationUnitDecl()->print(
*llvm::dyn_cast< llvm::raw_ostream >(out), ctx.getPrintingPolicy(), 0
);
}

llvm::errs() << "Generate mlir\n";
llvm::raw_fd_ostream file_os(outfile + ".mlir", ec);
std::error_code ec;
llvm::raw_fd_ostream file_os(options.output_file + ".mlir", ec);
codegen->generate_source_ir(ctx, location_map, file_os);
}

Expand Down
5 changes: 2 additions & 3 deletions test/pcode-lifter/adc_init.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// RUN: bash %strip-json-comments %s > %t.json
// RUN: %pcode-lifter %t.json -output %t
// RUN: %file-check --input-file %t --check-prefix=EXISTS < /dev/null
// CHECK-EMPTY:
// RUN: %pcode-lifter -input %t.json -output %t
// RUN: test -e %t
{
"arch": "ARM",
"format": "Executable and Linking Format (ELF)",
Expand Down
5 changes: 2 additions & 3 deletions test/pcode-lifter/adc_read.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// RUN: bash %strip-json-comments %s > %t.json
// RUN: %pcode-lifter %t.json -output %t
// RUN: %file-check --input-file %t --check-prefix=EXISTS < /dev/null
// CHECK-EMPTY:
// RUN: %pcode-lifter -input %t.json -output %t
// RUN: test -e %t
{
"arch": "ARM",
"format": "Executable and Linking Format (ELF)",
Expand Down
149 changes: 115 additions & 34 deletions tools/pcode-lifter/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
*/

#include <cstdlib>
#include <fstream>
#include <memory>
#include <ranges>
#include <string_view>

#include <clang/AST/ASTConsumer.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/Stmt.h>
#include <clang/Basic/DiagnosticOptions.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/Basic/TargetOptions.h>
Expand All @@ -27,36 +31,125 @@
#include <patchestry/AST/ASTConsumer.hpp>
#include <patchestry/Ghidra/JsonDeserialize.hpp>
#include <patchestry/Util/Log.hpp>
#include <patchestry/Util/Options.hpp>

const llvm::cl::opt< std::string > input_filename(
llvm::cl::Positional, llvm::cl::desc("<input JSON file>"), llvm::cl::Required
);
namespace {

const llvm::cl::opt< bool >
verbose("v", llvm::cl::desc("Enable debug logs"), llvm::cl::init(false));
const llvm::cl::opt< patchestry::EmitMLIRType > emit_mlir( // NOLINT(cert-err58-cpp)
"emit-mlir", llvm::cl::desc("MLIR Emission Type"),
llvm::cl::values(
clEnumVal(patchestry::EmitMLIRType::hl, "High-Level VAST MLIR Representation"),
clEnumVal(patchestry::EmitMLIRType::cir, "ClangIR representation")
),
llvm::cl::init(patchestry::EmitMLIRType::hl)
);

const llvm::cl::opt< bool > pprint(
"pretty-print", llvm::cl::desc("Pretty print translation unit"), llvm::cl::init(false)
);
// NOTE: Option field is there to test vast tower api. Will be removed in future.
const llvm::cl::opt< bool > emit_tower( // NOLINT(cert-err58-cpp)
"emit-tower", llvm::cl::desc("Emit MLIR tower representation"), llvm::cl::init(false)
);

const llvm::cl::opt< std::string > output_filename(
"output", llvm::cl::desc("Specify output filename"), llvm::cl::value_desc("filename"),
llvm::cl::init("/tmp/output.c")
);
const llvm::cl::opt< bool > emit_llvm( // NOLINT(cert-err58-cpp)
"emit-llvm", llvm::cl::desc("Emit LLVM IR Representation"), llvm::cl::init(false)
);

bool debug_mode = false;
const llvm::cl::opt< bool > emit_asm( // NOLINT(cert-err58-cpp)
"emit-asm", llvm::cl::desc("Emit ASM Representation"), llvm::cl::init(false)
);

int main(int argc, char **argv) {
llvm::cl::ParseCommandLineOptions(
argc, argv, "pcode-lifter to lift high pcode into clang ast\n"
const llvm::cl::opt< bool > emit_obj( // NOLINT(cert-err58-cpp)
"emit-obj", llvm::cl::desc("Emit Object file"), llvm::cl::init(false)
);

const llvm::cl::opt< std::string > input_filename( // NOLINT(cert-err58-cpp)
"input", llvm::cl::desc("Input JSON file"), llvm::cl::Required
);

const llvm::cl::opt< std::string > output_filename( // NOLINT(cert-err58-cpp)
"output", llvm::cl::desc("Specify output filename"), llvm::cl::value_desc("filename"),
llvm::cl::init("") // Initialize with empty string
);

const llvm::cl::opt< bool > verbose( // NOLINT(cert-err58-cpp)
"verbose", llvm::cl::desc("Enable debug logs"), llvm::cl::init(false)
); // NOLINT(cert-err58-cpp)

const llvm::cl::opt< bool > print_tu( // NOLINT(cert-err58-cpp)
"print-tu", llvm::cl::desc("Pretty print translation unit"), llvm::cl::init(false)
);

if (verbose) {
debug_mode = true;
const llvm::cl::opt< std::string > pipelines( // NOLINT(cert-err58-cpp)
"pipelines", llvm::cl::desc("Specify pipelines for lowering steps"),
llvm::cl::value_desc("string"), llvm::cl::init("")
);

patchestry::Options parseCommandLineOptions(int argc, char **argv) {
llvm::cl::ParseCommandLineOptions(
argc, argv, "patche-lifter to represent high pcode into mlir representations\n"
);

auto split_pipelines = [&](std::string_view pipelines,
char delim = ',') -> std::vector< std::string > {
std::vector< std::string > vec;
size_t start = 0;
size_t end = 0;
while ((end = pipelines.find(delim, start)) != std::string_view::npos) {
vec.emplace_back(pipelines.substr(start, end - start));
start = end + 1;
}
vec.emplace_back(pipelines.substr(start)); // Last part
return vec;
};

auto pipeline_stages = split_pipelines(pipelines.getValue());
return {
.emit_mlir = true, // It is set to true by default
.emit_llvm = emit_llvm.getValue(),
.emit_asm = emit_asm.getValue(),
.emit_obj = emit_obj.getValue(),
.verbose = verbose.getValue(),
.output_file = output_filename.getValue(),
.input_file = input_filename.getValue(),
.print_tu = print_tu.getValue(),
.pipelines = std::move(pipeline_stages),
};
}

void createSourceManager(clang::CompilerInstance &ci) {
// Create file manager and setup source manager
ci.createFileManager();
ci.createSourceManager(ci.getFileManager());

// get source manager and setup main_file_id for the source manager
auto &sm = ci.getSourceManager();

// Create fake file to support real file system needed for vast
// location translation
std::string data = "/patchestry";
std::string file_name = "/tmp/patchestry";
std::ofstream(file_name) << data;
llvm::ErrorOr< clang::FileEntryRef > file_entry_ref_or_err =
ci.getFileManager().getVirtualFileRef(file_name, data.size(), 0);
clang::FileID file_id = sm.createFileID(
*file_entry_ref_or_err, clang::SourceLocation(), clang::SrcMgr::C_User, 0
);
sm.setMainFileID(file_id);
}

void setCodegenOptions(clang::CompilerInstance &ci) {
clang::CodeGenOptions &cg_opts = ci.getCodeGenOpts();
cg_opts.OptimizationLevel = 0;
cg_opts.StrictReturn = false;
cg_opts.StrictEnums = false;
}

} // namespace

int main(int argc, char **argv) {
auto options = parseCommandLineOptions(argc, argv);

llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > file_or_err =
llvm::MemoryBuffer::getFile(input_filename);
llvm::MemoryBuffer::getFile(options.input_file);

if (std::error_code error_code = file_or_err.getError()) {
LOG(ERROR) << "Error reading json file : " << error_code.message() << "\n";
Expand Down Expand Up @@ -94,29 +187,17 @@ int main(int argc, char **argv) {

ci.getFrontendOpts().ProgramAction = clang::frontend::ParseSyntaxOnly;
ci.getLangOpts().C99 = true;
// Setup file manager and source manager
ci.createFileManager();
ci.createSourceManager(ci.getFileManager());

auto &sm = ci.getSourceManager();
std::string file_data = "/patchestry";
llvm::ErrorOr< clang::FileEntryRef > file_entry_ref_or_err =
ci.getFileManager().getVirtualFileRef("/tmp/patchestry", file_data.size(), 0);
clang::FileID file_id = sm.createFileID(
*file_entry_ref_or_err, clang::SourceLocation(), clang::SrcMgr::C_User, 0
);

sm.setMainFileID(file_id);
createSourceManager(ci);
setCodegenOptions(ci);

// Create the preprocessor and AST context
ci.createPreprocessor(clang::TU_Complete);
ci.createASTContext();

auto &ast_context = ci.getASTContext();

std::string outfile = output_filename.getValue();
std::unique_ptr< patchestry::ast::PcodeASTConsumer > consumer =
std::make_unique< patchestry::ast::PcodeASTConsumer >(ci, program.value(), outfile);
std::make_unique< patchestry::ast::PcodeASTConsumer >(ci, program.value(), options);
ci.setASTConsumer(std::move(consumer));
ci.createSema(clang::TU_Complete, nullptr);

Expand Down

0 comments on commit 05756da

Please sign in to comment.