brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.9 KiB · c1d991c Raw
598 lines · cpp
1//===- llvm/unittests/llvm-cfi-verify/GraphBuilder.cpp --------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "../tools/llvm-cfi-verify/lib/GraphBuilder.h"10#include "../tools/llvm-cfi-verify/lib/FileAnalysis.h"11#include "gmock/gmock.h"12#include "gtest/gtest.h"13 14#include "llvm/BinaryFormat/ELF.h"15#include "llvm/DebugInfo/Symbolize/SymbolizableModule.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/MC/TargetRegistry.h"28#include "llvm/Object/Binary.h"29#include "llvm/Object/COFF.h"30#include "llvm/Object/ELFObjectFile.h"31#include "llvm/Object/ObjectFile.h"32#include "llvm/Support/Casting.h"33#include "llvm/Support/CommandLine.h"34#include "llvm/Support/Error.h"35#include "llvm/Support/MemoryBuffer.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::SizeIs;53using ::testing::UnorderedElementsAre;54 55namespace llvm {56namespace cfi_verify {57// Printing helpers for gtest.58std::string HexStringifyContainer(const std::vector<uint64_t> &C) {59  std::stringstream Stream;60  if (C.empty()) {61    return "{ }";62  }63 64  Stream << "{ ";65  const auto &LastElemIt = std::end(C) - 1;66 67  for (auto It = std::begin(C); It != LastElemIt; ++It) {68    Stream << "0x" << std::hex << *It << ", ";69  }70  Stream << "0x" << std::hex << *LastElemIt << " }";71  return Stream.str();72}73 74void PrintTo(const ConditionalBranchNode &BranchNode, ::std::ostream *os) {75  *os << "ConditionalBranchNode<Address: 0x" << std::hex << BranchNode.Address76      << ", Target: 0x" << BranchNode.Target << ", Fallthrough: 0x"77      << BranchNode.Fallthrough78      << ", CFIProtection: " << BranchNode.CFIProtection << ">";79}80 81void PrintTo(const GraphResult &Result, ::std::ostream *os) {82  *os << "Result BaseAddress: 0x" << std::hex << Result.BaseAddress << "\n";83 84  if (Result.ConditionalBranchNodes.empty())85    *os << "  (No conditional branch nodes)\n";86 87  for (const auto &Node : Result.ConditionalBranchNodes) {88    *os << "  ";89    PrintTo(Node, os);90    *os << "\n    Fallthrough Path: " << std::hex91        << HexStringifyContainer(Result.flattenAddress(Node.Fallthrough))92        << "\n";93    *os << "    Target Path: " << std::hex94        << HexStringifyContainer(Result.flattenAddress(Node.Target)) << "\n";95  }96 97  if (Result.OrphanedNodes.empty())98    *os << "  (No orphaned nodes)";99 100  for (const auto &Orphan : Result.OrphanedNodes) {101    *os << "  Orphan (0x" << std::hex << Orphan102        << ") Path: " << HexStringifyContainer(Result.flattenAddress(Orphan))103        << "\n";104  }105}106 107namespace {108class ELFx86TestFileAnalysis : public FileAnalysis {109public:110  ELFx86TestFileAnalysis()111      : FileAnalysis(Triple("x86_64--"), SubtargetFeatures()) {}112 113  // Expose this method publicly for testing.114  void parseSectionContents(ArrayRef<uint8_t> SectionBytes,115                            object::SectionedAddress Address) {116    FileAnalysis::parseSectionContents(SectionBytes, Address);117  }118 119  Error initialiseDisassemblyMembers() {120    return FileAnalysis::initialiseDisassemblyMembers();121  }122};123 124class BasicGraphBuilderTest : public ::testing::Test {125protected:126  void SetUp() override {127    IgnoreDWARFFlag = true;128    SuccessfullyInitialised = true;129    if (auto Err = Analysis.initialiseDisassemblyMembers()) {130      handleAllErrors(std::move(Err), [&](const UnsupportedDisassembly &E) {131        SuccessfullyInitialised = false;132        outs()133            << "Note: CFIVerifyTests are disabled due to lack of x86 support "134               "on this build.\n";135      });136    }137  }138 139  bool SuccessfullyInitialised;140  ELFx86TestFileAnalysis Analysis;141};142 143MATCHER_P2(HasPath, Result, Matcher, "has path " + PrintToString(Matcher)) {144  const auto &Path = Result.flattenAddress(arg);145  *result_listener << "the path is " << PrintToString(Path);146  return Matches(Matcher)(Path);147}148 149TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestSinglePathFallthroughUd2) {150  if (!SuccessfullyInitialised)151    GTEST_SKIP();152  Analysis.parseSectionContents(153      {154          0x75, 0x02, // 0: jne 4 [+2]155          0x0f, 0x0b, // 2: ud2156          0xff, 0x10, // 4: callq *(%rax)157      },158      {0xDEADBEEF, 0x0});159  const auto Result =160      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 4, 0x0});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 176TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestSinglePathJumpUd2) {177  if (!SuccessfullyInitialised)178    GTEST_SKIP();179  Analysis.parseSectionContents(180      {181          0x75, 0x02, // 0: jne 4 [+2]182          0xff, 0x10, // 2: callq *(%rax)183          0x0f, 0x0b, // 4: ud2184      },185      {0xDEADBEEF, 0x0});186  const auto Result =187      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 2, 0x0});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 203TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestDualPathDualUd2) {204  if (!SuccessfullyInitialised)205    GTEST_SKIP();206  Analysis.parseSectionContents(207      {208          0x75, 0x03, // 0: jne 5 [+3]209          0x90,       // 2: nop210          0xff, 0x10, // 3: callq *(%rax)211          0x0f, 0x0b, // 5: ud2212          0x75, 0xf9, // 7: jne 2 [-7]213          0x0f, 0x0b, // 9: ud2214      },215      {0xDEADBEEF, 0x0});216  const auto Result =217      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 3, 0x0});218 219  EXPECT_THAT(Result.OrphanedNodes, IsEmpty());220  EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(2));221  EXPECT_THAT(Result.ConditionalBranchNodes,222              Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true))));223  EXPECT_THAT(224      Result.ConditionalBranchNodes,225      Contains(AllOf(226          Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),227          Field(&ConditionalBranchNode::Fallthrough,228                HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))),229          Field(&ConditionalBranchNode::Target,230                HasPath(Result, ElementsAre(0xDEADBEEF + 5))))))231      << PrintToString(Result);232  EXPECT_THAT(233      Result.ConditionalBranchNodes,234      Contains(AllOf(235          Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF + 7)),236          Field(&ConditionalBranchNode::Fallthrough,237                HasPath(Result, ElementsAre(0xDEADBEEF + 9))),238          Field(&ConditionalBranchNode::Target,239                HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))))))240      << PrintToString(Result);241}242 243TEST_F(BasicGraphBuilderTest, BuildFlowGraphTestDualPathSingleUd2) {244  if (!SuccessfullyInitialised)245    GTEST_SKIP();246  Analysis.parseSectionContents(247      {248          0x75, 0x05, // 0: jne 7 [+5]249          0x90,       // 2: nop250          0xff, 0x10, // 3: callq *(%rax)251          0x75, 0xfb, // 5: jne 2 [-5]252          0x0f, 0x0b, // 7: ud2253      },254      {0xDEADBEEF, 0x0});255  GraphResult Result =256      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 3, 0x0});257 258  EXPECT_THAT(Result.OrphanedNodes, IsEmpty());259  EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(2));260  EXPECT_THAT(Result.ConditionalBranchNodes,261              Each(Field(&ConditionalBranchNode::CFIProtection, Eq(true))));262  EXPECT_THAT(263      Result.ConditionalBranchNodes,264      Contains(AllOf(265          Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),266          Field(&ConditionalBranchNode::Fallthrough,267                HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))),268          Field(&ConditionalBranchNode::Target,269                HasPath(Result, ElementsAre(0xDEADBEEF + 7))))))270      << PrintToString(Result);271  EXPECT_THAT(272      Result.ConditionalBranchNodes,273      Contains(AllOf(274          Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF + 5)),275          Field(&ConditionalBranchNode::Fallthrough,276                HasPath(Result, ElementsAre(0xDEADBEEF + 7))),277          Field(&ConditionalBranchNode::Target,278                HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))))))279      << PrintToString(Result);280}281 282TEST_F(BasicGraphBuilderTest, BuildFlowGraphFailures) {283  if (!SuccessfullyInitialised)284    GTEST_SKIP();285  Analysis.parseSectionContents(286      {287          0x90,       // 0: nop288          0x75, 0xfe, // 1: jne 1 [-2]289      },290      {0xDEADBEEF, 0x0});291  GraphResult Result =292      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF, 0x0});293  EXPECT_THAT(Result.OrphanedNodes, IsEmpty());294  EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());295 296  Result = GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 1, 0x0});297  EXPECT_THAT(Result.OrphanedNodes, IsEmpty());298  EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());299 300  Result = GraphBuilder::buildFlowGraph(Analysis, {0xDEADC0DE, 0x0});301  EXPECT_THAT(Result.OrphanedNodes, IsEmpty());302  EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());303}304 305TEST_F(BasicGraphBuilderTest, BuildFlowGraphNoXrefs) {306  if (!SuccessfullyInitialised)307    GTEST_SKIP();308  Analysis.parseSectionContents(309      {310          0xeb, 0xfe, // 0: jmp 0 [-2]311          0xff, 0x10, // 2: callq *(%rax)312      },313      {0xDEADBEEF, 0x0});314  GraphResult Result =315      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 2, 0x0});316  EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());317  EXPECT_THAT(Result.OrphanedNodes, ElementsAre(0xDEADBEEF + 2));318  EXPECT_THAT(Result.IntermediateNodes, IsEmpty());319}320 321TEST_F(BasicGraphBuilderTest, BuildFlowGraphConditionalInfiniteLoop) {322  if (!SuccessfullyInitialised)323    GTEST_SKIP();324  Analysis.parseSectionContents(325      {326          0x75, 0xfe, // 0: jne 0 [-2]327          0xff, 0x10, // 2: callq *(%rax)328      },329      {0xDEADBEEF, 0x0});330  GraphResult Result =331      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 2, 0x0});332  EXPECT_THAT(Result.OrphanedNodes, IsEmpty());333  EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1));334  EXPECT_THAT(335      Result.ConditionalBranchNodes,336      Each(AllOf(Field(&ConditionalBranchNode::CFIProtection, Eq(false)),337                 Field(&ConditionalBranchNode::Target,338                       HasPath(Result, ElementsAre(0xDEADBEEF))),339                 Field(&ConditionalBranchNode::Fallthrough,340                       HasPath(Result, ElementsAre(0xDEADBEEF + 2))))))341      << PrintToString(Result);342}343 344TEST_F(BasicGraphBuilderTest, BuildFlowGraphUnconditionalInfiniteLoop) {345  if (!SuccessfullyInitialised)346    GTEST_SKIP();347  Analysis.parseSectionContents(348      {349          0x75, 0x02, // 0: jne 4 [+2]350          0xeb, 0xfc, // 2: jmp 0 [-4]351          0xff, 0x10, // 4: callq *(%rax)352      },353      {0xDEADBEEF, 0x0});354  GraphResult Result =355      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 4, 0x0});356  EXPECT_THAT(Result.OrphanedNodes, IsEmpty());357  EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(1));358  EXPECT_THAT(359      Result.ConditionalBranchNodes,360      Contains(361          AllOf(Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),362                Field(&ConditionalBranchNode::Fallthrough,363                      HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF))),364                Field(&ConditionalBranchNode::Target,365                      HasPath(Result, ElementsAre(0xDEADBEEF + 4))))))366      << PrintToString(Result);367}368 369TEST_F(BasicGraphBuilderTest, BuildFlowGraphNoFlowsToIndirection) {370  if (!SuccessfullyInitialised)371    GTEST_SKIP();372  Analysis.parseSectionContents(373      {374          0x75, 0x00, // 0: jne 2 [+0]375          0xeb, 0xfc, // 2: jmp 0 [-4]376          0xff, 0x10, // 4: callq *(%rax)377      },378      {0xDEADBEEF, 0x0});379  GraphResult Result =380      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 4, 0x0});381  EXPECT_THAT(Result.OrphanedNodes, ElementsAre(0xDEADBEEF + 4));382  EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());383}384 385TEST_F(BasicGraphBuilderTest, BuildFlowGraphLengthExceededUpwards) {386  if (!SuccessfullyInitialised)387    GTEST_SKIP();388  Analysis.parseSectionContents(389      {390          0x75, 0x06, // 0: jne 8 [+6]391          0x90,       // 2: nop392          0x90,       // 3: nop393          0x90,       // 4: nop394          0x90,       // 5: nop395          0xff, 0x10, // 6: callq *(%rax)396          0x0f, 0x0b, // 8: ud2397      },398      {0xDEADBEEF, 0x0});399  uint64_t PrevSearchLengthForConditionalBranch =400      SearchLengthForConditionalBranch;401  SearchLengthForConditionalBranch = 2;402 403  GraphResult Result =404      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 6, 0x0});405  EXPECT_THAT(Result.OrphanedNodes, SizeIs(1));406  EXPECT_THAT(Result.OrphanedNodes,407              Each(HasPath(Result, ElementsAre(0xDEADBEEF + 4, 0xDEADBEEF + 5,408                                               0xDEADBEEF + 6))))409      << PrintToString(Result);410  EXPECT_THAT(Result.ConditionalBranchNodes, IsEmpty());411 412  SearchLengthForConditionalBranch = PrevSearchLengthForConditionalBranch;413}414 415TEST_F(BasicGraphBuilderTest, BuildFlowGraphLengthExceededDownwards) {416  if (!SuccessfullyInitialised)417    GTEST_SKIP();418  Analysis.parseSectionContents(419      {420          0x75, 0x02, // 0: jne 4 [+2]421          0xff, 0x10, // 2: callq *(%rax)422          0x90,       // 4: nop423          0x90,       // 5: nop424          0x90,       // 6: nop425          0x90,       // 7: nop426          0x0f, 0x0b, // 8: ud2427      },428      {0xDEADBEEF, 0x0});429  uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;430  SearchLengthForUndef = 2;431 432  GraphResult Result =433      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 2, 0x0});434  EXPECT_THAT(Result.OrphanedNodes, IsEmpty());435  EXPECT_THAT(436      Result.ConditionalBranchNodes,437      Each(AllOf(438          Field(&ConditionalBranchNode::CFIProtection, Eq(false)),439          Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),440          Field(&ConditionalBranchNode::Target,441                HasPath(Result, ElementsAre(0xDEADBEEF + 4, 0xDEADBEEF + 5))),442          Field(&ConditionalBranchNode::Fallthrough,443                HasPath(Result, ElementsAre(0xDEADBEEF + 2))))))444      << PrintToString(Result);445 446  SearchLengthForUndef = PrevSearchLengthForUndef;447}448 449// This test ensures when avoiding doing repeated work we still generate the450// paths correctly. We don't need to recalculate the flow from 0x2 -> 0x3 as it451// should only need to be generated once.452TEST_F(BasicGraphBuilderTest, BuildFlowGraphWithRepeatedWork) {453  if (!SuccessfullyInitialised)454    GTEST_SKIP();455  Analysis.parseSectionContents(456      {457          0x75, 0x05, // 0: jne 7 [+5]458          0x90,       // 2: nop459          0xff, 0x10, // 3: callq *(%rax)460          0x75, 0xfb, // 5: jne 2 [-5]461          0x0f, 0x0b, // 7: ud2462      },463      {0xDEADBEEF, 0x0});464  GraphResult Result =465      GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 3, 0x0});466  EXPECT_THAT(Result.OrphanedNodes, IsEmpty());467  EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(2));468  EXPECT_THAT(469      Result.ConditionalBranchNodes,470      Contains(AllOf(471          Field(&ConditionalBranchNode::CFIProtection, Eq(true)),472          Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF)),473          Field(&ConditionalBranchNode::Target,474                HasPath(Result, ElementsAre(0xDEADBEEF + 7))),475          Field(&ConditionalBranchNode::Fallthrough,476                HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))))))477      << PrintToString(Result);478  EXPECT_THAT(479      Result.ConditionalBranchNodes,480      Contains(AllOf(481          Field(&ConditionalBranchNode::CFIProtection, Eq(true)),482          Field(&ConditionalBranchNode::Address, Eq(0xDEADBEEF + 5)),483          Field(&ConditionalBranchNode::Target,484                HasPath(Result, ElementsAre(0xDEADBEEF + 2, 0xDEADBEEF + 3))),485          Field(&ConditionalBranchNode::Fallthrough,486                HasPath(Result, ElementsAre(0xDEADBEEF + 7))))))487      << PrintToString(Result);488  EXPECT_THAT(Result.IntermediateNodes, SizeIs(1));489  EXPECT_THAT(Result.IntermediateNodes,490              UnorderedElementsAre(Pair(0xDEADBEEF + 2, 0xDEADBEEF + 3)));491}492 493TEST_F(BasicGraphBuilderTest, BuildFlowGraphComplexExample) {494  if (!SuccessfullyInitialised)495    GTEST_SKIP();496  // The following code has this graph:497  //  +----------+      +--------------+498  //  |    20    | <--- |      0       |499  //  +----------+      +--------------+500  //    |                 |501  //    v                 v502  //  +----------+      +--------------+503  //  |    21    |      |      2       |504  //  +----------+      +--------------+505  //    |                 |506  //    v                 v507  //  +----------+      +--------------+508  //  | 22 (ud2) |  +-> |      7       |509  //  +----------+  |   +--------------+510  //    ^           |     |511  //    |           |     v512  //  +----------+  |   +--------------+513  //  |    4     |  |   |      8       |514  //  +----------+  |   +--------------+515  //    |           |     |516  //    v           |     v517  //  +----------+  |   +--------------+    +------------+518  //  |    6     | -+   | 9 (indirect) | <- |     13     |519  //  +----------+      +--------------+    +------------+520  //                      ^                   |521  //                      |                   v522  //                    +--------------+    +------------+523  //                    |      11      |    | 15 (error) |524  //                    +--------------+    +------------+525  // Or, in image format: https://i.imgur.com/aX5fCoi.png526 527  Analysis.parseSectionContents(528      {529          0x75, 0x12,                   // 0: jne 20 [+18]530          0xeb, 0x03,                   // 2: jmp 7 [+3]531          0x75, 0x10,                   // 4: jne 22 [+16]532          0x90,                         // 6: nop533          0x90,                         // 7: nop534          0x90,                         // 8: nop535          0xff, 0x10,                   // 9: callq *(%rax)536          0xeb, 0xfc,                   // 11: jmp 9 [-4]537          0x75, 0xfa,                   // 13: jne 9 [-6]538          0xe8, 0x78, 0x56, 0x34, 0x12, // 15: callq OUTOFBOUNDS [+0x12345678]539          0x90,                         // 20: nop540          0x90,                         // 21: nop541          0x0f, 0x0b,                   // 22: ud2542      },543      {0x1000, 0x0});544  uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;545  SearchLengthForUndef = 5;546 547  GraphResult Result =548      GraphBuilder::buildFlowGraph(Analysis, {0x1000 + 9, 0x0});549 550  EXPECT_THAT(Result.OrphanedNodes, SizeIs(1));551  EXPECT_THAT(Result.ConditionalBranchNodes, SizeIs(3));552 553  EXPECT_THAT(554      Result.OrphanedNodes,555      Each(AllOf(Eq(0x1000u + 11),556                 HasPath(Result, ElementsAre(0x1000 + 11, 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)),563                  Field(&ConditionalBranchNode::Target,564                        HasPath(Result, ElementsAre(0x1000 + 20, 0x1000 + 21,565                                                    0x1000 + 22))),566                  Field(&ConditionalBranchNode::Fallthrough,567                        HasPath(Result, ElementsAre(0x1000 + 2, 0x1000 + 7,568                                                    0x1000 + 8, 0x1000 + 9))))))569      << PrintToString(Result);570 571  EXPECT_THAT(Result.ConditionalBranchNodes,572              Contains(AllOf(573                  Field(&ConditionalBranchNode::CFIProtection, Eq(true)),574                  Field(&ConditionalBranchNode::Address, Eq(0x1000u + 4)),575                  Field(&ConditionalBranchNode::Target,576                        HasPath(Result, ElementsAre(0x1000 + 22))),577                  Field(&ConditionalBranchNode::Fallthrough,578                        HasPath(Result, ElementsAre(0x1000 + 6, 0x1000 + 7,579                                                    0x1000 + 8, 0x1000 + 9))))))580      << PrintToString(Result);581 582  EXPECT_THAT(583      Result.ConditionalBranchNodes,584      Contains(AllOf(Field(&ConditionalBranchNode::CFIProtection, Eq(false)),585                     Field(&ConditionalBranchNode::Address, Eq(0x1000u + 13)),586                     Field(&ConditionalBranchNode::Target,587                           HasPath(Result, ElementsAre(0x1000 + 9))),588                     Field(&ConditionalBranchNode::Fallthrough,589                           HasPath(Result, ElementsAre(0x1000 + 15))))))590      << PrintToString(Result);591 592  SearchLengthForUndef = PrevSearchLengthForUndef;593}594 595} // anonymous namespace596} // end namespace cfi_verify597} // end namespace llvm598