Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add plug point for treating arguments as locals #315

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
image:
- { name: 'ubuntu', tag: '22.04' }
llvm: [
'16'
'17'
]

name: Rellic CI
Expand Down Expand Up @@ -129,7 +129,7 @@ jobs:
'macos-12'
]
llvm: [
'16'
'17'
]

runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -246,7 +246,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
llvm: ["16"]
llvm: ["17"]
ubuntu: ["22.04"]
steps:
- uses: actions/checkout@v2
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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 22.04 on amd64 you can run the following command:
To build the docker image using LLVM 17 for Ubuntu 22.04 on amd64 you can run the following command:

```sh
ARCH=amd64; UBUNTU=22.04; LLVM=16; docker build . \
ARCH=amd64; UBUNTU=22.04; LLVM=17; docker build . \
-t rellic:llvm${LLVM}-ubuntu${UBUNTU}-${ARCH} \
-f Dockerfile \
--platform linux/${ARCH}
Expand Down
2 changes: 2 additions & 0 deletions include/rellic/AST/ASTBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions include/rellic/AST/DecompilationContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <unordered_map>

#include "rellic/AST/ASTBuilder.h"
#include "rellic/AST/FunctionLayoutOverride.h"
#include "rellic/AST/TypeProvider.h"

namespace rellic {
Expand All @@ -43,6 +44,7 @@ struct DecompilationContext {
ASTBuilder ast;

std::unique_ptr<TypeProviderCombiner> type_provider;
std::unique_ptr<FunctionLayoutOverrideCombiner> function_layout_override;

StmtToIRMap stmt_provenance;
ExprToUseMap use_provenance;
Expand Down
62 changes: 62 additions & 0 deletions include/rellic/AST/FunctionLayoutOverride.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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 <clang/AST/Decl.h>
#include <clang/AST/Type.h>
#include <llvm/IR/Argument.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Instruction.h>

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<clang::QualType> 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);
virtual bool NeedsDereference(llvm::Function& func, llvm::Value& val);
};

class FunctionLayoutOverrideCombiner final : public FunctionLayoutOverride {
private:
std::vector<std::unique_ptr<FunctionLayoutOverride>> overrides;

public:
FunctionLayoutOverrideCombiner(DecompilationContext& dec_ctx);
template <typename T, typename... TArgs>
void AddOverride(TArgs&&... args) {
overrides.push_back(
std::make_unique<T>(dec_ctx, std::forward<TArgs>(args)...));
}

void AddOverride(std::unique_ptr<FunctionLayoutOverride> provider);

bool HasOverride(llvm::Function& func) final;

std::vector<clang::QualType> 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;
bool NeedsDereference(llvm::Function& func, llvm::Value& val) final;
};
} // namespace rellic
2 changes: 0 additions & 2 deletions include/rellic/AST/IRToASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ class IRToASTVisitor {
DecompilationContext &dec_ctx;
ASTBuilder &ast;

void VisitArgument(llvm::Argument &arg);

public:
IRToASTVisitor(DecompilationContext &dec_ctx);

Expand Down
3 changes: 2 additions & 1 deletion include/rellic/AST/StructGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct OffsetDIDerivedType;
class StructGenerator {
clang::ASTContext& ast_ctx;
rellic::ASTBuilder ast;
clang::DeclContext* decl_ctx;
std::unordered_map<llvm::DICompositeType*, clang::RecordDecl*>
fwd_decl_records{};
std::unordered_map<llvm::DICompositeType*, clang::QualType> enum_types{};
Expand Down Expand Up @@ -64,7 +65,7 @@ class StructGenerator {
std::unordered_set<llvm::DIType*>& visited);

public:
StructGenerator(clang::ASTUnit& ast_unit);
StructGenerator(clang::ASTUnit& ast_unit, clang::DeclContext* decl_ctx);

clang::QualType GetType(llvm::DIType* t);

Expand Down
14 changes: 10 additions & 4 deletions include/rellic/AST/TypeProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Instructions.h>

#include "rellic/AST/ASTBuilder.h"

Expand All @@ -35,9 +36,13 @@ 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 {
class TypeProviderCombiner final : public TypeProvider {
private:
std::vector<std::unique_ptr<TypeProvider>> providers;

Expand All @@ -51,8 +56,9 @@ class TypeProviderCombiner : public TypeProvider {

void AddProvider(std::unique_ptr<TypeProvider> provider);

clang::QualType GetFunctionReturnType(llvm::Function& func) override;
clang::QualType GetArgumentType(llvm::Argument& arg) override;
clang::QualType GetGlobalVarType(llvm::GlobalVariable& gvar) 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
23 changes: 22 additions & 1 deletion include/rellic/Decompiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <vector>

#include "Result.h"
#include "rellic/AST/FunctionLayoutOverride.h"
#include "rellic/AST/TypeProvider.h"

namespace rellic {
Expand All @@ -37,15 +38,35 @@ class SimpleTypeProviderFactory final : public TypeProviderFactory {
}
};

class FunctionLayoutOverrideFactory {
public:
virtual ~FunctionLayoutOverrideFactory() = default;
virtual std::unique_ptr<FunctionLayoutOverride> create(
DecompilationContext& ctx) = 0;
};

template <typename T>
class SimpleFunctionLayoutOverrideFactory final
: public FunctionLayoutOverrideFactory {
public:
std::unique_ptr<FunctionLayoutOverride> create(
DecompilationContext& ctx) override {
return std::make_unique<T>(ctx);
}
};

struct DecompilationOptions {
using TypeProviderFactoryPtr = std::unique_ptr<TypeProviderFactory>;
using FunctionLayoutOverrideFactoryPtr =
std::unique_ptr<FunctionLayoutOverrideFactory>;

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<TypeProviderFactoryPtr> additional_providers;
std::vector<TypeProviderFactoryPtr> additional_type_providers;
std::vector<FunctionLayoutOverrideFactoryPtr> additional_variable_providers;
};

struct DecompilationResult {
Expand Down
13 changes: 10 additions & 3 deletions lib/AST/ASTBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <clang/Sema/Sema.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <llvm/ADT/APFloat.h>

#include "rellic/AST/Util.h"
#include "rellic/Exception.h"
Expand Down Expand Up @@ -149,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
Expand Down Expand Up @@ -215,17 +216,23 @@ 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;
}

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)};
Expand Down
Loading
Loading