Mercurial > hg > CbC > CbC_llvm
comparison unittests/tools/llvm-cfi-verify/GraphBuilder.cpp @ 121:803732b1fca8
LLVM 5.0
author | kono |
---|---|
date | Fri, 27 Oct 2017 17:07:41 +0900 |
parents | |
children | 3a76565eade5 |
comparison
equal
deleted
inserted
replaced
120:1172e4bd9c6f | 121:803732b1fca8 |
---|---|
1 //===- llvm/unittests/llvm-cfi-verify/GraphBuilder.cpp --------------===// | |
2 // | |
3 // The LLVM Compiler Infrastructure | |
4 // | |
5 // This file is distributed under the University of Illinois Open Source | |
6 // License. See LICENSE.TXT for details. | |
7 // | |
8 //===----------------------------------------------------------------------===// | |
9 | |
10 #include "../tools/llvm-cfi-verify/lib/GraphBuilder.h" | |
11 #include "../tools/llvm-cfi-verify/lib/FileAnalysis.h" | |
12 #include "gmock/gmock.h" | |
13 #include "gtest/gtest.h" | |
14 | |
15 #include "llvm/BinaryFormat/ELF.h" | |
16 #include "llvm/MC/MCAsmInfo.h" | |
17 #include "llvm/MC/MCContext.h" | |
18 #include "llvm/MC/MCDisassembler/MCDisassembler.h" | |
19 #include "llvm/MC/MCInst.h" | |
20 #include "llvm/MC/MCInstPrinter.h" | |
21 #include "llvm/MC/MCInstrAnalysis.h" | |
22 #include "llvm/MC/MCInstrDesc.h" | |
23 #include "llvm/MC/MCInstrInfo.h" | |
24 #include "llvm/MC/MCObjectFileInfo.h" | |
25 #include "llvm/MC/MCRegisterInfo.h" | |
26 #include "llvm/MC/MCSubtargetInfo.h" | |
27 #include "llvm/Object/Binary.h" | |
28 #include "llvm/Object/COFF.h" | |
29 #include "llvm/Object/ELFObjectFile.h" | |
30 #include "llvm/Object/ObjectFile.h" | |
31 #include "llvm/Support/Casting.h" | |
32 #include "llvm/Support/CommandLine.h" | |
33 #include "llvm/Support/Error.h" | |
34 #include "llvm/Support/MemoryBuffer.h" | |
35 #include "llvm/Support/TargetRegistry.h" | |
36 #include "llvm/Support/TargetSelect.h" | |
37 #include "llvm/Support/raw_ostream.h" | |
38 | |
39 #include <cstdlib> | |
40 #include <sstream> | |
41 | |
42 using Instr = ::llvm::cfi_verify::FileAnalysis::Instr; | |
43 using ::testing::AllOf; | |
44 using ::testing::Each; | |
45 using ::testing::ElementsAre; | |
46 using ::testing::Eq; | |
47 using ::testing::Field; | |
48 using ::testing::IsEmpty; | |
49 using ::testing::Matches; | |
50 using ::testing::Pair; | |
51 using ::testing::PrintToString; | |
52 using ::testing::Property; | |
53 using ::testing::SizeIs; | |
54 using ::testing::UnorderedElementsAre; | |
55 using ::testing::Value; | |
56 | |
57 namespace llvm { | |
58 namespace cfi_verify { | |
59 // Printing helpers for gtest. | |
60 std::string HexStringifyContainer(const std::vector<uint64_t> &C) { | |
61 std::stringstream Stream; | |
62 if (C.empty()) { | |
63 return "{ }"; | |
64 } | |
65 | |
66 Stream << "{ "; | |
67 const auto &LastElemIt = std::end(C) - 1; | |
68 | |
69 for (auto It = std::begin(C); It != LastElemIt; ++It) { | |
70 Stream << "0x" << std::hex << *It << ", "; | |
71 } | |
72 Stream << "0x" << std::hex << *LastElemIt << " }"; | |
73 return Stream.str(); | |
74 } | |
75 | |
76 void PrintTo(const ConditionalBranchNode &BranchNode, ::std::ostream *os) { | |
77 *os << "ConditionalBranchNode<Address: 0x" << std::hex << BranchNode.Address | |
78 << ", Target: 0x" << BranchNode.Target << ", Fallthrough: 0x" | |
79 << BranchNode.Fallthrough | |
80 << ", CFIProtection: " << BranchNode.CFIProtection << ">"; | |
81 } | |
82 | |
83 void PrintTo(const GraphResult &Result, ::std::ostream *os) { | |
84 *os << "Result BaseAddress: 0x" << std::hex << Result.BaseAddress << "\n"; | |
85 | |
86 if (Result.ConditionalBranchNodes.empty()) | |
87 *os << " (No conditional branch nodes)\n"; | |
88 | |
89 for (const auto &Node : Result.ConditionalBranchNodes) { | |
90 *os << " "; | |
91 PrintTo(Node, os); | |
92 *os << "\n Fallthrough Path: " << std::hex | |
93 << HexStringifyContainer(Result.flattenAddress(Node.Fallthrough)) | |
94 << "\n"; | |
95 *os << " Target Path: " << std::hex | |
96 << HexStringifyContainer(Result.flattenAddress(Node.Target)) << "\n"; | |
97 } | |
98 | |
99 if (Result.OrphanedNodes.empty()) | |
100 *os << " (No orphaned nodes)"; | |
101 | |
102 for (const auto &Orphan : Result.OrphanedNodes) { | |
103 *os << " Orphan (0x" << std::hex << Orphan | |
104 << ") Path: " << HexStringifyContainer(Result.flattenAddress(Orphan)) | |
105 << "\n"; | |
106 } | |
107 } | |
108 | |
109 namespace { | |
110 class ELFx86TestFileAnalysis : public FileAnalysis { | |
111 public: | |
112 ELFx86TestFileAnalysis() | |
113 : FileAnalysis(Triple("x86_64--"), SubtargetFeatures()) {} | |
114 | |
115 // Expose this method publicly for testing. | |
116 void parseSectionContents(ArrayRef<uint8_t> SectionBytes, | |
117 uint64_t SectionAddress) { | |
118 FileAnalysis::parseSectionContents(SectionBytes, SectionAddress); | |
119 } | |
120 | |
121 Error initialiseDisassemblyMembers() { | |
122 return FileAnalysis::initialiseDisassemblyMembers(); | |
123 } | |
124 }; | |
125 | |
126 class BasicGraphBuilderTest : public ::testing::Test { | |
127 protected: | |
128 virtual void SetUp() { | |
129 SuccessfullyInitialised = true; | |
130 if (auto Err = Analysis.initialiseDisassemblyMembers()) { | |
131 handleAllErrors(std::move(Err), [&](const UnsupportedDisassembly &E) { | |
132 SuccessfullyInitialised = false; | |
133 outs() | |
134 << "Note: CFIVerifyTests are disabled due to lack of x86 support " | |
135 "on this build.\n"; | |
136 }); | |
137 } | |
138 } | |
139 | |
140 bool SuccessfullyInitialised; | |
141 ELFx86TestFileAnalysis Analysis; | |
142 }; | |
143 | |
144 MATCHER_P2(HasPath, Result, Matcher, "has path " + PrintToString(Matcher)) { | |
145 const auto &Path = Result.flattenAddress(arg); | |
146 *result_listener << "the path is " << PrintToString(Path); | |
147 return Matches(Matcher)(Path); | |
148 } | |
149 | |
150 TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestSinglePathFallthroughUd2) { | |
151 if (!SuccessfullyInitialised) | |
152 return; | |
153 Analysis.parseSectionContents( | |
154 { | |
155 0x75, 0x02, // 0: jne 4 [+2] | |
156 0x0f, 0x0b, // 2: ud2 | |
157 0xff, 0x10, // 4: callq *(%rax) | |
158 }, | |
159 0xDEADBEEF); | |
160 const auto Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4); | |
161 | |
162 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
163 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1)); | |
164 EXPECT_THAT(Result.ConditionalBranchNodes, | |
165 Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true)))); | |
166 EXPECT_THAT( | |
167 Result.ConditionalBranchNodes, | |
168 Contains(AllOf(Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)), | |
169 Field(&ConditionalBranchNode::Target, | |
170 HasPath(Result, ElementsAre(0xDEADBEEF + 4))), | |
171 Field(&ConditionalBranchNode::Fallthrough, | |
172 HasPath(Result, ElementsAre(0xDEADBEEF + 2)))))) | |
173 << PrintToString(Result); | |
174 } | |
175 | |
176 TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestSinglePathJumpUd2) { | |
177 if (!SuccessfullyInitialised) | |
178 return; | |
179 Analysis.parseSectionContents( | |
180 { | |
181 0x75, 0x02, // 0: jne 4 [+2] | |
182 0xff, 0x10, // 2: callq *(%rax) | |
183 0x0f, 0x0b, // 4: ud2 | |
184 }, | |
185 0xDEADBEEF); | |
186 const auto Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2); | |
187 | |
188 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
189 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1)); | |
190 EXPECT_THAT(Result.ConditionalBranchNodes, | |
191 Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true)))); | |
192 EXPECT_THAT( | |
193 Result.ConditionalBranchNodes, | |
194 Contains(AllOf(Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)), | |
195 Field(&ConditionalBranchNode::Target, | |
196 HasPath(Result, ElementsAre(0xDEADBEEF + 4))), | |
197 Field(&ConditionalBranchNode::Fallthrough, | |
198 HasPath(Result, ElementsAre(0xDEADBEEF + 2)))))) | |
199 << PrintToString(Result); | |
200 } | |
201 | |
202 TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestDualPathDualUd2) { | |
203 if (!SuccessfullyInitialised) | |
204 return; | |
205 Analysis.parseSectionContents( | |
206 { | |
207 0x75, 0x03, // 0: jne 5 [+3] | |
208 0x90, // 2: nop | |
209 0xff, 0x10, // 3: callq *(%rax) | |
210 0x0f, 0x0b, // 5: ud2 | |
211 0x75, 0xf9, // 7: jne 2 [-7] | |
212 0x0f, 0x0b, // 9: ud2 | |
213 }, | |
214 0xDEADBEEF); | |
215 const auto Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3); | |
216 | |
217 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
218 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(2)); | |
219 EXPECT_THAT(Result.ConditionalBranchNodes, | |
220 Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true)))); | |
221 EXPECT_THAT( | |
222 Result.ConditionalBranchNodes, | |
223 Contains(AllOf( | |
224 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)), | |
225 Field(&ConditionalBranchNode::Fallthrough, | |
226 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))), | |
227 Field(&ConditionalBranchNode::Target, | |
228 HasPath(Result, ElementsAre(0xDEADBEEF + 5)))))) | |
229 << PrintToString(Result); | |
230 EXPECT_THAT( | |
231 Result.ConditionalBranchNodes, | |
232 Contains(AllOf( | |
233 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF + 7)), | |
234 Field(&ConditionalBranchNode::Fallthrough, | |
235 HasPath(Result, ElementsAre(0xDEADBEEF + 9))), | |
236 Field(&ConditionalBranchNode::Target, | |
237 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3)))))) | |
238 << PrintToString(Result); | |
239 } | |
240 | |
241 TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestDualPathSingleUd2) { | |
242 if (!SuccessfullyInitialised) | |
243 return; | |
244 Analysis.parseSectionContents( | |
245 { | |
246 0x75, 0x05, // 0: jne 7 [+5] | |
247 0x90, // 2: nop | |
248 0xff, 0x10, // 3: callq *(%rax) | |
249 0x75, 0xfb, // 5: jne 2 [-5] | |
250 0x0f, 0x0b, // 7: ud2 | |
251 }, | |
252 0xDEADBEEF); | |
253 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3); | |
254 | |
255 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
256 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(2)); | |
257 EXPECT_THAT(Result.ConditionalBranchNodes, | |
258 Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true)))); | |
259 EXPECT_THAT( | |
260 Result.ConditionalBranchNodes, | |
261 Contains(AllOf( | |
262 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)), | |
263 Field(&ConditionalBranchNode::Fallthrough, | |
264 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))), | |
265 Field(&ConditionalBranchNode::Target, | |
266 HasPath(Result, ElementsAre(0xDEADBEEF + 7)))))) | |
267 << PrintToString(Result); | |
268 EXPECT_THAT( | |
269 Result.ConditionalBranchNodes, | |
270 Contains(AllOf( | |
271 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF + 5)), | |
272 Field(&ConditionalBranchNode::Fallthrough, | |
273 HasPath(Result, ElementsAre(0xDEADBEEF + 7))), | |
274 Field(&ConditionalBranchNode::Target, | |
275 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3)))))) | |
276 << PrintToString(Result); | |
277 } | |
278 | |
279 TEST_F(BasicGraphBuilderTest, BuildFlowGraphFailures) { | |
280 if (!SuccessfullyInitialised) | |
281 return; | |
282 Analysis.parseSectionContents( | |
283 { | |
284 0x90, // 0: nop | |
285 0x75, 0xfe, // 1: jne 1 [-2] | |
286 }, | |
287 0xDEADBEEF); | |
288 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF); | |
289 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
290 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty()); | |
291 | |
292 Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 1); | |
293 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
294 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty()); | |
295 | |
296 Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADC0DE); | |
297 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
298 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty()); | |
299 } | |
300 | |
301 TEST_F(BasicGraphBuilderTest, BuildFlowGraphNoXrefs) { | |
302 if (!SuccessfullyInitialised) | |
303 return; | |
304 Analysis.parseSectionContents( | |
305 { | |
306 0xeb, 0xfe, // 0: jmp 0 [-2] | |
307 0xff, 0x10, // 2: callq *(%rax) | |
308 }, | |
309 0xDEADBEEF); | |
310 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2); | |
311 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty()); | |
312 EXPECT_THAT(Result.OrphanedNodes, ElementsAre(0xDEADBEEF + 2)); | |
313 EXPECT_THAT(Result.IntermediateNodes, IsEmpty()); | |
314 } | |
315 | |
316 TEST_F(BasicGraphBuilderTest, BuildFlowGraphConditionalInfiniteLoop) { | |
317 if (!SuccessfullyInitialised) | |
318 return; | |
319 Analysis.parseSectionContents( | |
320 { | |
321 0x75, 0xfe, // 0: jne 0 [-2] | |
322 0xff, 0x10, // 2: callq *(%rax) | |
323 }, | |
324 0xDEADBEEF); | |
325 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2); | |
326 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
327 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1)); | |
328 EXPECT_THAT( | |
329 Result.ConditionalBranchNodes, | |
330 Each(AllOf(Field(&ConditionalBranchNode::CFIProtection, Eq(false)), | |
331 Field(&ConditionalBranchNode::Target, | |
332 HasPath(Result, ElementsAre(0xDEADBEEF))), | |
333 Field(&ConditionalBranchNode::Fallthrough, | |
334 HasPath(Result, ElementsAre(0xDEADBEEF + 2)))))) | |
335 << PrintToString(Result); | |
336 } | |
337 | |
338 TEST_F(BasicGraphBuilderTest, BuildFlowGraphUnconditionalInfiniteLoop) { | |
339 if (!SuccessfullyInitialised) | |
340 return; | |
341 Analysis.parseSectionContents( | |
342 { | |
343 0x75, 0x02, // 0: jne 4 [+2] | |
344 0xeb, 0xfc, // 2: jmp 0 [-4] | |
345 0xff, 0x10, // 4: callq *(%rax) | |
346 }, | |
347 0xDEADBEEF); | |
348 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4); | |
349 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
350 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1)); | |
351 EXPECT_THAT( | |
352 Result.ConditionalBranchNodes, | |
353 Contains( | |
354 AllOf(Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)), | |
355 Field(&ConditionalBranchNode::Fallthrough, | |
356 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF))), | |
357 Field(&ConditionalBranchNode::Target, | |
358 HasPath(Result, ElementsAre(0xDEADBEEF + 4)))))) | |
359 << PrintToString(Result); | |
360 } | |
361 | |
362 TEST_F(BasicGraphBuilderTest, BuildFlowGraphNoFlowsToIndirection) { | |
363 if (!SuccessfullyInitialised) | |
364 return; | |
365 Analysis.parseSectionContents( | |
366 { | |
367 0x75, 0x00, // 0: jne 2 [+0] | |
368 0xeb, 0xfc, // 2: jmp 0 [-4] | |
369 0xff, 0x10, // 4: callq *(%rax) | |
370 }, | |
371 0xDEADBEEF); | |
372 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4); | |
373 EXPECT_THAT(Result.OrphanedNodes, ElementsAre(0xDEADBEEF + 4)); | |
374 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty()); | |
375 } | |
376 | |
377 TEST_F(BasicGraphBuilderTest, BuildFlowGraphLengthExceededUpwards) { | |
378 if (!SuccessfullyInitialised) | |
379 return; | |
380 Analysis.parseSectionContents( | |
381 { | |
382 0x75, 0x06, // 0: jne 8 [+6] | |
383 0x90, // 2: nop | |
384 0x90, // 3: nop | |
385 0x90, // 4: nop | |
386 0x90, // 5: nop | |
387 0xff, 0x10, // 6: callq *(%rax) | |
388 0x0f, 0x0b, // 8: ud2 | |
389 }, | |
390 0xDEADBEEF); | |
391 uint64_t PrevSearchLengthForConditionalBranch = | |
392 SearchLengthForConditionalBranch; | |
393 SearchLengthForConditionalBranch = 2; | |
394 | |
395 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 6); | |
396 EXPECT_THAT(Result.OrphanedNodes, SizeIs(1)); | |
397 EXPECT_THAT(Result.OrphanedNodes, | |
398 Each(HasPath(Result, ElementsAre(0xDEADBEEF + 4, 0xDEADBEEF + 5, | |
399 0xDEADBEEF + 6)))) | |
400 << PrintToString(Result); | |
401 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty()); | |
402 | |
403 SearchLengthForConditionalBranch = PrevSearchLengthForConditionalBranch; | |
404 } | |
405 | |
406 TEST_F(BasicGraphBuilderTest, BuildFlowGraphLengthExceededDownwards) { | |
407 if (!SuccessfullyInitialised) | |
408 return; | |
409 Analysis.parseSectionContents( | |
410 { | |
411 0x75, 0x02, // 0: jne 4 [+2] | |
412 0xff, 0x10, // 2: callq *(%rax) | |
413 0x90, // 4: nop | |
414 0x90, // 5: nop | |
415 0x90, // 6: nop | |
416 0x90, // 7: nop | |
417 0x0f, 0x0b, // 8: ud2 | |
418 }, | |
419 0xDEADBEEF); | |
420 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef; | |
421 SearchLengthForUndef = 2; | |
422 | |
423 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2); | |
424 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
425 EXPECT_THAT( | |
426 Result.ConditionalBranchNodes, | |
427 Each(AllOf( | |
428 Field(&ConditionalBranchNode::CFIProtection, Eq(false)), | |
429 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)), | |
430 Field(&ConditionalBranchNode::Target, | |
431 HasPath(Result, ElementsAre(0xDEADBEEF + 4, 0xDEADBEEF + 5))), | |
432 Field(&ConditionalBranchNode::Fallthrough, | |
433 HasPath(Result, ElementsAre(0xDEADBEEF + 2)))))) | |
434 << PrintToString(Result); | |
435 | |
436 SearchLengthForUndef = PrevSearchLengthForUndef; | |
437 } | |
438 | |
439 // This test ensures when avoiding doing repeated work we still generate the | |
440 // paths correctly. We don't need to recalculate the flow from 0x2 -> 0x3 as it | |
441 // should only need to be generated once. | |
442 TEST_F(BasicGraphBuilderTest, BuildFlowGraphWithRepeatedWork) { | |
443 if (!SuccessfullyInitialised) | |
444 return; | |
445 Analysis.parseSectionContents( | |
446 { | |
447 0x75, 0x05, // 0: jne 7 [+5] | |
448 0x90, // 2: nop | |
449 0xff, 0x10, // 3: callq *(%rax) | |
450 0x75, 0xfb, // 5: jne 2 [-5] | |
451 0x0f, 0x0b, // 7: ud2 | |
452 }, | |
453 0xDEADBEEF); | |
454 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3); | |
455 EXPECT_THAT(Result.OrphanedNodes, IsEmpty()); | |
456 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(2)); | |
457 EXPECT_THAT( | |
458 Result.ConditionalBranchNodes, | |
459 Contains(AllOf( | |
460 Field(&ConditionalBranchNode::CFIProtection, Eq(true)), | |
461 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)), | |
462 Field(&ConditionalBranchNode::Target, | |
463 HasPath(Result, ElementsAre(0xDEADBEEF + 7))), | |
464 Field(&ConditionalBranchNode::Fallthrough, | |
465 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3)))))) | |
466 << PrintToString(Result); | |
467 EXPECT_THAT( | |
468 Result.ConditionalBranchNodes, | |
469 Contains(AllOf( | |
470 Field(&ConditionalBranchNode::CFIProtection, Eq(true)), | |
471 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF + 5)), | |
472 Field(&ConditionalBranchNode::Target, | |
473 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))), | |
474 Field(&ConditionalBranchNode::Fallthrough, | |
475 HasPath(Result, ElementsAre(0xDEADBEEF + 7)))))) | |
476 << PrintToString(Result); | |
477 EXPECT_THAT(Result.IntermediateNodes, SizeIs(1)); | |
478 EXPECT_THAT(Result.IntermediateNodes, | |
479 UnorderedElementsAre(Pair(0xDEADBEEF + 2, 0xDEADBEEF + 3))); | |
480 } | |
481 | |
482 TEST_F(BasicGraphBuilderTest, BuildFlowGraphComplexExample) { | |
483 if (!SuccessfullyInitialised) | |
484 return; | |
485 // The following code has this graph: | |
486 // +----------+ +--------------+ | |
487 // | 20 | <--- | 0 | | |
488 // +----------+ +--------------+ | |
489 // | | | |
490 // v v | |
491 // +----------+ +--------------+ | |
492 // | 21 | | 2 | | |
493 // +----------+ +--------------+ | |
494 // | | | |
495 // v v | |
496 // +----------+ +--------------+ | |
497 // | 22 (ud2) | +-> | 7 | | |
498 // +----------+ | +--------------+ | |
499 // ^ | | | |
500 // | | v | |
501 // +----------+ | +--------------+ | |
502 // | 4 | | | 8 | | |
503 // +----------+ | +--------------+ | |
504 // | | | | |
505 // v | v | |
506 // +----------+ | +--------------+ +------------+ | |
507 // | 6 | -+ | 9 (indirect) | <- | 13 | | |
508 // +----------+ +--------------+ +------------+ | |
509 // ^ | | |
510 // | v | |
511 // +--------------+ +------------+ | |
512 // | 11 | | 15 (error) | | |
513 // +--------------+ +------------+ | |
514 // Or, in image format: https://i.imgur.com/aX5fCoi.png | |
515 | |
516 Analysis.parseSectionContents( | |
517 { | |
518 0x75, 0x12, // 0: jne 20 [+18] | |
519 0xeb, 0x03, // 2: jmp 7 [+3] | |
520 0x75, 0x10, // 4: jne 22 [+16] | |
521 0x90, // 6: nop | |
522 0x90, // 7: nop | |
523 0x90, // 8: nop | |
524 0xff, 0x10, // 9: callq *(%rax) | |
525 0xeb, 0xfc, // 11: jmp 9 [-4] | |
526 0x75, 0xfa, // 13: jne 9 [-6] | |
527 0xe8, 0x78, 0x56, 0x34, 0x12, // 15: callq OUTOFBOUNDS [+0x12345678] | |
528 0x90, // 20: nop | |
529 0x90, // 21: nop | |
530 0x0f, 0x0b, // 22: ud2 | |
531 }, | |
532 0x1000); | |
533 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef; | |
534 SearchLengthForUndef = 5; | |
535 | |
536 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0x1000 + 9); | |
537 | |
538 EXPECT_THAT(Result.OrphanedNodes, SizeIs(1)); | |
539 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(3)); | |
540 | |
541 EXPECT_THAT( | |
542 Result.OrphanedNodes, | |
543 Each(AllOf(Eq(0x1000u + 11), | |
544 HasPath(Result, ElementsAre(0x1000 + 11, 0x1000 + 9))))) | |
545 << PrintToString(Result); | |
546 | |
547 EXPECT_THAT(Result.ConditionalBranchNodes, | |
548 Contains(AllOf( | |
549 Field(&ConditionalBranchNode::CFIProtection, Eq(true)), | |
550 Field(&ConditionalBranchNode::Address, Eq(0x1000u)), | |
551 Field(&ConditionalBranchNode::Target, | |
552 HasPath(Result, ElementsAre(0x1000 + 20, 0x1000 + 21, | |
553 0x1000 + 22))), | |
554 Field(&ConditionalBranchNode::Fallthrough, | |
555 HasPath(Result, ElementsAre(0x1000 + 2, 0x1000 + 7, | |
556 0x1000 + 8, 0x1000 + 9)))))) | |
557 << PrintToString(Result); | |
558 | |
559 EXPECT_THAT(Result.ConditionalBranchNodes, | |
560 Contains(AllOf( | |
561 Field(&ConditionalBranchNode::CFIProtection, Eq(true)), | |
562 Field(&ConditionalBranchNode::Address, Eq(0x1000u + 4)), | |
563 Field(&ConditionalBranchNode::Target, | |
564 HasPath(Result, ElementsAre(0x1000 + 22))), | |
565 Field(&ConditionalBranchNode::Fallthrough, | |
566 HasPath(Result, ElementsAre(0x1000 + 6, 0x1000 + 7, | |
567 0x1000 + 8, 0x1000 + 9)))))) | |
568 << PrintToString(Result); | |
569 | |
570 EXPECT_THAT( | |
571 Result.ConditionalBranchNodes, | |
572 Contains(AllOf(Field(&ConditionalBranchNode::CFIProtection, Eq(false)), | |
573 Field(&ConditionalBranchNode::Address, Eq(0x1000u + 13)), | |
574 Field(&ConditionalBranchNode::Target, | |
575 HasPath(Result, ElementsAre(0x1000 + 9))), | |
576 Field(&ConditionalBranchNode::Fallthrough, | |
577 HasPath(Result, ElementsAre(0x1000 + 15)))))) | |
578 << PrintToString(Result); | |
579 | |
580 SearchLengthForUndef = PrevSearchLengthForUndef; | |
581 } | |
582 | |
583 } // anonymous namespace | |
584 } // end namespace cfi_verify | |
585 } // end namespace llvm |