brintos

brintos / llvm-project-archived public Read only

0
0
Text · 70.4 KiB · d70e13d Raw
1670 lines · cpp
1//===- llvm/unittest/DebugInfo/DWARFDebugFrameTest.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 "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"10#include "llvm/ADT/DenseSet.h"11#include "llvm/ADT/SmallVector.h"12#include "llvm/ADT/StringRef.h"13#include "llvm/BinaryFormat/Dwarf.h"14#include "llvm/DebugInfo/DIContext.h"15#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"16#include "llvm/DebugInfo/DWARF/DWARFUnwindTablePrinter.h"17#include "llvm/Testing/Support/Error.h"18#include "gtest/gtest.h"19 20using namespace llvm;21 22namespace {23 24dwarf::CIE createCIE(bool IsDWARF64, uint64_t Offset, uint64_t Length) {25  return dwarf::CIE(IsDWARF64, Offset, Length,26                    /*Version=*/3,27                    /*Augmentation=*/StringRef(),28                    /*AddressSize=*/8,29                    /*SegmentDescriptorSize=*/0,30                    /*CodeAlignmentFactor=*/1,31                    /*DataAlignmentFactor=*/-8,32                    /*ReturnAddressRegister=*/16,33                    /*AugmentationData=*/StringRef(),34                    /*FDEPointerEncoding=*/dwarf::DW_EH_PE_absptr,35                    /*LSDAPointerEncoding=*/dwarf::DW_EH_PE_omit,36                    /*Personality=*/std::nullopt,37                    /*PersonalityEnc=*/std::nullopt,38                    /*Arch=*/Triple::x86_64);39}40 41void expectDumpResult(const dwarf::CIE &TestCIE, bool IsEH,42                      StringRef ExpectedFirstLine) {43  std::string Output;44  raw_string_ostream OS(Output);45  auto DumpOpts = DIDumpOptions();46  DumpOpts.IsEH = IsEH;47  TestCIE.dump(OS, DumpOpts);48  StringRef FirstLine = StringRef(Output).split('\n').first;49  EXPECT_EQ(FirstLine, ExpectedFirstLine);50}51 52void expectDumpResult(const dwarf::FDE &TestFDE, bool IsEH,53                      StringRef ExpectedFirstLine) {54  std::string Output;55  raw_string_ostream OS(Output);56  auto DumpOpts = DIDumpOptions();57  DumpOpts.IsEH = IsEH;58  TestFDE.dump(OS, DumpOpts);59  StringRef FirstLine = StringRef(Output).split('\n').first;60  EXPECT_EQ(FirstLine, ExpectedFirstLine);61}62 63TEST(DWARFDebugFrame, DumpDWARF32CIE) {64  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,65                                 /*Offset=*/0x1111abcd,66                                 /*Length=*/0x2222abcd);67  expectDumpResult(TestCIE, /*IsEH=*/false, "1111abcd 2222abcd ffffffff CIE");68}69 70TEST(DWARFDebugFrame, DumpDWARF64CIE) {71  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/true,72                                 /*Offset=*/0x1111abcdabcd,73                                 /*Length=*/0x2222abcdabcd);74  expectDumpResult(TestCIE, /*IsEH=*/false,75                   "1111abcdabcd 00002222abcdabcd ffffffffffffffff CIE");76}77 78TEST(DWARFDebugFrame, DumpEHCIE) {79  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,80                                 /*Offset=*/0x1000,81                                 /*Length=*/0x20);82  expectDumpResult(TestCIE, /*IsEH=*/true, "00001000 00000020 00000000 CIE");83}84 85TEST(DWARFDebugFrame, DumpEH64CIE) {86  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/true,87                                 /*Offset=*/0x1000,88                                 /*Length=*/0x20);89  expectDumpResult(TestCIE, /*IsEH=*/true,90                   "00001000 0000000000000020 00000000 CIE");91}92 93TEST(DWARFDebugFrame, DumpDWARF64FDE) {94  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/true,95                                 /*Offset=*/0x1111abcdabcd,96                                 /*Length=*/0x2222abcdabcd);97  dwarf::FDE TestFDE(/*IsDWARF64=*/true,98                     /*Offset=*/0x3333abcdabcd,99                     /*Length=*/0x4444abcdabcd,100                     /*CIEPointer=*/0x1111abcdabcd,101                     /*InitialLocation=*/0x5555abcdabcd,102                     /*AddressRange=*/0x111111111111,103                     /*Cie=*/&TestCIE,104                     /*LSDAAddress=*/std::nullopt,105                     /*Arch=*/Triple::x86_64);106  expectDumpResult(TestFDE, /*IsEH=*/false,107                   "3333abcdabcd 00004444abcdabcd 00001111abcdabcd FDE "108                   "cie=1111abcdabcd pc=5555abcdabcd...6666bcdebcde");109}110 111TEST(DWARFDebugFrame, DumpEH64FDE) {112  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/true,113                                 /*Offset=*/0x1111ab9a000c,114                                 /*Length=*/0x20);115  dwarf::FDE TestFDE(/*IsDWARF64=*/true,116                     /*Offset=*/0x1111abcdabcd,117                     /*Length=*/0x2222abcdabcd,118                     /*CIEPointer=*/0x33abcd,119                     /*InitialLocation=*/0x4444abcdabcd,120                     /*AddressRange=*/0x111111111111,121                     /*Cie=*/&TestCIE,122                     /*LSDAAddress=*/std::nullopt,123                     /*Arch=*/Triple::x86_64);124  expectDumpResult(TestFDE, /*IsEH=*/true,125                   "1111abcdabcd 00002222abcdabcd 0033abcd FDE "126                   "cie=1111ab9a000c pc=4444abcdabcd...5555bcdebcde");127}128 129static Error parseCFI(dwarf::CIE &C, ArrayRef<uint8_t> Instructions,130                      std::optional<uint64_t> Size = std::nullopt) {131  DWARFDataExtractor Data(Instructions, /*IsLittleEndian=*/true,132                          /*AddressSize=*/8);133  uint64_t Offset = 0;134  const uint64_t EndOffset = Size ? *Size : (uint64_t)Instructions.size();135  return C.cfis().parse(Data, &Offset, EndOffset);136}137 138static Error parseCFI(dwarf::FDE &FDE, ArrayRef<uint8_t> Instructions) {139  DWARFDataExtractor Data(Instructions, /*IsLittleEndian=*/true,140                          /*AddressSize=*/8);141  uint64_t Offset = 0;142  return FDE.cfis().parse(Data, &Offset, Instructions.size());143}144 145TEST(DWARFDebugFrame, InvalidCFIOpcodesTest) {146  llvm::DenseSet<uint8_t> ValidExtendedOpcodes = {147      dwarf::DW_CFA_nop,148      dwarf::DW_CFA_advance_loc,149      dwarf::DW_CFA_offset,150      dwarf::DW_CFA_restore,151      dwarf::DW_CFA_set_loc,152      dwarf::DW_CFA_advance_loc1,153      dwarf::DW_CFA_advance_loc2,154      dwarf::DW_CFA_advance_loc4,155      dwarf::DW_CFA_offset_extended,156      dwarf::DW_CFA_restore_extended,157      dwarf::DW_CFA_undefined,158      dwarf::DW_CFA_same_value,159      dwarf::DW_CFA_register,160      dwarf::DW_CFA_remember_state,161      dwarf::DW_CFA_restore_state,162      dwarf::DW_CFA_def_cfa,163      dwarf::DW_CFA_def_cfa_register,164      dwarf::DW_CFA_def_cfa_offset,165      dwarf::DW_CFA_def_cfa_expression,166      dwarf::DW_CFA_expression,167      dwarf::DW_CFA_offset_extended_sf,168      dwarf::DW_CFA_def_cfa_sf,169      dwarf::DW_CFA_def_cfa_offset_sf,170      dwarf::DW_CFA_LLVM_def_aspace_cfa,171      dwarf::DW_CFA_LLVM_def_aspace_cfa_sf,172      dwarf::DW_CFA_val_offset,173      dwarf::DW_CFA_val_offset_sf,174      dwarf::DW_CFA_val_expression,175      dwarf::DW_CFA_MIPS_advance_loc8,176      dwarf::DW_CFA_GNU_window_save,177      dwarf::DW_CFA_AARCH64_negate_ra_state,178      dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc,179      dwarf::DW_CFA_GNU_args_size};180 181  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,182                                 /*Offset=*/0x0,183                                 /*Length=*/0xff);184 185  // See DWARF standard v3, section 7.23: low 6 bits are used to encode an186  // extended opcode.187  for (uint8_t Code = 0; Code <= 63; ++Code) {188    if (ValidExtendedOpcodes.count(Code))189      continue;190 191    EXPECT_THAT_ERROR(parseCFI(TestCIE, Code),192                      FailedWithMessage(("invalid extended CFI opcode 0x" +193                                         Twine::utohexstr(Code))194                                            .str()195                                            .c_str()));196  }197}198 199// Here we test how truncated Call Frame Instructions are parsed.200TEST(DWARFDebugFrame, ParseTruncatedCFITest) {201  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,202                                 /*Offset=*/0x0,203                                 /*Length=*/0xff);204 205  // Having an empty instructions list is fine.206  EXPECT_THAT_ERROR(parseCFI(TestCIE, {}), Succeeded());207 208  // Unable to read an opcode, because the instructions list is empty, but we209  // say to the parser that it is not.210  EXPECT_THAT_ERROR(211      parseCFI(TestCIE, {}, /*Size=*/1),212      FailedWithMessage(213          "unexpected end of data at offset 0x0 while reading [0x0, 0x1)"));214 215  // Unable to read a truncated DW_CFA_offset instruction.216  EXPECT_THAT_ERROR(217      parseCFI(TestCIE, {dwarf::DW_CFA_offset}),218      FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "219                        "malformed uleb128, extends past end"));220 221  // Unable to read a truncated DW_CFA_set_loc instruction.222  EXPECT_THAT_ERROR(223      parseCFI(TestCIE, {dwarf::DW_CFA_set_loc}),224      FailedWithMessage(225          "unexpected end of data at offset 0x1 while reading [0x1, 0x9)"));226 227  // Unable to read a truncated DW_CFA_advance_loc1 instruction.228  EXPECT_THAT_ERROR(229      parseCFI(TestCIE, {dwarf::DW_CFA_advance_loc1}),230      FailedWithMessage(231          "unexpected end of data at offset 0x1 while reading [0x1, 0x2)"));232 233  // Unable to read a truncated DW_CFA_advance_loc2 instruction.234  EXPECT_THAT_ERROR(235      parseCFI(TestCIE, {dwarf::DW_CFA_advance_loc2}),236      FailedWithMessage(237          "unexpected end of data at offset 0x1 while reading [0x1, 0x3)"));238 239  // Unable to read a truncated DW_CFA_advance_loc4 instruction.240  EXPECT_THAT_ERROR(241      parseCFI(TestCIE, {dwarf::DW_CFA_advance_loc4}),242      FailedWithMessage(243          "unexpected end of data at offset 0x1 while reading [0x1, 0x5)"));244 245  // A test for an instruction with a single ULEB128 operand.246  auto CheckOp_ULEB128 = [&](uint8_t Inst) {247    EXPECT_THAT_ERROR(248        parseCFI(TestCIE, Inst),249        FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "250                          "malformed uleb128, extends past end"));251  };252 253  for (uint8_t Inst :254       {dwarf::DW_CFA_restore_extended, dwarf::DW_CFA_undefined,255        dwarf::DW_CFA_same_value, dwarf::DW_CFA_def_cfa_register,256        dwarf::DW_CFA_def_cfa_offset, dwarf::DW_CFA_GNU_args_size})257    CheckOp_ULEB128(Inst);258 259  // Unable to read a truncated DW_CFA_def_cfa_offset_sf instruction.260  EXPECT_THAT_ERROR(261      parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_offset_sf}),262      FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "263                        "malformed sleb128, extends past end"));264 265  // A test for an instruction with two ULEB128 operands.266  auto CheckOp_ULEB128_ULEB128 = [&](uint8_t Inst) {267    EXPECT_THAT_ERROR(268        parseCFI(TestCIE, Inst),269        FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "270                          "malformed uleb128, extends past end"));271 272    EXPECT_THAT_ERROR(273        parseCFI(TestCIE, {Inst, /*Op1=*/0}),274        FailedWithMessage("unable to decode LEB128 at offset 0x00000002: "275                          "malformed uleb128, extends past end"));276  };277 278  for (uint8_t Inst : {dwarf::DW_CFA_offset_extended, dwarf::DW_CFA_register,279                       dwarf::DW_CFA_def_cfa, dwarf::DW_CFA_LLVM_def_aspace_cfa,280                       dwarf::DW_CFA_val_offset})281    CheckOp_ULEB128_ULEB128(Inst);282 283  // A test for an instruction with two operands: ULEB128, SLEB128.284  auto CheckOp_ULEB128_SLEB128 = [&](uint8_t Inst) {285    EXPECT_THAT_ERROR(286        parseCFI(TestCIE, Inst),287        FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "288                          "malformed uleb128, extends past end"));289 290    EXPECT_THAT_ERROR(291        parseCFI(TestCIE, {Inst, /*Op1=*/0}),292        FailedWithMessage("unable to decode LEB128 at offset 0x00000002: "293                          "malformed sleb128, extends past end"));294  };295 296  for (uint8_t Inst :297       {dwarf::DW_CFA_offset_extended_sf, dwarf::DW_CFA_def_cfa_sf,298        dwarf::DW_CFA_LLVM_def_aspace_cfa_sf, dwarf::DW_CFA_val_offset_sf})299    CheckOp_ULEB128_SLEB128(Inst);300 301  // Unable to read a truncated DW_CFA_def_cfa_expression instruction.302  EXPECT_THAT_ERROR(303      parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_expression}),304      FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "305                        "malformed uleb128, extends past end"));306  EXPECT_THAT_ERROR(307      parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_expression,308                         /*expression length=*/0x1}),309      FailedWithMessage(310          "unexpected end of data at offset 0x2 while reading [0x2, 0x3)"));311  // The DW_CFA_def_cfa_expression can contain a zero length expression.312  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_expression,313                                       /*ExprLen=*/0}),314                    Succeeded());315 316  // A test for an instruction with three operands: ULEB128, expression length317  // (ULEB128) and expression bytes.318  auto CheckOp_ULEB128_Expr = [&](uint8_t Inst) {319    EXPECT_THAT_ERROR(320        parseCFI(TestCIE, {Inst}),321        FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "322                          "malformed uleb128, extends past end"));323    EXPECT_THAT_ERROR(324        parseCFI(TestCIE, {Inst, /*Op1=*/0}),325        FailedWithMessage("unable to decode LEB128 at offset 0x00000002: "326                          "malformed uleb128, extends past end"));327    // A zero length expression is fine328    EXPECT_THAT_ERROR(parseCFI(TestCIE, {Inst,329                                         /*Op1=*/0, /*ExprLen=*/0}),330                      Succeeded());331    EXPECT_THAT_ERROR(332        parseCFI(TestCIE, {Inst,333                           /*Op1=*/0, /*ExprLen=*/1}),334        FailedWithMessage(335            "unexpected end of data at offset 0x3 while reading [0x3, 0x4)"));336  };337 338  for (uint8_t Inst : {dwarf::DW_CFA_expression, dwarf::DW_CFA_val_expression})339    CheckOp_ULEB128_Expr(Inst);340}341 342void expectDumpResult(const dwarf::UnwindLocation &Loc,343                      StringRef ExpectedFirstLine) {344  std::string Output;345  raw_string_ostream OS(Output);346  OS << Loc;347  StringRef FirstLine = StringRef(Output).split('\n').first;348  EXPECT_EQ(FirstLine, ExpectedFirstLine);349}350 351TEST(DWARFDebugFrame, DumpUnwindLocations) {352  // Test constructing unwind locations and dumping each kind.353  constexpr int32_t PlusOff = 8;354  constexpr int32_t MinusOff = -8;355  constexpr uint8_t RegNum = 12;356  expectDumpResult(dwarf::UnwindLocation::createUnspecified(), "unspecified");357  expectDumpResult(dwarf::UnwindLocation::createUndefined(), "undefined");358  expectDumpResult(dwarf::UnwindLocation::createSame(), "same");359  expectDumpResult(dwarf::UnwindLocation::createIsCFAPlusOffset(PlusOff),360                   "CFA+8");361  expectDumpResult(dwarf::UnwindLocation::createIsCFAPlusOffset(MinusOff),362                   "CFA-8");363  expectDumpResult(dwarf::UnwindLocation::createAtCFAPlusOffset(PlusOff),364                   "[CFA+8]");365  expectDumpResult(dwarf::UnwindLocation::createAtCFAPlusOffset(MinusOff),366                   "[CFA-8]");367 368  expectDumpResult(369      dwarf::UnwindLocation::createIsRegisterPlusOffset(RegNum, PlusOff),370      "reg12+8");371  expectDumpResult(372      dwarf::UnwindLocation::createIsRegisterPlusOffset(RegNum, MinusOff),373      "reg12-8");374  expectDumpResult(375      dwarf::UnwindLocation::createAtRegisterPlusOffset(RegNum, PlusOff),376      "[reg12+8]");377  expectDumpResult(378      dwarf::UnwindLocation::createAtRegisterPlusOffset(RegNum, MinusOff),379      "[reg12-8]");380  expectDumpResult(dwarf::UnwindLocation::createIsConstant(12), "12");381  expectDumpResult(dwarf::UnwindLocation::createIsConstant(-32), "-32");382}383 384void expectDumpResult(const dwarf::RegisterLocations &Locs,385                      StringRef ExpectedFirstLine) {386  std::string Output;387  raw_string_ostream OS(Output);388  OS << Locs;389  StringRef FirstLine = StringRef(Output).split('\n').first;390  EXPECT_EQ(FirstLine, ExpectedFirstLine);391}392 393TEST(DWARFDebugFrame, RegisterLocations) {394  // Test the functionality of the RegisterLocations class.395  dwarf::RegisterLocations Locs;396  expectDumpResult(Locs, "");397  EXPECT_FALSE(Locs.hasLocations());398  // Set a register location for reg12 to unspecified and verify it dumps399  // correctly.400  Locs.setRegisterLocation(12, dwarf::UnwindLocation::createUnspecified());401  EXPECT_TRUE(Locs.hasLocations());402  expectDumpResult(Locs, "reg12=unspecified");403 404  // Replace the register location for reg12 to "same" and verify it dumps405  // correctly after it is modified406  Locs.setRegisterLocation(12, dwarf::UnwindLocation::createSame());407  EXPECT_TRUE(Locs.hasLocations());408  expectDumpResult(Locs, "reg12=same");409 410  // Remove the register location for reg12 verify it dumps correctly after it411  // is removed.412  Locs.removeRegisterLocation(12);413  EXPECT_FALSE(Locs.hasLocations());414  expectDumpResult(Locs, "");415 416  // Verify multiple registers added to the list dump correctly.417  auto Reg12Loc = dwarf::UnwindLocation::createAtCFAPlusOffset(4);418  auto Reg13Loc = dwarf::UnwindLocation::createAtCFAPlusOffset(8);419  auto Reg14Loc = dwarf::UnwindLocation::createSame();420  Locs.setRegisterLocation(12, Reg12Loc);421  Locs.setRegisterLocation(13, Reg13Loc);422  Locs.setRegisterLocation(14, Reg14Loc);423  EXPECT_TRUE(Locs.hasLocations());424  expectDumpResult(Locs, "reg12=[CFA+4], reg13=[CFA+8], reg14=same");425 426  // Verify RegisterLocations::getRegisterLocation() works as expected.427  std::optional<dwarf::UnwindLocation> OptionalLoc;428  OptionalLoc = Locs.getRegisterLocation(0);429  EXPECT_FALSE(OptionalLoc.has_value());430 431  OptionalLoc = Locs.getRegisterLocation(12);432  EXPECT_TRUE(OptionalLoc.has_value());433  EXPECT_EQ(*OptionalLoc, Reg12Loc);434 435  OptionalLoc = Locs.getRegisterLocation(13);436  EXPECT_TRUE(OptionalLoc.has_value());437  EXPECT_EQ(*OptionalLoc, Reg13Loc);438 439  OptionalLoc = Locs.getRegisterLocation(14);440  EXPECT_TRUE(OptionalLoc.has_value());441  EXPECT_EQ(*OptionalLoc, Reg14Loc);442 443  // Verify registers are correctly removed when multiple exist in the list.444  Locs.removeRegisterLocation(13);445  EXPECT_FALSE(Locs.getRegisterLocation(13).has_value());446  EXPECT_TRUE(Locs.hasLocations());447  expectDumpResult(Locs, "reg12=[CFA+4], reg14=same");448  Locs.removeRegisterLocation(14);449  EXPECT_FALSE(Locs.getRegisterLocation(14).has_value());450  EXPECT_TRUE(Locs.hasLocations());451  expectDumpResult(Locs, "reg12=[CFA+4]");452  Locs.removeRegisterLocation(12);453  EXPECT_FALSE(Locs.getRegisterLocation(12).has_value());454  EXPECT_FALSE(Locs.hasLocations());455  expectDumpResult(Locs, "");456}457 458// Test that empty rows are not added to UnwindTable when459// dwarf::CIE::CFIs or dwarf::FDE::CFIs is empty.460TEST(DWARFDebugFrame, UnwindTableEmptyRows) {461  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,462                                 /*Offset=*/0x0,463                                 /*Length=*/0xff);464 465  // Having an empty instructions list is fine.466  EXPECT_THAT_ERROR(parseCFI(TestCIE, {}), Succeeded());467  EXPECT_TRUE(TestCIE.cfis().empty());468 469  // Verify dwarf::createUnwindTable() won't result in errors and470  // and empty rows are not added to CIE UnwindTable.471  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestCIE);472  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());473  const size_t ExpectedNumOfRows = 0;474  EXPECT_EQ(RowsOrErr->size(), ExpectedNumOfRows);475 476  dwarf::FDE TestFDE(/*IsDWARF64=*/true,477                     /*Offset=*/0x3333abcdabcd,478                     /*Length=*/0x4444abcdabcd,479                     /*CIEPointer=*/0x1111abcdabcd,480                     /*InitialLocation=*/0x1000,481                     /*AddressRange=*/0x1000,482                     /*Cie=*/&TestCIE,483                     /*LSDAAddress=*/std::nullopt,484                     /*Arch=*/Triple::x86_64);485 486  // Having an empty instructions list is fine.487  EXPECT_THAT_ERROR(parseCFI(TestFDE, {}), Succeeded());488  EXPECT_TRUE(TestFDE.cfis().empty());489 490  // Verify dwarf::createUnwindTable() won't result in errors and491  // and empty rows are not added to FDE UnwindTable.492  RowsOrErr = dwarf::createUnwindTable(&TestFDE);493  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());494  EXPECT_EQ(RowsOrErr->size(), ExpectedNumOfRows);495}496 497// Test that empty rows are not added to UnwindTable when dwarf::CIE::CFIs498// or dwarf::FDE::CFIs is not empty but has only DW_CFA_nop instructions.499TEST(DWARFDebugFrame, UnwindTableEmptyRows_NOPs) {500  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,501                                 /*Offset=*/0x0,502                                 /*Length=*/0xff);503 504  // Make a CIE that has only DW_CFA_nop instructions.505  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_nop}), Succeeded());506  EXPECT_TRUE(!TestCIE.cfis().empty());507 508  // Verify dwarf::createUnwindTable() won't result in errors and509  // and empty rows are not added to CIE UnwindTable.510  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestCIE);511  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());512  const size_t ExpectedNumOfRows = 0;513  EXPECT_EQ(RowsOrErr->size(), ExpectedNumOfRows);514 515  dwarf::FDE TestFDE(/*IsDWARF64=*/true,516                     /*Offset=*/0x3333abcdabcd,517                     /*Length=*/0x4444abcdabcd,518                     /*CIEPointer=*/0x1111abcdabcd,519                     /*InitialLocation=*/0x1000,520                     /*AddressRange=*/0x1000,521                     /*Cie=*/&TestCIE,522                     /*LSDAAddress=*/std::nullopt,523                     /*Arch=*/Triple::x86_64);524 525  // Make an FDE that has only DW_CFA_nop instructions.526  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_nop}), Succeeded());527  EXPECT_TRUE(!TestFDE.cfis().empty());528 529  // Verify dwarf::createUnwindTable() won't result in errors and530  // and empty rows are not added to FDE UnwindTable.531  RowsOrErr = dwarf::createUnwindTable(&TestFDE);532  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());533  EXPECT_EQ(RowsOrErr->size(), ExpectedNumOfRows);534}535 536TEST(DWARFDebugFrame, UnwindTableErrorNonAscendingFDERows) {537  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,538                                 /*Offset=*/0x0,539                                 /*Length=*/0xff);540 541  dwarf::FDE TestFDE(/*IsDWARF64=*/true,542                     /*Offset=*/0x3333abcdabcd,543                     /*Length=*/0x4444abcdabcd,544                     /*CIEPointer=*/0x1111abcdabcd,545                     /*InitialLocation=*/0x1000,546                     /*AddressRange=*/0x1000,547                     /*Cie=*/&TestCIE,548                     /*LSDAAddress=*/std::nullopt,549                     /*Arch=*/Triple::x86_64);550 551  // Make a CIE that has a valid CFA definition.552  constexpr uint8_t Reg = 12;553  constexpr uint8_t Offset = 32;554  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, Reg, Offset}),555                    Succeeded());556 557  // Make a FDE with DWARF call frame instruction opcodes that have valid558  // syntax, but will cause an error when we parse them into a UnwindTable.559  // Here we encode two DW_CFA_set_loc opcodes:560  //   DW_CFA_set_loc(0x1100)561  //   DW_CFA_set_loc(0x1000)562  // These opcodes cause a new row to be appended to the rows in a UnwindTable563  // and the resulting rows are not in ascending address order and should cause564  // a state machine error.565  EXPECT_THAT_ERROR(566      parseCFI(TestFDE, {dwarf::DW_CFA_set_loc, 0x00, 0x11, 0, 0, 0, 0, 0, 0,567                         dwarf::DW_CFA_set_loc, 0x00, 0x10, 0, 0, 0, 0, 0, 0}),568      Succeeded());569 570  // Verify we catch state machine error.571  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);572  EXPECT_THAT_ERROR(RowsOrErr.takeError(),573                    FailedWithMessage("DW_CFA_set_loc with adrress 0x1000 which"574                                      " must be greater than the current row "575                                      "address 0x1100"));576}577 578TEST(DWARFDebugFrame, UnwindTableError_DW_CFA_restore_state) {579  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,580                                 /*Offset=*/0x0,581                                 /*Length=*/0xff);582 583  dwarf::FDE TestFDE(/*IsDWARF64=*/true,584                     /*Offset=*/0x3333abcdabcd,585                     /*Length=*/0x4444abcdabcd,586                     /*CIEPointer=*/0x1111abcdabcd,587                     /*InitialLocation=*/0x1000,588                     /*AddressRange=*/0x1000,589                     /*Cie=*/&TestCIE,590                     /*LSDAAddress=*/std::nullopt,591                     /*Arch=*/Triple::x86_64);592 593  // Make a CIE that has a valid CFA definition.594  constexpr uint8_t Reg = 12;595  constexpr uint8_t Offset = 32;596  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, Reg, Offset}),597                    Succeeded());598 599  // Make a FDE with DWARF call frame instruction opcodes that have valid600  // syntax, but will cause an error when we parse them into a UnwindTable.601  // Here we encode a DW_CFA_restore_state opcode that was not preceded by a602  // DW_CFA_remember_state, and an error should be returned.603  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_restore_state}),604                    Succeeded());605 606  // Verify we catch state machine error.607  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);608  EXPECT_THAT_ERROR(RowsOrErr.takeError(),609                    FailedWithMessage("DW_CFA_restore_state without a matching "610                                      "previous DW_CFA_remember_state"));611}612 613TEST(DWARFDebugFrame, UnwindTableError_DW_CFA_GNU_window_save) {614  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,615                                 /*Offset=*/0x0,616                                 /*Length=*/0xff);617 618  dwarf::FDE TestFDE(/*IsDWARF64=*/true,619                     /*Offset=*/0x3333abcdabcd,620                     /*Length=*/0x4444abcdabcd,621                     /*CIEPointer=*/0x1111abcdabcd,622                     /*InitialLocation=*/0x1000,623                     /*AddressRange=*/0x1000,624                     /*Cie=*/&TestCIE,625                     /*LSDAAddress=*/std::nullopt,626                     /*Arch=*/Triple::x86_64);627 628  // Make a CIE that has a valid CFA definition.629  constexpr uint8_t Reg = 12;630  constexpr uint8_t Offset = 32;631  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, Reg, Offset}),632                    Succeeded());633 634  // Make a FDE with DWARF call frame instruction opcodes that have valid635  // syntax, but will cause an error when we parse them into a UnwindTable.636  // Here we encode a DW_CFA_GNU_window_save that is not supported. I have not637  // found any documentation that describes what this does after some brief638  // searching.639  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_GNU_window_save}),640                    Succeeded());641 642  // Verify we catch state machine error.643  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);644  EXPECT_THAT_ERROR(RowsOrErr.takeError(),645                    FailedWithMessage("DW_CFA opcode 0x2d is not supported for "646                                      "architecture x86_64"));647}648 649TEST(DWARFDebugFrame, UnwindTableError_DW_CFA_def_cfa_offset) {650  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,651                                 /*Offset=*/0x0,652                                 /*Length=*/0xff);653 654  dwarf::FDE TestFDE(/*IsDWARF64=*/true,655                     /*Offset=*/0x3333abcdabcd,656                     /*Length=*/0x4444abcdabcd,657                     /*CIEPointer=*/0x1111abcdabcd,658                     /*InitialLocation=*/0x1000,659                     /*AddressRange=*/0x1000,660                     /*Cie=*/&TestCIE,661                     /*LSDAAddress=*/std::nullopt,662                     /*Arch=*/Triple::x86_64);663 664  // Make a CIE that has an invalid CFA definition. We do this so we can try665  // and use a DW_CFA_def_cfa_register opcode in the FDE and get an appropriate666  // error back.667  EXPECT_THAT_ERROR(parseCFI(TestCIE, {}), Succeeded());668 669  // Make a FDE with DWARF call frame instruction opcodes that have valid670  // syntax, but will cause an error when we parse them into a UnwindTable.671  // Here we encode a DW_CFA_def_cfa_offset with a offset of 16, but our CIE672  // didn't define the CFA in terms of a register plus offset, so this should673  // cause an error.674  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_def_cfa_offset, 16}),675                    Succeeded());676 677  // Verify we catch state machine error.678  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);679  EXPECT_THAT_ERROR(RowsOrErr.takeError(),680                    FailedWithMessage("DW_CFA_def_cfa_offset found when CFA "681                                      "rule was not RegPlusOffset"));682}683 684TEST(DWARFDebugFrame, UnwindTableDefCFAOffsetSFCFAError) {685  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,686                                 /*Offset=*/0x0,687                                 /*Length=*/0xff);688 689  dwarf::FDE TestFDE(/*IsDWARF64=*/true,690                     /*Offset=*/0x3333abcdabcd,691                     /*Length=*/0x4444abcdabcd,692                     /*CIEPointer=*/0x1111abcdabcd,693                     /*InitialLocation=*/0x1000,694                     /*AddressRange=*/0x1000,695                     /*Cie=*/&TestCIE,696                     /*LSDAAddress=*/std::nullopt,697                     /*Arch=*/Triple::x86_64);698 699  // Make a CIE that has an invalid CFA definition. We do this so we can try700  // and use a DW_CFA_def_cfa_offset_sf opcode in the FDE and get an701  // appropriate error back.702  EXPECT_THAT_ERROR(parseCFI(TestCIE, {}), Succeeded());703 704  // Make a FDE with DWARF call frame instruction opcodes that have valid705  // syntax, but will cause an error when we parse them into a UnwindTable.706  // Here we encode a DW_CFA_def_cfa_offset_sf with a offset of 4, but our CIE707  // didn't define the CFA in terms of a register plus offset, so this should708  // cause an error.709  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_def_cfa_offset_sf, 4}),710                    Succeeded());711 712  // Verify we catch state machine error.713  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);714  EXPECT_THAT_ERROR(RowsOrErr.takeError(),715                    FailedWithMessage("DW_CFA_def_cfa_offset_sf found when CFA "716                                      "rule was not RegPlusOffset"));717}718 719TEST(DWARFDebugFrame, UnwindTable_DW_CFA_def_cfa_register) {720  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,721                                 /*Offset=*/0x0,722                                 /*Length=*/0xff);723 724  dwarf::FDE TestFDE(/*IsDWARF64=*/true,725                     /*Offset=*/0x3333abcdabcd,726                     /*Length=*/0x4444abcdabcd,727                     /*CIEPointer=*/0x1111abcdabcd,728                     /*InitialLocation=*/0x1000,729                     /*AddressRange=*/0x1000,730                     /*Cie=*/&TestCIE,731                     /*LSDAAddress=*/std::nullopt,732                     /*Arch=*/Triple::x86_64);733 734  // Make a CIE that has only defines the CFA register with no offset. Some735  // architectures do this and we must ensure that we set the CFA value to be736  // equal to that register with no offset.737  constexpr uint8_t CFAReg = 12;738  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_register, CFAReg}),739                    Succeeded());740 741  // Make a FDE with DWARF call frame instruction opcodes that have valid742  // syntax, but will cause an error when we parse them into a UnwindTable.743  // Here we encode a DW_CFA_def_cfa_register with a register number of 12, but744  // our CIE didn't define the CFA in terms of a register plus offset, so this745  // should cause an error.746  EXPECT_THAT_ERROR(parseCFI(TestFDE, {}), Succeeded());747 748  // Verify we catch state machine error.749  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);750  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());751  const dwarf::UnwindTable &Rows = RowsOrErr.get();752  EXPECT_EQ(Rows.size(), 1u);753  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);754  EXPECT_EQ(Rows[0].getCFAValue(),755            dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg, 0));756}757 758TEST(DWARFDebugFrame, UnwindTableRowPushingOpcodes) {759  // Test all opcodes that should end up pushing a UnwindRow into a UnwindTable.760  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,761                                 /*Offset=*/0x0,762                                 /*Length=*/0xff);763 764  dwarf::FDE TestFDE(/*IsDWARF64=*/true,765                     /*Offset=*/0x3333abcdabcd,766                     /*Length=*/0x4444abcdabcd,767                     /*CIEPointer=*/0x1111abcdabcd,768                     /*InitialLocation=*/0x1000,769                     /*AddressRange=*/0x1000,770                     /*Cie=*/&TestCIE,771                     /*LSDAAddress=*/std::nullopt,772                     /*Arch=*/Triple::x86_64);773 774  // Make a CIE that has a valid CFA definition and a single register unwind775  // rule for register that we will verify is in all of the pushed rows.776  constexpr uint8_t CFAReg = 12;777  constexpr uint8_t CFAOffset = 32;778  constexpr uint8_t Reg = 13;779  constexpr uint8_t InReg = 14;780 781  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, CFAReg, CFAOffset,782                                       dwarf::DW_CFA_register, Reg, InReg}),783                    Succeeded());784 785  // Make a FDE with DWARF call frame instruction opcodes that use all of the786  // row pushing opcodes. This will verify that all opcodes that should create787  // a row are correctly working. Each opcode will push a row prior to788  // advancing the address, and then a row will be automatically pushed at the789  // end of the parsing, so we should end up with 6 rows starting at address790  // 0x1000 (from the FDE) and incrementing each one by 4 * CodeAlignmentFactor791  // from the CIE.792  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_advance_loc | 4,793                                       dwarf::DW_CFA_advance_loc1,794                                       4,795                                       dwarf::DW_CFA_advance_loc2,796                                       4,797                                       0,798                                       dwarf::DW_CFA_advance_loc4,799                                       4,800                                       0,801                                       0,802                                       0,803                                       dwarf::DW_CFA_set_loc,804                                       0x14,805                                       0x10,806                                       0,807                                       0,808                                       0,809                                       0,810                                       0,811                                       0}),812                    Succeeded());813 814  // Create locations that we expect the UnwindRow objects to contain after815  // parsing the DWARF call frame instructions.816  dwarf::RegisterLocations VerifyLocs;817  VerifyLocs.setRegisterLocation(818      Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));819 820  // Verify we catch state machine error.821  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);822  ASSERT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());823  const dwarf::UnwindTable &Rows = RowsOrErr.get();824  EXPECT_EQ(Rows.size(), 6u);825  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);826  EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);827  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);828  EXPECT_EQ(Rows[1].getAddress(), 0x1004u);829  EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);830  EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs);831  EXPECT_EQ(Rows[2].getAddress(), 0x1008u);832  EXPECT_EQ(Rows[2].getRegisterLocations().size(), 1u);833  EXPECT_EQ(Rows[2].getRegisterLocations(), VerifyLocs);834  EXPECT_EQ(Rows[3].getAddress(), 0x100cu);835  EXPECT_EQ(Rows[3].getRegisterLocations().size(), 1u);836  EXPECT_EQ(Rows[3].getRegisterLocations(), VerifyLocs);837  EXPECT_EQ(Rows[4].getAddress(), 0x1010u);838  EXPECT_EQ(Rows[4].getRegisterLocations().size(), 1u);839  EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs);840  EXPECT_EQ(Rows[5].getAddress(), 0x1014u);841  EXPECT_EQ(Rows[5].getRegisterLocations().size(), 1u);842  EXPECT_EQ(Rows[5].getRegisterLocations(), VerifyLocs);843}844 845TEST(DWARFDebugFrame, UnwindTable_DW_CFA_restore) {846  // Test that DW_CFA_restore works as expected when parsed in the state847  // machine.848  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,849                                 /*Offset=*/0x0,850                                 /*Length=*/0xff);851 852  dwarf::FDE TestFDE(/*IsDWARF64=*/true,853                     /*Offset=*/0x3333abcdabcd,854                     /*Length=*/0x4444abcdabcd,855                     /*CIEPointer=*/0x1111abcdabcd,856                     /*InitialLocation=*/0x1000,857                     /*AddressRange=*/0x1000,858                     /*Cie=*/&TestCIE,859                     /*LSDAAddress=*/std::nullopt,860                     /*Arch=*/Triple::x86_64);861 862  // Make a CIE that has a valid CFA definition and a single register unwind863  // rule for register that we will verify is in all of the pushed rows.864  constexpr uint8_t CFAReg = 12;865  constexpr uint8_t CFAOffset = 32;866  constexpr uint8_t Reg = 13;867  constexpr uint8_t InReg = 14;868  constexpr int32_t RegCFAOffset = -8;869 870  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, CFAReg, CFAOffset,871                                       dwarf::DW_CFA_register, Reg, InReg}),872                    Succeeded());873 874  // Make a FDE with DWARF call frame instruction opcodes that changes the rule875  // for register "Reg" to be [CFA-8], then push a row, and then restore the876  // register unwind rule for "Reg" using DW_CFA_restore. We should end up with877  // two rows:878  //   - one with Reg = [CFA-8]879  //   - one with Reg = InReg880  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_offset | Reg, 1,881                                       dwarf::DW_CFA_advance_loc | 4,882                                       dwarf::DW_CFA_restore | Reg}),883                    Succeeded());884 885  // Create locations that we expect the UnwindRow objects to contain after886  // parsing the DWARF call frame instructions.887  dwarf::RegisterLocations VerifyLocs1;888  VerifyLocs1.setRegisterLocation(889      Reg, dwarf::UnwindLocation::createAtCFAPlusOffset(RegCFAOffset));890 891  dwarf::RegisterLocations VerifyLocs2;892  VerifyLocs2.setRegisterLocation(893      Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));894 895  // Verify we catch state machine error.896  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);897  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());898  const dwarf::UnwindTable &Rows = RowsOrErr.get();899  EXPECT_EQ(Rows.size(), 2u);900  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);901  EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);902  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs1);903  EXPECT_EQ(Rows[1].getAddress(), 0x1004u);904  EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);905  EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs2);906}907 908TEST(DWARFDebugFrame, UnwindTable_DW_CFA_restore_extended) {909  // Test that DW_CFA_restore works as expected when parsed in the state910  // machine.911  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,912                                 /*Offset=*/0x0,913                                 /*Length=*/0xff);914 915  dwarf::FDE TestFDE(/*IsDWARF64=*/true,916                     /*Offset=*/0x3333abcdabcd,917                     /*Length=*/0x4444abcdabcd,918                     /*CIEPointer=*/0x1111abcdabcd,919                     /*InitialLocation=*/0x1000,920                     /*AddressRange=*/0x1000,921                     /*Cie=*/&TestCIE,922                     /*LSDAAddress=*/std::nullopt,923                     /*Arch=*/Triple::x86_64);924 925  // Make a CIE that has a valid CFA definition and a single register unwind926  // rule for register that we will verify is in all of the pushed rows.927  constexpr uint8_t CFAReg = 12;928  constexpr uint8_t CFAOffset = 32;929  constexpr uint8_t Reg = 13;930  constexpr uint8_t InReg = 14;931  constexpr int32_t RegCFAOffset = -8;932 933  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, CFAReg, CFAOffset,934                                       dwarf::DW_CFA_register, Reg, InReg}),935                    Succeeded());936 937  // Make a FDE with DWARF call frame instruction opcodes that changes the rule938  // for register "Reg" to be [CFA-8], then push a row, and then restore the939  // register unwind rule for "Reg" using DW_CFA_restore_extended. We should940  // end up with two rows:941  //   - one with Reg = [CFA-8]942  //   - one with Reg = InReg943  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_offset | Reg, 1,944                                       dwarf::DW_CFA_advance_loc | 4,945                                       dwarf::DW_CFA_restore_extended, Reg}),946                    Succeeded());947 948  // Create locations that we expect the UnwindRow objects to contain after949  // parsing the DWARF call frame instructions.950  dwarf::RegisterLocations VerifyLocs1;951  VerifyLocs1.setRegisterLocation(952      Reg, dwarf::UnwindLocation::createAtCFAPlusOffset(RegCFAOffset));953 954  dwarf::RegisterLocations VerifyLocs2;955  VerifyLocs2.setRegisterLocation(956      Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));957 958  // Verify we catch state machine error.959  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);960  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());961  const dwarf::UnwindTable &Rows = RowsOrErr.get();962  EXPECT_EQ(Rows.size(), 2u);963  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);964  EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);965  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs1);966  EXPECT_EQ(Rows[1].getAddress(), 0x1004u);967  EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);968  EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs2);969}970 971TEST(DWARFDebugFrame, UnwindTable_DW_CFA_offset) {972  // Test that DW_CFA_offset, DW_CFA_offset_extended and973  // DW_CFA_offset_extended_sf work as expected when parsed in the state974  // machine.975  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,976                                 /*Offset=*/0x0,977                                 /*Length=*/0xff);978 979  dwarf::FDE TestFDE(/*IsDWARF64=*/true,980                     /*Offset=*/0x3333abcdabcd,981                     /*Length=*/0x4444abcdabcd,982                     /*CIEPointer=*/0x1111abcdabcd,983                     /*InitialLocation=*/0x1000,984                     /*AddressRange=*/0x1000,985                     /*Cie=*/&TestCIE,986                     /*LSDAAddress=*/std::nullopt,987                     /*Arch=*/Triple::x86_64);988 989  // Make a CIE that has a valid CFA definition and a single register unwind990  // rule for register that we will verify is in all of the pushed rows.991  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),992                    Succeeded());993 994  // Make a FDE with DWARF call frame instruction opcodes that changes the995  // unwind rules for the follwing registers:996  //   Reg1 = [CFA-8]997  //   Reg2 = [CFA-16]998  //   Reg3 = [CFA+8]999  constexpr uint8_t Reg1 = 14;1000  constexpr uint8_t Reg2 = 15;1001  constexpr uint8_t Reg3 = 16;1002  constexpr uint8_t Neg1SLEB = 0x7f;1003  EXPECT_THAT_ERROR(1004      parseCFI(TestFDE,1005               {dwarf::DW_CFA_offset | Reg1, 1, dwarf::DW_CFA_offset_extended,1006                Reg2, 2, dwarf::DW_CFA_offset_extended_sf, Reg3, Neg1SLEB}),1007      Succeeded());1008 1009  // Create locations that we expect the UnwindRow objects to contain after1010  // parsing the DWARF call frame instructions.1011  dwarf::RegisterLocations VerifyLocs;1012  VerifyLocs.setRegisterLocation(1013      Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));1014  VerifyLocs.setRegisterLocation(1015      Reg2, dwarf::UnwindLocation::createAtCFAPlusOffset(-16));1016  VerifyLocs.setRegisterLocation(1017      Reg3, dwarf::UnwindLocation::createAtCFAPlusOffset(8));1018 1019  // Verify we catch state machine error.1020  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1021  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1022  const dwarf::UnwindTable &Rows = RowsOrErr.get();1023  EXPECT_EQ(Rows.size(), 1u);1024  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1025  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1026}1027 1028TEST(DWARFDebugFrame, UnwindTable_DW_CFA_val_offset) {1029  // Test that DW_CFA_val_offset and DW_CFA_val_offset_sf work as expected when1030  // parsed in the state machine.1031  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1032                                 /*Offset=*/0x0,1033                                 /*Length=*/0xff);1034 1035  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1036                     /*Offset=*/0x3333abcdabcd,1037                     /*Length=*/0x4444abcdabcd,1038                     /*CIEPointer=*/0x1111abcdabcd,1039                     /*InitialLocation=*/0x1000,1040                     /*AddressRange=*/0x1000,1041                     /*Cie=*/&TestCIE,1042                     /*LSDAAddress=*/std::nullopt,1043                     /*Arch=*/Triple::x86_64);1044 1045  // Make a CIE that has a valid CFA definition and a single register unwind1046  // rule for register that we will verify is in all of the pushed rows.1047  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),1048                    Succeeded());1049 1050  // Make a FDE with DWARF call frame instruction opcodes that changes the1051  // unwind rules for the follwing registers:1052  //   Reg1 = [CFA-8]1053  //   Reg2 = [CFA-16]1054  //   Reg3 = [CFA+8]1055  constexpr uint8_t Reg1 = 14;1056  constexpr uint8_t Reg2 = 15;1057  constexpr uint8_t Neg1SLEB = 0x7f;1058  EXPECT_THAT_ERROR(1059      parseCFI(TestFDE, {dwarf::DW_CFA_val_offset, Reg1, 1,1060                         dwarf::DW_CFA_val_offset_sf, Reg2, Neg1SLEB}),1061      Succeeded());1062 1063  // Create locations that we expect the UnwindRow objects to contain after1064  // parsing the DWARF call frame instructions.1065  dwarf::RegisterLocations VerifyLocs;1066  VerifyLocs.setRegisterLocation(1067      Reg1, dwarf::UnwindLocation::createIsCFAPlusOffset(-8));1068  VerifyLocs.setRegisterLocation(1069      Reg2, dwarf::UnwindLocation::createIsCFAPlusOffset(8));1070 1071  // Verify we catch state machine error.1072  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1073  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1074  const dwarf::UnwindTable &Rows = RowsOrErr.get();1075  EXPECT_EQ(Rows.size(), 1u);1076  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1077  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1078}1079 1080TEST(DWARFDebugFrame, UnwindTable_DW_CFA_nop) {1081  // Test that DW_CFA_nop works as expected when parsed in the state machine.1082  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1083                                 /*Offset=*/0x0,1084                                 /*Length=*/0xff);1085 1086  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1087                     /*Offset=*/0x3333abcdabcd,1088                     /*Length=*/0x4444abcdabcd,1089                     /*CIEPointer=*/0x1111abcdabcd,1090                     /*InitialLocation=*/0x1000,1091                     /*AddressRange=*/0x1000,1092                     /*Cie=*/&TestCIE,1093                     /*LSDAAddress=*/std::nullopt,1094                     /*Arch=*/Triple::x86_64);1095 1096  // Make a CIE that has a valid CFA definition and a single register unwind1097  // rule for register that we will verify is in all of the pushed rows.1098  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),1099                    Succeeded());1100 1101  // Make a FDE with DWARF call frame instruction opcodes that changes the1102  // unwind rules for the follwing registers:1103  //   Reg1 = [CFA-8]1104  // The opcodes for setting Reg1 are preceded by a DW_CFA_nop.1105  constexpr uint8_t Reg1 = 14;1106  EXPECT_THAT_ERROR(1107      parseCFI(TestFDE, {dwarf::DW_CFA_nop, dwarf::DW_CFA_offset | Reg1, 1}),1108      Succeeded());1109 1110  // Create locations that we expect the UnwindRow objects to contain after1111  // parsing the DWARF call frame instructions.1112  dwarf::RegisterLocations VerifyLocs;1113  VerifyLocs.setRegisterLocation(1114      Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));1115 1116  // Verify we catch state machine error.1117  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1118  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1119  const dwarf::UnwindTable &Rows = RowsOrErr.get();1120  EXPECT_EQ(Rows.size(), 1u);1121  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1122  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1123}1124 1125TEST(DWARFDebugFrame, UnwindTable_DW_CFA_remember_state) {1126  // Test that DW_CFA_remember_state and DW_CFA_restore_state work as expected1127  // when parsed in the state machine.1128  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1129                                 /*Offset=*/0x0,1130                                 /*Length=*/0xff);1131 1132  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1133                     /*Offset=*/0x3333abcdabcd,1134                     /*Length=*/0x4444abcdabcd,1135                     /*CIEPointer=*/0x1111abcdabcd,1136                     /*InitialLocation=*/0x1000,1137                     /*AddressRange=*/0x1000,1138                     /*Cie=*/&TestCIE,1139                     /*LSDAAddress=*/std::nullopt,1140                     /*Arch=*/Triple::x86_64);1141 1142  // Make a CIE that has a valid CFA definition and a single register unwind1143  // rule for register that we will verify is in all of the pushed rows.1144  constexpr uint8_t CFAOff1 = 32;1145  constexpr uint8_t CFAOff2 = 16;1146  constexpr uint8_t Reg1 = 14;1147  constexpr uint8_t Reg2 = 15;1148  constexpr uint8_t Reg3 = 16;1149 1150  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, CFAOff1}),1151                    Succeeded());1152 1153  // Make a FDE with DWARF call frame instruction opcodes that encodes the1154  // follwing rows:1155  // 0x1000: CFA=reg12+CFAOff1: Reg1=[CFA-8]1156  // 0x1004: CFA=reg12+CFAOff1: Reg1=[CFA-8] Reg2=[CFA-16]1157  // 0x1008: CFA=reg12+CFAOff2: Reg1=[CFA-8] Reg2=[CFA-16] Reg3=[CFA-24]1158  // 0x100C: CFA=reg12+CFAOff1: Reg1=[CFA-8] Reg2=[CFA-16]1159  // 0x1010: CFA=reg12+CFAOff1: Reg1=[CFA-8]1160  // This state machine will:1161  //  - set Reg1 location1162  //  - push a row (from DW_CFA_advance_loc)1163  //  - remember the state1164  //  - set Reg2 location1165  //  - push a row (from DW_CFA_advance_loc)1166  //  - remember the state1167  //  - set CFA offset to CFAOff21168  //  - set Reg3 location1169  //  - push a row (from DW_CFA_advance_loc)1170  //  - remember the state where Reg1 and Reg2 were set1171  //  - push a row (from DW_CFA_advance_loc)1172  //  - remember the state where only Reg1 was set1173  //  - push a row (automatically at the end of instruction parsing)1174  // Then we verify that all registers are correct in all generated rows.1175  EXPECT_THAT_ERROR(1176      parseCFI(TestFDE,1177               {dwarf::DW_CFA_offset | Reg1, 1, dwarf::DW_CFA_advance_loc | 4,1178                dwarf::DW_CFA_remember_state, dwarf::DW_CFA_offset | Reg2, 2,1179                dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_remember_state,1180                dwarf::DW_CFA_def_cfa_offset, CFAOff2,1181                dwarf::DW_CFA_offset | Reg3, 3, dwarf::DW_CFA_advance_loc | 4,1182                dwarf::DW_CFA_restore_state, dwarf::DW_CFA_advance_loc | 4,1183                dwarf::DW_CFA_restore_state}),1184      Succeeded());1185 1186  // Create locations that we expect the UnwindRow objects to contain after1187  // parsing the DWARF call frame instructions.1188  dwarf::RegisterLocations VerifyLocs1;1189  VerifyLocs1.setRegisterLocation(1190      Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));1191 1192  dwarf::RegisterLocations VerifyLocs2;1193  VerifyLocs2.setRegisterLocation(1194      Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));1195  VerifyLocs2.setRegisterLocation(1196      Reg2, dwarf::UnwindLocation::createAtCFAPlusOffset(-16));1197 1198  dwarf::RegisterLocations VerifyLocs3;1199  VerifyLocs3.setRegisterLocation(1200      Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));1201  VerifyLocs3.setRegisterLocation(1202      Reg2, dwarf::UnwindLocation::createAtCFAPlusOffset(-16));1203  VerifyLocs3.setRegisterLocation(1204      Reg3, dwarf::UnwindLocation::createAtCFAPlusOffset(-24));1205 1206  // Verify we catch state machine error.1207  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1208  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1209  const dwarf::UnwindTable &Rows = RowsOrErr.get();1210  EXPECT_EQ(Rows.size(), 5u);1211  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1212  EXPECT_EQ(Rows[0].getCFAValue(),1213            dwarf::UnwindLocation::createIsRegisterPlusOffset(12, CFAOff1));1214  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs1);1215 1216  EXPECT_EQ(Rows[1].getAddress(), 0x1004u);1217  EXPECT_EQ(Rows[1].getCFAValue(),1218            dwarf::UnwindLocation::createIsRegisterPlusOffset(12, CFAOff1));1219  EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs2);1220 1221  EXPECT_EQ(Rows[2].getAddress(), 0x1008u);1222  EXPECT_EQ(Rows[2].getCFAValue(),1223            dwarf::UnwindLocation::createIsRegisterPlusOffset(12, CFAOff2));1224  EXPECT_EQ(Rows[2].getRegisterLocations(), VerifyLocs3);1225 1226  EXPECT_EQ(Rows[3].getAddress(), 0x100Cu);1227  EXPECT_EQ(Rows[3].getCFAValue(),1228            dwarf::UnwindLocation::createIsRegisterPlusOffset(12, CFAOff1));1229  EXPECT_EQ(Rows[3].getRegisterLocations(), VerifyLocs2);1230 1231  EXPECT_EQ(Rows[4].getAddress(), 0x1010u);1232  EXPECT_EQ(Rows[4].getCFAValue(),1233            dwarf::UnwindLocation::createIsRegisterPlusOffset(12, CFAOff1));1234  EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs1);1235}1236 1237TEST(DWARFDebugFrame, UnwindTable_DW_CFA_undefined) {1238  // Test that DW_CFA_undefined works as expected when parsed in the state1239  // machine.1240  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1241                                 /*Offset=*/0x0,1242                                 /*Length=*/0xff);1243 1244  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1245                     /*Offset=*/0x3333abcdabcd,1246                     /*Length=*/0x4444abcdabcd,1247                     /*CIEPointer=*/0x1111abcdabcd,1248                     /*InitialLocation=*/0x1000,1249                     /*AddressRange=*/0x1000,1250                     /*Cie=*/&TestCIE,1251                     /*LSDAAddress=*/std::nullopt,1252                     /*Arch=*/Triple::x86_64);1253 1254  // Make a CIE that has a valid CFA definition and a single register unwind1255  // rule for register that we will verify is in all of the pushed rows.1256  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),1257                    Succeeded());1258 1259  // Make a FDE with DWARF call frame instruction opcodes that encodes the1260  // follwing rows:1261  // 0x1000: CFA=reg12+32: Reg1=undefined1262  // Then we verify that all registers are correct in all generated rows.1263  constexpr uint8_t Reg1 = 14;1264  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_undefined, Reg1}),1265                    Succeeded());1266 1267  // Create locations that we expect the UnwindRow objects to contain after1268  // parsing the DWARF call frame instructions.1269  dwarf::RegisterLocations VerifyLocs;1270  VerifyLocs.setRegisterLocation(Reg1,1271                                 dwarf::UnwindLocation::createUndefined());1272 1273  // Verify we catch state machine error.1274  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1275  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1276  const dwarf::UnwindTable &Rows = RowsOrErr.get();1277  EXPECT_EQ(Rows.size(), 1u);1278  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1279  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1280}1281 1282TEST(DWARFDebugFrame, UnwindTable_DW_CFA_same_value) {1283  // Test that DW_CFA_same_value works as expected when parsed in the state1284  // machine.1285  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1286                                 /*Offset=*/0x0,1287                                 /*Length=*/0xff);1288 1289  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1290                     /*Offset=*/0x3333abcdabcd,1291                     /*Length=*/0x4444abcdabcd,1292                     /*CIEPointer=*/0x1111abcdabcd,1293                     /*InitialLocation=*/0x1000,1294                     /*AddressRange=*/0x1000,1295                     /*Cie=*/&TestCIE,1296                     /*LSDAAddress=*/std::nullopt,1297                     /*Arch=*/Triple::x86_64);1298 1299  // Make a CIE that has a valid CFA definition and a single register unwind1300  // rule for register that we will verify is in all of the pushed rows.1301  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),1302                    Succeeded());1303 1304  // Make a FDE with DWARF call frame instruction opcodes that encodes the1305  // follwing rows:1306  // 0x1000: CFA=reg12+32: Reg1=same1307  // Then we verify that all registers are correct in all generated rows.1308  constexpr uint8_t Reg1 = 14;1309  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_same_value, Reg1}),1310                    Succeeded());1311 1312  // Create locations that we expect the UnwindRow objects to contain after1313  // parsing the DWARF call frame instructions.1314  dwarf::RegisterLocations VerifyLocs;1315  VerifyLocs.setRegisterLocation(Reg1, dwarf::UnwindLocation::createSame());1316 1317  // Verify we catch state machine error.1318  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1319  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1320  const dwarf::UnwindTable &Rows = RowsOrErr.get();1321  EXPECT_EQ(Rows.size(), 1u);1322  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1323  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1324}1325 1326TEST(DWARFDebugFrame, UnwindTable_DW_CFA_register) {1327  // Test that DW_CFA_register works as expected when parsed in the state1328  // machine.1329  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1330                                 /*Offset=*/0x0,1331                                 /*Length=*/0xff);1332 1333  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1334                     /*Offset=*/0x3333abcdabcd,1335                     /*Length=*/0x4444abcdabcd,1336                     /*CIEPointer=*/0x1111abcdabcd,1337                     /*InitialLocation=*/0x1000,1338                     /*AddressRange=*/0x1000,1339                     /*Cie=*/&TestCIE,1340                     /*LSDAAddress=*/std::nullopt,1341                     /*Arch=*/Triple::x86_64);1342 1343  // Make a CIE that has a valid CFA definition and a single register unwind1344  // rule for register that we will verify is in all of the pushed rows.1345  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),1346                    Succeeded());1347 1348  // Make a FDE with DWARF call frame instruction opcodes that encodes the1349  // follwing rows:1350  // 0x1000: CFA=reg12+32: Reg1=same1351  // Then we verify that all registers are correct in all generated rows.1352  constexpr uint8_t Reg = 13;1353  constexpr uint8_t InReg = 14;1354  EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_register, Reg, InReg}),1355                    Succeeded());1356 1357  // Create locations that we expect the UnwindRow objects to contain after1358  // parsing the DWARF call frame instructions.1359  dwarf::RegisterLocations VerifyLocs;1360  VerifyLocs.setRegisterLocation(1361      Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));1362 1363  // Verify we catch state machine error.1364  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1365  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1366  const dwarf::UnwindTable &Rows = RowsOrErr.get();1367  EXPECT_EQ(Rows.size(), 1u);1368  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1369  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1370}1371 1372TEST(DWARFDebugFrame, UnwindTable_DW_CFA_expression) {1373  // Test that DW_CFA_expression works as expected when parsed in the state1374  // machine.1375  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1376                                 /*Offset=*/0x0,1377                                 /*Length=*/0xff);1378 1379  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1380                     /*Offset=*/0x3333abcdabcd,1381                     /*Length=*/0x4444abcdabcd,1382                     /*CIEPointer=*/0x1111abcdabcd,1383                     /*InitialLocation=*/0x1000,1384                     /*AddressRange=*/0x1000,1385                     /*Cie=*/&TestCIE,1386                     /*LSDAAddress=*/std::nullopt,1387                     /*Arch=*/Triple::x86_64);1388 1389  // Make a CIE that has a valid CFA definition and a single register unwind1390  // rule for register that we will verify is in all of the pushed rows.1391  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),1392                    Succeeded());1393 1394  // Make a FDE with DWARF call frame instruction opcodes that encodes the1395  // follwing rows:1396  // 0x1000: CFA=reg12+32: Reg1=DWARFExpr(DW_OP_reg12)1397  // Then we verify that all registers are correct in all generated rows.1398  constexpr uint8_t Reg = 13;1399  constexpr uint8_t AddrSize = 8;1400  std::vector<uint8_t> CFIBytes = {dwarf::DW_CFA_expression, Reg, 1,1401                                   dwarf::DW_OP_reg12};1402 1403  EXPECT_THAT_ERROR(parseCFI(TestFDE, CFIBytes), Succeeded());1404 1405  // Create locations that we expect the UnwindRow objects to contain after1406  // parsing the DWARF call frame instructions.1407  dwarf::RegisterLocations VerifyLocs;1408 1409  std::vector<uint8_t> ExprBytes = {dwarf::DW_OP_reg12};1410  DataExtractor ExprData(ExprBytes, true, AddrSize);1411  DWARFExpression Expr(ExprData, AddrSize);1412  VerifyLocs.setRegisterLocation(1413      Reg, dwarf::UnwindLocation::createAtDWARFExpression(Expr));1414 1415  // Verify we catch state machine error.1416  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1417  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1418  const dwarf::UnwindTable &Rows = RowsOrErr.get();1419  EXPECT_EQ(Rows.size(), 1u);1420  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1421  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1422}1423 1424TEST(DWARFDebugFrame, UnwindTable_DW_CFA_val_expression) {1425  // Test that DW_CFA_val_expression works as expected when parsed in the state1426  // machine.1427  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1428                                 /*Offset=*/0x0,1429                                 /*Length=*/0xff);1430 1431  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1432                     /*Offset=*/0x3333abcdabcd,1433                     /*Length=*/0x4444abcdabcd,1434                     /*CIEPointer=*/0x1111abcdabcd,1435                     /*InitialLocation=*/0x1000,1436                     /*AddressRange=*/0x1000,1437                     /*Cie=*/&TestCIE,1438                     /*LSDAAddress=*/std::nullopt,1439                     /*Arch=*/Triple::x86_64);1440 1441  // Make a CIE that has a valid CFA definition and a single register unwind1442  // rule for register that we will verify is in all of the pushed rows.1443  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),1444                    Succeeded());1445 1446  // Make a FDE with DWARF call frame instruction opcodes that encodes the1447  // follwing rows:1448  // 0x1000: CFA=reg12+32: Reg1=DWARFExpr(DW_OP_reg12)1449  // Then we verify that all registers are correct in all generated rows.1450  constexpr uint8_t Reg = 13;1451  constexpr uint8_t AddrSize = 8;1452  std::vector<uint8_t> CFIBytes = {dwarf::DW_CFA_val_expression, Reg, 1,1453                                   dwarf::DW_OP_reg12};1454 1455  EXPECT_THAT_ERROR(parseCFI(TestFDE, CFIBytes), Succeeded());1456 1457  // Create locations that we expect the UnwindRow objects to contain after1458  // parsing the DWARF call frame instructions.1459  dwarf::RegisterLocations VerifyLocs;1460 1461  std::vector<uint8_t> ExprBytes = {dwarf::DW_OP_reg12};1462  DataExtractor ExprData(ExprBytes, true, AddrSize);1463  DWARFExpression Expr(ExprData, AddrSize);1464  VerifyLocs.setRegisterLocation(1465      Reg, dwarf::UnwindLocation::createIsDWARFExpression(Expr));1466 1467  // Verify we catch state machine error.1468  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1469  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1470  const dwarf::UnwindTable &Rows = RowsOrErr.get();1471  EXPECT_EQ(Rows.size(), 1u);1472  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1473  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1474}1475 1476TEST(DWARFDebugFrame, UnwindTable_DW_CFA_def_cfa) {1477  // Test that DW_CFA_def_cfa, DW_CFA_def_cfa_sf, DW_CFA_def_cfa_register,1478  // DW_CFA_def_cfa_offset, and DW_CFA_def_cfa_offset_sf works as expected when1479  // parsed in the state machine.1480  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1481                                 /*Offset=*/0x0,1482                                 /*Length=*/0xff);1483 1484  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1485                     /*Offset=*/0x3333abcdabcd,1486                     /*Length=*/0x4444abcdabcd,1487                     /*CIEPointer=*/0x1111abcdabcd,1488                     /*InitialLocation=*/0x1000,1489                     /*AddressRange=*/0x1000,1490                     /*Cie=*/&TestCIE,1491                     /*LSDAAddress=*/std::nullopt,1492                     /*Arch=*/Triple::x86_64);1493 1494  // Make a CIE that has a valid CFA definition and a single register unwind1495  // rule for register that we will verify is in all of the pushed rows.1496  constexpr uint8_t CFAReg1 = 12;1497  constexpr uint8_t CFAOff1 = 32;1498  constexpr uint8_t CFAReg2 = 13;1499  constexpr uint8_t CFAOff2 = 48;1500  constexpr uint8_t Reg = 13;1501  constexpr uint8_t InReg = 14;1502 1503  EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, CFAReg1, CFAOff1,1504                                       dwarf::DW_CFA_register, Reg, InReg}),1505                    Succeeded());1506 1507  // Make a FDE with DWARF call frame instruction opcodes that use all of the1508  // DW_CFA_def_cfa* opcodes. This will verify that all opcodes that should1509  // create a row are correctly working.1510  EXPECT_THAT_ERROR(1511      parseCFI(1512          TestFDE,1513          {1514              dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_register,1515              CFAReg2, dwarf::DW_CFA_advance_loc | 4,1516              dwarf::DW_CFA_def_cfa_offset, CFAOff2,1517              dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_offset_sf,1518              0x7c, // -4 SLEB to make offset = 32 (CFAOff1)1519              dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_sf, CFAReg1,1520              0x7a, // -6 SLEB to make CFA offset 48 (CFAOff2)1521          }),1522      Succeeded());1523 1524  // Create locations that we expect the UnwindRow objects to contain after1525  // parsing the DWARF call frame instructions.1526  dwarf::RegisterLocations VerifyLocs;1527  VerifyLocs.setRegisterLocation(1528      Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));1529 1530  // Verify we catch state machine error.1531  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1532  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1533  const dwarf::UnwindTable &Rows = RowsOrErr.get();1534  EXPECT_EQ(Rows.size(), 5u);1535  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1536  EXPECT_EQ(1537      Rows[0].getCFAValue(),1538      dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff1));1539  EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);1540  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1541 1542  EXPECT_EQ(Rows[1].getAddress(), 0x1004u);1543  EXPECT_EQ(1544      Rows[1].getCFAValue(),1545      dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1));1546  EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);1547  EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs);1548 1549  EXPECT_EQ(Rows[2].getAddress(), 0x1008u);1550  EXPECT_EQ(1551      Rows[2].getCFAValue(),1552      dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff2));1553  EXPECT_EQ(Rows[2].getRegisterLocations().size(), 1u);1554  EXPECT_EQ(Rows[2].getRegisterLocations(), VerifyLocs);1555 1556  EXPECT_EQ(Rows[3].getAddress(), 0x100cu);1557  EXPECT_EQ(1558      Rows[3].getCFAValue(),1559      dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1));1560  EXPECT_EQ(Rows[3].getRegisterLocations().size(), 1u);1561  EXPECT_EQ(Rows[3].getRegisterLocations(), VerifyLocs);1562 1563  EXPECT_EQ(Rows[4].getAddress(), 0x1010u);1564  EXPECT_EQ(1565      Rows[4].getCFAValue(),1566      dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff2));1567  EXPECT_EQ(Rows[4].getRegisterLocations().size(), 1u);1568  EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs);1569}1570 1571TEST(DWARFDebugFrame, UnwindTable_DW_CFA_LLVM_def_aspace_cfa) {1572  // Test that DW_CFA_LLVM_def_aspace_cfa, DW_CFA_LLVM_def_aspace_cfa_sf,1573  // DW_CFA_def_cfa_register, DW_CFA_def_cfa_offset, and1574  // DW_CFA_def_cfa_offset_sf works as expected when parsed in the state1575  // machine.1576  dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,1577                                 /*Offset=*/0x0,1578                                 /*Length=*/0xff);1579 1580  dwarf::FDE TestFDE(/*IsDWARF64=*/true,1581                     /*Offset=*/0x3333abcdabcd,1582                     /*Length=*/0x4444abcdabcd,1583                     /*CIEPointer=*/0x1111abcdabcd,1584                     /*InitialLocation=*/0x1000,1585                     /*AddressRange=*/0x1000,1586                     /*Cie=*/&TestCIE,1587                     /*LSDAAddress=*/std::nullopt,1588                     /*Arch=*/Triple::x86_64);1589 1590  // Make a CIE that has a valid CFA definition and a single register unwind1591  // rule for register that we will verify is in all of the pushed rows.1592  constexpr uint8_t CFAReg1 = 12;1593  constexpr uint8_t CFAOff1 = 32;1594  constexpr uint8_t CFAReg2 = 13;1595  constexpr uint8_t CFAOff2 = 48;1596  constexpr uint8_t Reg = 13;1597  constexpr uint8_t InReg = 14;1598  constexpr uint8_t AddrSpace = 2;1599 1600  EXPECT_THAT_ERROR(1601      parseCFI(TestCIE, {dwarf::DW_CFA_LLVM_def_aspace_cfa, CFAReg1, CFAOff1,1602                         AddrSpace, dwarf::DW_CFA_register, Reg, InReg}),1603      Succeeded());1604 1605  // Make a FDE with DWARF call frame instruction opcodes that use all of the1606  // DW_CFA_def_cfa* opcodes. This will verify that all opcodes that should1607  // create a row are correctly working.1608  EXPECT_THAT_ERROR(1609      parseCFI(1610          TestFDE,1611          {1612              dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_register,1613              CFAReg2, dwarf::DW_CFA_advance_loc | 4,1614              dwarf::DW_CFA_def_cfa_offset, CFAOff2,1615              dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_offset_sf,1616              0x7c, // -4 SLEB to make offset = 32 (CFAOff1)1617              dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_sf, CFAReg1,1618              0x7a, // -6 SLEB to make CFA offset 48 (CFAOff2)1619          }),1620      Succeeded());1621 1622  // Create locations that we expect the UnwindRow objects to contain after1623  // parsing the DWARF call frame instructions.1624  dwarf::RegisterLocations VerifyLocs;1625  VerifyLocs.setRegisterLocation(1626      Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));1627 1628  // Verify we catch state machine error.1629  Expected<dwarf::UnwindTable> RowsOrErr = dwarf::createUnwindTable(&TestFDE);1630  EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());1631  const dwarf::UnwindTable &Rows = RowsOrErr.get();1632  EXPECT_EQ(Rows.size(), 5u);1633  EXPECT_EQ(Rows[0].getAddress(), 0x1000u);1634  EXPECT_EQ(Rows[0].getCFAValue(),1635            dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff1,1636                                                              AddrSpace));1637  EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);1638  EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);1639 1640  EXPECT_EQ(Rows[1].getAddress(), 0x1004u);1641  EXPECT_EQ(Rows[1].getCFAValue(),1642            dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1,1643                                                              AddrSpace));1644  EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);1645  EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs);1646 1647  EXPECT_EQ(Rows[2].getAddress(), 0x1008u);1648  EXPECT_EQ(Rows[2].getCFAValue(),1649            dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff2,1650                                                              AddrSpace));1651  EXPECT_EQ(Rows[2].getRegisterLocations().size(), 1u);1652  EXPECT_EQ(Rows[2].getRegisterLocations(), VerifyLocs);1653 1654  EXPECT_EQ(Rows[3].getAddress(), 0x100cu);1655  EXPECT_EQ(Rows[3].getCFAValue(),1656            dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1,1657                                                              AddrSpace));1658  EXPECT_EQ(Rows[3].getRegisterLocations().size(), 1u);1659  EXPECT_EQ(Rows[3].getRegisterLocations(), VerifyLocs);1660 1661  EXPECT_EQ(Rows[4].getAddress(), 0x1010u);1662  EXPECT_EQ(Rows[4].getCFAValue(),1663            dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff2,1664                                                              AddrSpace));1665  EXPECT_EQ(Rows[4].getRegisterLocations().size(), 1u);1666  EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs);1667}1668 1669} // end anonymous namespace1670