Skip to content

Commit fdfe905

Browse files
authored
Type providers (#304)
* Bring `ast_unit`, `ast_ctx`, `ast` into `dec_ctx` * Move `GetQualType` to `DecompilationContext` * Add type provider * Add type provider for `main` * Update copyright * Revert formatting change * Emit non-signed `char`s * Allow adding type providers from decomp API * Fix merge error * More merge errors
1 parent 2dea01c commit fdfe905

10 files changed

+509
-246
lines changed
+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright (c) 2021-present, Trail of Bits, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed in accordance with the terms specified in
6+
* the LICENSE file found in the root directory of this source tree.
7+
*/
8+
9+
#pragma once
10+
11+
#include <clang/AST/ASTContext.h>
12+
#include <clang/Frontend/ASTUnit.h>
13+
#include <llvm/IR/Instructions.h>
14+
#include <llvm/IR/Value.h>
15+
#include <z3++.h>
16+
17+
#include <unordered_map>
18+
19+
#include "rellic/AST/ASTBuilder.h"
20+
#include "rellic/AST/TypeProvider.h"
21+
22+
namespace rellic {
23+
24+
struct DecompilationContext {
25+
using StmtToIRMap = std::unordered_map<clang::Stmt *, llvm::Value *>;
26+
using ExprToUseMap = std::unordered_map<clang::Expr *, llvm::Use *>;
27+
using IRToTypeDeclMap = std::unordered_map<llvm::Type *, clang::TypeDecl *>;
28+
using IRToValDeclMap = std::unordered_map<llvm::Value *, clang::ValueDecl *>;
29+
using IRToStmtMap = std::unordered_map<llvm::Value *, clang::Stmt *>;
30+
using ArgToTempMap = std::unordered_map<llvm::Argument *, clang::VarDecl *>;
31+
using BlockToUsesMap =
32+
std::unordered_map<llvm::BasicBlock *, std::vector<llvm::Use *>>;
33+
using Z3CondMap = std::unordered_map<clang::Stmt *, unsigned>;
34+
35+
using BBEdge = std::pair<llvm::BasicBlock *, llvm::BasicBlock *>;
36+
using BrEdge = std::pair<llvm::BranchInst *, bool>;
37+
using SwEdge = std::pair<llvm::SwitchInst *, llvm::ConstantInt *>;
38+
39+
DecompilationContext(clang::ASTUnit &ast_unit);
40+
41+
clang::ASTUnit &ast_unit;
42+
clang::ASTContext &ast_ctx;
43+
ASTBuilder ast;
44+
45+
std::unique_ptr<TypeProviderCombiner> type_provider;
46+
47+
StmtToIRMap stmt_provenance;
48+
ExprToUseMap use_provenance;
49+
IRToTypeDeclMap type_decls;
50+
IRToValDeclMap value_decls;
51+
ArgToTempMap temp_decls;
52+
BlockToUsesMap outgoing_uses;
53+
z3::context z3_ctx;
54+
z3::expr_vector z3_exprs{z3_ctx};
55+
Z3CondMap conds;
56+
57+
clang::Expr *marker_expr;
58+
59+
std::unordered_map<unsigned, BrEdge> z3_br_edges_inv;
60+
61+
// Pairs do not have a std::hash specialization so we can't use unordered maps
62+
// here. If this turns out to be a performance issue, investigate adding hash
63+
// specializations for these specifically
64+
std::map<BrEdge, unsigned> z3_br_edges;
65+
66+
std::unordered_map<llvm::SwitchInst *, unsigned> z3_sw_vars;
67+
std::unordered_map<unsigned, llvm::SwitchInst *> z3_sw_vars_inv;
68+
std::map<SwEdge, unsigned> z3_sw_edges;
69+
70+
std::map<BBEdge, unsigned> z3_edges;
71+
std::unordered_map<llvm::BasicBlock *, unsigned> reaching_conds;
72+
73+
size_t num_literal_structs = 0;
74+
size_t num_declared_structs = 0;
75+
76+
// Inserts an expression into z3_exprs and returns its index
77+
unsigned InsertZExpr(const z3::expr &e);
78+
79+
clang::QualType GetQualType(llvm::Type *type);
80+
};
81+
82+
} // namespace rellic

include/rellic/AST/TypeProvider.h

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2022-present, Trail of Bits, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed in accordance with the terms specified in
6+
* the LICENSE file found in the root directory of this source tree.
7+
*/
8+
9+
#pragma once
10+
#include <llvm/IR/DerivedTypes.h>
11+
#include <llvm/IR/Function.h>
12+
#include <llvm/IR/GlobalVariable.h>
13+
14+
#include "rellic/AST/ASTBuilder.h"
15+
16+
namespace rellic {
17+
struct DecompilationContext;
18+
19+
class TypeProvider {
20+
protected:
21+
DecompilationContext& dec_ctx;
22+
23+
public:
24+
TypeProvider(DecompilationContext& dec_ctx);
25+
virtual ~TypeProvider();
26+
27+
// Returns the return type of a function if available.
28+
// A null return value is assumed to mean that no info is available.
29+
virtual clang::QualType GetFunctionReturnType(llvm::Function& func);
30+
31+
// Returns the type of the argument if available.
32+
// A null return value is assumed to mean that no info is available.
33+
virtual clang::QualType GetArgumentType(llvm::Argument& arg);
34+
35+
// Returns the type of a global variable if available.
36+
// A null return value is assumed to mean that no info is available.
37+
virtual clang::QualType GetGlobalVarType(llvm::GlobalVariable& gvar);
38+
};
39+
40+
class TypeProviderCombiner : public TypeProvider {
41+
private:
42+
std::vector<std::unique_ptr<TypeProvider>> providers;
43+
44+
public:
45+
TypeProviderCombiner(DecompilationContext& dec_ctx);
46+
template <typename T, typename... TArgs>
47+
void AddProvider(TArgs&&... args) {
48+
providers.push_back(
49+
std::make_unique<T>(dec_ctx, std::forward<TArgs>(args)...));
50+
}
51+
52+
void AddProvider(std::unique_ptr<TypeProvider> provider);
53+
54+
clang::QualType GetFunctionReturnType(llvm::Function& func) override;
55+
clang::QualType GetArgumentType(llvm::Argument& arg) override;
56+
clang::QualType GetGlobalVarType(llvm::GlobalVariable& gvar) override;
57+
};
58+
} // namespace rellic

include/rellic/AST/Util.h

+1-65
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,7 @@
88

99
#pragma once
1010

11-
#include <clang/AST/ASTContext.h>
12-
#include <clang/AST/DeclBase.h>
13-
#include <clang/AST/Stmt.h>
14-
#include <clang/Frontend/ASTUnit.h>
15-
#include <llvm/IR/Instructions.h>
16-
#include <llvm/IR/Value.h>
17-
#include <z3++.h>
18-
19-
#include <unordered_map>
20-
21-
#include "rellic/AST/ASTBuilder.h"
11+
#include "rellic/AST/DecompilationContext.h"
2212

2313
namespace rellic {
2414

@@ -52,60 +42,6 @@ size_t GetNumDecls(clang::DeclContext *decl_ctx) {
5242
return result;
5343
}
5444

55-
struct DecompilationContext {
56-
using StmtToIRMap = std::unordered_map<clang::Stmt *, llvm::Value *>;
57-
using ExprToUseMap = std::unordered_map<clang::Expr *, llvm::Use *>;
58-
using IRToTypeDeclMap = std::unordered_map<llvm::Type *, clang::TypeDecl *>;
59-
using IRToValDeclMap = std::unordered_map<llvm::Value *, clang::ValueDecl *>;
60-
using IRToStmtMap = std::unordered_map<llvm::Value *, clang::Stmt *>;
61-
using ArgToTempMap = std::unordered_map<llvm::Argument *, clang::VarDecl *>;
62-
using BlockToUsesMap =
63-
std::unordered_map<llvm::BasicBlock *, std::vector<llvm::Use *>>;
64-
using Z3CondMap = std::unordered_map<clang::Stmt *, unsigned>;
65-
66-
using BBEdge = std::pair<llvm::BasicBlock *, llvm::BasicBlock *>;
67-
using BrEdge = std::pair<llvm::BranchInst *, bool>;
68-
using SwEdge = std::pair<llvm::SwitchInst *, llvm::ConstantInt *>;
69-
70-
DecompilationContext(clang::ASTUnit &ast_unit);
71-
72-
clang::ASTUnit &ast_unit;
73-
clang::ASTContext &ast_ctx;
74-
ASTBuilder ast;
75-
76-
StmtToIRMap stmt_provenance;
77-
ExprToUseMap use_provenance;
78-
IRToTypeDeclMap type_decls;
79-
IRToValDeclMap value_decls;
80-
ArgToTempMap temp_decls;
81-
BlockToUsesMap outgoing_uses;
82-
z3::context z3_ctx;
83-
z3::expr_vector z3_exprs{z3_ctx};
84-
Z3CondMap conds;
85-
86-
clang::Expr *marker_expr;
87-
88-
std::unordered_map<unsigned, BrEdge> z3_br_edges_inv;
89-
90-
// Pairs do not have a std::hash specialization so we can't use unordered maps
91-
// here. If this turns out to be a performance issue, investigate adding hash
92-
// specializations for these specifically
93-
std::map<BrEdge, unsigned> z3_br_edges;
94-
95-
std::unordered_map<llvm::SwitchInst *, unsigned> z3_sw_vars;
96-
std::unordered_map<unsigned, llvm::SwitchInst *> z3_sw_vars_inv;
97-
std::map<SwEdge, unsigned> z3_sw_edges;
98-
99-
std::map<BBEdge, unsigned> z3_edges;
100-
std::unordered_map<llvm::BasicBlock *, unsigned> reaching_conds;
101-
102-
size_t num_literal_structs = 0;
103-
size_t num_declared_structs = 0;
104-
105-
// Inserts an expression into z3_exprs and returns its index
106-
unsigned InsertZExpr(const z3::expr &e);
107-
};
108-
10945
template <typename TKey1, typename TKey2, typename TKey3, typename TValue>
11046
void CopyProvenance(TKey1 *from, TKey2 *to,
11147
std::unordered_map<TKey3 *, TValue *> &map) {

include/rellic/Decompiler.h

+26
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,39 @@
1313

1414
#include <memory>
1515
#include <unordered_map>
16+
#include <vector>
1617

1718
#include "Result.h"
19+
#include "rellic/AST/TypeProvider.h"
1820

1921
namespace rellic {
22+
23+
/* This additional level of indirection is needed to alleviate the users from
24+
* the burden of having to instantiate custom TypeProviders before the actual
25+
* DecompilationContext has been created */
26+
class TypeProviderFactory {
27+
public:
28+
virtual ~TypeProviderFactory() = default;
29+
virtual std::unique_ptr<TypeProvider> create(DecompilationContext& ctx) = 0;
30+
};
31+
32+
template <typename T>
33+
class SimpleTypeProviderFactory final : public TypeProviderFactory {
34+
public:
35+
std::unique_ptr<TypeProvider> create(DecompilationContext& ctx) override {
36+
return std::make_unique<T>(ctx);
37+
}
38+
};
39+
2040
struct DecompilationOptions {
41+
using TypeProviderFactoryPtr = std::unique_ptr<TypeProviderFactory>;
42+
2143
bool lower_switches = false;
2244
bool remove_phi_nodes = false;
45+
46+
// Additional type providers to be used during code generation.
47+
// Providers added later will have higher priority.
48+
std::vector<TypeProviderFactoryPtr> additional_providers;
2349
};
2450

2551
struct DecompilationResult {

0 commit comments

Comments
 (0)