Index: llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -259,6 +259,12 @@ /// Get a pointer to the parsed dwo abbreviations object. const DWARFDebugAbbrev *getDebugAbbrevDWO(); + /// Get a pointer to the parsed DebugLoc object. + const DWARFDebugLoclists *getDebugLocDWO(); + + /// Get a pointer to the parsed DebugLoclists object. + const DWARFDebugLoclists *getDebugLoclistsDWO(); + /// Get a pointer to the parsed DebugAranges object. const DWARFDebugAranges *getDebugAranges(); Index: llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -60,6 +60,7 @@ virtual StringRef getAbbrevDWOSection() const { return ""; } virtual const DWARFSection &getLineDWOSection() const { return Dummy; } virtual const DWARFSection &getLocDWOSection() const { return Dummy; } + virtual const DWARFSection &getLoclistsDWOSection() const { return Dummy; } virtual StringRef getStrDWOSection() const { return ""; } virtual const DWARFSection &getStrOffsetsDWOSection() const { return Dummy; Index: llvm/include/llvm/MC/MCObjectFileInfo.h =================================================================== --- llvm/include/llvm/MC/MCObjectFileInfo.h +++ llvm/include/llvm/MC/MCObjectFileInfo.h @@ -120,8 +120,9 @@ /// The DWARF v5 locations list section. MCSection *DwarfLoclistsSection = nullptr; - /// The DWARF v5 range list section for fission. + /// The DWARF v5 range and location list sections for fission. MCSection *DwarfRnglistsDWOSection = nullptr; + MCSection *DwarfLoclistsDWOSection = nullptr; // These are for Fission DWP files. MCSection *DwarfCUIndexSection = nullptr; @@ -299,6 +300,9 @@ MCSection *getDwarfRnglistsDWOSection() const { return DwarfRnglistsDWOSection; } + MCSection *getDwarfLoclistsDWOSection() const { + return DwarfLoclistsDWOSection; + } MCSection *getDwarfCUIndexSection() const { return DwarfCUIndexSection; } MCSection *getDwarfTUIndexSection() const { return DwarfTUIndexSection; } MCSection *getDwarfSwiftASTSection() const { return DwarfSwiftASTSection; } Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1143,11 +1143,12 @@ if (U.hasRangeLists()) U.addRnglistsBase(); - if (!DebugLocs.getLists().empty() && !useSplitDwarf()) { + if (!DebugLocs.getLists().empty()) { DebugLocs.setSym(Asm->createTempSymbol("loclists_table_base")); - U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_loclists_base, - DebugLocs.getSym(), - TLOF.getDwarfLoclistsSection()->getBeginSymbol()); + if (!useSplitDwarf()) + U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_loclists_base, + DebugLocs.getSym(), + TLOF.getDwarfLoclistsSection()->getBeginSymbol()); } } @@ -1191,10 +1192,11 @@ emitDebugStr(); - if (useSplitDwarf()) + if (useSplitDwarf() && getDwarfVersion() <= 4) + // Handles only debug_loc.dwo section emission emitDebugLocDWO(); else - // Emit info into a debug loc section. + // Handles all the remaining cases. emitDebugLoc(); // Corresponding abbreviations into a abbrev section. @@ -2425,16 +2427,26 @@ } } +// Handles emission of both debug_loclist / debug_loclist.dwo static void emitLocList(DwarfDebug &DD, AsmPrinter *Asm, const DebugLocStream::List &List) { - emitRangeList( - DD, Asm, List.Label, DD.getDebugLocs().getEntries(List), *List.CU, - dwarf::DW_LLE_base_addressx, dwarf::DW_LLE_offset_pair, - dwarf::DW_LLE_startx_length, dwarf::DW_LLE_end_of_list, - llvm::dwarf::LocListEncodingString, - /* ShouldUseBaseAddress */ true, - [&](const DebugLocStream::Entry &E) { - DD.emitDebugLocEntryLocation(E, List.CU); - }); + if (!DD.useSplitDwarf()) + emitRangeList(DD, Asm, List.Label, DD.getDebugLocs().getEntries(List), + *List.CU, dwarf::DW_LLE_base_addressx, + dwarf::DW_LLE_offset_pair, dwarf::DW_LLE_startx_length, + dwarf::DW_LLE_end_of_list, llvm::dwarf::LocListEncodingString, + /* ShouldUseBaseAddress */ true, + [&](const DebugLocStream::Entry &E) { + DD.emitDebugLocEntryLocation(E, List.CU); + }); + else + emitRangeList(DD, Asm, List.Label, DD.getDebugLocs().getEntries(List), + *List.CU, dwarf::DW_LLE_base_addressx, + dwarf::DW_LLE_offset_pair, dwarf::DW_LLE_startx_length, + dwarf::DW_LLE_end_of_list, llvm::dwarf::LocListEncodingString, + /* ShouldUseBaseAddress */ false, + [&](const DebugLocStream::Entry &E) { + DD.emitDebugLocEntryLocation(E, List.CU); + }); } // Emit locations into the .debug_loc/.debug_rnglists section. @@ -2444,8 +2456,14 @@ MCSymbol *TableEnd = nullptr; if (getDwarfVersion() >= 5) { - Asm->OutStreamer->SwitchSection( - Asm->getObjFileLowering().getDwarfLoclistsSection()); + + // Switch to appropriate section based on split or not + useSplitDwarf() + ? Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfLoclistsDWOSection()) + : Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfLoclistsSection()); + TableEnd = emitLoclistsTableHeader(Asm, *this); } else { Asm->OutStreamer->SwitchSection( @@ -2460,10 +2478,15 @@ } void DwarfDebug::emitDebugLocDWO() { + if (DebugLocs.getLists().empty()) + return; + + unsigned char Size = Asm->MAI->getCodePointerSize(); for (const auto &List : DebugLocs.getLists()) { Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfLocDWOSection()); Asm->OutStreamer->EmitLabel(List.Label); + for (const auto &Entry : DebugLocs.getEntries(List)) { // GDB only supports startx_length in pre-standard split-DWARF. // (in v5 standard loclists, it currently* /only/ supports base_address + @@ -2476,10 +2499,12 @@ unsigned idx = AddrPool.getIndex(Entry.Begin); Asm->EmitULEB128(idx); Asm->EmitLabelDifference(Entry.End, Entry.Begin, 4); - emitDebugLocEntryLocation(Entry, List.CU); } - Asm->emitInt8(dwarf::DW_LLE_end_of_list); + // Pre-standardized fission uses two 0 to mark + // end of the location list + Asm->OutStreamer->EmitIntValue(0, Size); + Asm->OutStreamer->EmitIntValue(0, Size); } } Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -400,6 +400,14 @@ 0); dumpLoclistsSection(OS, DumpOpts, Data, getRegisterInfo(), *Off); } + if (const auto *Off = + shouldDump(ExplicitDWO, ".debug_loclists.dwo", DIDT_ID_DebugLoclists, + DObj->getLoclistsDWOSection().Data)) { + DWARFDataExtractor Data(*DObj, DObj->getLoclistsDWOSection(), + isLittleEndian(), 0); + dumpLoclistsSection(OS, DumpOpts, Data, getRegisterInfo(), *Off); + } + if (const auto *Off = shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc, DObj->getLocDWOSection().Data)) { @@ -1382,6 +1390,7 @@ DWARFSectionMap LocSection; DWARFSectionMap LoclistsSection; + DWARFSectionMap LoclistsDWOSection; DWARFSectionMap LineSection; DWARFSectionMap RangesSection; DWARFSectionMap RnglistsSection; @@ -1408,6 +1417,7 @@ return StringSwitch(Name) .Case("debug_loc", &LocSection) .Case("debug_loclists", &LoclistsSection) + .Case("debug_loclists.dwo", &LoclistsDWOSection) .Case("debug_line", &LineSection) .Case("debug_frame", &FrameSection) .Case("eh_frame", &EHFrameSection) @@ -1738,6 +1748,9 @@ const DWARFSection &getRnglistsDWOSection() const override { return RnglistsDWOSection; } + const DWARFSection &getLoclistsDWOSection() const override { + return LoclistsDWOSection; + } const DWARFSection &getAddrSection() const override { return AddrSection; } StringRef getCUIndexSection() const override { return CUIndexSection; } StringRef getGdbIndexSection() const override { return GdbIndexSection; } Index: llvm/lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -75,6 +75,22 @@ } } +static DWARFDataExtractor extractLoclistContents(bool UseDWO, int Version, + DWARFUnit *U) { + + DWARFContext &Ctx = U->getContext(); + const DWARFObject &Obj = Ctx.getDWARFObj(); + if (Version >= 5) + return UseDWO + ? DWARFDataExtractor(Obj, Obj.getLoclistsDWOSection(), + Ctx.isLittleEndian(), Obj.getAddressSize()) + : DWARFDataExtractor(Obj, Obj.getLoclistsSection(), + Ctx.isLittleEndian(), Obj.getAddressSize()); + else + return DWARFDataExtractor(U->getLocSectionData(), Ctx.isLittleEndian(), + Obj.getAddressSize()); +} + static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue, DWARFUnit *U, unsigned Indent, DIDumpOptions DumpOpts) { @@ -120,13 +136,8 @@ return; } - bool UseLocLists = !U->isDWOUnit(); - auto Data = - UseLocLists - ? DWARFDataExtractor(Obj, Obj.getLoclistsSection(), - Ctx.isLittleEndian(), Obj.getAddressSize()) - : DWARFDataExtractor(U->getLocSectionData(), Ctx.isLittleEndian(), - Obj.getAddressSize()); + bool Loclistsv5 = U->getVersion() >= 5; + auto Data = extractLoclistContents(U->isDWOUnit(), U->getVersion(), U); if (!Data.getData().empty()) { // Old-style location list were used in DWARF v4 (.debug_loc.dwo section). @@ -134,8 +145,8 @@ // Ideally we should take the version from the .debug_loclists section // header, but using CU's version for simplicity. DWARFDebugLoclists::dumpLocationList( - Data, &Offset, UseLocLists ? U->getVersion() : 4, OS, BaseAddr, MRI, - U, LLDumpOpts, Indent); + Data, &Offset, Loclistsv5 ? U->getVersion() : 4, OS, BaseAddr, MRI, U, + LLDumpOpts, Indent); } return; } Index: llvm/lib/MC/MCObjectFileInfo.cpp =================================================================== --- llvm/lib/MC/MCObjectFileInfo.cpp +++ llvm/lib/MC/MCObjectFileInfo.cpp @@ -464,6 +464,9 @@ DwarfRnglistsDWOSection = Ctx->getELFSection(".debug_rnglists.dwo", DebugSecType, ELF::SHF_EXCLUDE); + DwarfLoclistsDWOSection = + Ctx->getELFSection(".debug_loclists.dwo", DebugSecType, ELF::SHF_EXCLUDE); + // DWP Sections DwarfCUIndexSection = Ctx->getELFSection(".debug_cu_index", DebugSecType, 0); Index: llvm/test/CodeGen/X86/debug-loclists.ll =================================================================== --- llvm/test/CodeGen/X86/debug-loclists.ll +++ llvm/test/CodeGen/X86/debug-loclists.ll @@ -1,6 +1,9 @@ ; RUN: llc -mtriple=x86_64-pc-linux -filetype=obj -function-sections -o %t < %s ; RUN: llvm-dwarfdump -v -debug-info -debug-loclists %t | FileCheck %s +; RUN: llc -dwarf-version=5 -split-dwarf-file=foo.dwo -mtriple=x86_64-pc-linux -filetype=obj -function-sections -o %t < %s +; RUN: llvm-dwarfdump -v -debug-info -debug-loclists %t | FileCheck %s --check-prefix=DWO + ; CHECK: DW_TAG_variable ; FIXME: Use DW_FORM_loclistx to reduce relocations ; CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x0000000c @@ -8,21 +11,43 @@ ; CHECK-NEXT: [0x0000000000000003, 0x0000000000000004): DW_OP_consts +4, DW_OP_stack_value) ; CHECK-NEXT: DW_AT_name {{.*}} "y" +; With split-dwarf enbabled with dwarf-5 check contents of .debug_info.dwo contents +; DWO: .debug_info.dwo +; DWO: DW_TAG_variable +; DWO-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x0000000c: +; DWO-NEXT: Addr idx 0 (w/ length 3): DW_OP_consts +3, DW_OP_stack_value +; DWO-NEXT: Addr idx 2 (w/ length 1): DW_OP_consts +4, DW_OP_stack_value) +; DWO-NEXT: DW_AT_name {{.*}} "y" + ; CHECK: DW_TAG_variable ; FIXME: Use DW_FORM_loclistx to reduce relocations ; CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x0000001d ; CHECK-NEXT: Addr idx 0 (w/ length 3): DW_OP_consts +5, DW_OP_stack_value) ; CHECK-NEXT: DW_AT_name {{.*}} "x" +; DWO: DW_TAG_variable +; DWO-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x0000001b: +; DWO-NEXT: Addr idx 0 (w/ length 3): DW_OP_consts +5, DW_OP_stack_value) +; DWO-NEXT: DW_AT_name {{.*}} "x" + ; CHECK: DW_TAG_variable ; FIXME: Use DW_FORM_loclistx to reduce relocations ; CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000025 ; CHECK-NEXT: [0x0000000000000003, 0x0000000000000004): DW_OP_reg0 RAX) ; CHECK-NEXT: DW_AT_name {{.*}} "r" +; DWO: DW_TAG_variable +; DWO-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000023: +; DWO-NEXT: Addr idx 2 (w/ length 1): DW_OP_reg0 RAX) +; DWO-NEXT: DW_AT_name {{.*}} "r" + ; CHECK: .debug_loclists contents: ; CHECK-NEXT: 0x00000000: locations list header: length = 0x00000029, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +; With split-dwarf enbabled with dwarf-5 check contents of .debug_loclists.dwo contents +; DWO: .debug_loclists.dwo contents: +; DWO-NEXT: 0x00000000: locations list header: length = 0x00000025, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 + ; Don't use startx_length if there's more than one entry, because the shared ; base address will be useful for both the range that does start at the start of ; the function, and the one that doesn't. @@ -35,6 +60,13 @@ ; CHECK-NEXT: => [0x0000000000000003, 0x0000000000000004): DW_OP_consts +4, DW_OP_stack_value ; CHECK-NEXT: DW_LLE_end_of_list () +; DWO-NEXT: 0x0000000c: +; DWO-NEXT: DW_LLE_startx_length (0x0000000000000000, 0x0000000000000003) +; DWO-NEXT: => Addr idx 0 (w/ length 3): DW_OP_consts +3, DW_OP_stack_value +; DWO-NEXT: DW_LLE_startx_length (0x0000000000000002, 0x0000000000000001) +; DWO-NEXT: => Addr idx 2 (w/ length 1): DW_OP_consts +4, DW_OP_stack_value +; DWO-NEXT: DW_LLE_end_of_list () + ; Show that startx_length can be used when the address range starts at the start of the function. ; CHECK: 0x0000001d: @@ -42,6 +74,11 @@ ; CHECK-NEXT: => Addr idx 0 (w/ length 3): DW_OP_consts +5, DW_OP_stack_value ; CHECK-NEXT: DW_LLE_end_of_list () +; DWO: 0x0000001b: +; DWO-NEXT: DW_LLE_startx_length (0x0000000000000000, 0x0000000000000003) +; DWO-NEXT: => Addr idx 0 (w/ length 3): DW_OP_consts +5, DW_OP_stack_value +; DWO-NEXT: DW_LLE_end_of_list () + ; And use a base address when the range doesn't start at an existing/useful ; address in the pool. @@ -51,6 +88,11 @@ ; CHECK-NEXT: => [0x0000000000000003, 0x0000000000000004): DW_OP_reg0 RAX ; CHECK-NEXT: DW_LLE_end_of_list () +; DWO: 0x00000023: +; DWO-NEXT: DW_LLE_startx_length (0x0000000000000002, 0x0000000000000001) +; DWO-NEXT: => Addr idx 2 (w/ length 1): DW_OP_reg0 RAX +; DWO-NEXT: DW_LLE_end_of_list () + ; Built with clang -O3 -ffunction-sections from source: ; ; int f1(int i, int j) { Index: llvm/test/DebugInfo/Inputs/dwarfdump-test-loclists-dwo.c =================================================================== --- /dev/null +++ llvm/test/DebugInfo/Inputs/dwarfdump-test-loclists-dwo.c @@ -0,0 +1,18 @@ +// clang -c -O2 -gdwarf-5 -gsplit-dwarf dwarfdump-test-loclists-dwo.c + +#include +int func(int *ptr) { + + printf("%d\n", *ptr); + return *ptr + 5; +} + +int main(int argc, char **argv) { + + int a = 4; + int *ptr_a = &a; + + int b = func(ptr_a); + + return 0; +} Index: llvm/test/DebugInfo/X86/dwarfdump-debug-loclists-dwo.test =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-debug-loclists-dwo.test @@ -0,0 +1,29 @@ +# Test for loclists.dwo section emission DWARFv5 fission +# source dwarfdump-test-loclists-dwo.c +# RUN: llvm-dwarfdump -v %p/../Inputs/dwarfdump-test-loclists-dwo.dwo | FileCheck %s + +# CHECK: .debug_info.dwo +# CHECK: DW_AT_location [DW_FORM_sec_offset] (0x0000000c +# CHECK-NEXT: Addr idx 0 (w/ length 4): DW_OP_reg5 RDI +# CHECK-NEXT: Addr idx 3 (w/ length 20): DW_OP_reg3 RBX) +# CHECK: DW_AT_location [DW_FORM_sec_offset] (0x00000017 +# CHECK-NEXT: Addr idx 1 (w/ length 6): DW_OP_reg5 RDI) +# CHECK: DW_AT_location [DW_FORM_sec_offset] (0x0000001d +# CHECK-NEXT: Addr idx 1 (w/ length 11): DW_OP_reg4 RSI) + +# CHECK: .debug_loclists.dwo contents: +# CHECK-NEXT: 0x00000000: locations list header: length = 0x0000001f, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# CHECK-NEXT: 0x0000000c: +# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000000, 0x0000000000000004) +# CHECK-NEXT: => Addr idx 0 (w/ length 4): DW_OP_reg5 RDI +# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000003, 0x0000000000000014) +# CHECK-NEXT: => Addr idx 3 (w/ length 20): DW_OP_reg3 RBX +# CHECK-NEXT DW_LLE_end_of_list () +# CHECK: 0x00000017: +# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000001, 0x0000000000000006) +# CHECK-NEXT: => Addr idx 1 (w/ length 6): DW_OP_reg5 RDI +# CHECK-NEXT: DW_LLE_end_of_list () +# CHECK: 0x0000001d: +# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000001, 0x000000000000000b) +# CHECK-NEXT: => Addr idx 1 (w/ length 11): DW_OP_reg4 RSI +# CHECK-NEXT: DW_LLE_end_of_list ()