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