Index: llvm/test/tools/llvm-dwp/X86/simple-v5.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-dwp/X86/simple-v5.test @@ -0,0 +1,62 @@ +RUN: llvm-dwp %p/../Inputs/simple/notypes/a-v5.dwo %p/../Inputs/simple/notypes/b-v5.dwo -o %t +RUN: llvm-dwarfdump -v %t | FileCheck %s + +a-v5.c: + struct foo { }; + foo a; + +b-v5.c: + struct bar { }; + void b(bar) { + } + +CHECK-LABEL: .debug_abbrev.dwo contents: +CHECK-LABEL: Abbrev table for offset: +CHECK: 0x0000[[AAOFF:.*]] +CHECK: DW_TAG_compile_unit +CHECK: DW_TAG_variable +CHECK: DW_TAG_structure_type +CHECK-LABEL: Abbrev table for offset: +CHECK: 0x0000[[BAOFF:.*]] +CHECK: DW_TAG_compile_unit +CHECK: DW_TAG_subprogram +CHECK: DW_TAG_formal_parameter +CHECK: DW_TAG_structure_type + +CHECK: .debug_info.dwo contents: +CHECK: [[AOFF:0x[0-9a-f]*]]: +CHECK-LABEL: Compile Unit: length = {{.*}} version = 0x0005 unit_type = DW_UT_split_compile abbr_offset = +CHECK: 0x[[AAOFF]] addr_size = 0x08 DWO_id = [[DWOA:.*]] (next unit at [[BOFF:.*]]) +CHECK: DW_TAG_compile_unit +CHECK: DW_AT_name {{.*}} "a-v5.c" +CHECK: DW_TAG_variable +CHECK: DW_AT_name {{.*}} "a" +CHECK: DW_TAG_structure_type +CHECK: DW_AT_name {{.*}} "foo" + +CHECK: [[BOFF]]: +CHECK-LABEL: Compile Unit: length = {{.*}} version = 0x0005 unit_type = DW_UT_split_compile abbr_offset = +CHECK: 0x[[BAOFF]] addr_size = 0x08 DWO_id = [[DWOB:.*]] (next unit at [[XOFF:.*]]) +CHECK: DW_AT_name {{.*}} "b-v5.c" +CHECK: DW_TAG_subprogram +CHECK: DW_AT_name {{.*}} "b" +CHECK: DW_TAG_formal_parameter +CHECK: DW_TAG_structure_type +CHECK: DW_AT_name {{.*}} "bar" + +CHECK-LABEL: .debug_cu_index contents: +CHECK: Index Signature INFO ABBREV STR_OFFSETS +CHECK: 1 [[DWOA]] {{\[}}[[AOFF]], [[BOFF]]) [0x0000[[AAOFF]], 0x0000[[BAOFF]]) [0x00000000, 0x0000001c) +CHECK: 3 [[DWOB]] {{\[}}[[BOFF]], [[XOFF]]) [0x0000[[BAOFF]], 0x0000006b) [0x0000001c, 0x0000003c) + +CHECK-LABEL: .debug_str.dwo contents: +CHECK: "clang version +CHECK: 0x[[AC:.*]]: "a-v5.c" +CHECK-NOT: "clang version +CHECK: 0x[[BC:.*]]: "b-v5.c" + +CHECK-LABEL: .debug_str_offsets.dwo contents: +CHECK-NEXT: 0x00000000: Contribution size = 24, Format = DWARF32, Version = 5 +CHECK: : [[AC]] +CHECK-LABEL: 0x0000001c: Contribution size = 28, Format = DWARF32, Version = 5 +CHECK: : [[BC]] Index: llvm/tools/llvm-dwp/llvm-dwp.cpp =================================================================== --- llvm/tools/llvm-dwp/llvm-dwp.cpp +++ llvm/tools/llvm-dwp/llvm-dwp.cpp @@ -64,7 +64,8 @@ static void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings, MCSection *StrOffsetSection, StringRef CurStrSection, - StringRef CurStrOffsetSection) { + StringRef CurStrOffsetSection, + uint16_t Version) { // Could possibly produce an error or warning if one of these was non-null but // the other was null. if (CurStrSection.empty() || CurStrOffsetSection.empty()) @@ -85,8 +86,15 @@ Out.SwitchSection(StrOffsetSection); - uint64_t Offset = 0; uint64_t Size = CurStrOffsetSection.size(); + // Write DWARFv5 debug_str_offsets section header. + if (Version >= 5) { + // Unit_length field should not include the length field(4 bytes) it self. + Out.EmitIntValue(Size - 4, 4); + Out.EmitIntValue(5, 2); // Version. + Out.EmitIntValue(0, 2); // Padding. + } + uint64_t Offset = Version >= 5 ? 8 : 0; while (Offset < Size) { auto OldOffset = Data.getU32(&Offset); auto NewOffset = OffsetRemapping[OldOffset]; @@ -117,16 +125,23 @@ }; static Expected -getIndexedString(dwarf::Form Form, DataExtractor InfoData, - uint64_t &InfoOffset, StringRef StrOffsets, StringRef Str) { +getIndexedString(dwarf::Form Form, DataExtractor InfoData, uint64_t &InfoOffset, + StringRef StrOffsets, StringRef Str, uint16_t Version) { + uint64_t StrOffsetsOffset = 0; if (Form == dwarf::DW_FORM_string) return InfoData.getCStr(&InfoOffset); - if (Form != dwarf::DW_FORM_GNU_str_index) + if (Form != dwarf::DW_FORM_strx1 && Form != dwarf::DW_FORM_strx2 && + Form != dwarf::DW_FORM_strx3 && Form != dwarf::DW_FORM_strx4 && + Form != dwarf::DW_FORM_GNU_str_index) return make_error( - "string field encoded without DW_FORM_string or DW_FORM_GNU_str_index"); + "string field encoded without DW_FORM_string or DW_FORM_GNU_str_index \ + or DW_FORM_strx*"); auto StrIndex = InfoData.getULEB128(&InfoOffset); DataExtractor StrOffsetsData(StrOffsets, true, 0); - uint64_t StrOffsetsOffset = 4 * StrIndex; + if (Version >= 5) + StrOffsetsOffset = 4 * StrIndex + 8 /*Header Size*/; + else + StrOffsetsOffset = 4 * StrIndex; uint64_t StrOffset = StrOffsetsData.getU32(&StrOffsetsOffset); DataExtractor StrData(Str, true, 0); return StrData.getCStr(&StrOffset); @@ -140,6 +155,8 @@ DataExtractor InfoData(Info, true, 0); dwarf::DwarfFormat Format = dwarf::DwarfFormat::DWARF32; uint64_t Length = InfoData.getU32(&Offset); + CompileUnitIdentifiers ID; + Optional Signature = None; // If the length is 0xffffffff, then this indictes that this is a DWARF 64 // stream and the length is actually encoded into a 64 bit value that follows. if (Length == 0xffffffffU) { @@ -147,9 +164,17 @@ Length = InfoData.getU64(&Offset); } uint16_t Version = InfoData.getU16(&Offset); + if (Version >= 5) { + auto UnitType = InfoData.getU8(&Offset); + if (UnitType != dwarf::DW_UT_split_compile) + return make_error( + "unit type DW_UT_split_compile type not found in debug_info header"); + } InfoData.getU32(&Offset); // Abbrev offset (should be zero) uint8_t AddrSize = InfoData.getU8(&Offset); + if (Version >= 5) + Signature = InfoData.getU64(&Offset); uint32_t AbbrCode = InfoData.getULEB128(&Offset); DataExtractor AbbrevData(Abbrev, true, 0); @@ -161,23 +186,22 @@ AbbrevData.getU8(&AbbrevOffset); uint32_t Name; dwarf::Form Form; - CompileUnitIdentifiers ID; - Optional Signature = None; while ((Name = AbbrevData.getULEB128(&AbbrevOffset)) | (Form = static_cast(AbbrevData.getULEB128(&AbbrevOffset))) && (Name != 0 || Form != 0)) { switch (Name) { case dwarf::DW_AT_name: { Expected EName = - getIndexedString(Form, InfoData, Offset, StrOffsets, Str); + getIndexedString(Form, InfoData, Offset, StrOffsets, Str, Version); if (!EName) return EName.takeError(); ID.Name = *EName; break; } - case dwarf::DW_AT_GNU_dwo_name: { + case dwarf::DW_AT_GNU_dwo_name: + case dwarf::DW_AT_dwo_name: { Expected EName = - getIndexedString(Form, InfoData, Offset, StrOffsets, Str); + getIndexedString(Form, InfoData, Offset, StrOffsets, Str, Version); if (!EName) return EName.takeError(); ID.DWOName = *EName; @@ -562,8 +586,19 @@ if (InfoSection.empty()) continue; + /*Here we're extracting Dwarf Version from Info Section to pass it + * for reconstruction of debug_str_offset section based on Dwarf Version. + */ + auto getVersion = [&]() -> uint16_t { + DataExtractor InfoData(InfoSection, true, 0); + // Version field is located just after length field in Info section + // header. For DWARF32 length field is of 4 bytes. + uint64_t Offset = 4; + return InfoData.getU16(&Offset); + }; + auto DwarfVersion = getVersion(); writeStringsAndOffsets(Out, Strings, StrOffsetSection, CurStrSection, - CurStrOffsetSection); + CurStrOffsetSection, DwarfVersion); if (CurCUIndexSection.empty()) { Expected EID = getCUIdentifiers(