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