Index: llvm/include/llvm/DebugInfo/DWARF/DWARFAttribute.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFAttribute.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFAttribute.h @@ -42,6 +42,10 @@ return isValid(); } + /// Identifies DWARF attributes that may contain a reference to a + /// DWARF expression. + static bool mayHaveLocationDescription(dwarf::Attribute Attr); + void clear() { Offset = 0; ByteSize = 0; Index: llvm/lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -316,9 +316,7 @@ else formValue.dump(OS, DumpOpts); } - } else if (Attr == DW_AT_location || Attr == DW_AT_frame_base || - Attr == DW_AT_data_member_location || - Attr == DW_AT_GNU_call_site_value) + } else if (DWARFAttribute::mayHaveLocationDescription(Attr)) dumpLocation(OS, formValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts); else formValue.dump(OS, DumpOpts); @@ -709,3 +707,39 @@ updateForIndex(*AbbrDecl, Index + 1); return *this; } + +bool DWARFAttribute::mayHaveLocationDescription(dwarf::Attribute Attr) { + switch (Attr) { + // From the DWARF v5 specification. + case DW_AT_location: + case DW_AT_byte_size: + case DW_AT_bit_size: + case DW_AT_string_length: + case DW_AT_lower_bound: + case DW_AT_return_addr: + case DW_AT_bit_stride: + case DW_AT_upper_bound: + case DW_AT_count: + case DW_AT_data_member_location: + case DW_AT_frame_base: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_use_location: + case DW_AT_vtable_elem_location: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_byte_stride: + case DW_AT_rank: + case DW_AT_call_value: + case DW_AT_call_origin: + case DW_AT_call_target: + case DW_AT_call_target_clobbered: + case DW_AT_call_data_location: + case DW_AT_call_data_value: + // Extensions. + case DW_AT_GNU_call_site_value: + return true; + default: + return false; + } +} Index: llvm/test/tools/dsymutil/Inputs/op-convert.ll =================================================================== --- /dev/null +++ llvm/test/tools/dsymutil/Inputs/op-convert.ll @@ -0,0 +1,45 @@ +; ModuleID = 'dbg.ll' +source_filename = "dbg.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx" + +; Function Attrs: noinline nounwind uwtable +define signext i8 @foo(i8 signext %x) #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i8 42, metadata !17, metadata !DIExpression(DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)), !dbg !12 + call void @llvm.dbg.value(metadata i8 %x, metadata !11, metadata !DIExpression()), !dbg !12 + call void @llvm.dbg.value(metadata i8 %x, metadata !13, metadata !DIExpression(DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)), !dbg !15 + ret i8 %x, !dbg !16 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind uwtable } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "dbg.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "2a034da6937f5b9cf6dd2d89127f57fd") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "signed char", size: 8, encoding: DW_ATE_signed_char) +!11 = !DILocalVariable(name: "x", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!12 = !DILocation(line: 1, column: 29, scope: !7) +!13 = !DILocalVariable(name: "y", scope: !7, file: !1, line: 3, type: !14) +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DILocation(line: 3, column: 14, scope: !7) +!16 = !DILocation(line: 4, column: 3, scope: !7) +!17 = !DILocalVariable(name: "c", scope: !7, file: !1, line: 3, type: !14) Index: llvm/test/tools/dsymutil/X86/op-convert.test =================================================================== --- /dev/null +++ llvm/test/tools/dsymutil/X86/op-convert.test @@ -0,0 +1,33 @@ +# REQUIRES: object-emission +# RUN: dsymutil -f -o %t --verify -oso-prepend-path=%p/../Inputs -y %s +# RUN: llvm-dwarfdump %t | FileCheck %s + +--- +triple: 'x86_64-apple-darwin' +objects: + - filename: op-convert.macho.x86_64 + symbols: + - { sym: _foo, objAddr: 0x0, binAddr: 0x1000, size: 0x4 } +... + + +CHECK: DW_TAG_base_type +CHECK-NEXT: DW_AT_name ("DW_ATE_signed_8") +CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +CHECK-NEXT: DW_AT_byte_size (0x01) + +CHECK: DW_TAG_base_type +CHECK-NEXT: DW_AT_name ("DW_ATE_signed_32") +CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +CHECK-NEXT: DW_AT_byte_size (0x04) + +CHECK: DW_TAG_variable +CHECK-NEXT: DW_AT_location ( +CHECK-NEXT: [0x0000000000001000, 0x0000000000001002): DW_OP_breg5 RDI+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x0000002a) "DW_ATE_signed_8", DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value +CHECK-NEXT: [0x0000000000001002, 0x0000000000001003): DW_OP_breg0 RAX+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x0000002a) "DW_ATE_signed_8", DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value) +CHECK-NEXT: DW_AT_name ("y") + +CHECK: DW_TAG_variable +CHECK-NEXT: DW_AT_location (DW_OP_constu 0x2a, DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value) +CHECK-NEXT: DW_AT_name ("c") + Index: llvm/tools/dsymutil/DwarfLinker.h =================================================================== --- llvm/tools/dsymutil/DwarfLinker.h +++ llvm/tools/dsymutil/DwarfLinker.h @@ -136,7 +136,7 @@ CompileUnit::DIEInfo &Info); bool applyValidRelocs(MutableArrayRef Data, uint32_t BaseOffset, - bool isLittleEndian); + bool IsLittleEndian); }; /// Keeps track of data associated with one object during linking. @@ -200,7 +200,8 @@ UniquingStringPool &UniquingStringPoolStringPool, DeclContextTree &ODRContexts, uint64_t ModulesEndOffset, unsigned &UnitID, - unsigned Indent = 0, bool Quiet = false); + bool IsLittleEndian, unsigned Indent = 0, + bool Quiet = false); /// Recursively add the debug info in this clang module .pcm /// file (and all the modules imported by it in a bottom-up fashion) @@ -211,8 +212,8 @@ RangesTy &Ranges, OffsetsStringPool &OffsetsStringPool, UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts, uint64_t ModulesEndOffset, - unsigned &UnitID, unsigned Indent = 0, - bool Quiet = false); + unsigned &UnitID, bool IsLittleEndian, + unsigned Indent = 0, bool Quiet = false); /// Flags passed to DwarfLinker::lookForDIEsToKeep enum TraversalFlags { @@ -236,6 +237,8 @@ CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); + /// Check if a variable describing DIE should be kept. + /// \returns updated TraversalFlags. unsigned shouldKeepVariableDIE(RelocationManager &RelocMgr, const DWARFDie &DIE, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); @@ -286,14 +289,15 @@ DIE *cloneDIE(const DWARFDie &InputDIE, const DebugMapObject &DMO, CompileUnit &U, OffsetsStringPool &StringPool, int64_t PCOffset, uint32_t OutOffset, unsigned Flags, - DIE *Die = nullptr); + bool IsLittleEndian, DIE *Die = nullptr); /// Construct the output DIE tree by cloning the DIEs we /// chose to keep above. If there are no valid relocs, then there's /// nothing to clone/emit. void cloneAllCompileUnits(DWARFContext &DwarfContext, const DebugMapObject &DMO, RangesTy &Ranges, - OffsetsStringPool &StringPool); + OffsetsStringPool &StringPool, + bool IsLittleEndian); private: using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec; @@ -335,7 +339,7 @@ OffsetsStringPool &StringPool, const DWARFFormValue &Val, const AttributeSpec AttrSpec, unsigned AttrSize, - AttributesInfo &AttrInfo); + AttributesInfo &AttrInfo, bool IsLittleEndian); /// Clone a string attribute described by \p AttrSpec and add /// it to \p Die. @@ -355,11 +359,18 @@ const DebugMapObject &DMO, CompileUnit &Unit); + /// Clone a DWARF expression that may be referencing another DIE. + void cloneExpression(DataExtractor &Data, DWARFExpression Expression, + const DebugMapObject &DMO, CompileUnit &Unit, + SmallVectorImpl &OutputBuffer); + /// Clone an attribute referencing another DIE and add /// it to \p Die. /// \returns the size of the new attribute. - unsigned cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec, - const DWARFFormValue &Val, unsigned AttrSize); + unsigned cloneBlockAttribute(DIE &Die, const DebugMapObject &DMO, + CompileUnit &Unit, AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize, + bool IsLittleEndian); /// Clone an attribute referencing another DIE and add /// it to \p Die. Index: llvm/tools/dsymutil/DwarfLinker.cpp =================================================================== --- llvm/tools/dsymutil/DwarfLinker.cpp +++ llvm/tools/dsymutil/DwarfLinker.cpp @@ -125,7 +125,6 @@ CompileUnit *&RefCU) { assert(RefValue.isFormClass(DWARFFormValue::FC_Reference)); uint64_t RefOffset = *RefValue.getAsReference(); - if ((RefCU = getUnitForOffset(Units, RefOffset))) if (const auto RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) { // In a file with broken references, an attribute might point to a NULL @@ -585,7 +584,7 @@ MyInfo.InDebugMap = true; return Flags | TF_Keep; } - + Optional LocationIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_location); if (!LocationIdx) @@ -694,6 +693,9 @@ case dwarf::DW_TAG_label: return shouldKeepSubprogramDIE(RelocMgr, Ranges, DIE, DMO, Unit, MyInfo, Flags); + case dwarf::DW_TAG_base_type: + // DWARF Expressions may reference basic types, but scanning them + // is expensive. Basic types are tiny, so just keep all of them. case dwarf::DW_TAG_imported_module: case dwarf::DW_TAG_imported_declaration: case dwarf::DW_TAG_imported_unit: @@ -745,7 +747,6 @@ // Mark all DIEs referenced through attributes as kept. for (const auto &AttrSpec : Abbrev->attributes()) { DWARFFormValue Val(AttrSpec.Form); - if (!Val.isFormClass(DWARFFormValue::FC_Reference) || AttrSpec.Attr == dwarf::DW_AT_sibling) { DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, @@ -1052,15 +1053,74 @@ return AttrSize; } -unsigned DwarfLinker::DIECloner::cloneBlockAttribute(DIE &Die, - AttributeSpec AttrSpec, - const DWARFFormValue &Val, - unsigned AttrSize) { +void DwarfLinker::DIECloner::cloneExpression( + DataExtractor &Data, DWARFExpression Expression, const DebugMapObject &DMO, + CompileUnit &Unit, SmallVectorImpl &OutputBuffer) { + using Encoding = DWARFExpression::Operation::Encoding; + + uint32_t OpOffset = 0; + for (auto &Op : Expression) { + auto Description = Op.getDescription(); + // DW_OP_const_type is variable-length and has 3 + // operands. DWARFExpression thus far only supports 2. + auto Op0 = Description.Op[0]; + auto Op1 = Description.Op[1]; + if ((Op0 == Encoding::BaseTypeRef && Op1 != Encoding::SizeNA) || + (Op1 == Encoding::BaseTypeRef && Op0 != Encoding::Size1)) + Linker.reportWarning("Unsupported DW_OP encoding.", DMO); + + if ((Op0 == Encoding::BaseTypeRef && Op1 == Encoding::SizeNA) || + (Op1 == Encoding::BaseTypeRef && Op0 == Encoding::Size1)) { + // This code assumes that the other non-typeref operand fits into 1 byte. + assert(OpOffset < Op.getEndOffset()); + uint32_t ULEBsize = Op.getEndOffset() - OpOffset - 1; + assert(ULEBsize <= 16); + + // Copy over the operation. + OutputBuffer.push_back(Op.getCode()); + uint64_t RefOffset; + if (Op1 == Encoding::SizeNA) { + RefOffset = Op.getRawOperand(0); + } else { + OutputBuffer.push_back(Op.getRawOperand(0)); + RefOffset = Op.getRawOperand(1); + } + auto RefDie = Unit.getOrigUnit().getDIEForOffset(RefOffset); + uint32_t RefIdx = Unit.getOrigUnit().getDIEIndex(RefDie); + CompileUnit::DIEInfo &Info = Unit.getInfo(RefIdx); + uint32_t Offset = 0; + if (DIE *Clone = Info.Clone) + Offset = Clone->getOffset(); + else + Linker.reportWarning("base type ref doesn't point to DW_TAG_base_type.", + DMO); + uint8_t ULEB[16]; + unsigned RealSize = encodeULEB128(Offset, ULEB, ULEBsize); + if (RealSize > ULEBsize) { + // Emit the generic type as a fallback. + RealSize = encodeULEB128(0, ULEB, ULEBsize); + Linker.reportWarning("base type ref doesn't fit.", DMO); + } + assert(RealSize == ULEBsize && "padding failed"); + ArrayRef ULEBbytes(ULEB, ULEBsize); + OutputBuffer.append(ULEBbytes.begin(), ULEBbytes.end()); + } else { + // Copy over everything else unmodified. + StringRef Bytes = Data.getData().slice(OpOffset, Op.getEndOffset()); + OutputBuffer.append(Bytes.begin(), Bytes.end()); + } + OpOffset = Op.getEndOffset(); + } +} + +unsigned DwarfLinker::DIECloner::cloneBlockAttribute( + DIE &Die, const DebugMapObject &DMO, CompileUnit &Unit, + AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, + bool IsLittleEndian) { DIEValueList *Attr; DIEValue Value; DIELoc *Loc = nullptr; DIEBlock *Block = nullptr; - // Just copy the block data over. if (AttrSpec.Form == dwarf::DW_FORM_exprloc) { Loc = new (DIEAlloc) DIELoc; Linker.DIELocs.push_back(Loc); @@ -1077,10 +1137,26 @@ else Value = DIEValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form), Block); + + // If the block is a DWARF Expression, clone it using cloneExpression(), + // otherwise copy the data in bulk. + SmallVector Buffer; ArrayRef Bytes = *Val.getAsBlock(); + if (DWARFAttribute::mayHaveLocationDescription(AttrSpec.Attr) && + (Val.isFormClass(DWARFFormValue::FC_Block) || + Val.isFormClass(DWARFFormValue::FC_Exprloc))) { + DWARFUnit &OrigUnit = Unit.getOrigUnit(); + DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()), + IsLittleEndian, OrigUnit.getAddressByteSize()); + DWARFExpression Expr(Data, OrigUnit.getVersion(), + OrigUnit.getAddressByteSize()); + cloneExpression(Data, Expr, DMO, Unit, Buffer); + Bytes = Buffer; + } for (auto Byte : Bytes) Attr->addValue(DIEAlloc, static_cast(0), dwarf::DW_FORM_data1, DIEInteger(Byte)); + // FIXME: If DIEBlock and DIELoc just reuses the Size field of // the DIE class, this if could be replaced by // Attr->setSize(Bytes.size()). @@ -1198,8 +1274,9 @@ // A more generic way to check for location attributes would be // nice, but it's very unlikely that any other attribute needs a // location list. + // FIXME: use DWARFAttribute::mayHaveLocationDescription(). else if (AttrSpec.Attr == dwarf::DW_AT_location || - AttrSpec.Attr == dwarf::DW_AT_frame_base) + AttrSpec.Attr == dwarf::DW_AT_frame_base) Unit.noteLocationAttribute(Patch, Info.PCOffset); else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value) Info.IsDeclaration = true; @@ -1213,7 +1290,8 @@ unsigned DwarfLinker::DIECloner::cloneAttribute( DIE &Die, const DWARFDie &InputDIE, const DebugMapObject &DMO, CompileUnit &Unit, OffsetsStringPool &StringPool, const DWARFFormValue &Val, - const AttributeSpec AttrSpec, unsigned AttrSize, AttributesInfo &Info) { + const AttributeSpec AttrSpec, unsigned AttrSize, AttributesInfo &Info, + bool IsLittleEndian) { const DWARFUnit &U = Unit.getOrigUnit(); switch (AttrSpec.Form) { @@ -1232,7 +1310,8 @@ case dwarf::DW_FORM_block2: case dwarf::DW_FORM_block4: case dwarf::DW_FORM_exprloc: - return cloneBlockAttribute(Die, AttrSpec, Val, AttrSize); + return cloneBlockAttribute(Die, DMO, Unit, AttrSpec, Val, AttrSize, + IsLittleEndian); case dwarf::DW_FORM_addr: return cloneAddressAttribute(Die, AttrSpec, Val, Unit, Info); case dwarf::DW_FORM_data1: @@ -1264,7 +1343,7 @@ /// /// \returns whether any reloc has been applied. bool DwarfLinker::RelocationManager::applyValidRelocs( - MutableArrayRef Data, uint32_t BaseOffset, bool isLittleEndian) { + MutableArrayRef Data, uint32_t BaseOffset, bool IsLittleEndian) { assert((NextValidReloc == 0 || BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) && "BaseOffset should only be increasing."); @@ -1288,7 +1367,7 @@ uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress; Value += ValidReloc.Addend; for (unsigned i = 0; i != ValidReloc.Size; ++i) { - unsigned Index = isLittleEndian ? i : (ValidReloc.Size - i - 1); + unsigned Index = IsLittleEndian ? i : (ValidReloc.Size - i - 1); Buf[i] = uint8_t(Value >> (Index * 8)); } assert(ValidReloc.Size <= sizeof(Buf)); @@ -1370,12 +1449,10 @@ } } -DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, - const DebugMapObject &DMO, - CompileUnit &Unit, - OffsetsStringPool &StringPool, - int64_t PCOffset, uint32_t OutOffset, - unsigned Flags, DIE *Die) { +DIE *DwarfLinker::DIECloner::cloneDIE( + const DWARFDie &InputDIE, const DebugMapObject &DMO, CompileUnit &Unit, + OffsetsStringPool &StringPool, int64_t PCOffset, uint32_t OutOffset, + unsigned Flags, bool IsLittleEndian, DIE *Die) { DWARFUnit &U = Unit.getOrigUnit(); unsigned Idx = U.getDIEIndex(InputDIE); CompileUnit::DIEInfo &Info = Unit.getInfo(Idx); @@ -1481,7 +1558,7 @@ AttrSize = Offset - AttrSize; OutOffset += cloneAttribute(*Die, InputDIE, DMO, Unit, StringPool, Val, - AttrSpec, AttrSize, AttrInfo); + AttrSpec, AttrSize, AttrInfo, IsLittleEndian); } // Look for accelerator entries. @@ -1556,7 +1633,7 @@ // Recursively clone children. for (auto Child : InputDIE.children()) { if (DIE *Clone = cloneDIE(Child, DMO, Unit, StringPool, PCOffset, OutOffset, - Flags)) { + Flags, IsLittleEndian)) { Die->addChild(Clone); OutOffset = Clone->getOffset() + Clone->getSize(); } @@ -2033,7 +2110,8 @@ const DWARFDie &CUDie, const DWARFUnit &Unit, DebugMap &ModuleMap, const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool, UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts, - uint64_t ModulesEndOffset, unsigned &UnitID, unsigned Indent, bool Quiet) { + uint64_t ModulesEndOffset, unsigned &UnitID, bool IsLittleEndian, + unsigned Indent, bool Quiet) { std::string PCMfile = dwarf::toString( CUDie.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), ""); if (PCMfile.empty()) @@ -2075,10 +2153,10 @@ // Cyclic dependencies are disallowed by Clang, but we still // shouldn't run into an infinite loop, so mark it as processed now. ClangModules.insert({PCMfile, DwoId}); - if (Error E = - loadClangModule(PCMfile, PCMpath, Name, DwoId, ModuleMap, DMO, Ranges, - StringPool, UniquingStringPool, ODRContexts, - ModulesEndOffset, UnitID, Indent + 2, Quiet)) { + if (Error E = loadClangModule(PCMfile, PCMpath, Name, DwoId, ModuleMap, DMO, + Ranges, StringPool, UniquingStringPool, + ODRContexts, ModulesEndOffset, UnitID, + IsLittleEndian, Indent + 2, Quiet)) { consumeError(std::move(E)); return false; } @@ -2112,7 +2190,8 @@ uint64_t DwoId, DebugMap &ModuleMap, const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool, UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts, - uint64_t ModulesEndOffset, unsigned &UnitID, unsigned Indent, bool Quiet) { + uint64_t ModulesEndOffset, unsigned &UnitID, bool IsLittleEndian, + unsigned Indent, bool Quiet) { SmallString<80> Path(Options.PrependPath); if (sys::path::is_relative(Filename)) sys::path::append(Path, ModulePath, Filename); @@ -2174,7 +2253,8 @@ continue; if (!registerModuleReference(CUDie, *CU, ModuleMap, DMO, Ranges, StringPool, UniquingStringPool, ODRContexts, - ModulesEndOffset, UnitID, Indent, Quiet)) { + ModulesEndOffset, UnitID, IsLittleEndian, + Indent, Quiet)) { if (Unit) { std::string Err = (Filename + @@ -2218,13 +2298,14 @@ UnitListTy CompileUnits; CompileUnits.push_back(std::move(Unit)); DIECloner(*this, RelocMgr, DIEAlloc, CompileUnits, Options) - .cloneAllCompileUnits(*DwarfContext, DMO, Ranges, StringPool); + .cloneAllCompileUnits(*DwarfContext, DMO, Ranges, StringPool, + IsLittleEndian); return Error::success(); } void DwarfLinker::DIECloner::cloneAllCompileUnits( DWARFContext &DwarfContext, const DebugMapObject &DMO, RangesTy &Ranges, - OffsetsStringPool &StringPool) { + OffsetsStringPool &StringPool, bool IsLittleEndian) { if (!Linker.Streamer) return; @@ -2240,7 +2321,8 @@ // already has a DIE inside of it. CurrentUnit->createOutputDIE(); cloneDIE(InputDIE, DMO, *CurrentUnit, StringPool, 0 /* PC offset */, - 11 /* Unit Header size */, 0, CurrentUnit->getOutputUnitDIE()); + 11 /* Unit Header size */, 0, IsLittleEndian, + CurrentUnit->getOutputUnitDIE()); } Linker.OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(); @@ -2260,7 +2342,16 @@ continue; Linker.patchRangesForUnit(*CurrentUnit, DwarfContext, DMO); - Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext); + auto ProcessExpr = [&](StringRef Bytes, SmallVectorImpl &Buffer) { + DWARFUnit &OrigUnit = CurrentUnit->getOrigUnit(); + DataExtractor Data(Bytes, IsLittleEndian, OrigUnit.getAddressByteSize()); + cloneExpression(Data, + DWARFExpression(Data, OrigUnit.getVersion(), + OrigUnit.getAddressByteSize()), + DMO, *CurrentUnit, Buffer); + }; + Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext, + ProcessExpr); } if (Linker.Options.NoOutput) @@ -2490,7 +2581,8 @@ if (CUDie && !LLVM_UNLIKELY(Options.Update)) registerModuleReference(CUDie, *CU, ModuleMap, LinkContext.DMO, LinkContext.Ranges, OffsetsStringPool, - UniquingStringPool, ODRContexts, 0, UnitID); + UniquingStringPool, ODRContexts, 0, UnitID, + LinkContext.DwarfContext->isLittleEndian()); } } @@ -2583,7 +2675,8 @@ DIECloner(*this, LinkContext.RelocMgr, DIEAlloc, LinkContext.CompileUnits, Options) .cloneAllCompileUnits(*LinkContext.DwarfContext, LinkContext.DMO, - LinkContext.Ranges, OffsetsStringPool); + LinkContext.Ranges, OffsetsStringPool, + LinkContext.DwarfContext->isLittleEndian()); if (!Options.NoOutput && !LinkContext.CompileUnits.empty() && LLVM_LIKELY(!Options.Update)) patchFrameInfoForObject( Index: llvm/tools/dsymutil/DwarfStreamer.h =================================================================== --- llvm/tools/dsymutil/DwarfStreamer.h +++ llvm/tools/dsymutil/DwarfStreamer.h @@ -95,7 +95,9 @@ /// Emit the debug_loc contribution for \p Unit by copying the entries from /// \p Dwarf and offsetting them. Update the location attributes to point to /// the new entries. - void emitLocationsForUnit(const CompileUnit &Unit, DWARFContext &Dwarf); + void emitLocationsForUnit( + const CompileUnit &Unit, DWARFContext &Dwarf, + std::function &)> ProcessExpr); /// Emit the line table described in \p Rows into the debug_line section. void emitLineTableForUnit(MCDwarfLineTableParams Params, Index: llvm/tools/dsymutil/DwarfStreamer.cpp =================================================================== --- llvm/tools/dsymutil/DwarfStreamer.cpp +++ llvm/tools/dsymutil/DwarfStreamer.cpp @@ -384,8 +384,9 @@ /// Emit location lists for \p Unit and update attributes to point to the new /// entries. -void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit, - DWARFContext &Dwarf) { +void DwarfStreamer::emitLocationsForUnit( + const CompileUnit &Unit, DWARFContext &Dwarf, + std::function &)> ProcessExpr) { const auto &Attributes = Unit.getLocationAttributes(); if (Attributes.empty()) @@ -402,6 +403,7 @@ if (auto OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc))) UnitPcOffset = int64_t(*OrigLowPc) - Unit.getLowPc(); + SmallVector Buffer; for (const auto &Attr : Attributes) { uint32_t Offset = Attr.first.get(); Attr.first.set(LocSectionSize); @@ -421,9 +423,13 @@ Asm->OutStreamer->EmitIntValue(High + LocPcOffset, AddressSize); uint64_t Length = Data.getU16(&Offset); Asm->OutStreamer->EmitIntValue(Length, 2); - // Just copy the bytes over. + // Copy the bytes int to the buffer, process them, emit them. + Buffer.reserve(Length); + Buffer.resize(0); + StringRef Input = InputSec.Data.substr(Offset, Length); + ProcessExpr(Input, Buffer); Asm->OutStreamer->EmitBytes( - StringRef(InputSec.Data.substr(Offset, Length))); + StringRef((const char *)Buffer.data(), Length)); Offset += Length; LocSectionSize += Length + 2; }