blob: 5cff6577700c1a70424b30294218720b0c92f845 [file] [log] [blame]
Mitch Phillips99fa1402017-10-23 20:25:19 +00001//===- 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
42using Instr = ::llvm::cfi_verify::FileAnalysis::Instr;
43using ::testing::AllOf;
44using ::testing::Each;
45using ::testing::ElementsAre;
46using ::testing::Eq;
47using ::testing::Field;
48using ::testing::IsEmpty;
49using ::testing::Matches;
50using ::testing::Pair;
51using ::testing::PrintToString;
52using ::testing::Property;
53using ::testing::SizeIs;
54using ::testing::UnorderedElementsAre;
55using ::testing::Value;
56
57namespace llvm {
58namespace cfi_verify {
59// Printing helpers for gtest.
60std::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
76void 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
83void 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
109namespace {
110class ELFx86TestFileAnalysis : public FileAnalysis {
111public:
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
126class BasicGraphBuilderTest : public ::testing::Test {
127protected:
128 virtual void SetUp() {
129 if (Analysis.initialiseDisassemblyMembers()) {
130 FAIL() << "Failed to initialise FileAnalysis.";
131 }
132 }
133
134 ELFx86TestFileAnalysis Analysis;
135};
136
137MATCHER_P2(HasPath, Result, Matcher, "has path " + PrintToString(Matcher)) {
138 const auto &Path = Result.flattenAddress(arg);
139 *result_listener << "the path is " << PrintToString(Path);
140 return Matches(Matcher)(Path);
141}
142
143TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestSinglePathFallthroughUd2) {
144 Analysis.parseSectionContents(
145 {
146 0x75, 0x02, // 0: jne 4 [+2]
147 0x0f, 0x0b, // 2: ud2
148 0xff, 0x10, // 4: callq *(%rax)
149 },
150 0xDEADBEEF);
151 const auto Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
152
153 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
154 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1));
155 EXPECT_THAT(Result.ConditionalBranchNodes,
156 Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true))));
157 EXPECT_THAT(
158 Result.ConditionalBranchNodes,
159 Contains(AllOf(Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),
160 Field(&ConditionalBranchNode::Target,
161 HasPath(Result, ElementsAre(0xDEADBEEF + 4))),
162 Field(&ConditionalBranchNode::Fallthrough,
163 HasPath(Result, ElementsAre(0xDEADBEEF + 2))))))
164 << PrintToString(Result);
165}
166
167TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestSinglePathJumpUd2) {
168 Analysis.parseSectionContents(
169 {
170 0x75, 0x02, // 0: jne 4 [+2]
171 0xff, 0x10, // 2: callq *(%rax)
172 0x0f, 0x0b, // 4: ud2
173 },
174 0xDEADBEEF);
175 const auto Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2);
176
177 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
178 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1));
179 EXPECT_THAT(Result.ConditionalBranchNodes,
180 Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true))));
181 EXPECT_THAT(
182 Result.ConditionalBranchNodes,
183 Contains(AllOf(Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),
184 Field(&ConditionalBranchNode::Target,
185 HasPath(Result, ElementsAre(0xDEADBEEF + 4))),
186 Field(&ConditionalBranchNode::Fallthrough,
187 HasPath(Result, ElementsAre(0xDEADBEEF + 2))))))
188 << PrintToString(Result);
189}
190
191TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestDualPathDualUd2) {
192 Analysis.parseSectionContents(
193 {
194 0x75, 0x03, // 0: jne 5 [+3]
195 0x90, // 2: nop
196 0xff, 0x10, // 3: callq *(%rax)
197 0x0f, 0x0b, // 5: ud2
198 0x75, 0xf9, // 7: jne 2 [-7]
199 0x0f, 0x0b, // 9: ud2
200 },
201 0xDEADBEEF);
202 const auto Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3);
203
204 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
205 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(2));
206 EXPECT_THAT(Result.ConditionalBranchNodes,
207 Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true))));
208 EXPECT_THAT(
209 Result.ConditionalBranchNodes,
210 Contains(AllOf(
211 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),
212 Field(&ConditionalBranchNode::Fallthrough,
213 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))),
214 Field(&ConditionalBranchNode::Target,
215 HasPath(Result, ElementsAre(0xDEADBEEF + 5))))))
216 << PrintToString(Result);
217 EXPECT_THAT(
218 Result.ConditionalBranchNodes,
219 Contains(AllOf(
220 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF + 7)),
221 Field(&ConditionalBranchNode::Fallthrough,
222 HasPath(Result, ElementsAre(0xDEADBEEF + 9))),
223 Field(&ConditionalBranchNode::Target,
224 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))))))
225 << PrintToString(Result);
226}
227
228TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestDualPathSingleUd2) {
229 Analysis.parseSectionContents(
230 {
231 0x75, 0x05, // 0: jne 7 [+5]
232 0x90, // 2: nop
233 0xff, 0x10, // 3: callq *(%rax)
234 0x75, 0xfb, // 5: jne 2 [-5]
235 0x0f, 0x0b, // 7: ud2
236 },
237 0xDEADBEEF);
238 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3);
239
240 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
241 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(2));
242 EXPECT_THAT(Result.ConditionalBranchNodes,
243 Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true))));
244 EXPECT_THAT(
245 Result.ConditionalBranchNodes,
246 Contains(AllOf(
247 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),
248 Field(&ConditionalBranchNode::Fallthrough,
249 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))),
250 Field(&ConditionalBranchNode::Target,
251 HasPath(Result, ElementsAre(0xDEADBEEF + 7))))))
252 << PrintToString(Result);
253 EXPECT_THAT(
254 Result.ConditionalBranchNodes,
255 Contains(AllOf(
256 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF + 5)),
257 Field(&ConditionalBranchNode::Fallthrough,
258 HasPath(Result, ElementsAre(0xDEADBEEF + 7))),
259 Field(&ConditionalBranchNode::Target,
260 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))))))
261 << PrintToString(Result);
262}
263
264TEST_F(BasicGraphBuilderTest, BuildFlowGraphFailures) {
265 Analysis.parseSectionContents(
266 {
267 0x90, // 0: nop
268 0x75, 0xfe, // 1: jne 1 [-2]
269 },
270 0xDEADBEEF);
271 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF);
272 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
273 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());
274
275 Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 1);
276 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
277 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());
278
279 Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADC0DE);
280 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
281 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());
282}
283
284TEST_F(BasicGraphBuilderTest, BuildFlowGraphNoXrefs) {
285 Analysis.parseSectionContents(
286 {
287 0xeb, 0xfe, // 0: jmp 0 [-2]
288 0xff, 0x10, // 2: callq *(%rax)
289 },
290 0xDEADBEEF);
291 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2);
292 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());
293 EXPECT_THAT(Result.OrphanedNodes, ElementsAre(0xDEADBEEF + 2));
294 EXPECT_THAT(Result.IntermediateNodes, IsEmpty());
295}
296
297TEST_F(BasicGraphBuilderTest, BuildFlowGraphConditionalInfiniteLoop) {
298 Analysis.parseSectionContents(
299 {
300 0x75, 0xfe, // 0: jne 0 [-2]
301 0xff, 0x10, // 2: callq *(%rax)
302 },
303 0xDEADBEEF);
304 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2);
305 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
306 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1));
307 EXPECT_THAT(
308 Result.ConditionalBranchNodes,
309 Each(AllOf(Field(&ConditionalBranchNode::CFIProtection, Eq(false)),
310 Field(&ConditionalBranchNode::Target,
311 HasPath(Result, ElementsAre(0xDEADBEEF))),
312 Field(&ConditionalBranchNode::Fallthrough,
313 HasPath(Result, ElementsAre(0xDEADBEEF + 2))))))
314 << PrintToString(Result);
315}
316
317TEST_F(BasicGraphBuilderTest, BuildFlowGraphUnconditionalInfiniteLoop) {
318 Analysis.parseSectionContents(
319 {
320 0x75, 0x02, // 0: jne 4 [+2]
321 0xeb, 0xfc, // 2: jmp 0 [-4]
322 0xff, 0x10, // 4: callq *(%rax)
323 },
324 0xDEADBEEF);
325 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
326 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
327 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1));
328 EXPECT_THAT(
329 Result.ConditionalBranchNodes,
330 Contains(
331 AllOf(Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),
332 Field(&ConditionalBranchNode::Fallthrough,
333 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF))),
334 Field(&ConditionalBranchNode::Target,
335 HasPath(Result, ElementsAre(0xDEADBEEF + 4))))))
336 << PrintToString(Result);
337}
338
339TEST_F(BasicGraphBuilderTest, BuildFlowGraphNoFlowsToIndirection) {
340 Analysis.parseSectionContents(
341 {
342 0x75, 0x00, // 0: jne 2 [+0]
343 0xeb, 0xfc, // 2: jmp 0 [-4]
344 0xff, 0x10, // 4: callq *(%rax)
345 },
346 0xDEADBEEF);
347 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
348 EXPECT_THAT(Result.OrphanedNodes, ElementsAre(0xDEADBEEF + 4));
349 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());
350}
351
352TEST_F(BasicGraphBuilderTest, BuildFlowGraphLengthExceededUpwards) {
353 Analysis.parseSectionContents(
354 {
355 0x75, 0x06, // 0: jne 8 [+6]
356 0x90, // 2: nop
357 0x90, // 3: nop
358 0x90, // 4: nop
359 0x90, // 5: nop
360 0xff, 0x10, // 6: callq *(%rax)
361 0x0f, 0x0b, // 8: ud2
362 },
363 0xDEADBEEF);
364 uint64_t PrevSearchLengthForConditionalBranch =
365 SearchLengthForConditionalBranch;
366 SearchLengthForConditionalBranch = 2;
367
368 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 6);
369 EXPECT_THAT(Result.OrphanedNodes, SizeIs(1));
370 EXPECT_THAT(Result.OrphanedNodes,
371 Each(HasPath(Result, ElementsAre(0xDEADBEEF + 4, 0xDEADBEEF + 5,
372 0xDEADBEEF + 6))))
373 << PrintToString(Result);
374 EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());
375
376 SearchLengthForConditionalBranch = PrevSearchLengthForConditionalBranch;
377}
378
379TEST_F(BasicGraphBuilderTest, BuildFlowGraphLengthExceededDownwards) {
380 Analysis.parseSectionContents(
381 {
382 0x75, 0x02, // 0: jne 4 [+2]
383 0xff, 0x10, // 2: callq *(%rax)
384 0x90, // 4: nop
385 0x90, // 5: nop
386 0x90, // 6: nop
387 0x90, // 7: nop
388 0x0f, 0x0b, // 8: ud2
389 },
390 0xDEADBEEF);
391 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
392 SearchLengthForUndef = 2;
393
394 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2);
395 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
396 EXPECT_THAT(
397 Result.ConditionalBranchNodes,
398 Each(AllOf(
399 Field(&ConditionalBranchNode::CFIProtection, Eq(false)),
400 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),
401 Field(&ConditionalBranchNode::Target,
402 HasPath(Result, ElementsAre(0xDEADBEEF + 4, 0xDEADBEEF + 5))),
403 Field(&ConditionalBranchNode::Fallthrough,
404 HasPath(Result, ElementsAre(0xDEADBEEF + 2))))))
405 << PrintToString(Result);
406
407 SearchLengthForUndef = PrevSearchLengthForUndef;
408}
409
410// This test ensures when avoiding doing repeated work we still generate the
411// paths correctly. We don't need to recalculate the flow from 0x2 -> 0x3 as it
412// should only need to be generated once.
413TEST_F(BasicGraphBuilderTest, BuildFlowGraphWithRepeatedWork) {
414 Analysis.parseSectionContents(
415 {
416 0x75, 0x05, // 0: jne 7 [+5]
417 0x90, // 2: nop
418 0xff, 0x10, // 3: callq *(%rax)
419 0x75, 0xfb, // 5: jne 2 [-5]
420 0x0f, 0x0b, // 7: ud2
421 },
422 0xDEADBEEF);
423 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3);
424 EXPECT_THAT(Result.OrphanedNodes, IsEmpty());
425 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(2));
426 EXPECT_THAT(
427 Result.ConditionalBranchNodes,
428 Contains(AllOf(
429 Field(&ConditionalBranchNode::CFIProtection, Eq(true)),
430 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),
431 Field(&ConditionalBranchNode::Target,
432 HasPath(Result, ElementsAre(0xDEADBEEF + 7))),
433 Field(&ConditionalBranchNode::Fallthrough,
434 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))))))
435 << PrintToString(Result);
436 EXPECT_THAT(
437 Result.ConditionalBranchNodes,
438 Contains(AllOf(
439 Field(&ConditionalBranchNode::CFIProtection, Eq(true)),
440 Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF + 5)),
441 Field(&ConditionalBranchNode::Target,
442 HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))),
443 Field(&ConditionalBranchNode::Fallthrough,
444 HasPath(Result, ElementsAre(0xDEADBEEF + 7))))))
445 << PrintToString(Result);
446 EXPECT_THAT(Result.IntermediateNodes, SizeIs(1));
447 EXPECT_THAT(Result.IntermediateNodes,
448 UnorderedElementsAre(Pair(0xDEADBEEF + 2, 0xDEADBEEF + 3)));
449}
450
451TEST_F(BasicGraphBuilderTest, BuildFlowGraphComplexExample) {
452 // The following code has this graph:
453 // +----------+ +--------------+
454 // | 20 | <--- | 0 |
455 // +----------+ +--------------+
456 // | |
457 // v v
458 // +----------+ +--------------+
459 // | 21 | | 2 |
460 // +----------+ +--------------+
461 // | |
462 // v v
463 // +----------+ +--------------+
464 // | 22 (ud2) | +-> | 7 |
465 // +----------+ | +--------------+
466 // ^ | |
467 // | | v
468 // +----------+ | +--------------+
469 // | 4 | | | 8 |
470 // +----------+ | +--------------+
471 // | | |
472 // v | v
473 // +----------+ | +--------------+ +------------+
474 // | 6 | -+ | 9 (indirect) | <- | 13 |
475 // +----------+ +--------------+ +------------+
476 // ^ |
477 // | v
478 // +--------------+ +------------+
479 // | 11 | | 15 (error) |
480 // +--------------+ +------------+
481 // Or, in image format: https://i.imgur.com/aX5fCoi.png
482
483 Analysis.parseSectionContents(
484 {
485 0x75, 0x12, // 0: jne 20 [+18]
486 0xeb, 0x03, // 2: jmp 7 [+3]
487 0x75, 0x10, // 4: jne 22 [+16]
488 0x90, // 6: nop
489 0x90, // 7: nop
490 0x90, // 8: nop
491 0xff, 0x10, // 9: callq *(%rax)
492 0xeb, 0xfc, // 11: jmp 9 [-4]
493 0x75, 0xfa, // 13: jne 9 [-6]
494 0xe8, 0x78, 0x56, 0x34, 0x12, // 15: callq OUTOFBOUNDS [+0x12345678]
495 0x90, // 20: nop
496 0x90, // 21: nop
497 0x0f, 0x0b, // 22: ud2
498 },
499 0x1000);
500 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
501 SearchLengthForUndef = 5;
502
503 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0x1000 + 9);
504
505 EXPECT_THAT(Result.OrphanedNodes, SizeIs(1));
506 EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(3));
507
508 EXPECT_THAT(
509 Result.OrphanedNodes,
510 Each(AllOf(Eq(0x1000u + 11),
511 HasPath(Result, ElementsAre(0x1000 + 11, 0x1000 + 9)))))
512 << PrintToString(Result);
513
514 EXPECT_THAT(Result.ConditionalBranchNodes,
515 Contains(AllOf(
516 Field(&ConditionalBranchNode::CFIProtection, Eq(true)),
517 Field(&ConditionalBranchNode::Address, Eq(0x1000u)),
518 Field(&ConditionalBranchNode::Target,
519 HasPath(Result, ElementsAre(0x1000 + 20, 0x1000 + 21,
520 0x1000 + 22))),
521 Field(&ConditionalBranchNode::Fallthrough,
522 HasPath(Result, ElementsAre(0x1000 + 2, 0x1000 + 7,
523 0x1000 + 8, 0x1000 + 9))))))
524 << PrintToString(Result);
525
526 EXPECT_THAT(Result.ConditionalBranchNodes,
527 Contains(AllOf(
528 Field(&ConditionalBranchNode::CFIProtection, Eq(true)),
529 Field(&ConditionalBranchNode::Address, Eq(0x1000u + 4)),
530 Field(&ConditionalBranchNode::Target,
531 HasPath(Result, ElementsAre(0x1000 + 22))),
532 Field(&ConditionalBranchNode::Fallthrough,
533 HasPath(Result, ElementsAre(0x1000 + 6, 0x1000 + 7,
534 0x1000 + 8, 0x1000 + 9))))))
535 << PrintToString(Result);
536
537 EXPECT_THAT(
538 Result.ConditionalBranchNodes,
539 Contains(AllOf(Field(&ConditionalBranchNode::CFIProtection, Eq(false)),
540 Field(&ConditionalBranchNode::Address, Eq(0x1000u + 13)),
541 Field(&ConditionalBranchNode::Target,
542 HasPath(Result, ElementsAre(0x1000 + 9))),
543 Field(&ConditionalBranchNode::Fallthrough,
544 HasPath(Result, ElementsAre(0x1000 + 15))))))
545 << PrintToString(Result);
546
547 SearchLengthForUndef = PrevSearchLengthForUndef;
548}
549
550} // anonymous namespace
551} // end namespace cfi_verify
552} // end namespace llvm