Index: unittests/DebugInfo/DWARF/CMakeLists.txt =================================================================== --- unittests/DebugInfo/DWARF/CMakeLists.txt +++ unittests/DebugInfo/DWARF/CMakeLists.txt @@ -9,6 +9,7 @@ set(DebugInfoSources DwarfGenerator.cpp + DWARFContextTest.cpp DWARFDebugInfoTest.cpp DWARFFormValueTest.cpp ) Index: unittests/DebugInfo/DWARF/DWARFContextTest.cpp =================================================================== --- /dev/null +++ unittests/DebugInfo/DWARF/DWARFContextTest.cpp @@ -0,0 +1,215 @@ +//===- llvm/unittest/DebugInfo/DWARFContextTest.cpp -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DwarfGenerator.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" +#include + +using namespace llvm; +using namespace dwarf; + +namespace { + +void initLLVMIfNeeded() { + static bool gInitialized = false; + if (!gInitialized) { + gInitialized = true; + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + } +} + +Triple getHostTripleForAddrSize(uint8_t AddrSize) { + Triple PT(Triple::normalize(LLVM_HOST_TRIPLE)); + + if (AddrSize == 8 && PT.isArch32Bit()) + return PT.get64BitArchVariant(); + if (AddrSize == 4 && PT.isArch64Bit()) + return PT.get32BitArchVariant(); + return PT; +} + +/// Take any llvm::Expected and check and handle any errors. +/// +/// \param Expected a llvm::Excepted instance to check. +/// \returns true if there were errors, false otherwise. +template +static bool HandleExpectedError(T &Expected) { + std::string ErrorMsg; + handleAllErrors(Expected.takeError(), [&](const llvm::ErrorInfoBase &EI) { + ErrorMsg = EI.message(); + }); + if (!ErrorMsg.empty()) { + ::testing::AssertionFailure() << "error: " << ErrorMsg; + return true; + } + return false; +} + +template void TestDWARFLineInfo() { + // Test the DWARFContext APIs related to accessing the start line number for a + // function corresponding to an address. + const uint8_t AddrSize = sizeof(AddrType); + initLLVMIfNeeded(); + Triple Triple = getHostTripleForAddrSize(AddrSize); + auto ExpectedDG = dwarfgen::Generator::create(Triple, Version); + if (HandleExpectedError(ExpectedDG)) + return; + dwarfgen::Generator *DG = ExpectedDG.get().get(); + dwarfgen::CompileUnit &CU = DG->addCompileUnit(); + dwarfgen::DIE CUDie = CU.getUnitDIE(); + + CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "init.c"); + CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C); + + // Create some subprogram DIEs with the relevant fields. + dwarfgen::DIE DIE1 = CUDie.addChild(DW_TAG_subprogram); + DIE1.addAttribute(DW_AT_external, DW_FORM_data1, 1); + DIE1.addAttribute(DW_AT_name, DW_FORM_strp, "main"); + DIE1.addAttribute(DW_AT_decl_file, DW_FORM_data1, 1); + DIE1.addAttribute(DW_AT_decl_line, DW_FORM_data1, 8); + DIE1.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x40069c); + DIE1.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x4006c7); + + dwarfgen::DIE DIE2 = CUDie.addChild(DW_TAG_subprogram); + DIE2.addAttribute(DW_AT_external, DW_FORM_data1, 1); + DIE2.addAttribute(DW_AT_name, DW_FORM_strp, "__libc_csu_init"); + DIE2.addAttribute(DW_AT_decl_file, DW_FORM_data1, 1); + DIE2.addAttribute(DW_AT_decl_line, DW_FORM_data1, 106); + DIE2.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x4006d0); + DIE2.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x400759); + + dwarfgen::DIE DIE3 = CUDie.addChild(DW_TAG_subprogram); + DIE3.addAttribute(DW_AT_external, DW_FORM_data1, 1); + DIE3.addAttribute(DW_AT_name, DW_FORM_strp, "__libc_csu_fini"); + DIE3.addAttribute(DW_AT_decl_file, DW_FORM_data1, 1); + DIE3.addAttribute(DW_AT_decl_line, DW_FORM_data1, 132); + DIE3.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x400760); + DIE3.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x400762); + + // Generate the DWARF and read it into a DWARFContext + StringRef FileBytes = DG->generate(); + MemoryBufferRef FileBuffer(FileBytes, "dwarf"); + auto Obj = object::ObjectFile::createObjectFile(FileBuffer); + EXPECT_TRUE((bool)Obj); + DWARFContextInMemory DwarfContext(*Obj.get()); + + // Verify the number of compile units is correct. + uint32_t NumCUs = DwarfContext.getNumCompileUnits(); + EXPECT_EQ(NumCUs, 1u); + DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0); + + // Get the compile unit DIE is valid. + auto DieDG = U->getUnitDIE(false); + EXPECT_TRUE(DieDG.isValid()); + + DILineInfoSpecifier Spec; + Spec.FNKind = DINameKind::LinkageName; + + // Test beginning, middle, and end address for each function. + // TODO: Add line tables to test filenames. + // TODO: Uncomment StartLine checks in https://reviews.llvm.org/D27962. + { + DILineInfo Info = DwarfContext.getLineInfoForAddress(0x40069c, Spec); + //EXPECT_EQ(Info.FileName, "init.c"); + EXPECT_EQ(Info.FunctionName, "main"); + //EXPECT_EQ(Info.StartLine, 8); + } + { + DILineInfo Info = DwarfContext.getLineInfoForAddress(0x4006a0, Spec); + //EXPECT_EQ(Info.FileName, "init.c"); + EXPECT_EQ(Info.FunctionName, "main"); + //EXPECT_EQ(Info.StartLine, 8); + } + { + DILineInfo Info = DwarfContext.getLineInfoForAddress(0x4006c6, Spec); + //EXPECT_EQ(Info.FileName, "init.c"); + EXPECT_EQ(Info.FunctionName, "main"); + //EXPECT_EQ(Info.StartLine, 8); + } + + { + DILineInfo Info = DwarfContext.getLineInfoForAddress(0x4006d0, Spec); + //EXPECT_EQ(Info.FileName, "init.c"); + EXPECT_EQ(Info.FunctionName, "__libc_csu_init"); + //EXPECT_EQ(Info.StartLine, 106); + } + { + DILineInfo Info = DwarfContext.getLineInfoForAddress(0x400700, Spec); + //EXPECT_EQ(Info.FileName, "init.c"); + EXPECT_EQ(Info.FunctionName, "__libc_csu_init"); + //EXPECT_EQ(Info.StartLine, 106); + } + { + DILineInfo Info = DwarfContext.getLineInfoForAddress(0x400758, Spec); + //EXPECT_EQ(Info.FileName, "init.c"); + EXPECT_EQ(Info.FunctionName, "__libc_csu_init"); + //EXPECT_EQ(Info.StartLine, 106); + } + + { + DILineInfo Info = DwarfContext.getLineInfoForAddress(0x400760, Spec); + //EXPECT_EQ(Info.FileName, "init.c"); + EXPECT_EQ(Info.FunctionName, "__libc_csu_fini"); + //EXPECT_EQ(Info.StartLine, 132); + } + { + DILineInfo Info = DwarfContext.getLineInfoForAddress(0x400761, Spec); + //EXPECT_EQ(Info.FileName, "init.c"); + EXPECT_EQ(Info.FunctionName, "__libc_csu_fini"); + //EXPECT_EQ(Info.StartLine, 132); + } +} + +TEST(DWARFContext, TestDWARF32Version2Addr4LineInfo) { + // Test that we can look up line info in DWARF32, version 2, with 4 byte + // addresses. + TestDWARFLineInfo<2, uint32_t>(); +} + +TEST(DWARFContext, TestDWARF32Version2Addr8LineInfo) { + // Test that we can look up line info in DWARF32, version 2, with 8 byte + // addresses. + TestDWARFLineInfo<2, uint64_t>(); +} + +TEST(DWARFContext, TestDWARF32Version3Addr4LineInfo) { + // Test that we can look up line info in DWARF32, version 3, with 4 byte + // addresses. + TestDWARFLineInfo<3, uint32_t>(); +} + +TEST(DWARFContext, TestDWARF32Version3Addr8LineInfo) { + // Test that we can look up line info in DWARF32, version 3, with 8 byte + // addresses. + TestDWARFLineInfo<3, uint64_t>(); +} + +TEST(DWARFContext, TestDWARF32Version4Addr4LineInfo) { + // Test that we can look up line info in DWARF32, version 4, with 4 byte + // addresses. + TestDWARFLineInfo<4, uint32_t>(); +} + +TEST(DWARFContext, TestDWARF32Version4Addr8LineInfo) { + // Test that we can look up line info in DWARF32, version 4, with 8 byte + // addresses. + TestDWARFLineInfo<4, uint64_t>(); +} + +} // end anonymous namespace Index: unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -1,4 +1,4 @@ -//===- llvm/unittest/DebugInfo/DWARFFormValueTest.cpp ---------------------===// +//===- llvm/unittest/DebugInfo/DWARFDebugInfoTest.cpp ---------------------===// // // The LLVM Compiler Infrastructure //