forked from iowastateuniversity-programanalysis/hydrogen
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGraph.cpp
More file actions
342 lines (331 loc) · 14.9 KB
/
Graph.cpp
File metadata and controls
342 lines (331 loc) · 14.9 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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/**
* @author Ashwin K J
* @file
* Implementing Graph.hpp
*/
#include "Graph.hpp"
#include "Graph_Edge.hpp"
#include "Graph_Function.hpp"
#include "Graph_Instruction.hpp"
#include "Graph_Line.hpp"
namespace hydrogen_framework {
void Graph::pushGraphFunction(Graph_Function *func) {
func->setGraph(this);
graphFunctions.push_back(func);
} // End pushGraphFunction
void Graph::addEdge(Graph_Instruction *from, Graph_Instruction *to, Graph_Edge *edge) {
from->pushEdgeInstruction(edge);
to->pushEdgeInstruction(edge);
pushGraphEdges(edge);
} // End addEdge
void Graph::addSeqEdges(Graph_Line *line) {
std::list<Graph_Instruction *> instructions = line->getLineInstructions();
for (auto inst = instructions.begin(), instEnd = instructions.end(); inst != instEnd; ++inst) {
/* Double check to make sure it is not Br */
llvm::Instruction *llvmInst = (*inst)->getInstructionPtr();
if (llvmInst) {
if (llvmInst->getOpcode() == llvm::Instruction::Br) {
continue;
} // End check for Br
} // End check for llvmInst
auto nextInst = std::next(inst);
if (nextInst != instEnd) {
auto *seqEdge = new Graph_Edge(*inst, *nextInst, Graph_Edge::SEQUENTIAL, graphVersion);
addEdge(*inst, *nextInst, seqEdge);
} // End check for instEnd
} // End loop for inst
} // End addSeqEdges
Graph_Instruction *Graph::findMatchedInstruction(llvm::Instruction *matchInst) {
for (auto func : graphFunctions) {
for (auto line : func->getFunctionLines()) {
for (auto inst : line->getLineInstructions()) {
if (inst->getInstructionPtr() == matchInst) {
return inst;
} // End check for matchInst
} // End loop for inst
} // End loop for line
} // End loop for func
return nullptr;
} // End findMatchedInstruction
Graph_Instruction *Graph::findVirtualEntry(const std::string &funcName) {
for (auto func : graphFunctions) {
if (func->getFunctionName() == funcName) {
for (auto line : func->getFunctionLines()) {
for (auto inst : line->getLineInstructions()) {
if (inst->getInstructionLabel().find("Entry::") != std::string::npos) {
return inst;
} // End check for matchInst
} // End loop for inst
} // End loop for line
} // End check for function name
} // End loop for func
return nullptr;
} // End findVirtualEntry
Graph_Instruction *Graph::findVirtualExit(const std::string &funcName) {
for (auto func : graphFunctions) {
if (func->getFunctionName() == funcName) {
for (auto line : func->getFunctionLines()) {
for (auto inst : line->getLineInstructions()) {
if (inst->getInstructionLabel().find("Exit::") != std::string::npos) {
return inst;
} // End check for Exit
} // End loop for inst
} // End loop for line
} // End check for function name
} // End loop for func
return nullptr;
} // End findVirtualExit
void Graph::addBranchEdges() {
for (auto func : graphFunctions) {
std::list<Graph_Line *> lines = func->getFunctionLines();
for (auto line = lines.begin(); line != lines.end(); ++line) {
std::list<Graph_Instruction *> instructions = (*line)->getLineInstructions();
for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
llvm::Instruction *I = (*inst)->getInstructionPtr();
if (I) {
/* Adding edges for BB with multiple successors */
if (I->isTerminator()) {
unsigned int noSucc = I->getNumSuccessors();
for (unsigned int iterSucc = 0; iterSucc < noSucc; ++iterSucc) {
llvm::Instruction *iSucc = llvm::dyn_cast<llvm::Instruction>(I->getSuccessor(iterSucc)->begin());
Graph_Instruction *iSuccInst = findMatchedInstruction(iSucc);
if (iSucc) {
auto *branchEdge = new Graph_Edge(*inst, iSuccInst, Graph_Edge::BRANCH, graphVersion);
addEdge(*inst, iSuccInst, branchEdge);
} else {
std::cerr << "No matching Graph_Instruction found for edge from " << (*inst)->getInstructionLabel()
<< "\n";
} // End check for iSucc
} // End loop for iterSucc
} else if ((*inst)->getInstructionID() == instructions.back()->getInstructionID()) {
/* Adding Unique successors */
auto nextLine = std::next(line);
if (nextLine != lines.end()) {
std::list<Graph_Instruction *> nextInstructions = (*nextLine)->getLineInstructions();
auto nextI = nextInstructions.begin();
if (nextI != nextInstructions.end()) {
auto *seqEdge = new Graph_Edge(*inst, *nextI, Graph_Edge::SEQUENTIAL, graphVersion);
addEdge(*inst, *nextI, seqEdge);
} // End check for nextI
} // End check for nextLine
} // End check for TerminatorInst
} // End check for I
} // End loop for inst
} // End llop for line
} // End loop for func
} // End addBranchEdges
void Graph::addFunctionCallEdges() {
/* External Node */
auto *virtualNodeFunc = new Graph_Function(getNextID());
virtualNodeFunc->setFunctionFile("External_Node_File");
virtualNodeFunc->setFunctionName("External_Node_Func");
auto *virtualNodeLine = new Graph_Line(graphVersion);
virtualNodeLine->setLineNumber(graphVersion, graphEntryID);
auto *externalNode = new Graph_Instruction();
externalNode->setInstructionID(getNextID());
externalNode->setInstructionLabel("External_Node");
externalNode->setInstructionPtr(nullptr);
virtualNodeLine->pushLineInstruction(externalNode);
virtualNodeFunc->pushFunctionLines(virtualNodeLine);
pushGraphFunction(virtualNodeFunc);
std::list<std::string> funcNotFoud;
/* Get the whitelisted function names and merge with funcNotFoud */
std::list<std::string> whiteListedFunc = Graph::getWhiteList();
funcNotFoud.insert(funcNotFoud.end(), whiteListedFunc.begin(), whiteListedFunc.end());
for (auto func : graphFunctions) {
for (auto line : func->getFunctionLines()) {
for (auto inst : line->getLineInstructions()) {
llvm::Instruction *I = inst->getInstructionPtr();
if (I) {
if (auto callSite = llvm::CallSite(I)) {
const llvm::Function *Callee = callSite.getCalledFunction();
if (!Callee || !llvm::Intrinsic::isLeaf(Callee->getIntrinsicID())) {
/* Call Extern */
auto *callEdge = new Graph_Edge(inst, externalNode, Graph_Edge::EXTERNAL_CALL, graphVersion);
addEdge(inst, externalNode, callEdge);
} else if (!Callee->isIntrinsic()) {
/* Add Edge based on function name */
bool noEntry = false;
bool noExit = false;
if (!Callee->getName().empty()) {
std::string funcName = Callee->getName();
/* Call site to Entry */
Graph_Instruction *virtualEntry = findVirtualEntry(funcName);
if (virtualEntry) {
auto *callEdge = new Graph_Edge(inst, virtualEntry, Graph_Edge::CALL, graphVersion);
addEdge(inst, virtualEntry, callEdge);
} else {
noEntry = true;
} // End check for virtualEntry
/* Exit to Call site */
Graph_Instruction *virtualExit = findVirtualExit(funcName);
if (virtualExit) {
auto *callEdge = new Graph_Edge(virtualExit, inst, Graph_Edge::CALL, graphVersion);
addEdge(virtualExit, inst, callEdge);
} else {
noExit = true;
} // End check for virtualExit
auto findFunc = std::find_if(std::begin(funcNotFoud), std::end(funcNotFoud),
[=](const std::string &name) { return name == funcName; });
if (findFunc == funcNotFoud.end()) {
if (noEntry && noExit) {
funcNotFoud.push_back(funcName);
std::cerr << "Call edges not formed for " << funcName << "\n";
} else if (noEntry) {
std::cerr << "No Virtual Entry found for " << funcName << "\n";
} else if (noExit) {
std::cerr << "No Virtual Exit found for " << funcName << "\n";
} // End check for noEntry & noExit combinations
} // End check for findFunc
} else {
std::cerr << "Unknown function call from Instruction " << inst->getInstructionLabel() << "\n";
} // End check for Callee name
} // End check for Callee Intrinsic
} // End check for callSite
} // End check for I
} // End loop for inst
} // End loop for line
} // End loop for func
} // End addFunctionCallEdges
void Graph::addVirtualNodes(Graph_Function *func) {
std::string funcName = func->getFunctionName();
auto *virtualLine = new Graph_Line(graphVersion);
/* Entry Node */
virtualLine->setLineNumber(graphVersion, graphEntryID);
auto *virtualNode = new Graph_Instruction();
virtualNode->setInstructionID(getNextID());
virtualNode->setInstructionLabel("Entry::" + funcName);
virtualNode->setInstructionPtr(nullptr);
virtualLine->pushLineInstruction(virtualNode);
auto *to = func->getFunctionLines().front()->getLineInstructions().front();
func->pushFrontFunctionLines(virtualLine);
auto *virtualEdgeEntry = new Graph_Edge(virtualNode, to, Graph_Edge::VIRTUAL, graphVersion);
addEdge(virtualNode, to, virtualEdgeEntry);
/* Exit Node */
virtualLine = new Graph_Line(graphVersion);
virtualLine->setLineNumber(graphVersion, graphExitID);
virtualNode = new Graph_Instruction();
virtualNode->setInstructionID(getNextID());
virtualNode->setInstructionLabel("Exit::" + funcName);
virtualNode->setInstructionPtr(nullptr);
virtualLine->pushLineInstruction(virtualNode);
auto *from = func->getFunctionLines().back()->getLineInstructions().back();
func->pushFunctionLines(virtualLine);
auto *virtualEdgeExit = new Graph_Edge(from, virtualNode, Graph_Edge::VIRTUAL, graphVersion);
addEdge(from, virtualNode, virtualEdgeExit);
} // End addVirtualNodes
void Graph::printGraph(const std::string &graphName) {
std::ofstream gFile(graphName + ".dot", std::ios::trunc);
if (!gFile.is_open()) {
std::cerr << "Unable to open file for printing the output\n";
return;
} // End check for gFile
/* Initialize graph */
gFile << "digraph \"MVICFG\" {\n";
gFile << "\tlabel=\"" << graphName << "\";\n";
/* Generating Nodes */
gFile << "/* Generating Nodes */\n";
for (auto func : graphFunctions) {
gFile << "\tsubgraph cluster_" << func->getFunctionID() << " {\n";
gFile << "\t\tlabel=\"" << func->getFunctionName() << "\";\n";
for (auto line : func->getFunctionLines()) {
for (auto inst : line->getLineInstructions()) {
std::string outputString = std::regex_replace(inst->getInstructionLabel(), std::regex("\""), "\\\"");
gFile << "\t\t\"" << inst->getInstructionID() << "\" [label=\"" << line->getLineNumber(graphVersion)
<< "::" << outputString << "\"];\n";
} // End loop for inst
} // End loop for line
gFile << "\t}\n";
} // End loop for func
/* Generating Edges*/
gFile << "\n/* Generating Edges */\n";
for (auto edge : graphEdges) {
std::string outputString = "\t\t\"" + std::to_string(edge->getEdgeFrom()->getInstructionID()) + "\" -> \"" +
std::to_string(edge->getEdgeTo()->getInstructionID());
switch (edge->getEdgeType()) {
case Graph_Edge::SEQUENTIAL:
outputString += "\" [arrowhead = normal, penwidth = 1.0, color = black, label=\"" +
edge->getPrintableEdgeVersions() + "\"];\n";
break;
case Graph_Edge::BRANCH:
outputString += "\" [arrowhead = dot, penwidth = 1.0, color = black, label=\"" +
edge->getPrintableEdgeVersions() + "::Branch\"];\n";
break;
case Graph_Edge::VIRTUAL:
outputString += "\" [arrowhead = normal, penwidth = 1.0, color = pink, label=\"" +
edge->getPrintableEdgeVersions() + "::Virtual\"];\n";
break;
case Graph_Edge::CALL:
outputString += "\" [arrowhead = odot, penwidth = 1.0, color = blue, label=\"" +
edge->getPrintableEdgeVersions() + "::Call\"];\n";
break;
case Graph_Edge::EXTERNAL_CALL:
outputString += "\" [arrowhead = odot, penwidth = 1.0, color = yellow, label=\"" +
edge->getPrintableEdgeVersions() + "::External_Call\"];\n";
break;
case Graph_Edge::MVICFG_ADD:
outputString += "\" [arrowhead = normal, penwidth = 1.0, color = green, label=\"" +
edge->getPrintableEdgeVersions() + "::Add\"];\n";
break;
case Graph_Edge::MVICFG_DEL:
outputString += "\" [arrowhead = normal, penwidth = 1.0, color = red, label=\"" +
edge->getPrintableEdgeVersions() + "::Del\"];\n";
break;
case Graph_Edge::ANY:
std::cerr << "Should not have ANY as edgeType\n";
outputString += "\" [arrowhead = normal, penwidth = 2.0, color = red, label=\"" +
edge->getPrintableEdgeVersions() + "::ANY\"];\n";
break;
} // End switch for edge
gFile << outputString;
} // End loop for edge
/* Finalizing graph */
gFile << "}\n";
gFile.close();
} // End printGraph
void getLocationInfo(llvm::Instruction &I, unsigned int &DILocLine, std::string &DIFile) {
if (llvm::DILocation *DILoc = I.getDebugLoc()) {
DILocLine = DILoc->getLine();
DIFile = DILoc->getFilename();
return;
} else {
bool resolvedLine = false;
/* Search backward */
llvm::Instruction *backward_iter = &I;
while (true) {
auto prev = backward_iter->getPrevNode();
if (prev) {
if (prev->getDebugLoc()) {
DILocLine = prev->getDebugLoc()->getLine();
DIFile = prev->getDebugLoc()->getFilename();
return;
} // End check for getDebugLoc
backward_iter = backward_iter->getPrevNode();
} else {
break;
} // End check for prev
}
/* Search forward */
llvm::Instruction *forward_iter = &I;
while (true) {
auto next = forward_iter->getNextNode();
if (next) {
if (next->getDebugLoc()) {
DILocLine = next->getDebugLoc()->getLine();
DIFile = next->getDebugLoc()->getFilename();
return;
} // End check for getDebugLoc
forward_iter = forward_iter->getNextNode();
} else {
break;
} // End check for next
}
} // End check for getDebugLoc
} // End getLocationInfo
bool Graph::isVirtualNodeLineNumber(unsigned lineNumber) const {
if (lineNumber == graphEntryID || lineNumber == graphExitID) {
return true;
} // End check for Exit and Entry
return false;
} // End isVirtualNode
} // namespace hydrogen_framework