#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
dwarf::CIE createCIE(bool IsDWARF64, uint64_t Offset, uint64_t Length) {
return dwarf::CIE(IsDWARF64, Offset, Length,
3,
StringRef(),
8,
0,
1,
-8,
16,
StringRef(),
dwarf::DW_EH_PE_absptr,
dwarf::DW_EH_PE_omit,
None,
None,
Triple::x86_64);
}
void expectDumpResult(const dwarf::CIE &TestCIE, bool IsEH,
StringRef ExpectedFirstLine) {
std::string Output;
raw_string_ostream OS(Output);
TestCIE.dump(OS, DIDumpOptions(), nullptr, IsEH);
OS.flush();
StringRef FirstLine = StringRef(Output).split('\n').first;
EXPECT_EQ(FirstLine, ExpectedFirstLine);
}
void expectDumpResult(const dwarf::FDE &TestFDE, bool IsEH,
StringRef ExpectedFirstLine) {
std::string Output;
raw_string_ostream OS(Output);
TestFDE.dump(OS, DIDumpOptions(), nullptr, IsEH);
OS.flush();
StringRef FirstLine = StringRef(Output).split('\n').first;
EXPECT_EQ(FirstLine, ExpectedFirstLine);
}
TEST(DWARFDebugFrame, DumpDWARF32CIE) {
dwarf::CIE TestCIE = createCIE(false,
0x1111abcd,
0x2222abcd);
expectDumpResult(TestCIE, false, "1111abcd 2222abcd ffffffff CIE");
}
TEST(DWARFDebugFrame, DumpDWARF64CIE) {
dwarf::CIE TestCIE = createCIE(true,
0x1111abcdabcd,
0x2222abcdabcd);
expectDumpResult(TestCIE, false,
"1111abcdabcd 00002222abcdabcd ffffffffffffffff CIE");
}
TEST(DWARFDebugFrame, DumpEHCIE) {
dwarf::CIE TestCIE = createCIE(false,
0x1000,
0x20);
expectDumpResult(TestCIE, true, "00001000 00000020 00000000 CIE");
}
TEST(DWARFDebugFrame, DumpEH64CIE) {
dwarf::CIE TestCIE = createCIE(true,
0x1000,
0x20);
expectDumpResult(TestCIE, true,
"00001000 0000000000000020 00000000 CIE");
}
TEST(DWARFDebugFrame, DumpDWARF64FDE) {
dwarf::CIE TestCIE = createCIE(true,
0x1111abcdabcd,
0x2222abcdabcd);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x5555abcdabcd,
0x111111111111,
&TestCIE,
None,
Triple::x86_64);
expectDumpResult(TestFDE, false,
"3333abcdabcd 00004444abcdabcd 00001111abcdabcd FDE "
"cie=1111abcdabcd pc=5555abcdabcd...6666bcdebcde");
}
TEST(DWARFDebugFrame, DumpEH64FDE) {
dwarf::CIE TestCIE = createCIE(true,
0x1111ab9a000c,
0x20);
dwarf::FDE TestFDE(true,
0x1111abcdabcd,
0x2222abcdabcd,
0x33abcd,
0x4444abcdabcd,
0x111111111111,
&TestCIE,
None,
Triple::x86_64);
expectDumpResult(TestFDE, true,
"1111abcdabcd 00002222abcdabcd 0033abcd FDE "
"cie=1111ab9a000c pc=4444abcdabcd...5555bcdebcde");
}
static Error parseCFI(dwarf::CIE &C, ArrayRef<uint8_t> Instructions,
Optional<uint64_t> Size = None) {
DWARFDataExtractor Data(Instructions, true,
8);
uint64_t Offset = 0;
const uint64_t EndOffset = Size ? *Size : (uint64_t)Instructions.size();
return C.cfis().parse(Data, &Offset, EndOffset);
}
static Error parseCFI(dwarf::FDE &FDE, ArrayRef<uint8_t> Instructions) {
DWARFDataExtractor Data(Instructions, true,
8);
uint64_t Offset = 0;
return FDE.cfis().parse(Data, &Offset, Instructions.size());
}
TEST(DWARFDebugFrame, InvalidCFIOpcodesTest) {
llvm::DenseSet<uint8_t> ValidExtendedOpcodes = {
dwarf::DW_CFA_nop,
dwarf::DW_CFA_advance_loc,
dwarf::DW_CFA_offset,
dwarf::DW_CFA_restore,
dwarf::DW_CFA_set_loc,
dwarf::DW_CFA_advance_loc1,
dwarf::DW_CFA_advance_loc2,
dwarf::DW_CFA_advance_loc4,
dwarf::DW_CFA_offset_extended,
dwarf::DW_CFA_restore_extended,
dwarf::DW_CFA_undefined,
dwarf::DW_CFA_same_value,
dwarf::DW_CFA_register,
dwarf::DW_CFA_remember_state,
dwarf::DW_CFA_restore_state,
dwarf::DW_CFA_def_cfa,
dwarf::DW_CFA_def_cfa_register,
dwarf::DW_CFA_def_cfa_offset,
dwarf::DW_CFA_def_cfa_expression,
dwarf::DW_CFA_expression,
dwarf::DW_CFA_offset_extended_sf,
dwarf::DW_CFA_def_cfa_sf,
dwarf::DW_CFA_def_cfa_offset_sf,
dwarf::DW_CFA_LLVM_def_aspace_cfa,
dwarf::DW_CFA_LLVM_def_aspace_cfa_sf,
dwarf::DW_CFA_val_offset,
dwarf::DW_CFA_val_offset_sf,
dwarf::DW_CFA_val_expression,
dwarf::DW_CFA_MIPS_advance_loc8,
dwarf::DW_CFA_GNU_window_save,
dwarf::DW_CFA_AARCH64_negate_ra_state,
dwarf::DW_CFA_GNU_args_size};
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
for (uint8_t Code = 0; Code <= 63; ++Code) {
if (ValidExtendedOpcodes.count(Code))
continue;
EXPECT_THAT_ERROR(parseCFI(TestCIE, Code),
FailedWithMessage(("invalid extended CFI opcode 0x" +
Twine::utohexstr(Code))
.str()
.c_str()));
}
}
TEST(DWARFDebugFrame, ParseTruncatedCFITest) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {}), Succeeded());
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {}, 1),
FailedWithMessage(
"unexpected end of data at offset 0x0 while reading [0x0, 0x1)"));
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {dwarf::DW_CFA_offset}),
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
"malformed uleb128, extends past end"));
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {dwarf::DW_CFA_set_loc}),
FailedWithMessage(
"unexpected end of data at offset 0x1 while reading [0x1, 0x9)"));
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {dwarf::DW_CFA_advance_loc1}),
FailedWithMessage(
"unexpected end of data at offset 0x1 while reading [0x1, 0x2)"));
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {dwarf::DW_CFA_advance_loc2}),
FailedWithMessage(
"unexpected end of data at offset 0x1 while reading [0x1, 0x3)"));
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {dwarf::DW_CFA_advance_loc4}),
FailedWithMessage(
"unexpected end of data at offset 0x1 while reading [0x1, 0x5)"));
auto CheckOp_ULEB128 = [&](uint8_t Inst) {
EXPECT_THAT_ERROR(
parseCFI(TestCIE, Inst),
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
"malformed uleb128, extends past end"));
};
for (uint8_t Inst :
{dwarf::DW_CFA_restore_extended, dwarf::DW_CFA_undefined,
dwarf::DW_CFA_same_value, dwarf::DW_CFA_def_cfa_register,
dwarf::DW_CFA_def_cfa_offset, dwarf::DW_CFA_GNU_args_size})
CheckOp_ULEB128(Inst);
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_offset_sf}),
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
"malformed sleb128, extends past end"));
auto CheckOp_ULEB128_ULEB128 = [&](uint8_t Inst) {
EXPECT_THAT_ERROR(
parseCFI(TestCIE, Inst),
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
"malformed uleb128, extends past end"));
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {Inst, 0}),
FailedWithMessage("unable to decode LEB128 at offset 0x00000002: "
"malformed uleb128, extends past end"));
};
for (uint8_t Inst : {dwarf::DW_CFA_offset_extended, dwarf::DW_CFA_register,
dwarf::DW_CFA_def_cfa, dwarf::DW_CFA_LLVM_def_aspace_cfa,
dwarf::DW_CFA_val_offset})
CheckOp_ULEB128_ULEB128(Inst);
auto CheckOp_ULEB128_SLEB128 = [&](uint8_t Inst) {
EXPECT_THAT_ERROR(
parseCFI(TestCIE, Inst),
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
"malformed uleb128, extends past end"));
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {Inst, 0}),
FailedWithMessage("unable to decode LEB128 at offset 0x00000002: "
"malformed sleb128, extends past end"));
};
for (uint8_t Inst :
{dwarf::DW_CFA_offset_extended_sf, dwarf::DW_CFA_def_cfa_sf,
dwarf::DW_CFA_LLVM_def_aspace_cfa_sf, dwarf::DW_CFA_val_offset_sf})
CheckOp_ULEB128_SLEB128(Inst);
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_expression}),
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
"malformed uleb128, extends past end"));
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_expression,
0x1}),
FailedWithMessage(
"unexpected end of data at offset 0x2 while reading [0x2, 0x3)"));
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_expression,
0}),
Succeeded());
auto CheckOp_ULEB128_Expr = [&](uint8_t Inst) {
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {Inst}),
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
"malformed uleb128, extends past end"));
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {Inst, 0}),
FailedWithMessage("unable to decode LEB128 at offset 0x00000002: "
"malformed uleb128, extends past end"));
EXPECT_THAT_ERROR(parseCFI(TestCIE, {Inst,
0, 0}),
Succeeded());
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {Inst,
0, 1}),
FailedWithMessage(
"unexpected end of data at offset 0x3 while reading [0x3, 0x4)"));
};
for (uint8_t Inst : {dwarf::DW_CFA_expression, dwarf::DW_CFA_val_expression})
CheckOp_ULEB128_Expr(Inst);
}
void expectDumpResult(const dwarf::UnwindLocation &Loc,
StringRef ExpectedFirstLine) {
std::string Output;
raw_string_ostream OS(Output);
OS << Loc;
OS.flush();
StringRef FirstLine = StringRef(Output).split('\n').first;
EXPECT_EQ(FirstLine, ExpectedFirstLine);
}
TEST(DWARFDebugFrame, DumpUnwindLocations) {
constexpr int32_t PlusOff = 8;
constexpr int32_t MinusOff = -8;
constexpr uint8_t RegNum = 12;
expectDumpResult(dwarf::UnwindLocation::createUnspecified(), "unspecified");
expectDumpResult(dwarf::UnwindLocation::createUndefined(), "undefined");
expectDumpResult(dwarf::UnwindLocation::createSame(), "same");
expectDumpResult(dwarf::UnwindLocation::createIsCFAPlusOffset(PlusOff),
"CFA+8");
expectDumpResult(dwarf::UnwindLocation::createIsCFAPlusOffset(MinusOff),
"CFA-8");
expectDumpResult(dwarf::UnwindLocation::createAtCFAPlusOffset(PlusOff),
"[CFA+8]");
expectDumpResult(dwarf::UnwindLocation::createAtCFAPlusOffset(MinusOff),
"[CFA-8]");
expectDumpResult(
dwarf::UnwindLocation::createIsRegisterPlusOffset(RegNum, PlusOff),
"reg12+8");
expectDumpResult(
dwarf::UnwindLocation::createIsRegisterPlusOffset(RegNum, MinusOff),
"reg12-8");
expectDumpResult(
dwarf::UnwindLocation::createAtRegisterPlusOffset(RegNum, PlusOff),
"[reg12+8]");
expectDumpResult(
dwarf::UnwindLocation::createAtRegisterPlusOffset(RegNum, MinusOff),
"[reg12-8]");
expectDumpResult(dwarf::UnwindLocation::createIsConstant(12), "12");
expectDumpResult(dwarf::UnwindLocation::createIsConstant(-32), "-32");
}
void expectDumpResult(const dwarf::RegisterLocations &Locs,
StringRef ExpectedFirstLine) {
std::string Output;
raw_string_ostream OS(Output);
OS << Locs;
OS.flush();
StringRef FirstLine = StringRef(Output).split('\n').first;
EXPECT_EQ(FirstLine, ExpectedFirstLine);
}
TEST(DWARFDebugFrame, RegisterLocations) {
dwarf::RegisterLocations Locs;
expectDumpResult(Locs, "");
EXPECT_FALSE(Locs.hasLocations());
Locs.setRegisterLocation(12, dwarf::UnwindLocation::createUnspecified());
EXPECT_TRUE(Locs.hasLocations());
expectDumpResult(Locs, "reg12=unspecified");
Locs.setRegisterLocation(12, dwarf::UnwindLocation::createSame());
EXPECT_TRUE(Locs.hasLocations());
expectDumpResult(Locs, "reg12=same");
Locs.removeRegisterLocation(12);
EXPECT_FALSE(Locs.hasLocations());
expectDumpResult(Locs, "");
auto Reg12Loc = dwarf::UnwindLocation::createAtCFAPlusOffset(4);
auto Reg13Loc = dwarf::UnwindLocation::createAtCFAPlusOffset(8);
auto Reg14Loc = dwarf::UnwindLocation::createSame();
Locs.setRegisterLocation(12, Reg12Loc);
Locs.setRegisterLocation(13, Reg13Loc);
Locs.setRegisterLocation(14, Reg14Loc);
EXPECT_TRUE(Locs.hasLocations());
expectDumpResult(Locs, "reg12=[CFA+4], reg13=[CFA+8], reg14=same");
Optional<dwarf::UnwindLocation> OptionalLoc;
OptionalLoc = Locs.getRegisterLocation(0);
EXPECT_FALSE(OptionalLoc.has_value());
OptionalLoc = Locs.getRegisterLocation(12);
EXPECT_TRUE(OptionalLoc.has_value());
EXPECT_EQ(*OptionalLoc, Reg12Loc);
OptionalLoc = Locs.getRegisterLocation(13);
EXPECT_TRUE(OptionalLoc.has_value());
EXPECT_EQ(*OptionalLoc, Reg13Loc);
OptionalLoc = Locs.getRegisterLocation(14);
EXPECT_TRUE(OptionalLoc.has_value());
EXPECT_EQ(*OptionalLoc, Reg14Loc);
Locs.removeRegisterLocation(13);
EXPECT_FALSE(Locs.getRegisterLocation(13).has_value());
EXPECT_TRUE(Locs.hasLocations());
expectDumpResult(Locs, "reg12=[CFA+4], reg14=same");
Locs.removeRegisterLocation(14);
EXPECT_FALSE(Locs.getRegisterLocation(14).has_value());
EXPECT_TRUE(Locs.hasLocations());
expectDumpResult(Locs, "reg12=[CFA+4]");
Locs.removeRegisterLocation(12);
EXPECT_FALSE(Locs.getRegisterLocation(12).has_value());
EXPECT_FALSE(Locs.hasLocations());
expectDumpResult(Locs, "");
}
TEST(DWARFDebugFrame, UnwindTableEmptyRows) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {}), Succeeded());
EXPECT_TRUE(TestCIE.cfis().empty());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestCIE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const size_t ExpectedNumOfRows = 0;
EXPECT_EQ(RowsOrErr->size(), ExpectedNumOfRows);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestFDE, {}), Succeeded());
EXPECT_TRUE(TestFDE.cfis().empty());
RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
EXPECT_EQ(RowsOrErr->size(), ExpectedNumOfRows);
}
TEST(DWARFDebugFrame, UnwindTableEmptyRows_NOPs) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_nop}), Succeeded());
EXPECT_TRUE(!TestCIE.cfis().empty());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestCIE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const size_t ExpectedNumOfRows = 0;
EXPECT_EQ(RowsOrErr->size(), ExpectedNumOfRows);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_nop}), Succeeded());
EXPECT_TRUE(!TestFDE.cfis().empty());
RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
EXPECT_EQ(RowsOrErr->size(), ExpectedNumOfRows);
}
TEST(DWARFDebugFrame, UnwindTableErrorNonAscendingFDERows) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
constexpr uint8_t Reg = 12;
constexpr uint8_t Offset = 32;
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, Reg, Offset}),
Succeeded());
EXPECT_THAT_ERROR(
parseCFI(TestFDE, {dwarf::DW_CFA_set_loc, 0x00, 0x11, 0, 0, 0, 0, 0, 0,
dwarf::DW_CFA_set_loc, 0x00, 0x10, 0, 0, 0, 0, 0, 0}),
Succeeded());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(),
FailedWithMessage("DW_CFA_set_loc with adrress 0x1000 which"
" must be greater than the current row "
"address 0x1100"));
}
TEST(DWARFDebugFrame, UnwindTableError_DW_CFA_restore_state) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
constexpr uint8_t Reg = 12;
constexpr uint8_t Offset = 32;
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, Reg, Offset}),
Succeeded());
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_restore_state}),
Succeeded());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(),
FailedWithMessage("DW_CFA_restore_state without a matching "
"previous DW_CFA_remember_state"));
}
TEST(DWARFDebugFrame, UnwindTableError_DW_CFA_GNU_window_save) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
constexpr uint8_t Reg = 12;
constexpr uint8_t Offset = 32;
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, Reg, Offset}),
Succeeded());
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_GNU_window_save}),
Succeeded());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(),
FailedWithMessage("DW_CFA opcode 0x2d is not supported for "
"architecture x86_64"));
}
TEST(DWARFDebugFrame, UnwindTableError_DW_CFA_def_cfa_offset) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {}), Succeeded());
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_def_cfa_offset, 16}),
Succeeded());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(),
FailedWithMessage("DW_CFA_def_cfa_offset found when CFA "
"rule was not RegPlusOffset"));
}
TEST(DWARFDebugFrame, UnwindTableDefCFAOffsetSFCFAError) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {}), Succeeded());
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_def_cfa_offset_sf, 4}),
Succeeded());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(),
FailedWithMessage("DW_CFA_def_cfa_offset_sf found when CFA "
"rule was not RegPlusOffset"));
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_def_cfa_register) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
constexpr uint8_t CFAReg = 12;
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa_register, CFAReg}),
Succeeded());
EXPECT_THAT_ERROR(parseCFI(TestFDE, {}), Succeeded());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg, 0));
}
TEST(DWARFDebugFrame, UnwindTableRowPushingOpcodes) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
constexpr uint8_t CFAReg = 12;
constexpr uint8_t CFAOffset = 32;
constexpr uint8_t Reg = 13;
constexpr uint8_t InReg = 14;
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, CFAReg, CFAOffset,
dwarf::DW_CFA_register, Reg, InReg}),
Succeeded());
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_advance_loc | 4,
dwarf::DW_CFA_advance_loc1,
4,
dwarf::DW_CFA_advance_loc2,
4,
0,
dwarf::DW_CFA_advance_loc4,
4,
0,
0,
0,
dwarf::DW_CFA_set_loc,
0x14,
0x10,
0,
0,
0,
0,
0,
0}),
Succeeded());
dwarf::RegisterLocations VerifyLocs;
VerifyLocs.setRegisterLocation(
Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
ASSERT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 6u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[1].getAddress(), 0x1004u);
EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[2].getAddress(), 0x1008u);
EXPECT_EQ(Rows[2].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[2].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[3].getAddress(), 0x100cu);
EXPECT_EQ(Rows[3].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[3].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[4].getAddress(), 0x1010u);
EXPECT_EQ(Rows[4].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[5].getAddress(), 0x1014u);
EXPECT_EQ(Rows[5].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[5].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_restore) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
constexpr uint8_t CFAReg = 12;
constexpr uint8_t CFAOffset = 32;
constexpr uint8_t Reg = 13;
constexpr uint8_t InReg = 14;
constexpr int32_t RegCFAOffset = -8;
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, CFAReg, CFAOffset,
dwarf::DW_CFA_register, Reg, InReg}),
Succeeded());
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_offset | Reg, 1,
dwarf::DW_CFA_advance_loc | 4,
dwarf::DW_CFA_restore | Reg}),
Succeeded());
dwarf::RegisterLocations VerifyLocs1;
VerifyLocs1.setRegisterLocation(
Reg, dwarf::UnwindLocation::createAtCFAPlusOffset(RegCFAOffset));
dwarf::RegisterLocations VerifyLocs2;
VerifyLocs2.setRegisterLocation(
Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 2u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs1);
EXPECT_EQ(Rows[1].getAddress(), 0x1004u);
EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs2);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_restore_extended) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
constexpr uint8_t CFAReg = 12;
constexpr uint8_t CFAOffset = 32;
constexpr uint8_t Reg = 13;
constexpr uint8_t InReg = 14;
constexpr int32_t RegCFAOffset = -8;
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, CFAReg, CFAOffset,
dwarf::DW_CFA_register, Reg, InReg}),
Succeeded());
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_offset | Reg, 1,
dwarf::DW_CFA_advance_loc | 4,
dwarf::DW_CFA_restore_extended, Reg}),
Succeeded());
dwarf::RegisterLocations VerifyLocs1;
VerifyLocs1.setRegisterLocation(
Reg, dwarf::UnwindLocation::createAtCFAPlusOffset(RegCFAOffset));
dwarf::RegisterLocations VerifyLocs2;
VerifyLocs2.setRegisterLocation(
Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 2u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs1);
EXPECT_EQ(Rows[1].getAddress(), 0x1004u);
EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs2);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_offset) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),
Succeeded());
constexpr uint8_t Reg1 = 14;
constexpr uint8_t Reg2 = 15;
constexpr uint8_t Reg3 = 16;
constexpr uint8_t Neg1SLEB = 0x7f;
EXPECT_THAT_ERROR(
parseCFI(TestFDE,
{dwarf::DW_CFA_offset | Reg1, 1, dwarf::DW_CFA_offset_extended,
Reg2, 2, dwarf::DW_CFA_offset_extended_sf, Reg3, Neg1SLEB}),
Succeeded());
dwarf::RegisterLocations VerifyLocs;
VerifyLocs.setRegisterLocation(
Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));
VerifyLocs.setRegisterLocation(
Reg2, dwarf::UnwindLocation::createAtCFAPlusOffset(-16));
VerifyLocs.setRegisterLocation(
Reg3, dwarf::UnwindLocation::createAtCFAPlusOffset(8));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_val_offset) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),
Succeeded());
constexpr uint8_t Reg1 = 14;
constexpr uint8_t Reg2 = 15;
constexpr uint8_t Neg1SLEB = 0x7f;
EXPECT_THAT_ERROR(
parseCFI(TestFDE, {dwarf::DW_CFA_val_offset, Reg1, 1,
dwarf::DW_CFA_val_offset_sf, Reg2, Neg1SLEB}),
Succeeded());
dwarf::RegisterLocations VerifyLocs;
VerifyLocs.setRegisterLocation(
Reg1, dwarf::UnwindLocation::createIsCFAPlusOffset(-8));
VerifyLocs.setRegisterLocation(
Reg2, dwarf::UnwindLocation::createIsCFAPlusOffset(8));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_nop) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),
Succeeded());
constexpr uint8_t Reg1 = 14;
EXPECT_THAT_ERROR(
parseCFI(TestFDE, {dwarf::DW_CFA_nop, dwarf::DW_CFA_offset | Reg1, 1}),
Succeeded());
dwarf::RegisterLocations VerifyLocs;
VerifyLocs.setRegisterLocation(
Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_remember_state) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),
Succeeded());
constexpr uint8_t Reg1 = 14;
constexpr uint8_t Reg2 = 15;
constexpr uint8_t Reg3 = 16;
EXPECT_THAT_ERROR(
parseCFI(TestFDE,
{dwarf::DW_CFA_offset | Reg1, 1, dwarf::DW_CFA_advance_loc | 4,
dwarf::DW_CFA_remember_state, dwarf::DW_CFA_offset | Reg2, 2,
dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_remember_state,
dwarf::DW_CFA_offset | Reg3, 3, dwarf::DW_CFA_advance_loc | 4,
dwarf::DW_CFA_restore_state, dwarf::DW_CFA_advance_loc | 4,
dwarf::DW_CFA_restore_state}),
Succeeded());
dwarf::RegisterLocations VerifyLocs1;
VerifyLocs1.setRegisterLocation(
Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));
dwarf::RegisterLocations VerifyLocs2;
VerifyLocs2.setRegisterLocation(
Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));
VerifyLocs2.setRegisterLocation(
Reg2, dwarf::UnwindLocation::createAtCFAPlusOffset(-16));
dwarf::RegisterLocations VerifyLocs3;
VerifyLocs3.setRegisterLocation(
Reg1, dwarf::UnwindLocation::createAtCFAPlusOffset(-8));
VerifyLocs3.setRegisterLocation(
Reg2, dwarf::UnwindLocation::createAtCFAPlusOffset(-16));
VerifyLocs3.setRegisterLocation(
Reg3, dwarf::UnwindLocation::createAtCFAPlusOffset(-24));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 5u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs1);
EXPECT_EQ(Rows[1].getAddress(), 0x1004u);
EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs2);
EXPECT_EQ(Rows[2].getAddress(), 0x1008u);
EXPECT_EQ(Rows[2].getRegisterLocations(), VerifyLocs3);
EXPECT_EQ(Rows[3].getAddress(), 0x100Cu);
EXPECT_EQ(Rows[3].getRegisterLocations(), VerifyLocs2);
EXPECT_EQ(Rows[4].getAddress(), 0x1010u);
EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs1);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_undefined) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),
Succeeded());
constexpr uint8_t Reg1 = 14;
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_undefined, Reg1}),
Succeeded());
dwarf::RegisterLocations VerifyLocs;
VerifyLocs.setRegisterLocation(Reg1,
dwarf::UnwindLocation::createUndefined());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_same_value) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),
Succeeded());
constexpr uint8_t Reg1 = 14;
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_same_value, Reg1}),
Succeeded());
dwarf::RegisterLocations VerifyLocs;
VerifyLocs.setRegisterLocation(Reg1, dwarf::UnwindLocation::createSame());
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_register) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),
Succeeded());
constexpr uint8_t Reg = 13;
constexpr uint8_t InReg = 14;
EXPECT_THAT_ERROR(parseCFI(TestFDE, {dwarf::DW_CFA_register, Reg, InReg}),
Succeeded());
dwarf::RegisterLocations VerifyLocs;
VerifyLocs.setRegisterLocation(
Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_expression) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),
Succeeded());
constexpr uint8_t Reg = 13;
constexpr uint8_t AddrSize = 8;
std::vector<uint8_t> CFIBytes = {dwarf::DW_CFA_expression, Reg, 1,
dwarf::DW_OP_reg12};
EXPECT_THAT_ERROR(parseCFI(TestFDE, CFIBytes), Succeeded());
dwarf::RegisterLocations VerifyLocs;
std::vector<uint8_t> ExprBytes = {dwarf::DW_OP_reg12};
DataExtractor ExprData(ExprBytes, true, AddrSize);
DWARFExpression Expr(ExprData, AddrSize);
VerifyLocs.setRegisterLocation(
Reg, dwarf::UnwindLocation::createAtDWARFExpression(Expr));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_val_expression) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, 12, 32}),
Succeeded());
constexpr uint8_t Reg = 13;
constexpr uint8_t AddrSize = 8;
std::vector<uint8_t> CFIBytes = {dwarf::DW_CFA_val_expression, Reg, 1,
dwarf::DW_OP_reg12};
EXPECT_THAT_ERROR(parseCFI(TestFDE, CFIBytes), Succeeded());
dwarf::RegisterLocations VerifyLocs;
std::vector<uint8_t> ExprBytes = {dwarf::DW_OP_reg12};
DataExtractor ExprData(ExprBytes, true, AddrSize);
DWARFExpression Expr(ExprData, AddrSize);
VerifyLocs.setRegisterLocation(
Reg, dwarf::UnwindLocation::createIsDWARFExpression(Expr));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_def_cfa) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
constexpr uint8_t CFAReg1 = 12;
constexpr uint8_t CFAOff1 = 32;
constexpr uint8_t CFAReg2 = 13;
constexpr uint8_t CFAOff2 = 48;
constexpr uint8_t Reg = 13;
constexpr uint8_t InReg = 14;
EXPECT_THAT_ERROR(parseCFI(TestCIE, {dwarf::DW_CFA_def_cfa, CFAReg1, CFAOff1,
dwarf::DW_CFA_register, Reg, InReg}),
Succeeded());
EXPECT_THAT_ERROR(
parseCFI(
TestFDE,
{
dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_register,
CFAReg2, dwarf::DW_CFA_advance_loc | 4,
dwarf::DW_CFA_def_cfa_offset, CFAOff2,
dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_offset_sf,
0x7c, dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_sf, CFAReg1,
0x7a, }),
Succeeded());
dwarf::RegisterLocations VerifyLocs;
VerifyLocs.setRegisterLocation(
Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 5u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(
Rows[0].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff1));
EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[1].getAddress(), 0x1004u);
EXPECT_EQ(
Rows[1].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1));
EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[2].getAddress(), 0x1008u);
EXPECT_EQ(
Rows[2].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff2));
EXPECT_EQ(Rows[2].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[2].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[3].getAddress(), 0x100cu);
EXPECT_EQ(
Rows[3].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1));
EXPECT_EQ(Rows[3].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[3].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[4].getAddress(), 0x1010u);
EXPECT_EQ(
Rows[4].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff2));
EXPECT_EQ(Rows[4].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs);
}
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_LLVM_def_aspace_cfa) {
dwarf::CIE TestCIE = createCIE(false,
0x0,
0xff);
dwarf::FDE TestFDE(true,
0x3333abcdabcd,
0x4444abcdabcd,
0x1111abcdabcd,
0x1000,
0x1000,
&TestCIE,
None,
Triple::x86_64);
constexpr uint8_t CFAReg1 = 12;
constexpr uint8_t CFAOff1 = 32;
constexpr uint8_t CFAReg2 = 13;
constexpr uint8_t CFAOff2 = 48;
constexpr uint8_t Reg = 13;
constexpr uint8_t InReg = 14;
constexpr uint8_t AddrSpace = 2;
EXPECT_THAT_ERROR(
parseCFI(TestCIE, {dwarf::DW_CFA_LLVM_def_aspace_cfa, CFAReg1, CFAOff1,
AddrSpace, dwarf::DW_CFA_register, Reg, InReg}),
Succeeded());
EXPECT_THAT_ERROR(
parseCFI(
TestFDE,
{
dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_register,
CFAReg2, dwarf::DW_CFA_advance_loc | 4,
dwarf::DW_CFA_def_cfa_offset, CFAOff2,
dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_offset_sf,
0x7c, dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_sf, CFAReg1,
0x7a, }),
Succeeded());
dwarf::RegisterLocations VerifyLocs;
VerifyLocs.setRegisterLocation(
Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
const dwarf::UnwindTable &Rows = RowsOrErr.get();
EXPECT_EQ(Rows.size(), 5u);
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
EXPECT_EQ(Rows[0].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff1,
AddrSpace));
EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[1].getAddress(), 0x1004u);
EXPECT_EQ(Rows[1].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1,
AddrSpace));
EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[2].getAddress(), 0x1008u);
EXPECT_EQ(Rows[2].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff2,
AddrSpace));
EXPECT_EQ(Rows[2].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[2].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[3].getAddress(), 0x100cu);
EXPECT_EQ(Rows[3].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1,
AddrSpace));
EXPECT_EQ(Rows[3].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[3].getRegisterLocations(), VerifyLocs);
EXPECT_EQ(Rows[4].getAddress(), 0x1010u);
EXPECT_EQ(Rows[4].getCFAValue(),
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff2,
AddrSpace));
EXPECT_EQ(Rows[4].getRegisterLocations().size(), 1u);
EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs);
}
}