mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 02:52:53 +02:00
dsymutil support for DW_OP_convert
Add support for cloning DWARF expressions that contain base type DIE references in dsymutil. <rdar://problem/48167812> Differential Revision: https://reviews.llvm.org/D58534 llvm-svn: 355148
This commit is contained in:
parent
21b919ec87
commit
64b92e8c26
@ -42,6 +42,10 @@ struct DWARFAttribute {
|
||||
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;
|
||||
|
@ -312,9 +312,7 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
|
||||
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);
|
||||
@ -702,3 +700,39 @@ DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
45
test/tools/dsymutil/Inputs/op-convert.ll
Normal file
45
test/tools/dsymutil/Inputs/op-convert.ll
Normal file
@ -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)
|
BIN
test/tools/dsymutil/Inputs/op-convert.macho.x86_64
Normal file
BIN
test/tools/dsymutil/Inputs/op-convert.macho.x86_64
Normal file
Binary file not shown.
33
test/tools/dsymutil/X86/op-convert.test
Normal file
33
test/tools/dsymutil/X86/op-convert.test
Normal file
@ -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")
|
||||
|
@ -125,7 +125,6 @@ static DWARFDie resolveDIEReference(const DwarfLinker &Linker,
|
||||
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 @@ unsigned DwarfLinker::shouldKeepVariableDIE(RelocationManager &RelocMgr,
|
||||
MyInfo.InDebugMap = true;
|
||||
return Flags | TF_Keep;
|
||||
}
|
||||
|
||||
|
||||
Optional<uint32_t> LocationIdx =
|
||||
Abbrev->findAttributeIndex(dwarf::DW_AT_location);
|
||||
if (!LocationIdx)
|
||||
@ -694,6 +693,9 @@ unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr,
|
||||
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 @@ void DwarfLinker::keepDIEAndDependencies(
|
||||
// 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 @@ unsigned DwarfLinker::DIECloner::cloneDieReferenceAttribute(
|
||||
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<uint8_t> &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<uint8_t> 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 @@ unsigned DwarfLinker::DIECloner::cloneBlockAttribute(DIE &Die,
|
||||
else
|
||||
Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),
|
||||
dwarf::Form(AttrSpec.Form), Block);
|
||||
|
||||
// If the block is a DWARF Expression, clone it into the temporary
|
||||
// buffer using cloneExpression(), otherwise copy the data directly.
|
||||
SmallVector<uint8_t, 32> Buffer;
|
||||
ArrayRef<uint8_t> 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<dwarf::Attribute>(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 @@ unsigned DwarfLinker::DIECloner::cloneScalarAttribute(
|
||||
// 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::cloneScalarAttribute(
|
||||
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 @@ unsigned DwarfLinker::DIECloner::cloneAttribute(
|
||||
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 @@ unsigned DwarfLinker::DIECloner::cloneAttribute(
|
||||
///
|
||||
/// \returns whether any reloc has been applied.
|
||||
bool DwarfLinker::RelocationManager::applyValidRelocs(
|
||||
MutableArrayRef<char> Data, uint32_t BaseOffset, bool isLittleEndian) {
|
||||
MutableArrayRef<char> Data, uint32_t BaseOffset, bool IsLittleEndian) {
|
||||
assert((NextValidReloc == 0 ||
|
||||
BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) &&
|
||||
"BaseOffset should only be increasing.");
|
||||
@ -1288,7 +1367,7 @@ bool DwarfLinker::RelocationManager::applyValidRelocs(
|
||||
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 @@ shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
|
||||
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 @@ DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
|
||||
// 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 @@ bool DwarfLinker::registerModuleReference(
|
||||
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 @@ bool DwarfLinker::registerModuleReference(
|
||||
// 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 @@ Error DwarfLinker::loadClangModule(
|
||||
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 @@ Error DwarfLinker::loadClangModule(
|
||||
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 @@ Error DwarfLinker::loadClangModule(
|
||||
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 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(
|
||||
// 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 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(
|
||||
continue;
|
||||
|
||||
Linker.patchRangesForUnit(*CurrentUnit, DwarfContext, DMO);
|
||||
Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext);
|
||||
auto ProcessExpr = [&](StringRef Bytes, SmallVectorImpl<uint8_t> &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 @@ bool DwarfLinker::link(const DebugMap &Map) {
|
||||
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 @@ bool DwarfLinker::link(const DebugMap &Map) {
|
||||
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(
|
||||
|
@ -136,7 +136,7 @@ private:
|
||||
CompileUnit::DIEInfo &Info);
|
||||
|
||||
bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
|
||||
bool isLittleEndian);
|
||||
bool IsLittleEndian);
|
||||
};
|
||||
|
||||
/// Keeps track of data associated with one object during linking.
|
||||
@ -200,7 +200,8 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
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<uint8_t> &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.
|
||||
|
@ -384,8 +384,9 @@ void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit,
|
||||
|
||||
/// 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<void(StringRef, SmallVectorImpl<uint8_t> &)> ProcessExpr) {
|
||||
const auto &Attributes = Unit.getLocationAttributes();
|
||||
|
||||
if (Attributes.empty())
|
||||
@ -402,6 +403,7 @@ void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
|
||||
if (auto OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc)))
|
||||
UnitPcOffset = int64_t(*OrigLowPc) - Unit.getLowPc();
|
||||
|
||||
SmallVector<uint8_t, 32> Buffer;
|
||||
for (const auto &Attr : Attributes) {
|
||||
uint32_t Offset = Attr.first.get();
|
||||
Attr.first.set(LocSectionSize);
|
||||
@ -421,9 +423,13 @@ void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
|
||||
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 into 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;
|
||||
}
|
||||
|
@ -95,7 +95,9 @@ public:
|
||||
/// 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<void(StringRef, SmallVectorImpl<uint8_t> &)> ProcessExpr);
|
||||
|
||||
/// Emit the line table described in \p Rows into the debug_line section.
|
||||
void emitLineTableForUnit(MCDwarfLineTableParams Params,
|
||||
|
Loading…
Reference in New Issue
Block a user