forked from secure-software-engineering/phasar
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLLVMProjectIRDB.h
More file actions
256 lines (217 loc) · 9.91 KB
/
LLVMProjectIRDB.h
File metadata and controls
256 lines (217 loc) · 9.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/******************************************************************************
* Copyright (c) 2022 Philipp Schubert.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of LICENSE.txt.
*
* Contributors:
* Fabian Schiebel and others
*****************************************************************************/
#ifndef PHASAR_PHASARLLVM_DB_LLVMPROJECTIRDB_H
#define PHASAR_PHASARLLVM_DB_LLVMPROJECTIRDB_H
#include "phasar/DB/ProjectIRDBBase.h"
#include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h"
#include "phasar/Utils/MaybeUniquePtr.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
namespace psr {
class LLVMProjectIRDB;
template <> struct ProjectIRDBTraits<LLVMProjectIRDB> {
using n_t = const llvm::Instruction *;
using f_t = const llvm::Function *;
using m_t = const llvm::Module *;
using g_t = const llvm::GlobalVariable *;
};
/// \brief Project IR Database that manages a LLVM IR module.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
class LLVMProjectIRDB : public ProjectIRDBBase<LLVMProjectIRDB> {
#pragma GCC diagnostic pop
friend ProjectIRDBBase;
public:
/// Reads and parses the given LLVM IR file and owns the resulting IR Module.
/// If an error occurs, an error message is written to stderr and subsequent
/// calls to isValid() return false.
explicit LLVMProjectIRDB(const llvm::Twine &IRFileName);
/// Reads and parses the given LLVM IR file and owns the resulting IR Module.
/// If an error occurs, an error message is written to stderr and subsequent
/// calls to isValid() return false.
[[deprecated("When moving to the next LLVM version, opaque pointers support "
"is removed completely. Please use one of the other "
"constructors of LLVMProjectIRDB.")]]
explicit LLVMProjectIRDB(const llvm::Twine &IRFileName,
bool EnableOpaquePointers);
/// Initializes the new ProjectIRDB with the given IR Module _without_ taking
/// ownership. The module is optionally being preprocessed.
///
/// CAUTION: Do not manage the same LLVM Module with multiple LLVMProjectIRDB
/// instances at the same time! This will confuse the ModulesToSlotTracker
explicit LLVMProjectIRDB(llvm::Module *Mod, bool DoPreprocessing = true);
/// Initializes the new ProjectIRDB with the given IR Module and takes
/// ownership of it. The module is optionally being preprocessed.
explicit LLVMProjectIRDB(std::unique_ptr<llvm::Module> Mod,
bool DoPreprocessing = true);
/// Initializes the new ProjectIRDB with the given IR Module and takes
/// ownership of it. The module is optionally being preprocessed. Takes the
/// given LLVMContext and binds its lifetime to the lifetime of the
/// constructed ProjectIRDB
explicit LLVMProjectIRDB(std::unique_ptr<llvm::Module> Mod,
std::unique_ptr<llvm::LLVMContext> Ctx,
bool DoPreprocessing = true);
/// Parses the given LLVM IR file and owns the resulting IR Module.
/// If an error occurs, an error message is written to stderr and subsequent
/// calls to isValid() return false.
explicit LLVMProjectIRDB(llvm::MemoryBufferRef Buf);
/// Parses the given LLVM IR file and owns the resulting IR Module.
/// If an error occurs, an error message is written to stderr and subsequent
/// calls to isValid() return false.
[[deprecated("When moving to the next LLVM version, opaque pointers support "
"is removed completely. Please use one of the other "
"constructors of LLVMProjectIRDB.")]]
explicit LLVMProjectIRDB(llvm::MemoryBufferRef Buf,
bool EnableOpaquePointers);
LLVMProjectIRDB(const LLVMProjectIRDB &) = delete;
LLVMProjectIRDB &operator=(const LLVMProjectIRDB &) = delete;
LLVMProjectIRDB(LLVMProjectIRDB &&) noexcept = default;
LLVMProjectIRDB &operator=(LLVMProjectIRDB &&) noexcept = default;
~LLVMProjectIRDB();
[[nodiscard]] static llvm::ErrorOr<std::unique_ptr<llvm::Module>>
getParsedIRModuleOrErr(const llvm::Twine &IRFileName,
llvm::LLVMContext &Ctx) noexcept;
[[nodiscard]] static llvm::ErrorOr<std::unique_ptr<llvm::Module>>
getParsedIRModuleOrErr(llvm::MemoryBufferRef IRFileContent,
llvm::LLVMContext &Ctx) noexcept;
[[nodiscard]] static llvm::ErrorOr<LLVMProjectIRDB>
load(const llvm::Twine &IRFileName);
[[nodiscard]] static LLVMProjectIRDB loadOrExit(const llvm::Twine &IRFileName,
int ErrorExitCode = 1);
[[nodiscard]] static LLVMProjectIRDB
loadOrExit(const llvm::Twine &IRFileName, bool EnableOpaquePointers) = delete;
/// Also use the const overload
using ProjectIRDBBase::getFunction;
/// Non-const overload
[[nodiscard]] llvm::Function *getFunction(llvm::StringRef FunctionName) {
return Mod->getFunction(FunctionName);
}
/// Also use the const overload
using ProjectIRDBBase::getFunctionDefinition;
/// Non-const overload
[[nodiscard]] llvm::Function *
getFunctionDefinition(llvm::StringRef FunctionName);
/// Also use the const overload
using ProjectIRDBBase::getModule;
/// Non-const overload
[[nodiscard]] llvm::Module *getModule() noexcept { return Mod.get(); }
/// Similar to getInstruction(size_t), but is also able to return global
/// variables by id
[[nodiscard]] const llvm::Value *getValueFromId(size_t Id) const noexcept {
return Id < IdToInst.size() ? IdToInst[Id] : nullptr;
}
void emitPreprocessedIR(llvm::raw_ostream &OS) const;
/// Insert a new function F into the IRDB. F should be present in the same
/// llvm::Module that is managed by the IRDB. insertFunction should not be
/// called twice for the same function. Use with care!
void insertFunction(llvm::Function *F, bool DoPreprocessing = true);
/// Returns the function that contains the given instruction Inst.
///
/// \remark This function should eventually replace
/// LLVMBasedCFG::getFunctionOf()
[[nodiscard]] f_t getFunctionOf(n_t Inst) const {
return Inst ? Inst->getFunction() : nullptr;
}
/// Returns an iterable range of all instructions of the given function that
/// are part of the control-flow graph.
///
/// \remark This function should eventually replace
/// LLVMBasedCFG::getAllInstructionsOf()
[[nodiscard]] auto getAllInstructionsOf(f_t Fun) const {
return llvm::map_range(llvm::instructions(Fun),
Ref2PointerConverter<llvm::Instruction>{});
}
/// Returns a range of all global variables (and global constants, e.g, string
/// literals) in the managed module
[[nodiscard]] auto getAllGlobals() const {
return llvm::map_range(std::as_const(*Mod).globals(),
Ref2PointerConverter<llvm::GlobalVariable>{});
}
explicit operator bool() const noexcept { return isValid(); }
private:
[[nodiscard]] m_t getModuleImpl() const noexcept { return Mod.get(); }
[[nodiscard]] bool debugInfoAvailableImpl() const;
[[nodiscard]] FunctionRange getAllFunctionsImpl() const {
return llvm::map_range(ProjectIRDBBase::getModule()->functions(),
Ref2PointerConverter<llvm::Function>{});
}
[[nodiscard]] f_t getFunctionImpl(llvm::StringRef FunctionName) const {
return Mod->getFunction(FunctionName);
}
[[nodiscard]] f_t
getFunctionDefinitionImpl(llvm::StringRef FunctionName) const;
[[nodiscard]] bool
hasFunctionImpl(llvm::StringRef FunctionName) const noexcept {
return Mod->getFunction(FunctionName) != nullptr;
}
[[nodiscard]] f_t getFunctionOfImpl(n_t Inst) const {
assert(Inst != nullptr);
return Inst->getFunction();
}
[[nodiscard]] g_t
getGlobalVariableImpl(llvm::StringRef GlobalVariableName) const;
[[nodiscard]] g_t
getGlobalVariableDefinitionImpl(llvm::StringRef GlobalVariableName) const;
[[nodiscard]] size_t getNumInstructionsImpl() const noexcept {
return IdToInst.size() - IdOffset;
}
[[nodiscard]] size_t getNumFunctionsImpl() const noexcept {
return Mod->size();
}
[[nodiscard]] size_t getNumGlobalsImpl() const noexcept {
return Mod->global_size();
}
[[nodiscard]] n_t getInstructionImpl(size_t Id) const noexcept {
// Effectively make use of integer overflow here...
if (Id - IdOffset < IdToInst.size() - IdOffset) {
return llvm::cast<llvm::Instruction>(IdToInst[Id]);
}
return n_t{};
}
[[nodiscard]] auto getAllInstructionsImpl() const noexcept {
return llvm::map_range(
llvm::ArrayRef(IdToInst).drop_front(IdOffset),
[](const llvm::Value *V) { return llvm::cast<llvm::Instruction>(V); });
}
[[nodiscard]] size_t getInstructionIdImpl(n_t Inst) const {
auto It = InstToId.find(Inst);
assert(It != InstToId.end());
return It->second;
}
[[nodiscard]] bool isValidImpl() const noexcept;
void dumpImpl() const;
void initInstructionIds();
/// XXX Later we might get rid of the metadata IDs entirely and therefore of
/// the preprocessing as well
void preprocessModule(llvm::Module *NonConstMod);
// LLVMContext is not movable, so wrap it into a unique_ptr
std::unique_ptr<llvm::LLVMContext> Ctx;
MaybeUniquePtr<llvm::Module> Mod = nullptr;
size_t IdOffset = 0;
llvm::SmallVector<const llvm::Value *, 0> IdToInst;
llvm::DenseMap<const llvm::Value *, size_t> InstToId;
};
/**
* Revserses the getMetaDataID function
*/
const llvm::Value *fromMetaDataId(const LLVMProjectIRDB &IRDB,
llvm::StringRef Id);
extern template class ProjectIRDBBase<LLVMProjectIRDB>;
} // namespace psr
#endif // PHASAR_PHASARLLVM_DB_LLVMPROJECTIRDB_H