diff options
-rw-r--r-- | llvm/lib/MC/MCDwarf.cpp | 7 | ||||
-rw-r--r-- | llvm/unittests/MC/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/unittests/MC/DwarfLineTables.cpp | 179 |
3 files changed, 185 insertions, 2 deletions
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp index f2de2fc7255..e3e5f239ef6 100644 --- a/llvm/lib/MC/MCDwarf.cpp +++ b/llvm/lib/MC/MCDwarf.cpp @@ -452,7 +452,8 @@ void MCDwarfLineAddr::Encode(MCContext &Context, MCDwarfLineTableParams Params, // If the line increment is out of range of a special opcode, we must encode // it with DW_LNS_advance_line. - if (Temp >= Params.DWARF2LineRange) { + if (Temp >= Params.DWARF2LineRange || + Temp + Params.DWARF2LineOpcodeBase > 255) { OS << char(dwarf::DW_LNS_advance_line); encodeSLEB128(LineDelta, OS); @@ -494,8 +495,10 @@ void MCDwarfLineAddr::Encode(MCContext &Context, MCDwarfLineTableParams Params, if (NeedCopy) OS << char(dwarf::DW_LNS_copy); - else + else { + assert(Temp <= 255 && "Buggy special opcode encoding."); OS << char(Temp); + } } // Utility function to write a tuple for .debug_abbrev. diff --git a/llvm/unittests/MC/CMakeLists.txt b/llvm/unittests/MC/CMakeLists.txt index f83eaf4779f..9d68e783a55 100644 --- a/llvm/unittests/MC/CMakeLists.txt +++ b/llvm/unittests/MC/CMakeLists.txt @@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(MCTests Disassembler.cpp + DwarfLineTables.cpp StringTableBuilderTest.cpp YAMLTest.cpp ) diff --git a/llvm/unittests/MC/DwarfLineTables.cpp b/llvm/unittests/MC/DwarfLineTables.cpp new file mode 100644 index 00000000000..4bfb5acea03 --- /dev/null +++ b/llvm/unittests/MC/DwarfLineTables.cpp @@ -0,0 +1,179 @@ +//===- llvm/unittest/MC/DwarfLineTables.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Dwarf.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { +struct Context { + const char *Triple = "x86_64-pc-linux"; + std::unique_ptr<MCRegisterInfo> MRI; + std::unique_ptr<MCAsmInfo> MAI; + std::unique_ptr<MCContext> Ctx; + + Context() { + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllDisassemblers(); + + // If we didn't build x86, do not run the test. + std::string Error; + const Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); + if (!TheTarget) + return; + + MRI.reset(TheTarget->createMCRegInfo(Triple)); + MAI.reset(TheTarget->createMCAsmInfo(*MRI, Triple)); + Ctx = llvm::make_unique<MCContext>(MAI.get(), MRI.get(), nullptr); + } + + operator bool() { return Ctx.get(); } + operator MCContext &() { return *Ctx; }; +}; + +Context Ctxt; +} + +void verifyEncoding(MCDwarfLineTableParams Params, int LineDelta, int AddrDelta, + ArrayRef<uint8_t> ExpectedEncoding) { + SmallString<16> Buffer; + raw_svector_ostream EncodingOS(Buffer); + MCDwarfLineAddr::Encode(Ctxt, Params, LineDelta, AddrDelta, EncodingOS); + ArrayRef<uint8_t> Encoding(reinterpret_cast<uint8_t *>(Buffer.data()), + Buffer.size()); + EXPECT_EQ(ExpectedEncoding, Encoding); +} + +TEST(DwarfLineTables, TestDefaultParams) { + if (!Ctxt) + return; + + MCDwarfLineTableParams Params; + + // Minimal line offset expressible through extended opcode, 0 addr delta + const uint8_t Encoding0[] = {13}; // Special opcode Addr += 0, Line += -5 + verifyEncoding(Params, -5, 0, Encoding0); + + // Maximal line offset expressible through extended opcode, + const uint8_t Encoding1[] = {26}; // Special opcode Addr += 0, Line += +8 + verifyEncoding(Params, 8, 0, Encoding1); + + // Random value in the middle of the special ocode range + const uint8_t Encoding2[] = {146}; // Special opcode Addr += 9, Line += 2 + verifyEncoding(Params, 2, 9, Encoding2); + + // Minimal line offset expressible through extended opcode, max addr delta + const uint8_t Encoding3[] = {251}; // Special opcode Addr += 17, Line += -5 + verifyEncoding(Params, -5, 17, Encoding3); + + // Biggest special opcode + const uint8_t Encoding4[] = {255}; // Special opcode Addr += 17, Line += -1 + verifyEncoding(Params, -1, 17, Encoding4); + + // Line delta outside of the special opcode range, address delta in range + const uint8_t Encoding5[] = {dwarf::DW_LNS_advance_line, 9, + 158}; // Special opcode Addr += 10, Line += 0 + verifyEncoding(Params, 9, 10, Encoding5); + + // Address delta outside of the special opcode range, but small + // enough to do DW_LNS_const_add_pc + special opcode. + const uint8_t Encoding6[] = {dwarf::DW_LNS_const_add_pc, // pc += 17 + 62}; // Special opcode Addr += 3, Line += 2 + verifyEncoding(Params, 2, 20, Encoding6); + + // Address delta big enough to require the use of DW_LNS_advance_pc + // Line delta in special opcode range + const uint8_t Encoding7[] = {dwarf::DW_LNS_advance_pc, 100, + 20}; // Special opcode Addr += 0, Line += 2 + verifyEncoding(Params, 2, 100, Encoding7); + + // No special opcode possible. + const uint8_t Encoding8[] = {dwarf::DW_LNS_advance_line, 20, + dwarf::DW_LNS_advance_pc, 100, + dwarf::DW_LNS_copy}; + verifyEncoding(Params, 20, 100, Encoding8); +} + +TEST(DwarfLineTables, TestCustomParams) { + if (!Ctxt) + return; + + // Some tests against the example values given in the standard. + MCDwarfLineTableParams Params; + Params.DWARF2LineOpcodeBase = 13; + Params.DWARF2LineBase = -3; + Params.DWARF2LineRange = 12; + + // Minimal line offset expressible through extended opcode, 0 addr delta + const uint8_t Encoding0[] = {13}; // Special opcode Addr += 0, Line += -5 + verifyEncoding(Params, -3, 0, Encoding0); + + // Maximal line offset expressible through extended opcode, + const uint8_t Encoding1[] = {24}; // Special opcode Addr += 0, Line += +8 + verifyEncoding(Params, 8, 0, Encoding1); + + // Random value in the middle of the special ocode range + const uint8_t Encoding2[] = {126}; // Special opcode Addr += 9, Line += 2 + verifyEncoding(Params, 2, 9, Encoding2); + + // Minimal line offset expressible through extended opcode, max addr delta + const uint8_t Encoding3[] = {253}; // Special opcode Addr += 20, Line += -3 + verifyEncoding(Params, -3, 20, Encoding3); + + // Biggest special opcode + const uint8_t Encoding4[] = {255}; // Special opcode Addr += 17, Line += -1 + verifyEncoding(Params, -1, 20, Encoding4); + + // Line delta outside of the special opcode range, address delta in range + const uint8_t Encoding5[] = {dwarf::DW_LNS_advance_line, 9, + 136}; // Special opcode Addr += 10, Line += 0 + verifyEncoding(Params, 9, 10, Encoding5); + + // Address delta outside of the special opcode range, but small + // enough to do DW_LNS_const_add_pc + special opcode. + const uint8_t Encoding6[] = {dwarf::DW_LNS_const_add_pc, // pc += 20 + 138}; // Special opcode Addr += 10, Line += 2 + verifyEncoding(Params, 2, 30, Encoding6); + + // Address delta big enough to require the use of DW_LNS_advance_pc + // Line delta in special opcode range + const uint8_t Encoding7[] = {dwarf::DW_LNS_advance_pc, 100, + 18}; // Special opcode Addr += 0, Line += 2 + verifyEncoding(Params, 2, 100, Encoding7); + + // No special opcode possible. + const uint8_t Encoding8[] = {dwarf::DW_LNS_advance_line, 20, + dwarf::DW_LNS_advance_pc, 100, + dwarf::DW_LNS_copy}; + verifyEncoding(Params, 20, 100, Encoding8); +} + +TEST(DwarfLineTables, TestCustomParams2) { + if (!Ctxt) + return; + + // Corner case param values. + MCDwarfLineTableParams Params; + Params.DWARF2LineOpcodeBase = 13; + Params.DWARF2LineBase = 1; + Params.DWARF2LineRange = 255; + + const uint8_t Encoding0[] = {dwarf::DW_LNS_advance_line, 248, 1, + dwarf::DW_LNS_copy}; + verifyEncoding(Params, 248, 0, Encoding0); +} |