From 9caed2761b799debeb15039a29e5f5b4d22db708 Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Thu, 22 Dec 2022 15:04:02 +0100 Subject: [PATCH 01/11] Interface for choosing local variable types --- include/rellic/AST/TypeProvider.h | 6 ++++++ lib/AST/IRToASTVisitor.cpp | 2 +- lib/AST/TypeProvider.cpp | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/rellic/AST/TypeProvider.h b/include/rellic/AST/TypeProvider.h index e3137d44..6a7e3369 100644 --- a/include/rellic/AST/TypeProvider.h +++ b/include/rellic/AST/TypeProvider.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "rellic/AST/ASTBuilder.h" @@ -35,6 +36,10 @@ class TypeProvider { // Returns the type of a global variable if available. // A null return value is assumed to mean that no info is available. virtual clang::QualType GetGlobalVarType(llvm::GlobalVariable& gvar); + + // Returns the type of an alloca variable if available. + // A null return value is assumed to mean that no info is available. + virtual clang::QualType GetAllocaType(llvm::AllocaInst& alloca); }; class TypeProviderCombiner : public TypeProvider { @@ -54,5 +59,6 @@ class TypeProviderCombiner : public TypeProvider { clang::QualType GetFunctionReturnType(llvm::Function& func) override; clang::QualType GetArgumentType(llvm::Argument& arg) override; clang::QualType GetGlobalVarType(llvm::GlobalVariable& gvar) override; + clang::QualType GetAllocaType(llvm::AllocaInst& alloca) override; }; } // namespace rellic \ No newline at end of file diff --git a/lib/AST/IRToASTVisitor.cpp b/lib/AST/IRToASTVisitor.cpp index 5fb781ff..a08f55c4 100755 --- a/lib/AST/IRToASTVisitor.cpp +++ b/lib/AST/IRToASTVisitor.cpp @@ -1182,7 +1182,7 @@ void IRToASTVisitor::VisitFunctionDecl(llvm::Function &func) { // storage for parameters e.g. a parameter named "foo" has a corresponding // local variable named "foo_addr"). var = ast.CreateVarDecl( - fdecl, dec_ctx.GetQualType(alloca->getAllocatedType()), name); + fdecl, dec_ctx.type_provider->GetAllocaType(*alloca), name); fdecl->addDecl(var); } else if (inst.hasNUsesOrMore(2) || (inst.hasNUsesOrMore(1) && llvm::isa(inst)) || diff --git a/lib/AST/TypeProvider.cpp b/lib/AST/TypeProvider.cpp index 7b64b543..8ea1c1ba 100644 --- a/lib/AST/TypeProvider.cpp +++ b/lib/AST/TypeProvider.cpp @@ -24,6 +24,8 @@ clang::QualType TypeProvider::GetGlobalVarType(llvm::GlobalVariable&) { return {}; } +clang::QualType TypeProvider::GetAllocaType(llvm::AllocaInst&) { return {}; } + // Defers to DecompilationContext::GetQualType class FallbackTypeProvider : public TypeProvider { public: @@ -31,6 +33,7 @@ class FallbackTypeProvider : public TypeProvider { clang::QualType GetFunctionReturnType(llvm::Function& func) override; clang::QualType GetArgumentType(llvm::Argument& arg) override; clang::QualType GetGlobalVarType(llvm::GlobalVariable& gvar) override; + clang::QualType GetAllocaType(llvm::AllocaInst& alloca) override; }; FallbackTypeProvider::FallbackTypeProvider(DecompilationContext& dec_ctx) @@ -50,6 +53,10 @@ clang::QualType FallbackTypeProvider::GetGlobalVarType( return dec_ctx.GetQualType(gvar.getValueType()); } +clang::QualType FallbackTypeProvider::GetAllocaType(llvm::AllocaInst& alloca) { + return dec_ctx.GetQualType(alloca.getAllocatedType()); +} + // Fixes function arguments that have a byval attribute class ByValFixupTypeProvider : public TypeProvider { public: @@ -167,4 +174,15 @@ clang::QualType TypeProviderCombiner::GetGlobalVarType( } return {}; } + +clang::QualType TypeProviderCombiner::GetAllocaType(llvm::AllocaInst& alloca) { + for (auto it{providers.rbegin()}; it != providers.rend(); ++it) { + auto& provider{*it}; + auto res{provider->GetAllocaType(alloca)}; + if (!res.isNull()) { + return res; + } + } + return {}; +} } // namespace rellic \ No newline at end of file From 744b60247d1350bdcec0bfbf28e08ec7c1ca4a0a Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Thu, 22 Dec 2022 17:13:03 +0100 Subject: [PATCH 02/11] Allow users to make arguments appear as locals --- include/rellic/AST/DecompilationContext.h | 2 + include/rellic/AST/TypeProvider.h | 10 ++--- include/rellic/AST/VariableProvider.h | 48 +++++++++++++++++++++++ include/rellic/Decompiler.h | 20 +++++++++- lib/AST/IRToASTVisitor.cpp | 22 ++++++++--- lib/AST/Util.cpp | 4 +- lib/AST/VariableProvider.cpp | 43 ++++++++++++++++++++ lib/CMakeLists.txt | 1 + lib/Decompiler.cpp | 6 ++- 9 files changed, 142 insertions(+), 14 deletions(-) create mode 100644 include/rellic/AST/VariableProvider.h create mode 100644 lib/AST/VariableProvider.cpp diff --git a/include/rellic/AST/DecompilationContext.h b/include/rellic/AST/DecompilationContext.h index b9ba9417..700c2b8a 100644 --- a/include/rellic/AST/DecompilationContext.h +++ b/include/rellic/AST/DecompilationContext.h @@ -18,6 +18,7 @@ #include "rellic/AST/ASTBuilder.h" #include "rellic/AST/TypeProvider.h" +#include "rellic/AST/VariableProvider.h" namespace rellic { @@ -43,6 +44,7 @@ struct DecompilationContext { ASTBuilder ast; std::unique_ptr type_provider; + std::unique_ptr var_provider; StmtToIRMap stmt_provenance; ExprToUseMap use_provenance; diff --git a/include/rellic/AST/TypeProvider.h b/include/rellic/AST/TypeProvider.h index 6a7e3369..46df4b1a 100644 --- a/include/rellic/AST/TypeProvider.h +++ b/include/rellic/AST/TypeProvider.h @@ -42,7 +42,7 @@ class TypeProvider { virtual clang::QualType GetAllocaType(llvm::AllocaInst& alloca); }; -class TypeProviderCombiner : public TypeProvider { +class TypeProviderCombiner final : public TypeProvider { private: std::vector> providers; @@ -56,9 +56,9 @@ class TypeProviderCombiner : public TypeProvider { void AddProvider(std::unique_ptr provider); - clang::QualType GetFunctionReturnType(llvm::Function& func) override; - clang::QualType GetArgumentType(llvm::Argument& arg) override; - clang::QualType GetGlobalVarType(llvm::GlobalVariable& gvar) override; - clang::QualType GetAllocaType(llvm::AllocaInst& alloca) override; + clang::QualType GetFunctionReturnType(llvm::Function& func) final; + clang::QualType GetArgumentType(llvm::Argument& arg) final; + clang::QualType GetGlobalVarType(llvm::GlobalVariable& gvar) final; + clang::QualType GetAllocaType(llvm::AllocaInst& alloca) final; }; } // namespace rellic \ No newline at end of file diff --git a/include/rellic/AST/VariableProvider.h b/include/rellic/AST/VariableProvider.h new file mode 100644 index 00000000..799806ad --- /dev/null +++ b/include/rellic/AST/VariableProvider.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022-present, Trail of Bits, Inc. + * All rights reserved. + * + * 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 +#include +#include +#include +#include + +#include "rellic/AST/ASTBuilder.h" + +namespace rellic { +struct DecompilationContext; + +class VariableProvider { + protected: + DecompilationContext& dec_ctx; + + public: + VariableProvider(DecompilationContext& dec_ctx); + virtual ~VariableProvider(); + + virtual clang::QualType ArgumentAsLocal(llvm::Argument& arg); +}; + +class VariableProviderCombiner final : public VariableProvider { + private: + std::vector> providers; + + public: + VariableProviderCombiner(DecompilationContext& dec_ctx); + template + void AddProvider(TArgs&&... args) { + providers.push_back( + std::make_unique(dec_ctx, std::forward(args)...)); + } + + void AddProvider(std::unique_ptr provider); + + clang::QualType ArgumentAsLocal(llvm::Argument& arg) final; +}; +} // namespace rellic \ No newline at end of file diff --git a/include/rellic/Decompiler.h b/include/rellic/Decompiler.h index bfee1e43..7e8be271 100644 --- a/include/rellic/Decompiler.h +++ b/include/rellic/Decompiler.h @@ -17,6 +17,7 @@ #include "Result.h" #include "rellic/AST/TypeProvider.h" +#include "rellic/AST/VariableProvider.h" namespace rellic { @@ -37,15 +38,32 @@ class SimpleTypeProviderFactory final : public TypeProviderFactory { } }; +class VariableProviderFactory { + public: + virtual ~VariableProviderFactory() = default; + virtual std::unique_ptr create( + DecompilationContext& ctx) = 0; +}; + +template +class SimpleVariableProviderFactory final : public VariableProviderFactory { + public: + std::unique_ptr create(DecompilationContext& ctx) override { + return std::make_unique(ctx); + } +}; + struct DecompilationOptions { using TypeProviderFactoryPtr = std::unique_ptr; + using VariableProviderFactoryPtr = std::unique_ptr; bool lower_switches = false; bool remove_phi_nodes = false; // Additional type providers to be used during code generation. // Providers added later will have higher priority. - std::vector additional_providers; + std::vector additional_type_providers; + std::vector additional_variable_providers; }; struct DecompilationResult { diff --git a/lib/AST/IRToASTVisitor.cpp b/lib/AST/IRToASTVisitor.cpp index a08f55c4..1eec6a01 100755 --- a/lib/AST/IRToASTVisitor.cpp +++ b/lib/AST/IRToASTVisitor.cpp @@ -1094,9 +1094,15 @@ void IRToASTVisitor::VisitArgument(llvm::Argument &arg) { // Get parent function declaration auto func{arg.getParent()}; auto fdecl{clang::cast(dec_ctx.value_decls[func])}; - auto argtype{dec_ctx.type_provider->GetArgumentType(arg)}; - // Create a declaration - parm = ast.CreateParamDecl(fdecl, argtype, name); + auto argtype = dec_ctx.var_provider->ArgumentAsLocal(arg); + // Does the user want to treat this argument as a local variable? + if (!argtype.isNull()) { + parm = ast.CreateVarDecl(fdecl, argtype, name); + } else { + argtype = dec_ctx.type_provider->GetArgumentType(arg); + // Create a declaration + parm = ast.CreateParamDecl(fdecl, argtype, name); + } } void IRToASTVisitor::VisitBasicBlock(llvm::BasicBlock &block, @@ -1148,15 +1154,19 @@ void IRToASTVisitor::VisitFunctionDecl(llvm::Function &func) { decl = ast.CreateFunctionDecl(tudecl, ftype, name); tudecl->addDecl(decl); + auto fdecl{decl->getAsFunction()}; std::vector params; for (auto &arg : func.args()) { VisitArgument(arg); - params.push_back( - clang::cast(dec_ctx.value_decls[&arg])); + auto &decl{dec_ctx.value_decls[&arg]}; + if (auto param = clang::dyn_cast(decl)) { + params.push_back(param); + } else { + fdecl->addDecl(decl); + } } - auto fdecl{decl->getAsFunction()}; fdecl->setParams(params); for (auto &inst : llvm::instructions(func)) { diff --git a/lib/AST/Util.cpp b/lib/AST/Util.cpp index e6c1da99..e38eac6f 100644 --- a/lib/AST/Util.cpp +++ b/lib/AST/Util.cpp @@ -20,6 +20,7 @@ #include "rellic/AST/ASTBuilder.h" #include "rellic/AST/TypeProvider.h" +#include "rellic/AST/VariableProvider.h" #include "rellic/BC/Util.h" #include "rellic/Exception.h" @@ -394,7 +395,8 @@ DecompilationContext::DecompilationContext(clang::ASTUnit &ast_unit) ast_ctx(ast_unit.getASTContext()), ast(ast_unit), marker_expr(ast.CreateAdd(ast.CreateFalse(), ast.CreateFalse())), - type_provider(std::make_unique(*this)) {} + type_provider(std::make_unique(*this)), + var_provider(std::make_unique(*this)) {} unsigned DecompilationContext::InsertZExpr(const z3::expr &e) { auto idx{z3_exprs.size()}; diff --git a/lib/AST/VariableProvider.cpp b/lib/AST/VariableProvider.cpp new file mode 100644 index 00000000..10abcba0 --- /dev/null +++ b/lib/AST/VariableProvider.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-present, Trail of Bits, Inc. + * All rights reserved. + * + * This source code is licensed in accordance with the terms specified in + * the LICENSE file found in the root directory of this source tree. + */ + +#include "rellic/AST/VariableProvider.h" + +#include + +#include "rellic/AST/Util.h" + +namespace rellic { +VariableProvider::VariableProvider(DecompilationContext& dec_ctx) + : dec_ctx(dec_ctx) {} +VariableProvider::~VariableProvider() = default; + +clang::QualType VariableProvider::ArgumentAsLocal(llvm::Argument&) { + return {}; +} + +VariableProviderCombiner::VariableProviderCombiner( + DecompilationContext& dec_ctx) + : VariableProvider(dec_ctx) {} + +void VariableProviderCombiner::AddProvider( + std::unique_ptr provider) { + providers.push_back(std::move(provider)); +} + +clang::QualType VariableProviderCombiner::ArgumentAsLocal(llvm::Argument& arg) { + for (auto it{providers.rbegin()}; it != providers.rend(); ++it) { + auto& provider{*it}; + auto res{provider->ArgumentAsLocal(arg)}; + if (!res.isNull()) { + return res; + } + } + return {}; +} +} // namespace rellic \ No newline at end of file diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index b8bf2089..999b8045 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -82,6 +82,7 @@ set(AST_SOURCES AST/StructGenerator.cpp AST/SubprogramGenerator.cpp AST/TypeProvider.cpp + AST/VariableProvider.cpp ) set(BC_SOURCES diff --git a/lib/Decompiler.cpp b/lib/Decompiler.cpp index 7bcbe5dd..492d4bc2 100644 --- a/lib/Decompiler.cpp +++ b/lib/Decompiler.cpp @@ -90,10 +90,14 @@ Result Decompile( auto ast_unit{clang::tooling::buildASTFromCodeWithArgs("", args, "out.c")}; rellic::DecompilationContext dec_ctx(*ast_unit); - for (auto& provider : options.additional_providers) { + for (auto& provider : options.additional_type_providers) { dec_ctx.type_provider->AddProvider(provider->create(dec_ctx)); } + for (auto& provider : options.additional_variable_providers) { + dec_ctx.var_provider->AddProvider(provider->create(dec_ctx)); + } + rellic::GenerateAST::run(*module, dec_ctx); // TODO(surovic): Add llvm::Value* -> clang::Decl* map // Especially for llvm::Argument* and llvm::Function*. From cb34c4c6c12c5ba1f0fde79db18cfdc758ca7ddf Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Mon, 2 Jan 2023 15:15:36 +0100 Subject: [PATCH 03/11] Fix number of arguments in generated functions --- lib/AST/IRToASTVisitor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/AST/IRToASTVisitor.cpp b/lib/AST/IRToASTVisitor.cpp index 1eec6a01..38d5caef 100755 --- a/lib/AST/IRToASTVisitor.cpp +++ b/lib/AST/IRToASTVisitor.cpp @@ -1145,7 +1145,9 @@ void IRToASTVisitor::VisitFunctionDecl(llvm::Function &func) { std::vector arg_types; for (auto &arg : func.args()) { - arg_types.push_back(dec_ctx.type_provider->GetArgumentType(arg)); + if (dec_ctx.var_provider->ArgumentAsLocal(arg).isNull()) { + arg_types.push_back(dec_ctx.type_provider->GetArgumentType(arg)); + } } auto ret_type{dec_ctx.type_provider->GetFunctionReturnType(func)}; clang::FunctionProtoType::ExtProtoInfo epi; From 97ca11bf9dd26053e910a8ed295f8b91a4b94551 Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Mon, 23 Jan 2023 15:59:34 +0100 Subject: [PATCH 04/11] Refactor interface --- include/rellic/AST/DecompilationContext.h | 4 +- include/rellic/AST/FunctionLayoutOverride.h | 60 ++++++++++++++ include/rellic/AST/VariableProvider.h | 48 ----------- include/rellic/Decompiler.h | 19 +++-- lib/AST/FunctionLayoutOverride.cpp | 90 +++++++++++++++++++++ lib/AST/IRToASTVisitor.cpp | 49 +++++------ lib/AST/Util.cpp | 5 +- lib/AST/VariableProvider.cpp | 43 ---------- lib/CMakeLists.txt | 2 +- lib/Decompiler.cpp | 2 +- 10 files changed, 194 insertions(+), 128 deletions(-) create mode 100644 include/rellic/AST/FunctionLayoutOverride.h delete mode 100644 include/rellic/AST/VariableProvider.h create mode 100644 lib/AST/FunctionLayoutOverride.cpp delete mode 100644 lib/AST/VariableProvider.cpp diff --git a/include/rellic/AST/DecompilationContext.h b/include/rellic/AST/DecompilationContext.h index 700c2b8a..6af1c5f3 100644 --- a/include/rellic/AST/DecompilationContext.h +++ b/include/rellic/AST/DecompilationContext.h @@ -17,8 +17,8 @@ #include #include "rellic/AST/ASTBuilder.h" +#include "rellic/AST/FunctionLayoutOverride.h" #include "rellic/AST/TypeProvider.h" -#include "rellic/AST/VariableProvider.h" namespace rellic { @@ -44,7 +44,7 @@ struct DecompilationContext { ASTBuilder ast; std::unique_ptr type_provider; - std::unique_ptr var_provider; + std::unique_ptr function_layout_override; StmtToIRMap stmt_provenance; ExprToUseMap use_provenance; diff --git a/include/rellic/AST/FunctionLayoutOverride.h b/include/rellic/AST/FunctionLayoutOverride.h new file mode 100644 index 00000000..f1d6310a --- /dev/null +++ b/include/rellic/AST/FunctionLayoutOverride.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022-present, Trail of Bits, Inc. + * All rights reserved. + * + * 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 +#include +#include +#include +#include +#include + +namespace rellic { +struct DecompilationContext; + +class FunctionLayoutOverride { + protected: + DecompilationContext& dec_ctx; + + public: + FunctionLayoutOverride(DecompilationContext& dec_ctx); + virtual ~FunctionLayoutOverride(); + + virtual bool HasOverride(llvm::Function& func); + + virtual std::vector GetArguments(llvm::Function& func); + virtual void BeginFunctionVisit(llvm::Function& func, + clang::FunctionDecl* fdecl); + virtual bool VisitInstruction(llvm::Instruction& insn, + clang::FunctionDecl* fdecl, + clang::ValueDecl*& vdecl); +}; + +class FunctionLayoutOverrideCombiner final : public FunctionLayoutOverride { + private: + std::vector> overrides; + + public: + FunctionLayoutOverrideCombiner(DecompilationContext& dec_ctx); + template + void AddOverride(TArgs&&... args) { + overrides.push_back( + std::make_unique(dec_ctx, std::forward(args)...)); + } + + void AddOverride(std::unique_ptr provider); + + bool HasOverride(llvm::Function& func) final; + + std::vector GetArguments(llvm::Function& func) final; + void BeginFunctionVisit(llvm::Function& func, + clang::FunctionDecl* fdecl) final; + bool VisitInstruction(llvm::Instruction& insn, clang::FunctionDecl* fdecl, + clang::ValueDecl*& vdecl) final; +}; +} // namespace rellic \ No newline at end of file diff --git a/include/rellic/AST/VariableProvider.h b/include/rellic/AST/VariableProvider.h deleted file mode 100644 index 799806ad..00000000 --- a/include/rellic/AST/VariableProvider.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022-present, Trail of Bits, Inc. - * All rights reserved. - * - * 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 -#include -#include -#include -#include - -#include "rellic/AST/ASTBuilder.h" - -namespace rellic { -struct DecompilationContext; - -class VariableProvider { - protected: - DecompilationContext& dec_ctx; - - public: - VariableProvider(DecompilationContext& dec_ctx); - virtual ~VariableProvider(); - - virtual clang::QualType ArgumentAsLocal(llvm::Argument& arg); -}; - -class VariableProviderCombiner final : public VariableProvider { - private: - std::vector> providers; - - public: - VariableProviderCombiner(DecompilationContext& dec_ctx); - template - void AddProvider(TArgs&&... args) { - providers.push_back( - std::make_unique(dec_ctx, std::forward(args)...)); - } - - void AddProvider(std::unique_ptr provider); - - clang::QualType ArgumentAsLocal(llvm::Argument& arg) final; -}; -} // namespace rellic \ No newline at end of file diff --git a/include/rellic/Decompiler.h b/include/rellic/Decompiler.h index 7e8be271..552c52bc 100644 --- a/include/rellic/Decompiler.h +++ b/include/rellic/Decompiler.h @@ -16,8 +16,8 @@ #include #include "Result.h" +#include "rellic/AST/FunctionLayoutOverride.h" #include "rellic/AST/TypeProvider.h" -#include "rellic/AST/VariableProvider.h" namespace rellic { @@ -38,24 +38,27 @@ class SimpleTypeProviderFactory final : public TypeProviderFactory { } }; -class VariableProviderFactory { +class FunctionLayoutOverrideFactory { public: - virtual ~VariableProviderFactory() = default; - virtual std::unique_ptr create( + virtual ~FunctionLayoutOverrideFactory() = default; + virtual std::unique_ptr create( DecompilationContext& ctx) = 0; }; template -class SimpleVariableProviderFactory final : public VariableProviderFactory { +class SimpleFunctionLayoutOverrideFactory final + : public FunctionLayoutOverrideFactory { public: - std::unique_ptr create(DecompilationContext& ctx) override { + std::unique_ptr create( + DecompilationContext& ctx) override { return std::make_unique(ctx); } }; struct DecompilationOptions { using TypeProviderFactoryPtr = std::unique_ptr; - using VariableProviderFactoryPtr = std::unique_ptr; + using FunctionLayoutOverrideFactoryPtr = + std::unique_ptr; bool lower_switches = false; bool remove_phi_nodes = false; @@ -63,7 +66,7 @@ struct DecompilationOptions { // Additional type providers to be used during code generation. // Providers added later will have higher priority. std::vector additional_type_providers; - std::vector additional_variable_providers; + std::vector additional_variable_providers; }; struct DecompilationResult { diff --git a/lib/AST/FunctionLayoutOverride.cpp b/lib/AST/FunctionLayoutOverride.cpp new file mode 100644 index 00000000..eae4906c --- /dev/null +++ b/lib/AST/FunctionLayoutOverride.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022-present, Trail of Bits, Inc. + * All rights reserved. + * + * This source code is licensed in accordance with the terms specified in + * the LICENSE file found in the root directory of this source tree. + */ + +#include "rellic/AST/FunctionLayoutOverride.h" + +#include +#include + +#include "rellic/AST/Util.h" + +namespace rellic { +FunctionLayoutOverride::FunctionLayoutOverride(DecompilationContext &dec_ctx) + : dec_ctx(dec_ctx) {} +FunctionLayoutOverride::~FunctionLayoutOverride() = default; + +bool FunctionLayoutOverride::HasOverride(llvm::Function &func) { return false; } + +std::vector FunctionLayoutOverride::GetArguments( + llvm::Function &func) { + return {}; +} + +void FunctionLayoutOverride::BeginFunctionVisit(llvm::Function &func, + clang::FunctionDecl *fdecl) {} + +bool FunctionLayoutOverride::VisitInstruction(llvm::Instruction &insn, + clang::FunctionDecl *fdecl, + clang::ValueDecl *&vdecl) { + return false; +} + +FunctionLayoutOverrideCombiner::FunctionLayoutOverrideCombiner( + DecompilationContext &dec_ctx) + : FunctionLayoutOverride(dec_ctx) {} + +void FunctionLayoutOverrideCombiner::AddOverride( + std::unique_ptr provider) { + overrides.push_back(std::move(provider)); +} + +bool FunctionLayoutOverrideCombiner::HasOverride(llvm::Function &func) { + for (auto it{overrides.rbegin()}; it != overrides.rend(); ++it) { + auto &override{*it}; + if (override->HasOverride(func)) { + return true; + } + } + return false; +} + +std::vector FunctionLayoutOverrideCombiner::GetArguments( + llvm::Function &func) { + for (auto it{overrides.rbegin()}; it != overrides.rend(); ++it) { + auto &override{*it}; + if (override->HasOverride(func)) { + return override->GetArguments(func); + } + } + return {}; +} + +void FunctionLayoutOverrideCombiner::BeginFunctionVisit( + llvm::Function &func, clang::FunctionDecl *fdecl) { + for (auto it{overrides.rbegin()}; it != overrides.rend(); ++it) { + auto &override{*it}; + if (override->HasOverride(func)) { + override->BeginFunctionVisit(func, fdecl); + return; + } + } +} + +bool FunctionLayoutOverrideCombiner::VisitInstruction( + llvm::Instruction &insn, clang::FunctionDecl *fdecl, + clang::ValueDecl *&vdecl) { + for (auto it{overrides.rbegin()}; it != overrides.rend(); ++it) { + auto &override{*it}; + if (override->HasOverride(*insn.getFunction())) { + return override->VisitInstruction(insn, fdecl, vdecl); + } + } + return false; +} + +} // namespace rellic \ No newline at end of file diff --git a/lib/AST/IRToASTVisitor.cpp b/lib/AST/IRToASTVisitor.cpp index 38d5caef..2926a0c6 100755 --- a/lib/AST/IRToASTVisitor.cpp +++ b/lib/AST/IRToASTVisitor.cpp @@ -1094,15 +1094,9 @@ void IRToASTVisitor::VisitArgument(llvm::Argument &arg) { // Get parent function declaration auto func{arg.getParent()}; auto fdecl{clang::cast(dec_ctx.value_decls[func])}; - auto argtype = dec_ctx.var_provider->ArgumentAsLocal(arg); - // Does the user want to treat this argument as a local variable? - if (!argtype.isNull()) { - parm = ast.CreateVarDecl(fdecl, argtype, name); - } else { - argtype = dec_ctx.type_provider->GetArgumentType(arg); - // Create a declaration - parm = ast.CreateParamDecl(fdecl, argtype, name); - } + auto argtype = dec_ctx.type_provider->GetArgumentType(arg); + // Create a declaration + parm = ast.CreateParamDecl(fdecl, argtype, name); } void IRToASTVisitor::VisitBasicBlock(llvm::BasicBlock &block, @@ -1143,9 +1137,14 @@ void IRToASTVisitor::VisitFunctionDecl(llvm::Function &func) { DLOG(INFO) << "Creating FunctionDecl for " << name; auto tudecl{dec_ctx.ast_ctx.getTranslationUnitDecl()}; + bool override_function_layout = + dec_ctx.function_layout_override->HasOverride(func); + std::vector arg_types; - for (auto &arg : func.args()) { - if (dec_ctx.var_provider->ArgumentAsLocal(arg).isNull()) { + if (override_function_layout) { + arg_types = dec_ctx.function_layout_override->GetArguments(func); + } else { + for (auto &arg : func.args()) { arg_types.push_back(dec_ctx.type_provider->GetArgumentType(arg)); } } @@ -1157,22 +1156,26 @@ void IRToASTVisitor::VisitFunctionDecl(llvm::Function &func) { tudecl->addDecl(decl); auto fdecl{decl->getAsFunction()}; - - std::vector params; - for (auto &arg : func.args()) { - VisitArgument(arg); - auto &decl{dec_ctx.value_decls[&arg]}; - if (auto param = clang::dyn_cast(decl)) { - params.push_back(param); - } else { - fdecl->addDecl(decl); + if (override_function_layout) { + dec_ctx.function_layout_override->BeginFunctionVisit(func, fdecl); + } else { + std::vector params; + for (auto &arg : func.args()) { + VisitArgument(arg); + params.push_back( + clang::dyn_cast(dec_ctx.value_decls[&arg])); } - } - fdecl->setParams(params); + fdecl->setParams(params); + } for (auto &inst : llvm::instructions(func)) { auto &var{dec_ctx.value_decls[&inst]}; + if (dec_ctx.function_layout_override->VisitInstruction(inst, fdecl, var)) { + // The user has overridden our choices + continue; + } + if (auto alloca = llvm::dyn_cast(&inst)) { auto name{"var" + std::to_string(GetNumDecls(fdecl))}; // TLDR: Here we discard the variable name as present in the bitcode @@ -1256,7 +1259,7 @@ void IRToASTVisitor::VisitFunctionDecl(llvm::Function &func) { } auto fdecl{decl->getAsFunction()}; - fdecl->setParams(params); + fdecl->setParams(iasm_params); tudecl->addDecl(decl); } diff --git a/lib/AST/Util.cpp b/lib/AST/Util.cpp index e38eac6f..9dfe9ae6 100644 --- a/lib/AST/Util.cpp +++ b/lib/AST/Util.cpp @@ -19,8 +19,8 @@ #include #include "rellic/AST/ASTBuilder.h" +#include "rellic/AST/FunctionLayoutOverride.h" #include "rellic/AST/TypeProvider.h" -#include "rellic/AST/VariableProvider.h" #include "rellic/BC/Util.h" #include "rellic/Exception.h" @@ -396,7 +396,8 @@ DecompilationContext::DecompilationContext(clang::ASTUnit &ast_unit) ast(ast_unit), marker_expr(ast.CreateAdd(ast.CreateFalse(), ast.CreateFalse())), type_provider(std::make_unique(*this)), - var_provider(std::make_unique(*this)) {} + function_layout_override( + std::make_unique(*this)) {} unsigned DecompilationContext::InsertZExpr(const z3::expr &e) { auto idx{z3_exprs.size()}; diff --git a/lib/AST/VariableProvider.cpp b/lib/AST/VariableProvider.cpp deleted file mode 100644 index 10abcba0..00000000 --- a/lib/AST/VariableProvider.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2022-present, Trail of Bits, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include "rellic/AST/VariableProvider.h" - -#include - -#include "rellic/AST/Util.h" - -namespace rellic { -VariableProvider::VariableProvider(DecompilationContext& dec_ctx) - : dec_ctx(dec_ctx) {} -VariableProvider::~VariableProvider() = default; - -clang::QualType VariableProvider::ArgumentAsLocal(llvm::Argument&) { - return {}; -} - -VariableProviderCombiner::VariableProviderCombiner( - DecompilationContext& dec_ctx) - : VariableProvider(dec_ctx) {} - -void VariableProviderCombiner::AddProvider( - std::unique_ptr provider) { - providers.push_back(std::move(provider)); -} - -clang::QualType VariableProviderCombiner::ArgumentAsLocal(llvm::Argument& arg) { - for (auto it{providers.rbegin()}; it != providers.rend(); ++it) { - auto& provider{*it}; - auto res{provider->ArgumentAsLocal(arg)}; - if (!res.isNull()) { - return res; - } - } - return {}; -} -} // namespace rellic \ No newline at end of file diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 999b8045..eb328da1 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -82,7 +82,7 @@ set(AST_SOURCES AST/StructGenerator.cpp AST/SubprogramGenerator.cpp AST/TypeProvider.cpp - AST/VariableProvider.cpp + AST/FunctionLayoutOverride.cpp ) set(BC_SOURCES diff --git a/lib/Decompiler.cpp b/lib/Decompiler.cpp index 492d4bc2..53059e96 100644 --- a/lib/Decompiler.cpp +++ b/lib/Decompiler.cpp @@ -95,7 +95,7 @@ Result Decompile( } for (auto& provider : options.additional_variable_providers) { - dec_ctx.var_provider->AddProvider(provider->create(dec_ctx)); + dec_ctx.function_layout_override->AddOverride(provider->create(dec_ctx)); } rellic::GenerateAST::run(*module, dec_ctx); From 9ef3bcf6b8ed2224dd0c3d2f86dae4cb66afa585 Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Wed, 25 Jan 2023 15:36:48 +0100 Subject: [PATCH 05/11] Allow type generation in arbitrary decl contexts --- include/rellic/AST/StructGenerator.h | 3 +- lib/AST/StructGenerator.cpp | 50 +++++++++++++--------------- tools/headergen/HeaderGen.cpp | 3 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/include/rellic/AST/StructGenerator.h b/include/rellic/AST/StructGenerator.h index 4adbf62f..ac4bdb43 100644 --- a/include/rellic/AST/StructGenerator.h +++ b/include/rellic/AST/StructGenerator.h @@ -24,6 +24,7 @@ struct OffsetDIDerivedType; class StructGenerator { clang::ASTContext& ast_ctx; rellic::ASTBuilder ast; + clang::DeclContext* decl_ctx; std::unordered_map fwd_decl_records{}; std::unordered_map enum_types{}; @@ -64,7 +65,7 @@ class StructGenerator { std::unordered_set& visited); public: - StructGenerator(clang::ASTUnit& ast_unit); + StructGenerator(clang::ASTUnit& ast_unit, clang::DeclContext* decl_ctx); clang::QualType GetType(llvm::DIType* t); diff --git a/lib/AST/StructGenerator.cpp b/lib/AST/StructGenerator.cpp index 57a0d694..8bc6e490 100644 --- a/lib/AST/StructGenerator.cpp +++ b/lib/AST/StructGenerator.cpp @@ -138,14 +138,14 @@ static clang::FieldDecl* FieldInfoToFieldDecl(clang::ASTContext& ast_ctx, } static unsigned GetStructSize(clang::ASTContext& ast_ctx, ASTBuilder& ast, + clang::DeclContext* decl_ctx, std::vector& fields) { if (!fields.size()) { return 0; } static auto count{0U}; - auto tudecl{ast_ctx.getTranslationUnitDecl()}; - auto decl{ast.CreateStructDecl(tudecl, "temp" + std::to_string(count++))}; + auto decl{ast.CreateStructDecl(decl_ctx, "temp" + std::to_string(count++))}; clang::AttributeCommonInfo info{clang::SourceLocation{}}; decl->addAttr(clang::PackedAttr::Create(ast_ctx, info)); for (auto& field : fields) { @@ -223,7 +223,8 @@ void StructGenerator::VisitFields(clang::RecordDecl* decl, std::unordered_set visible_field_names; for (auto elem : elems) { - auto curr_offset{isUnion ? 0 : GetStructSize(ast_ctx, ast, fields)}; + auto curr_offset{isUnion ? 0 + : GetStructSize(ast_ctx, ast, decl_ctx, fields)}; DLOG(INFO) << "Field " << elem.type->getName().str() << " offset: " << curr_offset << " in " << decl->getName().str(); CHECK_LE(curr_offset, elem.offset) @@ -254,7 +255,7 @@ void StructGenerator::VisitFields(clang::RecordDecl* decl, } if (!isUnion) { - auto cur_size{GetStructSize(ast_ctx, ast, fields)}; + auto cur_size{GetStructSize(ast_ctx, ast, decl_ctx, fields)}; auto expected_size{s->getSizeInBits()}; CHECK_LE(cur_size, expected_size); if (cur_size < expected_size) { @@ -271,8 +272,8 @@ void StructGenerator::VisitFields(clang::RecordDecl* decl, void StructGenerator::DefineStruct(llvm::DICompositeType* s) { VLOG(1) << "DefineStruct: " << rellic::LLVMThingToString(s); auto& fwd_decl{CHECK_NOTNULL(fwd_decl_records[s])}; - auto tudecl{ast_ctx.getTranslationUnitDecl()}; - auto decl{ast.CreateStructDecl(tudecl, fwd_decl->getName().str(), fwd_decl)}; + auto decl{ + ast.CreateStructDecl(decl_ctx, fwd_decl->getName().str(), fwd_decl)}; DeclToDbgInfo fmap{}; if (s->getFlags() & llvm::DICompositeType::DIFlags::FlagFwdDecl) { @@ -299,19 +300,18 @@ void StructGenerator::DefineStruct(llvm::DICompositeType* s) { } } - tudecl->addDecl(decl); + decl_ctx->addDecl(decl); } void StructGenerator::DefineUnion(llvm::DICompositeType* u) { VLOG(1) << "DefineUnion: " << rellic::LLVMThingToString(u); auto& fwd_decl{CHECK_NOTNULL(fwd_decl_records[u])}; - auto tudecl{ast_ctx.getTranslationUnitDecl()}; - auto decl{ast.CreateUnionDecl(tudecl, fwd_decl->getName().str(), fwd_decl)}; + auto decl{ast.CreateUnionDecl(decl_ctx, fwd_decl->getName().str(), fwd_decl)}; DeclToDbgInfo fmap{}; VisitFields(decl, u, fmap, /*isUnion=*/true); - tudecl->addDecl(decl); + decl_ctx->addDecl(decl); } void StructGenerator::DefineComposite(llvm::DICompositeType* t) { @@ -359,11 +359,10 @@ clang::QualType StructGenerator::BuildDerived(llvm::DIDerivedType* d, case llvm::dwarf::DW_TAG_typedef: { auto& tdef_decl{typedef_decls[d]}; if (!tdef_decl) { - auto tudecl{ast_ctx.getTranslationUnitDecl()}; auto name{GetUniqueName(d->getName().str(), visible_tdefs)}; tdef_decl = ast.CreateTypedefDecl( - tudecl, name, BuildType(d->getBaseType(), sizeHint)); - tudecl->addDecl(tdef_decl); + decl_ctx, name, BuildType(d->getBaseType(), sizeHint)); + decl_ctx->addDecl(tdef_decl); } return ast_ctx.getTypedefType(tdef_decl); } @@ -441,21 +440,20 @@ clang::QualType StructGenerator::BuildSubroutine(llvm::DISubroutineType* s) { clang::RecordDecl* StructGenerator::GetRecordDecl(llvm::DICompositeType* t) { auto& decl{fwd_decl_records[t]}; if (!decl) { - auto tudecl{ast_ctx.getTranslationUnitDecl()}; switch (t->getTag()) { case llvm::dwarf::DW_TAG_class_type: case llvm::dwarf::DW_TAG_structure_type: decl = ast.CreateStructDecl( - tudecl, GetUniqueName(t->getName().str(), visible_structs)); + decl_ctx, GetUniqueName(t->getName().str(), visible_structs)); break; case llvm::dwarf::DW_TAG_union_type: decl = ast.CreateUnionDecl( - tudecl, GetUniqueName(t->getName().str(), visible_unions)); + decl_ctx, GetUniqueName(t->getName().str(), visible_unions)); break; default: LOG(FATAL) << "Invalid DICompositeType: " << LLVMThingToString(t); } - tudecl->addDecl(decl); + decl_ctx->addDecl(decl); } return decl; } @@ -466,11 +464,10 @@ clang::QualType StructGenerator::GetEnumDecl(llvm::DICompositeType* t) { return type; } - auto tudecl{ast_ctx.getTranslationUnitDecl()}; auto base{BuildType(t->getBaseType())}; auto name{GetUniqueName(t->getName().str(), visible_enums)}; if (base == ast_ctx.IntTy || base == ast_ctx.UnsignedIntTy) { - auto decl{ast.CreateEnumDecl(tudecl, name)}; + auto decl{ast.CreateEnumDecl(decl_ctx, name)}; for (auto elem : t->getElements()) { if (auto enumerator = llvm::dyn_cast(elem)) { auto elem_name{ @@ -482,11 +479,11 @@ clang::QualType StructGenerator::GetEnumDecl(llvm::DICompositeType* t) { } decl->completeDefinition(base, base, 0, 0); - tudecl->addDecl(decl); + decl_ctx->addDecl(decl); type = ast_ctx.getEnumType(decl); } else { - auto tdef{ast.CreateTypedefDecl(tudecl, name, base)}; - tudecl->addDecl(tdef); + auto tdef{ast.CreateTypedefDecl(decl_ctx, name, base)}; + decl_ctx->addDecl(tdef); type = ast_ctx.getTypedefType(tdef); auto i{0U}; @@ -495,9 +492,9 @@ clang::QualType StructGenerator::GetEnumDecl(llvm::DICompositeType* t) { auto elem_name{ GetUniqueName(enumerator->getName().str(), visible_values)}; auto vdecl{ - ast.CreateVarDecl(tudecl, type, elem_name, clang::SC_Static)}; + ast.CreateVarDecl(decl_ctx, type, elem_name, clang::SC_Static)}; vdecl->setInit(ast.CreateIntLit(enumerator->getValue())); - tudecl->addDecl(vdecl); + decl_ctx->addDecl(vdecl); } } } @@ -628,7 +625,8 @@ std::vector StructGenerator::GetAccessor(clang::Expr* base, return res; } -StructGenerator::StructGenerator(clang::ASTUnit& ast_unit) - : ast_ctx(ast_unit.getASTContext()), ast(ast_unit) {} +StructGenerator::StructGenerator(clang::ASTUnit& ast_unit, + clang::DeclContext* decl_ctx) + : ast_ctx(ast_unit.getASTContext()), ast(ast_unit), decl_ctx(decl_ctx) {} } // namespace rellic diff --git a/tools/headergen/HeaderGen.cpp b/tools/headergen/HeaderGen.cpp index 625ead4e..ec7a64d8 100644 --- a/tools/headergen/HeaderGen.cpp +++ b/tools/headergen/HeaderGen.cpp @@ -96,7 +96,8 @@ int main(int argc, char* argv[]) { std::vector args{"-Wno-pointer-to-int-cast", "-Wno-pointer-sign", "-target", module->getTargetTriple()}; auto ast_unit{clang::tooling::buildASTFromCodeWithArgs("", args, "out.c")}; - rellic::StructGenerator strctgen(*ast_unit); + rellic::StructGenerator strctgen( + *ast_unit, ast_unit->getASTContext().getTranslationUnitDecl()); rellic::SubprogramGenerator subgen(*ast_unit, strctgen); auto types{dic->GetTypes()}; strctgen.GenerateDecls(types.begin(), types.end()); From 30194f3df30f010e16c4728e347c11d183daef00 Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Wed, 25 Jan 2023 15:45:40 +0100 Subject: [PATCH 06/11] Fix tests --- unittests/AST/StructGenerator.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unittests/AST/StructGenerator.cpp b/unittests/AST/StructGenerator.cpp index 2aefb55d..c5117418 100644 --- a/unittests/AST/StructGenerator.cpp +++ b/unittests/AST/StructGenerator.cpp @@ -30,7 +30,7 @@ TEST_SUITE("StructGenerator::GetAccessor") { auto &ctx{unit->getASTContext()}; auto tudecl{ctx.getTranslationUnitDecl()}; rellic::ASTBuilder ast(*unit); - rellic::StructGenerator gen(*unit); + rellic::StructGenerator gen(*unit, tudecl); auto var{GetDeclRef(ast, tudecl, "x")}; auto strct{GetDecl(tudecl, "s")}; THEN("return correct accessors") { @@ -53,7 +53,7 @@ TEST_SUITE("StructGenerator::GetAccessor") { auto &ctx{unit->getASTContext()}; auto tudecl{ctx.getTranslationUnitDecl()}; rellic::ASTBuilder ast(*unit); - rellic::StructGenerator gen(*unit); + rellic::StructGenerator gen(*unit, tudecl); auto var{GetDeclRef(ast, tudecl, "x")}; auto strct{GetDecl(tudecl, "s")}; THEN("return correct accessors") { @@ -76,7 +76,7 @@ TEST_SUITE("StructGenerator::GetAccessor") { auto &ctx{unit->getASTContext()}; auto tudecl{ctx.getTranslationUnitDecl()}; rellic::ASTBuilder ast(*unit); - rellic::StructGenerator gen(*unit); + rellic::StructGenerator gen(*unit, tudecl); auto var{GetDeclRef(ast, tudecl, "x")}; auto strct{GetDecl(tudecl, "u")}; THEN("return correct accessors") { @@ -101,7 +101,7 @@ TEST_SUITE("StructGenerator::GetAccessor") { auto &ctx{unit->getASTContext()}; auto tudecl{ctx.getTranslationUnitDecl()}; rellic::ASTBuilder ast(*unit); - rellic::StructGenerator gen(*unit); + rellic::StructGenerator gen(*unit, tudecl); auto var{GetDeclRef(ast, tudecl, "x")}; auto strct{GetDecl(tudecl, "s")}; THEN("return correct accessors") { From 842ae7e69bad37c797e936ad746e7f655bbd2401 Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Thu, 26 Jan 2023 13:57:23 +0100 Subject: [PATCH 07/11] Generate decl statements for all decls --- lib/AST/GenerateAST.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/AST/GenerateAST.cpp b/lib/AST/GenerateAST.cpp index 7fe9d227..7fc1afc1 100755 --- a/lib/AST/GenerateAST.cpp +++ b/lib/AST/GenerateAST.cpp @@ -629,9 +629,7 @@ GenerateAST::Result GenerateAST::run(llvm::Function &func, StmtVec fbody; // Add declarations of local variables for (auto decl : fdecl->decls()) { - if (clang::isa(decl)) { - fbody.push_back(ast.CreateDeclStmt(decl)); - } + fbody.push_back(ast.CreateDeclStmt(decl)); } // Add statements of the top-level region compound for (auto stmt : region_stmts[regions->getTopLevelRegion()]->body()) { From 60f92c29b24fb70197503a1b28e1a6875c72058e Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Thu, 26 Jan 2023 14:11:01 +0100 Subject: [PATCH 08/11] Ignore struct decls without type info --- lib/AST/StructFieldRenamer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/AST/StructFieldRenamer.cpp b/lib/AST/StructFieldRenamer.cpp index ac298a6b..0671b7ab 100644 --- a/lib/AST/StructFieldRenamer.cpp +++ b/lib/AST/StructFieldRenamer.cpp @@ -23,7 +23,9 @@ StructFieldRenamer::StructFieldRenamer(DecompilationContext &dec_ctx, bool StructFieldRenamer::VisitRecordDecl(clang::RecordDecl *decl) { auto type{decls[decl]}; - CHECK(type) << "Type information not present for declaration"; + if (!type) { + return !Stopped(); + } auto di{types[type]}; if (!di) { From a86c8b7a8f375bac0242698a1ace33d4d6bfc712 Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Mon, 6 Feb 2023 17:59:13 +0100 Subject: [PATCH 09/11] Move more logic into the function layout override --- include/rellic/AST/FunctionLayoutOverride.h | 2 + include/rellic/AST/IRToASTVisitor.h | 2 - lib/AST/FunctionLayoutOverride.cpp | 70 ++++++++++++++++++++- lib/AST/IRToASTVisitor.cpp | 49 +++------------ 4 files changed, 79 insertions(+), 44 deletions(-) diff --git a/include/rellic/AST/FunctionLayoutOverride.h b/include/rellic/AST/FunctionLayoutOverride.h index f1d6310a..2fbcec26 100644 --- a/include/rellic/AST/FunctionLayoutOverride.h +++ b/include/rellic/AST/FunctionLayoutOverride.h @@ -33,6 +33,7 @@ class FunctionLayoutOverride { virtual bool VisitInstruction(llvm::Instruction& insn, clang::FunctionDecl* fdecl, clang::ValueDecl*& vdecl); + virtual bool NeedsDereference(llvm::Function& func, llvm::Value& val); }; class FunctionLayoutOverrideCombiner final : public FunctionLayoutOverride { @@ -56,5 +57,6 @@ class FunctionLayoutOverrideCombiner final : public FunctionLayoutOverride { clang::FunctionDecl* fdecl) final; bool VisitInstruction(llvm::Instruction& insn, clang::FunctionDecl* fdecl, clang::ValueDecl*& vdecl) final; + bool NeedsDereference(llvm::Function& func, llvm::Value& val) final; }; } // namespace rellic \ No newline at end of file diff --git a/include/rellic/AST/IRToASTVisitor.h b/include/rellic/AST/IRToASTVisitor.h index f6fc6705..d0687e1e 100644 --- a/include/rellic/AST/IRToASTVisitor.h +++ b/include/rellic/AST/IRToASTVisitor.h @@ -30,8 +30,6 @@ class IRToASTVisitor { DecompilationContext &dec_ctx; ASTBuilder * - void VisitArgument(llvm::Argument &arg); - public: IRToASTVisitor(DecompilationContext &dec_ctx); diff --git a/lib/AST/FunctionLayoutOverride.cpp b/lib/AST/FunctionLayoutOverride.cpp index eae4906c..67bcb0aa 100644 --- a/lib/AST/FunctionLayoutOverride.cpp +++ b/lib/AST/FunctionLayoutOverride.cpp @@ -11,6 +11,7 @@ #include #include +#include "rellic/AST/DecompilationContext.h" #include "rellic/AST/Util.h" namespace rellic { @@ -34,9 +35,65 @@ bool FunctionLayoutOverride::VisitInstruction(llvm::Instruction &insn, return false; } +bool FunctionLayoutOverride::NeedsDereference(llvm::Function &func, + llvm::Value &val) { + return false; +} + +class FallbackFunctionLayoutOverride : public FunctionLayoutOverride { + public: + FallbackFunctionLayoutOverride(DecompilationContext &dec_ctx) + : FunctionLayoutOverride(dec_ctx) {} + + bool HasOverride(llvm::Function &func) final { return true; } + + std::vector GetArguments(llvm::Function &func) final { + std::vector arg_types; + for (auto &arg : func.args()) { + arg_types.push_back(dec_ctx.type_provider->GetArgumentType(arg)); + } + return arg_types; + } + + void BeginFunctionVisit(llvm::Function &func, + clang::FunctionDecl *fdecl) final { + std::vector params; + for (auto &arg : func.args()) { + auto &parm{dec_ctx.value_decls[&arg]}; + if (parm) { + return; + } + // Create a name + auto name{arg.hasName() ? arg.getName().str() + : "arg" + std::to_string(arg.getArgNo())}; + // Get parent function declaration + auto func{arg.getParent()}; + auto fdecl{clang::cast(dec_ctx.value_decls[func])}; + auto argtype = dec_ctx.type_provider->GetArgumentType(arg); + // Create a declaration + parm = dec_ctx.ast.CreateParamDecl(fdecl, argtype, name); + params.push_back( + clang::dyn_cast(dec_ctx.value_decls[&arg])); + } + + fdecl->setParams(params); + } + + bool VisitInstruction(llvm::Instruction &inst, clang::FunctionDecl *fdecl, + clang::ValueDecl *&vdecl) final { + return false; + } + + bool NeedsDereference(llvm::Function &func, llvm::Value &val) final { + return llvm::isa(val); + } +}; + FunctionLayoutOverrideCombiner::FunctionLayoutOverrideCombiner( DecompilationContext &dec_ctx) - : FunctionLayoutOverride(dec_ctx) {} + : FunctionLayoutOverride(dec_ctx) { + AddOverride(); +} void FunctionLayoutOverrideCombiner::AddOverride( std::unique_ptr provider) { @@ -87,4 +144,15 @@ bool FunctionLayoutOverrideCombiner::VisitInstruction( return false; } +bool FunctionLayoutOverrideCombiner::NeedsDereference(llvm::Function &func, + llvm::Value &val) { + for (auto it{overrides.rbegin()}; it != overrides.rend(); ++it) { + auto &override{*it}; + if (override->HasOverride(func)) { + return override->NeedsDereference(func, val); + } + } + return false; +} + } // namespace rellic \ No newline at end of file diff --git a/lib/AST/IRToASTVisitor.cpp b/lib/AST/IRToASTVisitor.cpp index 2926a0c6..8ac78202 100755 --- a/lib/AST/IRToASTVisitor.cpp +++ b/lib/AST/IRToASTVisitor.cpp @@ -346,10 +346,15 @@ clang::Expr *ExprGen::CreateOperandExpr(llvm::Use &val) { }}; clang::Expr *res{nullptr}; + llvm::Instruction *maybe_inst{llvm::dyn_cast(&val)}; + llvm::Argument *maybe_arg{llvm::dyn_cast(&val)}; if (auto constant = llvm::dyn_cast(val)) { // Operand is a constant value res = CreateConstantExpr(constant); - } else if (llvm::isa(val)) { + } else if ((maybe_inst && dec_ctx.function_layout_override->NeedsDereference( + *maybe_inst->getFunction(), *maybe_inst)) || + (maybe_arg && dec_ctx.function_layout_override->NeedsDereference( + *maybe_arg->getParent(), *maybe_arg))) { // Operand is an l-value (variable, function, ...) // Add a `&` operator res = ast.CreateAddrOf(CreateRef()); @@ -1082,23 +1087,6 @@ void IRToASTVisitor::VisitGlobalVar(llvm::GlobalVariable &gvar) { expr_gen.VisitGlobalVar(gvar); } -void IRToASTVisitor::VisitArgument(llvm::Argument &arg) { - DLOG(INFO) << "VisitArgument: " << LLVMThingToString(&arg); - auto &parm{dec_ctx.value_decls[&arg]}; - if (parm) { - return; - } - // Create a name - auto name{arg.hasName() ? arg.getName().str() - : "arg" + std::to_string(arg.getArgNo())}; - // Get parent function declaration - auto func{arg.getParent()}; - auto fdecl{clang::cast(dec_ctx.value_decls[func])}; - auto argtype = dec_ctx.type_provider->GetArgumentType(arg); - // Create a declaration - parm = ast.CreateParamDecl(fdecl, argtype, name); -} - void IRToASTVisitor::VisitBasicBlock(llvm::BasicBlock &block, std::vector &stmts) { ExprGen expr_gen{dec_ctx}; @@ -1137,17 +1125,7 @@ void IRToASTVisitor::VisitFunctionDecl(llvm::Function &func) { DLOG(INFO) << "Creating FunctionDecl for " << name; auto tudecl{dec_ctx.ast_ctx.getTranslationUnitDecl()}; - bool override_function_layout = - dec_ctx.function_layout_override->HasOverride(func); - - std::vector arg_types; - if (override_function_layout) { - arg_types = dec_ctx.function_layout_override->GetArguments(func); - } else { - for (auto &arg : func.args()) { - arg_types.push_back(dec_ctx.type_provider->GetArgumentType(arg)); - } - } + auto arg_types{dec_ctx.function_layout_override->GetArguments(func)}; auto ret_type{dec_ctx.type_provider->GetFunctionReturnType(func)}; clang::FunctionProtoType::ExtProtoInfo epi; epi.Variadic = func.isVarArg(); @@ -1156,18 +1134,7 @@ void IRToASTVisitor::VisitFunctionDecl(llvm::Function &func) { tudecl->addDecl(decl); auto fdecl{decl->getAsFunction()}; - if (override_function_layout) { - dec_ctx.function_layout_override->BeginFunctionVisit(func, fdecl); - } else { - std::vector params; - for (auto &arg : func.args()) { - VisitArgument(arg); - params.push_back( - clang::dyn_cast(dec_ctx.value_decls[&arg])); - } - - fdecl->setParams(params); - } + dec_ctx.function_layout_override->BeginFunctionVisit(func, fdecl); for (auto &inst : llvm::instructions(func)) { auto &var{dec_ctx.value_decls[&inst]}; From f2824263ce01eade67175321d52c121139d6919b Mon Sep 17 00:00:00 2001 From: 2over12 Date: Thu, 6 Jul 2023 09:06:38 -0400 Subject: [PATCH 10/11] Replace undef constant floats with 0 (#328) * use zero for undef floats * fix format --- include/rellic/AST/ASTBuilder.h | 2 ++ lib/AST/ASTBuilder.cpp | 7 +++++++ lib/AST/IRToASTVisitor.cpp | 12 ++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/rellic/AST/ASTBuilder.h b/include/rellic/AST/ASTBuilder.h index 3e9f7de8..b10c0fb0 100644 --- a/include/rellic/AST/ASTBuilder.h +++ b/include/rellic/AST/ASTBuilder.h @@ -59,6 +59,8 @@ class ASTBuilder { clang::Expr *CreateNull(); clang::Expr *CreateUndefPointer(clang::QualType type); clang::Expr *CreateUndefInteger(clang::QualType type); + clang::Expr *CreateUndefFloat(clang::QualType type); + // Identifiers clang::IdentifierInfo *CreateIdentifier(std::string name); // Variable declaration diff --git a/lib/AST/ASTBuilder.cpp b/lib/AST/ASTBuilder.cpp index 08b9e352..32138539 100644 --- a/lib/AST/ASTBuilder.cpp +++ b/lib/AST/ASTBuilder.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "rellic/AST/Util.h" #include "rellic/Exception.h" @@ -226,6 +227,12 @@ clang::Expr *ASTBuilder::CreateUndefInteger(clang::QualType type) { return lit; } +clang::Expr *ASTBuilder::CreateUndefFloat(clang::QualType type) { + auto lit = + CreateFPLit(llvm::APFloat::getZero(ctx.getFloatTypeSemantics(type))); + return lit; +} + clang::Expr *ASTBuilder::CreateUndefPointer(clang::QualType type) { auto null{CreateNull()}; auto cast{CreateCStyleCast(ctx.getPointerType(type), null)}; diff --git a/lib/AST/IRToASTVisitor.cpp b/lib/AST/IRToASTVisitor.cpp index 8ac78202..3a8b61d8 100755 --- a/lib/AST/IRToASTVisitor.cpp +++ b/lib/AST/IRToASTVisitor.cpp @@ -7,9 +7,11 @@ */ #include +#include #include #include #include +#include #include #define GOOGLE_STRIP_LOG 1 @@ -260,8 +262,14 @@ clang::Expr *ExprGen::CreateLiteralExpr(llvm::Constant *constant) { case llvm::Type::FloatTyID: case llvm::Type::DoubleTyID: case llvm::Type::X86_FP80TyID: { - result = ast.CreateFPLit( - llvm::cast(constant)->getValueAPF()); + if (auto f = llvm::dyn_cast(constant)) { + result = ast.CreateFPLit(f->getValueAPF()); + } else if (llvm::isa(constant)) { + result = ast.CreateUndefFloat(c_type); + } else { + THROW() << "Unsupported float constant"; + } + } break; // Integers case llvm::Type::IntegerTyID: { From 1961ac5ba1b8be5017b779ad337c1e0b2a34d119 Mon Sep 17 00:00:00 2001 From: 2over12 Date: Fri, 6 Oct 2023 11:51:58 -0400 Subject: [PATCH 11/11] llvm 17 fixes (#330) * llvm 17 fixes * Update CI --------- Co-authored-by: Francesco Bertolaccini --- .github/workflows/ci.yml | 6 +++--- README.md | 6 +++--- lib/AST/ASTBuilder.cpp | 6 +++--- lib/AST/StructGenerator.cpp | 14 ++++++++++---- lib/AST/Util.cpp | 7 +------ scripts/build.sh | 8 ++++++-- 6 files changed, 26 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d1759f5..a0d97253 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: image: - { name: 'ubuntu', tag: '20.04' } llvm: [ - '16' + '17' ] name: Rellic CI @@ -129,7 +129,7 @@ jobs: 'macos-12' ] llvm: [ - '16' + '17' ] runs-on: ${{ matrix.os }} @@ -246,7 +246,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - llvm: ["16"] + llvm: ["17"] ubuntu: ["20.04"] steps: - uses: actions/checkout@v2 diff --git a/README.md b/README.md index 5e2bcad3..a0989867 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ clang-14 -emit-llvm -c ./tests/tools/decomp/issue_4.c -o ./tests/tools/decomp/is ### On macOS -Make sure to have the latest release of cxx-common for LLVM 16. Then, build with +Make sure to have the latest release of cxx-common for LLVM 17. Then, build with ```shell cmake \ @@ -271,10 +271,10 @@ make -j8 The Docker image should provide an environment which can set-up, build, and run rellic. The Docker images are parameterized by Ubuntu verison, LLVM version, and architecture. -To build the docker image using LLVM 16 for Ubuntu 20.04 on amd64 you can run the following command: +To build the docker image using LLVM 17 for Ubuntu 20.04 on amd64 you can run the following command: ```sh -ARCH=amd64; UBUNTU=20.04; LLVM=16; docker build . \ +ARCH=amd64; UBUNTU=20.04; LLVM=17; docker build . \ -t rellic:llvm${LLVM}-ubuntu${UBUNTU}-${ARCH} \ -f Dockerfile \ --build-arg UBUNTU_VERSION=${UBUNTU} \ diff --git a/lib/AST/ASTBuilder.cpp b/lib/AST/ASTBuilder.cpp index 32138539..af9b92aa 100644 --- a/lib/AST/ASTBuilder.cpp +++ b/lib/AST/ASTBuilder.cpp @@ -150,7 +150,7 @@ clang::IntegerLiteral *ASTBuilder::CreateIntLit(llvm::APSInt val) { // Extend the literal value based on it's sign if we have a // mismatch between the bit width of the value and inferred type. auto type_size{ctx.getIntWidth(type)}; - if (val.getBitWidth() != type_size && val.getMinSignedBits() < type_size) { + if (val.getBitWidth() != type_size && val.getSignificantBits() < type_size) { val = val.extOrTrunc(type_size); } // Clang does this check in the `clang::IntegerLiteral::Create`, but @@ -216,13 +216,13 @@ clang::Expr *ASTBuilder::CreateFPLit(llvm::APFloat val) { clang::Expr *ASTBuilder::CreateNull() { auto type{ctx.UnsignedIntTy}; - auto val{llvm::APInt::getNullValue(ctx.getTypeSize(type))}; + auto val{llvm::APInt::getZero(ctx.getTypeSize(type))}; auto lit{CreateIntLit(val)}; return CreateCStyleCast(ctx.VoidPtrTy, lit); } clang::Expr *ASTBuilder::CreateUndefInteger(clang::QualType type) { - auto val{llvm::APInt::getNullValue(ctx.getTypeSize(type))}; + auto val{llvm::APInt::getZero(ctx.getTypeSize(type))}; auto lit{CreateIntLit(val)}; return lit; } diff --git a/lib/AST/StructGenerator.cpp b/lib/AST/StructGenerator.cpp index 8bc6e490..d183c7c4 100644 --- a/lib/AST/StructGenerator.cpp +++ b/lib/AST/StructGenerator.cpp @@ -5,10 +5,11 @@ * This source code is licensed in accordance with the terms specified in * the LICENSE file found in the root directory of this source tree. */ +#include +#include +#include #define GOOGLE_STRIP_LOG 1 -#include "rellic/AST/StructGenerator.h" - #include #include #include @@ -20,6 +21,7 @@ #include #include +#include "rellic/AST/StructGenerator.h" #include "rellic/BC/Util.h" static std::string MakeValid(const std::string& name, unsigned id) { @@ -146,7 +148,9 @@ static unsigned GetStructSize(clang::ASTContext& ast_ctx, ASTBuilder& ast, static auto count{0U}; auto decl{ast.CreateStructDecl(decl_ctx, "temp" + std::to_string(count++))}; - clang::AttributeCommonInfo info{clang::SourceLocation{}}; + clang::AttributeCommonInfo info(clang::SourceRange(), + clang::AttributeCommonInfo::Kind::AT_Common, + clang::AttributeCommonInfo::Form::Implicit()); decl->addAttr(clang::PackedAttr::Create(ast_ctx, info)); for (auto& field : fields) { decl->addDecl(FieldInfoToFieldDecl(ast_ctx, ast, decl, field)); @@ -217,7 +221,9 @@ void StructGenerator::VisitFields(clang::RecordDecl* decl, auto field_count{0U}; std::vector fields{}; if (!isUnion) { - clang::AttributeCommonInfo attrinfo{clang::SourceLocation{}}; + clang::AttributeCommonInfo attrinfo( + clang::SourceRange(), clang::AttributeCommonInfo::Kind::AT_Common, + clang::AttributeCommonInfo::Form::Implicit()); decl->addAttr(clang::PackedAttr::Create(ast_ctx, attrinfo)); } diff --git a/lib/AST/Util.cpp b/lib/AST/Util.cpp index 9dfe9ae6..0bb07dd0 100644 --- a/lib/AST/Util.cpp +++ b/lib/AST/Util.cpp @@ -458,12 +458,7 @@ clang::QualType DecompilationContext::GetQualType(llvm::Type *type) { case llvm::Type::PointerTyID: { auto ptr_type{llvm::cast(type)}; - if (ptr_type->isOpaque()) { - result = ast_ctx.VoidPtrTy; - } else { - result = ast_ctx.getPointerType( - GetQualType(ptr_type->getNonOpaquePointerElementType())); - } + result = ast_ctx.VoidPtrTy; } break; case llvm::Type::ArrayTyID: { diff --git a/scripts/build.sh b/scripts/build.sh index b205e86a..d76fa082 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -18,8 +18,8 @@ DOWNLOAD_DIR="$( cd "$( dirname "${SRC_DIR}" )" && pwd )/lifting-bits-downloads" CURR_DIR=$( pwd ) BUILD_DIR="${CURR_DIR}/rellic-build" INSTALL_DIR=/usr/local -LLVM_VERSION=llvm-16 -CXX_COMMON_VERSION=v0.3.2 +LLVM_VERSION=llvm-17 +CXX_COMMON_VERSION=v0.6.1 OS_VERSION=unknown ARCH_VERSION=unknown BUILD_FLAGS= @@ -342,6 +342,10 @@ function GetLLVMVersion LLVM_VERSION=llvm-16 return 0 ;; + 17) + LLVM_VERSION=llvm-17 + return 0 + ;; *) # unknown option echo "[x] Unknown or unsupported LLVM version ${1}. You may be able to manually build it with cxx-common."