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 if (Analysis.initialiseDisassemblyMembers()) { 130 FAIL() << "Failed to initialise FileAnalysis."; 131 } 132 } 133 134 ELFx86TestFileAnalysis Analysis; 135 }; 136 137 MATCHER_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 143 TEST_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 167 TEST_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 191 TEST_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 228 TEST_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 264 TEST_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 284 TEST_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 297 TEST_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 317 TEST_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 339 TEST_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 352 TEST_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 379 TEST_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. 413 TEST_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 451 TEST_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 553