Index: lib/CodeGen/AsmPrinter/DIE.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIE.cpp +++ lib/CodeGen/AsmPrinter/DIE.cpp @@ -388,6 +388,7 @@ case dwarf::DW_FORM_data2: case dwarf::DW_FORM_strx2: case dwarf::DW_FORM_addrx2: + case dwarf::DW_FORM_strx3: case dwarf::DW_FORM_strp: case dwarf::DW_FORM_ref4: case dwarf::DW_FORM_data4: @@ -410,6 +411,7 @@ case dwarf::DW_FORM_GNU_str_index: case dwarf::DW_FORM_GNU_addr_index: case dwarf::DW_FORM_ref_udata: + case dwarf::DW_FORM_strx: case dwarf::DW_FORM_udata: Asm->EmitULEB128(Integer); return; @@ -438,6 +440,8 @@ case dwarf::DW_FORM_strx2: case dwarf::DW_FORM_addrx2: return sizeof(int16_t); + case dwarf::DW_FORM_strx3: + return 3; case dwarf::DW_FORM_ref4: case dwarf::DW_FORM_data4: case dwarf::DW_FORM_ref_sup4: @@ -469,6 +473,7 @@ case dwarf::DW_FORM_GNU_str_index: case dwarf::DW_FORM_GNU_addr_index: case dwarf::DW_FORM_ref_udata: + case dwarf::DW_FORM_strx: case dwarf::DW_FORM_udata: return getULEB128Size(Integer); case dwarf::DW_FORM_sdata: @@ -564,44 +569,46 @@ /// EmitValue - Emit string value. /// void DIEString::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { - assert( - (Form == dwarf::DW_FORM_strp || Form == dwarf::DW_FORM_GNU_str_index) && - "Expected valid string form"); - // Index of string in symbol table. - if (Form == dwarf::DW_FORM_GNU_str_index) { + switch (Form) { + case dwarf::DW_FORM_GNU_str_index: + case dwarf::DW_FORM_strx: + case dwarf::DW_FORM_strx1: + case dwarf::DW_FORM_strx2: + case dwarf::DW_FORM_strx3: + case dwarf::DW_FORM_strx4: DIEInteger(S.getIndex()).EmitValue(AP, Form); return; - } - - // Relocatable symbol. - assert(Form == dwarf::DW_FORM_strp); - if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) { - DIELabel(S.getSymbol()).EmitValue(AP, Form); + case dwarf::DW_FORM_strp: + if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) + DIELabel(S.getSymbol()).EmitValue(AP, Form); + else + DIEInteger(S.getOffset()).EmitValue(AP, Form); return; + default: + llvm_unreachable("Expected valid string form"); } - - // Offset into symbol table. - DIEInteger(S.getOffset()).EmitValue(AP, Form); } /// SizeOf - Determine size of delta value in bytes. /// unsigned DIEString::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { - assert( - (Form == dwarf::DW_FORM_strp || Form == dwarf::DW_FORM_GNU_str_index) && - "Expected valid string form"); - // Index of string in symbol table. - if (Form == dwarf::DW_FORM_GNU_str_index) + switch (Form) { + case dwarf::DW_FORM_GNU_str_index: + case dwarf::DW_FORM_strx: + case dwarf::DW_FORM_strx1: + case dwarf::DW_FORM_strx2: + case dwarf::DW_FORM_strx3: + case dwarf::DW_FORM_strx4: return DIEInteger(S.getIndex()).SizeOf(AP, Form); - - // Relocatable symbol. - if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) - return DIELabel(S.getSymbol()).SizeOf(AP, Form); - - // Offset into symbol table. - return DIEInteger(S.getOffset()).SizeOf(AP, Form); + case dwarf::DW_FORM_strp: + if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) + return DIELabel(S.getSymbol()).SizeOf(AP, Form); + return DIEInteger(S.getOffset()).SizeOf(AP, Form); + default: + llvm_unreachable("Expected valid string form"); + } } LLVM_DUMP_METHOD Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -261,6 +261,12 @@ bool HasAppleExtensionAttributes; bool HasSplitDwarf; + /// Whether to generate the DWARF v5 string offsets table. + /// It consists of a series of contributions, each preceded by a header. + /// The pre-DWARF v5 string offsets table for split dwarf is, in contrast, + /// a monolithic sequence of string offsets. + bool UseSegmentedStringOffsetsTable; + /// Separated Dwarf Variables /// In general these will all be for bits that are left in the /// original object file, rather than things that are meant @@ -324,6 +330,9 @@ /// Emit the abbreviation section. void emitAbbreviations(); + /// Emit the string offsets table header. + void emitStringOffsetsTableHeader(); + /// Emit a specified accelerator table. void emitAccel(DwarfAccelTable &Accel, MCSection *Section, StringRef TableName); @@ -388,6 +397,9 @@ /// Emit the debug line dwo section. void emitDebugLineDWO(); + /// Emit the dwo stringoffsets table header. + void emitStringOffsetsTableHeaderDWO(); + /// Emit the debug str dwo section. void emitDebugStrDWO(); @@ -492,6 +504,16 @@ /// split dwarf proposal support. bool useSplitDwarf() const { return HasSplitDwarf; } + /// Returns whether to generate a string offsets table with (possibly shared) + /// contributions from each CU and type unit. This implies the use of + /// DW_FORM_strx* indirect references with DWARF v5 and beyond. Note that + /// DW_FORM_GNU_str_index is also an indirect reference, but it is used with + /// a pre-DWARF v5 implementation of split DWARF sections, which uses a + /// monolithic string offsets table. + bool useSegmentedStringOffsetsTable() const { + return UseSegmentedStringOffsetsTable; + } + bool shareAcrossDWOCUs() const; /// Returns the Dwarf Version. Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -321,6 +321,12 @@ // GDB does not fully support the DWARF 4 representation for bitfields. UseDWARF2Bitfields = (DwarfVersion < 4) || tuneForGDB(); + // The DWARF v5 string offsets table has - possibly shared - contributions + // from each compile and type unit each preceded by a header. The string + // offsets table used by the pre-DWARF v5 split-DWARF implementation uses + // a monolithic string offsets table without any header. + UseSegmentedStringOffsetsTable = DwarfVersion >= 5; + Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); } @@ -486,6 +492,10 @@ DIUnit->getSourceLanguage()); NewCU.addString(Die, dwarf::DW_AT_name, FN); + // Add DW_str_offsets_base to the unit DIE, except for split units. + if (useSegmentedStringOffsetsTable() && !useSplitDwarf()) + NewCU.addStringOffsetsStart(); + if (!useSplitDwarf()) { NewCU.initStmtList(); @@ -590,6 +600,13 @@ GVMap[GVE->getVariable()].push_back({&Global, GVE->getExpression()}); } + // Create the symbol that designates the start of the unit's contribution + // to the string offsets table. In a split DWARF scenario, only the skeleton + // unit has the DW_AT_str_offsets_base attribute (and hence needs the symbol). + if (useSegmentedStringOffsetsTable()) + (useSplitDwarf() ? SkeletonHolder : InfoHolder) + .setStringOffsetsStartSym(Asm->createTempSymbol("str_offsets_base")); + for (DICompileUnit *CUNode : M->debug_compile_units()) { // FIXME: Move local imported entities into a list attached to the // subprogram, then this search won't be needed and a @@ -1399,6 +1416,12 @@ Holder.emitAbbrevs(Asm->getObjFileLowering().getDwarfAbbrevSection()); } +void DwarfDebug::emitStringOffsetsTableHeader() { + DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; + Holder.emitStringOffsetsTableHeader( + Asm->getObjFileLowering().getDwarfStrOffSection()); +} + void DwarfDebug::emitAccel(DwarfAccelTable &Accel, MCSection *Section, StringRef TableName) { Accel.FinalizeTable(Asm, TableName); @@ -1573,8 +1596,14 @@ /// Emit null-terminated strings into a debug str section. void DwarfDebug::emitDebugStr() { + MCSection *StringOffsetsSection = nullptr; + if (useSegmentedStringOffsetsTable()) { + emitStringOffsetsTableHeader(); + StringOffsetsSection = Asm->getObjFileLowering().getDwarfStrOffSection(); + } DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; - Holder.emitStrings(Asm->getObjFileLowering().getDwarfStrSection()); + Holder.emitStrings(Asm->getObjFileLowering().getDwarfStrSection(), + StringOffsetsSection, /* UseRelativeOffsets = */ true); } void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, @@ -2024,6 +2053,9 @@ NewCU.initStmtList(); + if (useSegmentedStringOffsetsTable()) + NewCU.addStringOffsetsStart(); + initSkeletonUnit(CU, NewCU.getUnitDie(), std::move(OwnedUnit)); return NewCU; @@ -2051,14 +2083,22 @@ SplitTypeUnitFileTable.Emit(*Asm->OutStreamer, MCDwarfLineTableParams()); } +void DwarfDebug::emitStringOffsetsTableHeaderDWO() { + assert(useSplitDwarf() && "No split dwarf?"); + InfoHolder.emitStringOffsetsTableHeader( + Asm->getObjFileLowering().getDwarfStrOffDWOSection()); +} + // Emit the .debug_str.dwo section for separated dwarf. This contains the // string section and is identical in format to traditional .debug_str // sections. void DwarfDebug::emitDebugStrDWO() { + if (useSegmentedStringOffsetsTable()) + emitStringOffsetsTableHeaderDWO(); assert(useSplitDwarf() && "No split dwarf?"); MCSection *OffSec = Asm->getObjFileLowering().getDwarfStrOffDWOSection(); InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(), - OffSec); + OffSec, /* UseRelativeOffsets = */ false); } MCDwarfDwoLineTable *DwarfDebug::getDwoLineTable(const DwarfCompileUnit &CU) { @@ -2118,6 +2158,11 @@ NewTU.setSection(Asm->getObjFileLowering().getDwarfTypesSection(Signature)); } + // Add DW_AT_str_offsets_base to the type unit DIE, but not for split type + // units. + if (useSegmentedStringOffsetsTable() && !useSplitDwarf()) + NewTU.addStringOffsetsStart(); + NewTU.setType(NewTU.createTypeDIE(CTy)); if (TopLevelType) { Index: lib/CodeGen/AsmPrinter/DwarfFile.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.h +++ lib/CodeGen/AsmPrinter/DwarfFile.h @@ -43,6 +43,10 @@ DwarfStringPool StrPool; + /// DWARF v5: The symbol that designates the start of the contribution to + /// the string offsets table. The contribution is shared by all units. + MCSymbol *StringOffsetsStartSym = nullptr; + // Collection of dbg variables of a scope. DenseMap> ScopeVariables; @@ -75,6 +79,9 @@ /// \brief Add a unit to the list of CUs. void addUnit(std::unique_ptr U); + /// Emit the string table offsets header. + void emitStringOffsetsTableHeader(MCSection *Section); + /// \brief Emit all of the units to the section listed with the given /// abbreviation section. void emitUnits(bool UseOffsets); @@ -85,12 +92,20 @@ /// \brief Emit a set of abbreviations to the specific section. void emitAbbrevs(MCSection *); - /// \brief Emit all of the strings to the section given. - void emitStrings(MCSection *StrSection, MCSection *OffsetSection = nullptr); + /// Emit all of the strings to the section given. If OffsetSection is + /// non-null, emit a table of string offsets to it. If UseRelativeOffsets + /// is false, emit absolute offsets to the strings. Otherwise, emit + /// relocatable references to the strings if they are supported by the target. + void emitStrings(MCSection *StrSection, MCSection *OffsetSection = nullptr, + bool UseRelativeOffsets = false); /// \brief Returns the string pool. DwarfStringPool &getStringPool() { return StrPool; } + MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; } + + void setStringOffsetsStartSym(MCSymbol *Sym) { StringOffsetsStartSym = Sym; } + /// \returns false if the variable was merged with a previous one. bool addScopeVariable(LexicalScope *LS, DbgVariable *Var); Index: lib/CodeGen/AsmPrinter/DwarfFile.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -28,6 +28,26 @@ CUs.push_back(std::move(U)); } +void DwarfFile::emitStringOffsetsTableHeader(MCSection *Section) { + if (StrPool.empty()) + return; + Asm->OutStreamer->SwitchSection(Section); + unsigned EntrySize = 4; + // FIXME: DWARF64 + // We are emitting the header for a contribution to the string offsets + // table. The header consists of an entry with the contribution's + // size (not including the size of the header), the DWARF version and + // 2 bytes of padding. + Asm->EmitInt32(StrPool.size() * EntrySize); + Asm->EmitInt16(Asm->getDwarfVersion()); + Asm->EmitInt16(0); + // Define the symbol that marks the start of the contribution. It is + // referenced by most unit headers via DW_AT_str_offsets_base. + // Split units do not use the attribute. + if (StringOffsetsStartSym) + Asm->OutStreamer->EmitLabel(StringOffsetsStartSym); +} + // Emit the various dwarf units to the unit section USection with // the abbreviations going into ASection. void DwarfFile::emitUnits(bool UseOffsets) { @@ -77,8 +97,9 @@ void DwarfFile::emitAbbrevs(MCSection *Section) { Abbrevs.Emit(Asm, Section); } // Emit strings into a string section. -void DwarfFile::emitStrings(MCSection *StrSection, MCSection *OffsetSection) { - StrPool.emit(*Asm, StrSection, OffsetSection); +void DwarfFile::emitStrings(MCSection *StrSection, MCSection *OffsetSection, + bool UseRelativeOffsets) { + StrPool.emit(*Asm, StrSection, OffsetSection, UseRelativeOffsets); } bool DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) { Index: lib/CodeGen/AsmPrinter/DwarfStringPool.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfStringPool.h +++ lib/CodeGen/AsmPrinter/DwarfStringPool.h @@ -37,10 +37,13 @@ DwarfStringPool(BumpPtrAllocator &A, AsmPrinter &Asm, StringRef Prefix); void emit(AsmPrinter &Asm, MCSection *StrSection, - MCSection *OffsetSection = nullptr); + MCSection *OffsetSection = nullptr, + bool UseRelativeOffsets = false); bool empty() const { return Pool.empty(); } + unsigned size() const { return Pool.size(); } + /// Get a reference to an entry in the string pool. EntryRef getEntry(AsmPrinter &Asm, StringRef Str); }; Index: lib/CodeGen/AsmPrinter/DwarfStringPool.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfStringPool.cpp +++ lib/CodeGen/AsmPrinter/DwarfStringPool.cpp @@ -40,7 +40,7 @@ } void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection, - MCSection *OffsetSection) { + MCSection *OffsetSection, bool UseRelativeOffsets) { if (Pool.empty()) return; @@ -74,6 +74,9 @@ Asm.OutStreamer->SwitchSection(OffsetSection); unsigned size = 4; // FIXME: DWARF64 is 8. for (const auto &Entry : Entries) - Asm.OutStreamer->EmitIntValue(Entry->getValue().Offset, size); + if (UseRelativeOffsets) + Asm.emitDwarfStringOffset(Entry->getValue()); + else + Asm.OutStreamer->EmitIntValue(Entry->getValue().Offset, size); } } Index: lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.h +++ lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -273,6 +273,10 @@ /// call insertDIE if MD is not null. DIE &createAndAddDIE(unsigned Tag, DIE &Parent, const DINode *N = nullptr); + bool useSegmentedStringOffsetsTable() const { + return DD->useSegmentedStringOffsetsTable(); + } + /// Compute the size of a header for this unit, not including the initial /// length field. virtual unsigned getHeaderSize() const { @@ -286,6 +290,9 @@ /// Emit the header for this unit, not including the initial length field. virtual void emitHeader(bool UseOffsets) = 0; + /// Add the DW_AT_str_offsets_base attribute to the unit DIE. + void addStringOffsetsStart(); + virtual DwarfCompileUnit &getCU() = 0; void constructTypeDIE(DIE &Buffer, const DICompositeType *CTy); Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -241,9 +241,22 @@ void DwarfUnit::addString(DIE &Die, dwarf::Attribute Attribute, StringRef String) { - Die.addValue(DIEValueAllocator, Attribute, - isDwoUnit() ? dwarf::DW_FORM_GNU_str_index : dwarf::DW_FORM_strp, - DIEString(DU->getStringPool().getEntry(*Asm, String))); + auto StringPoolEntry = DU->getStringPool().getEntry(*Asm, String); + dwarf::Form IxForm = + isDwoUnit() ? dwarf::DW_FORM_GNU_str_index : dwarf::DW_FORM_strp; + // For DWARF v5 and beyond, use the smallest strx? form possible. + if (useSegmentedStringOffsetsTable()) { + IxForm = dwarf::DW_FORM_strx1; + unsigned Index = StringPoolEntry.getIndex(); + if (Index > 0xffffff) + IxForm = dwarf::DW_FORM_strx4; + else if (Index > 0xffff) + IxForm = dwarf::DW_FORM_strx3; + else if (Index > 0xff) + IxForm = dwarf::DW_FORM_strx2; + } + Die.addValue(DIEValueAllocator, Attribute, IxForm, + DIEString(StringPoolEntry)); } DIEValueList::value_iterator DwarfUnit::addLabel(DIEValueList &Die, @@ -1652,3 +1665,10 @@ return nullptr; return getSection()->getBeginSymbol(); } + +void DwarfUnit::addStringOffsetsStart() { + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + addSectionLabel(getUnitDie(), dwarf::DW_AT_str_offsets_base, + DU->getStringOffsetsStartSym(), + TLOF.getDwarfStrOffSection()->getBeginSymbol()); +} Index: test/DebugInfo/Generic/string-offsets-form.ll =================================================================== --- test/DebugInfo/Generic/string-offsets-form.ll +++ test/DebugInfo/Generic/string-offsets-form.ll @@ -0,0 +1,302 @@ +; RUN: %llc_dwarf -filetype=obj < %s | llvm-dwarfdump -all -show-form -v - \ +; RUN: | FileCheck %s +; +; Generated from the following source with clang -S -emit-llvm -gdwarf-5. +; +; enum E { +; econst1, +; econst2, +; ... +; econst254 +; } glob; +; +; This test verifies that we generate DW_FORM_strx2 for indexed strings properly. +; +; Check that we have an abbreviation for the DW_TAG_enumeration_type DIE and that it +; uses DW_FORM_strx2. +; +; CHECK: .debug_abbrev contents: +; CHECK-NOT: contents: +; CHECK: DW_TAG_enumeration_type +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name DW_FORM_strx2 + +; Check that the first usage of DW_FORM_strx2 is with index 256. +; +; CHECK: .debug_info contents: +; CHECK-NOT: DW_FORM_strx2 +; CHECK: DW_AT_name [DW_FORM_strx2] ( indexed (00000100) string = + +; ModuleID = 'enum.cpp' +source_filename = "enum.cpp" + +@glob = global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!260, !261, !262} +!llvm.ident = !{!263} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "glob", scope: !2, file: !3, line: 255, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 (trunk 322415)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !259) +!3 = !DIFile(filename: "enum.cpp", directory: "/home/test", checksumkind: CSK_MD5, checksum: "8965080a8027790e641e30c7762c53a0") +!4 = !{!5} +!5 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E", file: !3, line: 1, size: 32, elements: !6, identifier: "_ZTS1E") +!6 = !{!7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38, !39, !40, !41, !42, !43, !44, !45, !46, !47, !48, !49, !50, !51, !52, !53, !54, !55, !56, !57, !58, !59, !60, !61, !62, !63, !64, !65, !66, !67, !68, !69, !70, !71, !72, !73, !74, !75, !76, !77, !78, !79, !80, !81, !82, !83, !84, !85, !86, !87, !88, !89, !90, !91, !92, !93, !94, !95, !96, !97, !98, !99, !100, !101, !102, !103, !104, !105, !106, !107, !108, !109, !110, !111, !112, !113, !114, !115, !116, !117, !118, !119, !120, !121, !122, !123, !124, !125, !126, !127, !128, !129, !130, !131, !132, !133, !134, !135, !136, !137, !138, !139, !140, !141, !142, !143, !144, !145, !146, !147, !148, !149, !150, !151, !152, !153, !154, !155, !156, !157, !158, !159, !160, !161, !162, !163, !164, !165, !166, !167, !168, !169, !170, !171, !172, !173, !174, !175, !176, !177, !178, !179, !180, !181, !182, !183, !184, !185, !186, !187, !188, !189, !190, !191, !192, !193, !194, !195, !196, !197, !198, !199, !200, !201, !202, !203, !204, !205, !206, !207, !208, !209, !210, !211, !212, !213, !214, !215, !216, !217, !218, !219, !220, !221, !222, !223, !224, !225, !226, !227, !228, !229, !230, !231, !232, !233, !234, !235, !236, !237, !238, !239, !240, !241, !242, !243, !244, !245, !246, !247, !248, !249, !250, !251, !252, !253, !254, !255, !256, !257, !258} +!7 = !DIEnumerator(name: "econst1", value: 0) +!8 = !DIEnumerator(name: "econst2", value: 1) +!9 = !DIEnumerator(name: "econst3", value: 2) +!10 = !DIEnumerator(name: "econst4", value: 3) +!11 = !DIEnumerator(name: "econst5", value: 4) +!12 = !DIEnumerator(name: "econst6", value: 5) +!13 = !DIEnumerator(name: "econst7", value: 6) +!14 = !DIEnumerator(name: "econst8", value: 7) +!15 = !DIEnumerator(name: "econst9", value: 8) +!16 = !DIEnumerator(name: "econst10", value: 9) +!17 = !DIEnumerator(name: "econst11", value: 10) +!18 = !DIEnumerator(name: "econst12", value: 11) +!19 = !DIEnumerator(name: "econst13", value: 12) +!20 = !DIEnumerator(name: "econst14", value: 13) +!21 = !DIEnumerator(name: "econst15", value: 14) +!22 = !DIEnumerator(name: "econst16", value: 15) +!23 = !DIEnumerator(name: "econst17", value: 16) +!24 = !DIEnumerator(name: "econst18", value: 17) +!25 = !DIEnumerator(name: "econst19", value: 18) +!26 = !DIEnumerator(name: "econst20", value: 19) +!27 = !DIEnumerator(name: "econst21", value: 20) +!28 = !DIEnumerator(name: "econst22", value: 21) +!29 = !DIEnumerator(name: "econst23", value: 22) +!30 = !DIEnumerator(name: "econst24", value: 23) +!31 = !DIEnumerator(name: "econst25", value: 24) +!32 = !DIEnumerator(name: "econst26", value: 25) +!33 = !DIEnumerator(name: "econst27", value: 26) +!34 = !DIEnumerator(name: "econst28", value: 27) +!35 = !DIEnumerator(name: "econst29", value: 28) +!36 = !DIEnumerator(name: "econst30", value: 29) +!37 = !DIEnumerator(name: "econst31", value: 30) +!38 = !DIEnumerator(name: "econst32", value: 31) +!39 = !DIEnumerator(name: "econst33", value: 32) +!40 = !DIEnumerator(name: "econst34", value: 33) +!41 = !DIEnumerator(name: "econst35", value: 34) +!42 = !DIEnumerator(name: "econst36", value: 35) +!43 = !DIEnumerator(name: "econst37", value: 36) +!44 = !DIEnumerator(name: "econst38", value: 37) +!45 = !DIEnumerator(name: "econst39", value: 38) +!46 = !DIEnumerator(name: "econst40", value: 39) +!47 = !DIEnumerator(name: "econst41", value: 40) +!48 = !DIEnumerator(name: "econst42", value: 41) +!49 = !DIEnumerator(name: "econst43", value: 42) +!50 = !DIEnumerator(name: "econst44", value: 43) +!51 = !DIEnumerator(name: "econst45", value: 44) +!52 = !DIEnumerator(name: "econst46", value: 45) +!53 = !DIEnumerator(name: "econst47", value: 46) +!54 = !DIEnumerator(name: "econst48", value: 47) +!55 = !DIEnumerator(name: "econst49", value: 48) +!56 = !DIEnumerator(name: "econst50", value: 49) +!57 = !DIEnumerator(name: "econst51", value: 50) +!58 = !DIEnumerator(name: "econst52", value: 51) +!59 = !DIEnumerator(name: "econst53", value: 52) +!60 = !DIEnumerator(name: "econst54", value: 53) +!61 = !DIEnumerator(name: "econst55", value: 54) +!62 = !DIEnumerator(name: "econst56", value: 55) +!63 = !DIEnumerator(name: "econst57", value: 56) +!64 = !DIEnumerator(name: "econst58", value: 57) +!65 = !DIEnumerator(name: "econst59", value: 58) +!66 = !DIEnumerator(name: "econst60", value: 59) +!67 = !DIEnumerator(name: "econst61", value: 60) +!68 = !DIEnumerator(name: "econst62", value: 61) +!69 = !DIEnumerator(name: "econst63", value: 62) +!70 = !DIEnumerator(name: "econst64", value: 63) +!71 = !DIEnumerator(name: "econst65", value: 64) +!72 = !DIEnumerator(name: "econst66", value: 65) +!73 = !DIEnumerator(name: "econst67", value: 66) +!74 = !DIEnumerator(name: "econst68", value: 67) +!75 = !DIEnumerator(name: "econst69", value: 68) +!76 = !DIEnumerator(name: "econst70", value: 69) +!77 = !DIEnumerator(name: "econst71", value: 70) +!78 = !DIEnumerator(name: "econst72", value: 71) +!79 = !DIEnumerator(name: "econst73", value: 72) +!80 = !DIEnumerator(name: "econst74", value: 73) +!81 = !DIEnumerator(name: "econst75", value: 74) +!82 = !DIEnumerator(name: "econst76", value: 75) +!83 = !DIEnumerator(name: "econst77", value: 76) +!84 = !DIEnumerator(name: "econst78", value: 77) +!85 = !DIEnumerator(name: "econst79", value: 78) +!86 = !DIEnumerator(name: "econst80", value: 79) +!87 = !DIEnumerator(name: "econst81", value: 80) +!88 = !DIEnumerator(name: "econst82", value: 81) +!89 = !DIEnumerator(name: "econst83", value: 82) +!90 = !DIEnumerator(name: "econst84", value: 83) +!91 = !DIEnumerator(name: "econst85", value: 84) +!92 = !DIEnumerator(name: "econst86", value: 85) +!93 = !DIEnumerator(name: "econst87", value: 86) +!94 = !DIEnumerator(name: "econst88", value: 87) +!95 = !DIEnumerator(name: "econst89", value: 88) +!96 = !DIEnumerator(name: "econst90", value: 89) +!97 = !DIEnumerator(name: "econst91", value: 90) +!98 = !DIEnumerator(name: "econst92", value: 91) +!99 = !DIEnumerator(name: "econst93", value: 92) +!100 = !DIEnumerator(name: "econst94", value: 93) +!101 = !DIEnumerator(name: "econst95", value: 94) +!102 = !DIEnumerator(name: "econst96", value: 95) +!103 = !DIEnumerator(name: "econst97", value: 96) +!104 = !DIEnumerator(name: "econst98", value: 97) +!105 = !DIEnumerator(name: "econst99", value: 98) +!106 = !DIEnumerator(name: "econst100", value: 99) +!107 = !DIEnumerator(name: "econst101", value: 100) +!108 = !DIEnumerator(name: "econst102", value: 101) +!109 = !DIEnumerator(name: "econst103", value: 102) +!110 = !DIEnumerator(name: "econst104", value: 103) +!111 = !DIEnumerator(name: "econst105", value: 104) +!112 = !DIEnumerator(name: "econst106", value: 105) +!113 = !DIEnumerator(name: "econst107", value: 106) +!114 = !DIEnumerator(name: "econst108", value: 107) +!115 = !DIEnumerator(name: "econst109", value: 108) +!116 = !DIEnumerator(name: "econst110", value: 109) +!117 = !DIEnumerator(name: "econst111", value: 110) +!118 = !DIEnumerator(name: "econst112", value: 111) +!119 = !DIEnumerator(name: "econst113", value: 112) +!120 = !DIEnumerator(name: "econst114", value: 113) +!121 = !DIEnumerator(name: "econst115", value: 114) +!122 = !DIEnumerator(name: "econst116", value: 115) +!123 = !DIEnumerator(name: "econst117", value: 116) +!124 = !DIEnumerator(name: "econst118", value: 117) +!125 = !DIEnumerator(name: "econst119", value: 118) +!126 = !DIEnumerator(name: "econst120", value: 119) +!127 = !DIEnumerator(name: "econst121", value: 120) +!128 = !DIEnumerator(name: "econst122", value: 121) +!129 = !DIEnumerator(name: "econst123", value: 122) +!130 = !DIEnumerator(name: "econst124", value: 123) +!131 = !DIEnumerator(name: "econst125", value: 124) +!132 = !DIEnumerator(name: "econst126", value: 125) +!133 = !DIEnumerator(name: "econst127", value: 126) +!134 = !DIEnumerator(name: "econst128", value: 127) +!135 = !DIEnumerator(name: "econst129", value: 128) +!136 = !DIEnumerator(name: "econst130", value: 129) +!137 = !DIEnumerator(name: "econst131", value: 130) +!138 = !DIEnumerator(name: "econst132", value: 131) +!139 = !DIEnumerator(name: "econst133", value: 132) +!140 = !DIEnumerator(name: "econst134", value: 133) +!141 = !DIEnumerator(name: "econst135", value: 134) +!142 = !DIEnumerator(name: "econst136", value: 135) +!143 = !DIEnumerator(name: "econst137", value: 136) +!144 = !DIEnumerator(name: "econst138", value: 137) +!145 = !DIEnumerator(name: "econst139", value: 138) +!146 = !DIEnumerator(name: "econst140", value: 139) +!147 = !DIEnumerator(name: "econst141", value: 140) +!148 = !DIEnumerator(name: "econst142", value: 141) +!149 = !DIEnumerator(name: "econst143", value: 142) +!150 = !DIEnumerator(name: "econst144", value: 143) +!151 = !DIEnumerator(name: "econst145", value: 144) +!152 = !DIEnumerator(name: "econst146", value: 145) +!153 = !DIEnumerator(name: "econst147", value: 146) +!154 = !DIEnumerator(name: "econst148", value: 147) +!155 = !DIEnumerator(name: "econst149", value: 148) +!156 = !DIEnumerator(name: "econst150", value: 149) +!157 = !DIEnumerator(name: "econst151", value: 150) +!158 = !DIEnumerator(name: "econst152", value: 151) +!159 = !DIEnumerator(name: "econst153", value: 152) +!160 = !DIEnumerator(name: "econst154", value: 153) +!161 = !DIEnumerator(name: "econst155", value: 154) +!162 = !DIEnumerator(name: "econst156", value: 155) +!163 = !DIEnumerator(name: "econst157", value: 156) +!164 = !DIEnumerator(name: "econst158", value: 157) +!165 = !DIEnumerator(name: "econst159", value: 158) +!166 = !DIEnumerator(name: "econst160", value: 159) +!167 = !DIEnumerator(name: "econst161", value: 160) +!168 = !DIEnumerator(name: "econst162", value: 161) +!169 = !DIEnumerator(name: "econst163", value: 162) +!170 = !DIEnumerator(name: "econst164", value: 163) +!171 = !DIEnumerator(name: "econst165", value: 164) +!172 = !DIEnumerator(name: "econst166", value: 165) +!173 = !DIEnumerator(name: "econst167", value: 166) +!174 = !DIEnumerator(name: "econst168", value: 167) +!175 = !DIEnumerator(name: "econst169", value: 168) +!176 = !DIEnumerator(name: "econst170", value: 169) +!177 = !DIEnumerator(name: "econst171", value: 170) +!178 = !DIEnumerator(name: "econst172", value: 171) +!179 = !DIEnumerator(name: "econst173", value: 172) +!180 = !DIEnumerator(name: "econst174", value: 173) +!181 = !DIEnumerator(name: "econst175", value: 174) +!182 = !DIEnumerator(name: "econst176", value: 175) +!183 = !DIEnumerator(name: "econst177", value: 176) +!184 = !DIEnumerator(name: "econst178", value: 177) +!185 = !DIEnumerator(name: "econst179", value: 178) +!186 = !DIEnumerator(name: "econst180", value: 179) +!187 = !DIEnumerator(name: "econst181", value: 180) +!188 = !DIEnumerator(name: "econst182", value: 181) +!189 = !DIEnumerator(name: "econst183", value: 182) +!190 = !DIEnumerator(name: "econst184", value: 183) +!191 = !DIEnumerator(name: "econst185", value: 184) +!192 = !DIEnumerator(name: "econst186", value: 185) +!193 = !DIEnumerator(name: "econst187", value: 186) +!194 = !DIEnumerator(name: "econst188", value: 187) +!195 = !DIEnumerator(name: "econst189", value: 188) +!196 = !DIEnumerator(name: "econst190", value: 189) +!197 = !DIEnumerator(name: "econst191", value: 190) +!198 = !DIEnumerator(name: "econst192", value: 191) +!199 = !DIEnumerator(name: "econst193", value: 192) +!200 = !DIEnumerator(name: "econst194", value: 193) +!201 = !DIEnumerator(name: "econst195", value: 194) +!202 = !DIEnumerator(name: "econst196", value: 195) +!203 = !DIEnumerator(name: "econst197", value: 196) +!204 = !DIEnumerator(name: "econst198", value: 197) +!205 = !DIEnumerator(name: "econst199", value: 198) +!206 = !DIEnumerator(name: "econst200", value: 199) +!207 = !DIEnumerator(name: "econst201", value: 200) +!208 = !DIEnumerator(name: "econst202", value: 201) +!209 = !DIEnumerator(name: "econst203", value: 202) +!210 = !DIEnumerator(name: "econst204", value: 203) +!211 = !DIEnumerator(name: "econst205", value: 204) +!212 = !DIEnumerator(name: "econst206", value: 205) +!213 = !DIEnumerator(name: "econst207", value: 206) +!214 = !DIEnumerator(name: "econst208", value: 207) +!215 = !DIEnumerator(name: "econst209", value: 208) +!216 = !DIEnumerator(name: "econst210", value: 209) +!217 = !DIEnumerator(name: "econst211", value: 210) +!218 = !DIEnumerator(name: "econst212", value: 211) +!219 = !DIEnumerator(name: "econst213", value: 212) +!220 = !DIEnumerator(name: "econst214", value: 213) +!221 = !DIEnumerator(name: "econst215", value: 214) +!222 = !DIEnumerator(name: "econst216", value: 215) +!223 = !DIEnumerator(name: "econst217", value: 216) +!224 = !DIEnumerator(name: "econst218", value: 217) +!225 = !DIEnumerator(name: "econst219", value: 218) +!226 = !DIEnumerator(name: "econst220", value: 219) +!227 = !DIEnumerator(name: "econst221", value: 220) +!228 = !DIEnumerator(name: "econst222", value: 221) +!229 = !DIEnumerator(name: "econst223", value: 222) +!230 = !DIEnumerator(name: "econst224", value: 223) +!231 = !DIEnumerator(name: "econst225", value: 224) +!232 = !DIEnumerator(name: "econst226", value: 225) +!233 = !DIEnumerator(name: "econst227", value: 226) +!234 = !DIEnumerator(name: "econst228", value: 227) +!235 = !DIEnumerator(name: "econst229", value: 228) +!236 = !DIEnumerator(name: "econst230", value: 229) +!237 = !DIEnumerator(name: "econst231", value: 230) +!238 = !DIEnumerator(name: "econst232", value: 231) +!239 = !DIEnumerator(name: "econst233", value: 232) +!240 = !DIEnumerator(name: "econst234", value: 233) +!241 = !DIEnumerator(name: "econst235", value: 234) +!242 = !DIEnumerator(name: "econst236", value: 235) +!243 = !DIEnumerator(name: "econst237", value: 236) +!244 = !DIEnumerator(name: "econst238", value: 237) +!245 = !DIEnumerator(name: "econst239", value: 238) +!246 = !DIEnumerator(name: "econst240", value: 239) +!247 = !DIEnumerator(name: "econst241", value: 240) +!248 = !DIEnumerator(name: "econst242", value: 241) +!249 = !DIEnumerator(name: "econst243", value: 242) +!250 = !DIEnumerator(name: "econst244", value: 243) +!251 = !DIEnumerator(name: "econst245", value: 244) +!252 = !DIEnumerator(name: "econst246", value: 245) +!253 = !DIEnumerator(name: "econst247", value: 246) +!254 = !DIEnumerator(name: "econst248", value: 247) +!255 = !DIEnumerator(name: "econst249", value: 248) +!256 = !DIEnumerator(name: "econst250", value: 249) +!257 = !DIEnumerator(name: "econst251", value: 250) +!258 = !DIEnumerator(name: "econst252", value: 251) +!259 = !{!0} +!260 = !{i32 2, !"Dwarf Version", i32 5} +!261 = !{i32 2, !"Debug Info Version", i32 3} +!262 = !{i32 1, !"wchar_size", i32 4} +!263 = !{!"clang version 7.0.0 (trunk 322415)"} Index: test/DebugInfo/Generic/string-offsets-multiple-cus.ll =================================================================== --- test/DebugInfo/Generic/string-offsets-multiple-cus.ll +++ test/DebugInfo/Generic/string-offsets-multiple-cus.ll @@ -0,0 +1,158 @@ +; RUN: %llc_dwarf -filetype=obj < %s | llvm-dwarfdump -v - | FileCheck --check-prefix=DEFAULT \ +; RUN: --check-prefix=BOTH %s +; RUN: %llc_dwarf -filetype=obj -generate-type-units < %s | llvm-dwarfdump -v - | \ +; RUN: FileCheck --check-prefix=TYPEUNITS --check-prefix=BOTH %s +; +; Check that we generate the DWARF v5 string offsets section correctly when we +; have multiple compile and type units. All units share one contribution to +; the string offsets section. +; +; Constructed from the following sources with +; clang -gdwarf-5 -emit-llvm -S a.cpp +; clang -gdwarf-5 -emit-llvm -S b.cpp +; clang -gdwarf-5 -emit-llvm -S c.cpp +; llvm-link a.ll b.ll c.ll -o test.bc +; llvm-dis test.bc -o test.ll +; +; a.cpp: +; enum E1 {a, b, c}; +; E1 glob1; +; +; b.cpp: +; enum E2 {d, e, f}; +; E2 glob2; +; +; c.cpp: +; enum E3 {g, h, i}; +; E3 glob3; +; +; Check that all 3 compile units have the correct DW_AT_str_offsets_base attributes +; with the correct offsets. Check that strings referenced by compile units 2 and 3 +; are displayed correctly. +; +; CU 1 +; BOTH: .debug_info contents: +; BOTH-NOT: .contents: +; BOTH: DW_TAG_compile_unit +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[CU1_STROFF:[0-9a-f]+]]) +; +; CU 2 +; BOTH-NOT: contents: +; BOTH: DW_TAG_compile_unit +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[CU1_STROFF]]) +; BOTH-NOT: NULL +; BOTH: DW_TAG_variable +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_name [DW_FORM_strx1] ( indexed (00000009) string = "glob2") +; +; CU 3 +; BOTH-NOT: contents: +; BOTH: DW_TAG_compile_unit +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[CU1_STROFF]]) +; BOTH-NOT: NULL +; BOTH: DW_TAG_variable +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_name [DW_FORM_strx1] ( indexed (0000000f) string = "glob3") +; +; Verify that all 3 type units have the proper DW_AT_str_offsets_base attribute. +; TYPEUNITS: .debug_types contents: +; TYPEUNITS-NOT: contents: +; TYPEUNITS: DW_TAG_type_unit +; TYPEUNITS-NOT: {{DW_TAG|NULL}} +; TYPEUNITS: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[CU1_STROFF]]) +; TYPEUNITS-NOT: NULL +; TYPEUNITS: DW_TAG_enumerator +; TYPEUNITS-NOT: NULL +; TYPEUNITS: DW_TAG_enumerator +; TYPEUNITS-NOT: {{DW_TAG|NULL}} +; TYPEUNITS: DW_AT_name [DW_FORM_strx1] ( indexed (00000005) string = "b") +; TYPEUNITS-NOT: contents: +; TYPEUNITS: DW_TAG_type_unit +; TYPEUNITS-NOT: {{DW_TAG|NULL}} +; TYPEUNITS: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[CU1_STROFF]]) +; TYPEUNITS-NOT: NULL +; TYPEUNITS: DW_TAG_enumeration_type +; TYPEUNITS: DW_AT_name [DW_FORM_strx1] ( indexed (0000000d) string = "E2") +; TYPEUNITS-NOT: contents: +; TYPEUNITS: DW_TAG_type_unit +; TYPEUNITS-NOT: {{DW_TAG|NULL}} +; TYPEUNITS: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[CU1_STROFF]]) +; TYPEUNITS-NOT: NULL +; TYPEUNITS: DW_TAG_enumeration_type +; TYPEUNITS: DW_AT_name [DW_FORM_strx1] ( indexed (00000013) string = "E3") +; +; Extract the offset of a string to verify that it is referenced in the string +; offsets section. +; BOTH: .debug_str contents: +; BOTH-NOT: contents: +; BOTH: 0x[[GLOB2OFF:[0-9a-f]+]]: "glob2" +; +; Check the .debug_str_offsets section header and make sure the referenced string +; has the correct offset. +; BOTH: .debug_str_offsets contents: +; BOTH-NEXT: 0x00000000: Contribution size = 80, Format = DWARF32, Version = 5 +; BOTH-NEXT: 0x[[CU1_STROFF]]: +; BOTH-NEXT: {{.*:}} +; BOTH-NEXT: {{.*:}} +; BOTH-NEXT: {{.*:}} +; BOTH-NEXT: {{.*:}} +; BOTH-NEXT: {{.*:}} +; BOTH-NEXT: {{.*:}} +; BOTH-NEXT: {{.*:}} +; BOTH-NEXT: {{.*:}} +; The string with index 9 should be "glob2" +; BOTH-NEXT: {{.*:}} [[GLOB2OFF]] +; +; ModuleID = 'test.bc' +source_filename = "llvm-link" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@glob1 = global i32 0, align 4, !dbg !0 +@glob2 = global i32 0, align 4, !dbg !11 +@glob3 = global i32 0, align 4, !dbg !22 + +!llvm.dbg.cu = !{!2, !13, !24} +!llvm.ident = !{!33, !33, !33} +!llvm.module.flags = !{!34, !35, !36} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "glob1", scope: !2, file: !3, line: 2, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 (trunk 322415)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !10) +!3 = !DIFile(filename: "a1.cpp", directory: "/home/test", checksumkind: CSK_MD5, checksum: "2ca3eeed18355d6ebbae671eafda5aae") +!4 = !{!5} +!5 = distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "E1", file: !3, line: 1, size: 32, elements: !6, identifier: "_ZTS2E1") +!6 = !{!7, !8, !9} +!7 = !DIEnumerator(name: "a", value: 0) +!8 = !DIEnumerator(name: "b", value: 1) +!9 = !DIEnumerator(name: "c", value: 2) +!10 = !{!0} +!11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression()) +!12 = distinct !DIGlobalVariable(name: "glob2", scope: !13, file: !14, line: 2, type: !16, isLocal: false, isDefinition: true) +!13 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !14, producer: "clang version 7.0.0 (trunk 322415)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !15, globals: !21) +!14 = !DIFile(filename: "b.cpp", directory: "/home/test", checksumkind: CSK_MD5, checksum: "0e254f89617ecb6c4e5473546a99435c") +!15 = !{!16} +!16 = distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "E2", file: !14, line: 1, size: 32, elements: !17, identifier: "_ZTS2E2") +!17 = !{!18, !19, !20} +!18 = !DIEnumerator(name: "d", value: 0) +!19 = !DIEnumerator(name: "e", value: 1) +!20 = !DIEnumerator(name: "f", value: 2) +!21 = !{!11} +!22 = !DIGlobalVariableExpression(var: !23, expr: !DIExpression()) +!23 = distinct !DIGlobalVariable(name: "glob3", scope: !24, file: !25, line: 2, type: !27, isLocal: false, isDefinition: true) +!24 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !25, producer: "clang version 7.0.0 (trunk 322415)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !26, globals: !32) +!25 = !DIFile(filename: "c.cpp", directory: "/home/test", checksumkind: CSK_MD5, checksum: "7835aaaa683fa09d295adef0e934d392") +!26 = !{!27} +!27 = distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "E3", file: !25, line: 1, size: 32, elements: !28, identifier: "_ZTS2E3") +!28 = !{!29, !30, !31} +!29 = !DIEnumerator(name: "g", value: 0) +!30 = !DIEnumerator(name: "h", value: 1) +!31 = !DIEnumerator(name: "i", value: 2) +!32 = !{!22} +!33 = !{!"clang version 7.0.0 (trunk 322415)"} +!34 = !{i32 2, !"Dwarf Version", i32 5} +!35 = !{i32 2, !"Debug Info Version", i32 3} +!36 = !{i32 1, !"wchar_size", i32 4} Index: test/DebugInfo/Generic/string-offsets-table.ll =================================================================== --- test/DebugInfo/Generic/string-offsets-table.ll +++ test/DebugInfo/Generic/string-offsets-table.ll @@ -0,0 +1,121 @@ +; RUN: %llc_dwarf -filetype=obj < %s | llvm-dwarfdump -v - | FileCheck --check-prefix=MONOLITHIC %s +; RUN: %llc_dwarf -split-dwarf-file=%t.dwo -filetype=obj < %s | llvm-dwarfdump -v - \ +; RUN: | FileCheck --check-prefix=SPLIT %s + +; This basic test checks the emission of a DWARF v5 string offsets table in +; the split and non-split (monolithic) scenario. +; +; Constructed from the following source with +; clang -S -emit-llvm -gdwarf-5 +; +; enum E {a, b, c}; +; E glob; +; +; In the non-split scenario, check the DW_AT_str_offsets_base attribute +; in .debug_abbrev. +; MONOLITHIC: .debug_abbrev contents: +; MONOLITHIC-NOT: contents: +; MONOLITHIC: DW_TAG_compile_unit +; MONOLITHIC-NOT: DW_TAG +; MONOLITHIC: DW_AT_str_offsets_base DW_FORM_sec_offset + +; Check that indexed strings come out correctly and that the DW_str_offsets_base attribute +; is there and has the right value. +; MONOLITHIC: .debug_info contents: +; MONOLITHIC-NOT: contents: +; MONOLITHIC: DW_TAG_compile_unit +; MONOLITHIC-NOT: {{DW_TAG|NULL}} +; MONOLITHIC: DW_AT_producer [DW_FORM_strx1] ( indexed (00000000) string = "clang{{.*}}") +; MONOLITHIC-NOT: {{DW_TAG|NULL}} +; MONOLITHIC: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +; MONOLITHIC-NOT: {{DW_TAG|NULL}} +; MONOLITHIC: DW_AT_comp_dir [DW_FORM_strx1] ( indexed (00000002) string = "/home/{{.*}}") + +; Extract the string offsets from the .debug_str section so we can check that +; they are referenced correctly in the .debug_str_offsets section. +; MONOLITHIC: .debug_str contents: +; MONOLITHIC-NEXT: 0x00000000: +; MONOLITHIC-NEXT: 0x[[STRING2:[0-9a-f]]] +; MONOLITHIC-NEXT: 0x[[STRING3:[0-9a-f]]] +; MONOLITHIC-NEXT: 0x[[STRING4:[0-9a-f]]] + +; Verify that the .debug_str_offsets section is there and that it starts +; with an 8-byte header, followed by offsets into the .debug_str section. +; MONOLITHIC: .debug_str_offsets contents: +; MONOLITHIC-NEXT: Contribution size = 32, Format = DWARF32, Version = 5 +; MONOLITHIC-NEXT: 0x00000008: 00000000 +; MONOLITHIC-NEXT: 0x0000000c: [[STRING2]] +; MONOLITHIC-NEXT: 0x00000010: [[STRING3]] +; MONOLITHIC-NEXT: 0x00000014: [[STRING4]] + +; For split dwarf, verify that the skeleton unit has the DW_AT_str_offsets_base +; attribute and that it has the right value. +; +; SPLIT: .debug_info contents: +; SPLIT-NEXT: 0x00000000: Compile Unit:{{.*}}DW_UT_skeleton +; SPLIT-NOT: contents: +; SPLIT: DW_TAG_compile_unit +; SPLIT-NOT: {{DW_TAG|contents:}} +; SPLIT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) + +; Check for the split CU in .debug_info.dwo. +; SPLIT: .debug_info.dwo contents: +; SPLIT-NEXT: 0x00000000: Compile Unit:{{.*}}DW_UT_split_compile +; SPLIT-NOT: contents: +; SPLIT: DW_TAG_compile_unit +; +; Check that a couple of indexed strings are displayed correctly and that +; they have the right format (DW_FORM_strx1). +; SPLIT-NOT: contents: +; SPLIT: DW_TAG_enumerator +; SPLIT-NOT: {{DW_TAG|NULL}} +; SPLIT: DW_AT_name [DW_FORM_strx1] ( indexed (00000004) string = "a") +; SPLIT-NOT: contents: +; SPLIT: DW_TAG_enumerator +; SPLIT-NOT: {{DW_TAG|NULL}} +; SPLIT: DW_AT_name [DW_FORM_strx1] ( indexed (00000005) string = "b") +; +; Extract the string offsets referenced in the main file by the skeleton unit. +; SPLIT: .debug_str contents: +; SPLIT-NEXT: 0x00000000: +; SPLIT-NEXT: 0x[[STRING2SPLIT:[0-9a-f]*]] +; +; Extract the string offsets referenced in the .dwo file by the split unit. +; SPLIT: .debug_str.dwo contents: +; SPLIT-NEXT: 0x00000000: +; SPLIT-NEXT: 0x[[STRING2DWO:[0-9a-f]*]] +; SPLIT-NEXT: 0x[[STRING3DWO:[0-9a-f]*]] +; +; Check the string offsets sections in both the main and the .dwo files and +; verify that the extracted string offsets are referenced correctly. +; SPLIT: .debug_str_offsets contents: +; SPLIT-NEXT: 0x00000000: Contribution size = 8, Format = DWARF32, Version = 5 +; SPLIT-NEXT: 0x00000008: 00000000 +; SPLIT-NEXT: 0x0000000c: [[STRING2SPLIT]] +; SPLIT: .debug_str_offsets.dwo contents: +; SPLIT-NEXT: 0x00000000: Contribution size = 32, Format = DWARF32, Version = 5 +; SPLIT-NEXT: 0x00000008: 00000000 +; SPLIT-NEXT: 0x0000000c: [[STRING2DWO]] +; SPLIT-NEXT: 0x00000010: [[STRING3DWO]] + +@glob = global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "glob", scope: !2, file: !3, line: 3, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 (trunk 322415)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !10) +!3 = !DIFile(filename: "en.cpp", directory: "/home/test", checksumkind: CSK_MD5, checksum: "d96b2e2d618e550f0ddd0b6a49c98b02") +!4 = !{!5} +!5 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E", file: !3, line: 1, size: 32, elements: !6, identifier: "_ZTS1E") +!6 = !{!7, !8, !9} +!7 = !DIEnumerator(name: "a", value: 0) +!8 = !DIEnumerator(name: "b", value: 1) +!9 = !DIEnumerator(name: "c", value: 2) +!10 = !{!0} +!11 = !{i32 2, !"Dwarf Version", i32 5} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 7.0.0 (trunk 322415)"}