diff options
Diffstat (limited to 'contrib/llvm/lib/DebugInfo')
21 files changed, 1902 insertions, 45 deletions
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp new file mode 100644 index 0000000..91b71cc --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp @@ -0,0 +1,165 @@ +//===-- FieldListRecordBuilder.cpp ----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" + +using namespace llvm; +using namespace codeview; + +FieldListRecordBuilder::FieldListRecordBuilder() + : ListRecordBuilder(TypeRecordKind::FieldList) {} + +void FieldListRecordBuilder::writeBaseClass(MemberAccess Access, TypeIndex Type, + uint64_t Offset) { + TypeRecordBuilder &Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::BaseClass); + Builder.writeUInt16(static_cast<uint16_t>(Access)); + Builder.writeTypeIndex(Type); + Builder.writeEncodedUnsignedInteger(Offset); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeEnumerate(MemberAccess Access, uint64_t Value, + StringRef Name) { + TypeRecordBuilder &Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::Enumerate); + Builder.writeUInt16(static_cast<uint16_t>(Access)); + Builder.writeEncodedUnsignedInteger(Value); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeMember(MemberAccess Access, TypeIndex Type, + uint64_t Offset, StringRef Name) { + TypeRecordBuilder &Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::Member); + Builder.writeUInt16(static_cast<uint16_t>(Access)); + Builder.writeTypeIndex(Type); + Builder.writeEncodedUnsignedInteger(Offset); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeMethod(uint16_t OverloadCount, + TypeIndex MethodList, StringRef Name) { + TypeRecordBuilder &Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::Method); + Builder.writeUInt16(OverloadCount); + Builder.writeTypeIndex(MethodList); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeOneMethod( + MemberAccess Access, MethodKind Kind, MethodOptions Options, TypeIndex Type, + int32_t VTableSlotOffset, StringRef Name) { + TypeRecordBuilder &Builder = getBuilder(); + + uint16_t Flags = static_cast<uint16_t>(Access); + Flags |= static_cast<uint16_t>(Kind) << MethodKindShift; + Flags |= static_cast<uint16_t>(Options); + + Builder.writeTypeRecordKind(TypeRecordKind::OneMethod); + Builder.writeUInt16(Flags); + Builder.writeTypeIndex(Type); + switch (Kind) { + case MethodKind::IntroducingVirtual: + case MethodKind::PureIntroducingVirtual: + assert(VTableSlotOffset >= 0); + Builder.writeInt32(VTableSlotOffset); + break; + + default: + assert(VTableSlotOffset == -1); + break; + } + + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeOneMethod(const MethodInfo &Method, + StringRef Name) { + writeOneMethod(Method.getAccess(), Method.getKind(), Method.getOptions(), + Method.getType(), Method.getVTableSlotOffset(), Name); +} + +void FieldListRecordBuilder::writeNestedType(TypeIndex Type, StringRef Name) { + TypeRecordBuilder &Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::NestedType); + Builder.writeUInt16(0); + Builder.writeTypeIndex(Type); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeStaticMember(MemberAccess Access, + TypeIndex Type, StringRef Name) { + TypeRecordBuilder &Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::StaticMember); + Builder.writeUInt16(static_cast<uint16_t>(Access)); + Builder.writeTypeIndex(Type); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeIndirectVirtualBaseClass( + MemberAccess Access, TypeIndex Type, TypeIndex VirtualBasePointerType, + int64_t VirtualBasePointerOffset, uint64_t SlotIndex) { + writeVirtualBaseClass(TypeRecordKind::IndirectVirtualBaseClass, Access, Type, + VirtualBasePointerType, VirtualBasePointerOffset, + SlotIndex); +} + +void FieldListRecordBuilder::writeVirtualBaseClass( + MemberAccess Access, TypeIndex Type, TypeIndex VirtualBasePointerType, + int64_t VirtualBasePointerOffset, uint64_t SlotIndex) { + writeVirtualBaseClass(TypeRecordKind::VirtualBaseClass, Access, Type, + VirtualBasePointerType, VirtualBasePointerOffset, + SlotIndex); +} + +void FieldListRecordBuilder::writeVirtualBaseClass( + TypeRecordKind Kind, MemberAccess Access, TypeIndex Type, + TypeIndex VirtualBasePointerType, int64_t VirtualBasePointerOffset, + uint64_t SlotIndex) { + TypeRecordBuilder &Builder = getBuilder(); + + Builder.writeTypeRecordKind(Kind); + Builder.writeUInt16(static_cast<uint16_t>(Access)); + Builder.writeTypeIndex(Type); + Builder.writeTypeIndex(VirtualBasePointerType); + Builder.writeEncodedInteger(VirtualBasePointerOffset); + Builder.writeEncodedUnsignedInteger(SlotIndex); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeVirtualFunctionTablePointer(TypeIndex Type) { + TypeRecordBuilder &Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::VirtualFunctionTablePointer); + Builder.writeUInt16(0); + Builder.writeTypeIndex(Type); + + finishSubRecord(); +}
\ No newline at end of file diff --git a/contrib/llvm/lib/DebugInfo/CodeView/Line.cpp b/contrib/llvm/lib/DebugInfo/CodeView/Line.cpp new file mode 100644 index 0000000..4cb766b --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/Line.cpp @@ -0,0 +1,22 @@ +//===-- Line.cpp ----------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/Line.h" + +using namespace llvm; +using namespace codeview; + +LineInfo::LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement) { + LineData = StartLine & StartLineMask; + uint32_t LineDelta = EndLine - StartLine; + LineData |= (LineDelta << EndLineDeltaShift) & EndLineDeltaMask; + if (IsStatement) { + LineData |= StatementFlag; + } +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp new file mode 100644 index 0000000..69c7e87 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp @@ -0,0 +1,31 @@ +//===-- ListRecordBuilder.cpp ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h" + +using namespace llvm; +using namespace codeview; + +ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : Builder(Kind) {} + +void ListRecordBuilder::finishSubRecord() { + // The builder starts at offset 2 in the actual CodeView buffer, so add an + // additional offset of 2 before computing the alignment. + uint32_t Remainder = (Builder.size() + 2) % 4; + if (Remainder != 0) { + for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0; + --PaddingBytesLeft) { + Builder.writeUInt8(0xf0 + PaddingBytesLeft); + } + } + + // TODO: Split the list into multiple records if it's longer than 64KB, using + // a subrecord of TypeRecordKind::Index to chain the records together. + assert(Builder.size() < 65536); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp new file mode 100644 index 0000000..9afce92 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp @@ -0,0 +1,35 @@ +//===-- MemoryTypeTableBuilder.cpp ----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" + +using namespace llvm; +using namespace codeview; + +MemoryTypeTableBuilder::Record::Record(StringRef RData) + : Size(RData.size()), Data(new char[RData.size()]) { + memcpy(Data.get(), RData.data(), RData.size()); +} + +TypeIndex MemoryTypeTableBuilder::writeRecord(StringRef Data) { + auto I = HashedRecords.find(Data); + if (I != HashedRecords.end()) { + return I->second; + } + + std::unique_ptr<Record> R(new Record(Data)); + + TypeIndex TI(static_cast<uint32_t>(Records.size()) + + TypeIndex::FirstNonSimpleIndex); + HashedRecords.insert(std::make_pair(StringRef(R->data(), R->size()), TI)); + Records.push_back(std::move(R)); + + return TI; +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp new file mode 100644 index 0000000..8893025 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp @@ -0,0 +1,49 @@ +//===-- MethodListRecordBuilder.cpp ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" + +using namespace llvm; +using namespace codeview; + +MethodListRecordBuilder::MethodListRecordBuilder() + : ListRecordBuilder(TypeRecordKind::MethodList) {} + +void MethodListRecordBuilder::writeMethod(MemberAccess Access, MethodKind Kind, + MethodOptions Options, TypeIndex Type, + int32_t VTableSlotOffset) { + TypeRecordBuilder &Builder = getBuilder(); + + uint16_t Flags = static_cast<uint16_t>(Access); + Flags |= static_cast<uint16_t>(Kind) << MethodKindShift; + Flags |= static_cast<uint16_t>(Options); + + Builder.writeUInt16(Flags); + Builder.writeUInt16(0); + Builder.writeTypeIndex(Type); + switch (Kind) { + case MethodKind::IntroducingVirtual: + case MethodKind::PureIntroducingVirtual: + assert(VTableSlotOffset >= 0); + Builder.writeInt32(VTableSlotOffset); + break; + + default: + assert(VTableSlotOffset == -1); + break; + } + + // TODO: Fail if too big? +} + +void MethodListRecordBuilder::writeMethod(const MethodInfo &Method) { + writeMethod(Method.getAccess(), Method.getKind(), Method.getOptions(), + Method.getType(), Method.getVTableSlotOffset()); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp new file mode 100644 index 0000000..cbf464f --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp @@ -0,0 +1,113 @@ +//===-- TypeRecordBuilder.cpp ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h" + +using namespace llvm; +using namespace codeview; + +TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind) : Stream(Buffer), + Writer(Stream) { + writeTypeRecordKind(Kind); +} + +StringRef TypeRecordBuilder::str() { + return StringRef(Buffer.data(), Buffer.size()); +} + +void TypeRecordBuilder::writeUInt8(uint8_t Value) { + Writer.write(Value); +} + +void TypeRecordBuilder::writeInt16(int16_t Value) { + Writer.write(Value); +} + +void TypeRecordBuilder::writeUInt16(uint16_t Value) { + Writer.write(Value); +} + +void TypeRecordBuilder::writeInt32(int32_t Value) { + Writer.write(Value); +} + +void TypeRecordBuilder::writeUInt32(uint32_t Value) { + Writer.write(Value); +} + +void TypeRecordBuilder::writeInt64(int64_t Value) { + Writer.write(Value); +} + +void TypeRecordBuilder::writeUInt64(uint64_t Value) { + Writer.write(Value); +} + +void TypeRecordBuilder::writeEncodedInteger(int64_t Value) { + if (Value >= 0) { + writeEncodedUnsignedInteger(static_cast<uint64_t>(Value)); + } else { + writeEncodedSignedInteger(Value); + } +} + +void TypeRecordBuilder::writeEncodedSignedInteger(int64_t Value) { + if (Value >= std::numeric_limits<int8_t>::min() && + Value <= std::numeric_limits<int8_t>::max()) { + writeUInt16(static_cast<uint16_t>(TypeRecordKind::SByte)); + writeInt16(static_cast<int8_t>(Value)); + } else if (Value >= std::numeric_limits<int16_t>::min() && + Value <= std::numeric_limits<int16_t>::max()) { + writeUInt16(static_cast<uint16_t>(TypeRecordKind::Int16)); + writeInt16(static_cast<int16_t>(Value)); + } else if (Value >= std::numeric_limits<int32_t>::min() && + Value <= std::numeric_limits<int32_t>::max()) { + writeUInt16(static_cast<uint32_t>(TypeRecordKind::Int32)); + writeInt32(static_cast<int32_t>(Value)); + } else { + writeUInt16(static_cast<uint16_t>(TypeRecordKind::Int64)); + writeInt64(Value); + } +} + +void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) { + if (Value < static_cast<uint16_t>(TypeRecordKind::SByte)) { + writeUInt16(static_cast<uint16_t>(Value)); + } else if (Value <= std::numeric_limits<uint16_t>::max()) { + writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt16)); + writeUInt16(static_cast<uint16_t>(Value)); + } else if (Value <= std::numeric_limits<uint32_t>::max()) { + writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt32)); + writeUInt32(static_cast<uint32_t>(Value)); + } else { + writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt64)); + writeUInt64(Value); + } +} + +void TypeRecordBuilder::writeNullTerminatedString(const char *Value) { + assert(Value != nullptr); + + size_t Length = strlen(Value); + Stream.write(Value, Length); + writeUInt8(0); +} + +void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) { + Stream.write(Value.data(), Value.size()); + writeUInt8(0); +} + +void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) { + writeUInt32(TypeInd.getIndex()); +} + +void TypeRecordBuilder::writeTypeRecordKind(TypeRecordKind Kind) { + writeUInt16(static_cast<uint16_t>(Kind)); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp new file mode 100644 index 0000000..4af5dca --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp @@ -0,0 +1,217 @@ +//===-- TypeTableBuilder.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace codeview; + +namespace { + +const int PointerKindShift = 0; +const int PointerModeShift = 5; +const int PointerSizeShift = 13; + +const int ClassHfaKindShift = 11; +const int ClassWindowsRTClassKindShift = 14; + +void writePointerBase(TypeRecordBuilder &Builder, + const PointerRecordBase &Record) { + Builder.writeTypeIndex(Record.getReferentType()); + uint32_t flags = + static_cast<uint32_t>(Record.getOptions()) | + (Record.getSize() << PointerSizeShift) | + (static_cast<uint32_t>(Record.getMode()) << PointerModeShift) | + (static_cast<uint32_t>(Record.getPointerKind()) << PointerKindShift); + Builder.writeUInt32(flags); +} +} + +TypeTableBuilder::TypeTableBuilder() {} + +TypeTableBuilder::~TypeTableBuilder() {} + +TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::Modifier); + + Builder.writeTypeIndex(Record.getModifiedType()); + Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions())); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::Procedure); + + Builder.writeTypeIndex(Record.getReturnType()); + Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv())); + Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions())); + Builder.writeUInt16(Record.getParameterCount()); + Builder.writeTypeIndex(Record.getArgumentList()); + + return writeRecord(Builder); +} + +TypeIndex +TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::MemberFunction); + + Builder.writeTypeIndex(Record.getReturnType()); + Builder.writeTypeIndex(Record.getClassType()); + Builder.writeTypeIndex(Record.getThisType()); + Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv())); + Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions())); + Builder.writeUInt16(Record.getParameterCount()); + Builder.writeTypeIndex(Record.getArgumentList()); + Builder.writeInt32(Record.getThisPointerAdjustment()); + + return writeRecord(Builder); +} + +TypeIndex +TypeTableBuilder::writeArgumentList(const ArgumentListRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::ArgumentList); + + Builder.writeUInt32(Record.getArgumentTypes().size()); + for (TypeIndex TI : Record.getArgumentTypes()) { + Builder.writeTypeIndex(TI); + } + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::Pointer); + + writePointerBase(Builder, Record); + + return writeRecord(Builder); +} + +TypeIndex +TypeTableBuilder::writePointerToMember(const PointerToMemberRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::Pointer); + + writePointerBase(Builder, Record); + + Builder.writeTypeIndex(Record.getContainingType()); + Builder.writeUInt16(static_cast<uint16_t>(Record.getRepresentation())); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::Array); + + Builder.writeTypeIndex(Record.getElementType()); + Builder.writeTypeIndex(Record.getIndexType()); + Builder.writeEncodedUnsignedInteger(Record.getSize()); + Builder.writeNullTerminatedString(Record.getName()); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeAggregate(const AggregateRecord &Record) { + assert((Record.getKind() == TypeRecordKind::Structure) || + (Record.getKind() == TypeRecordKind::Class) || + (Record.getKind() == TypeRecordKind::Union)); + + TypeRecordBuilder Builder(Record.getKind()); + + Builder.writeUInt16(Record.getMemberCount()); + uint16_t Flags = + static_cast<uint16_t>(Record.getOptions()) | + (static_cast<uint16_t>(Record.getHfa()) << ClassHfaKindShift) | + (static_cast<uint16_t>(Record.getWinRTKind()) + << ClassWindowsRTClassKindShift); + Builder.writeUInt16(Flags); + Builder.writeTypeIndex(Record.getFieldList()); + if (Record.getKind() != TypeRecordKind::Union) { + Builder.writeTypeIndex(Record.getDerivationList()); + Builder.writeTypeIndex(Record.getVTableShape()); + } else { + assert(Record.getDerivationList() == TypeIndex()); + assert(Record.getVTableShape() == TypeIndex()); + } + Builder.writeEncodedUnsignedInteger(Record.getSize()); + Builder.writeNullTerminatedString(Record.getName()); + if ((Record.getOptions() & ClassOptions::HasUniqueName) != + ClassOptions::None) { + Builder.writeNullTerminatedString(Record.getUniqueName()); + } + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::Enum); + + Builder.writeUInt16(Record.getMemberCount()); + Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions())); + Builder.writeTypeIndex(Record.getUnderlyingType()); + Builder.writeTypeIndex(Record.getFieldList()); + Builder.writeNullTerminatedString(Record.getName()); + if ((Record.getOptions() & ClassOptions::HasUniqueName) != + ClassOptions::None) { + Builder.writeNullTerminatedString(Record.getUniqueName()); + } + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::BitField); + + Builder.writeTypeIndex(Record.getType()); + Builder.writeUInt8(Record.getBitSize()); + Builder.writeUInt8(Record.getBitOffset()); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeVirtualTableShape( + const VirtualTableShapeRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::VirtualTableShape); + + ArrayRef<VirtualTableSlotKind> Slots = Record.getSlots(); + + Builder.writeUInt16(Slots.size()); + for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) { + uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4; + if ((SlotIndex + 1) < Slots.size()) { + Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]); + } + Builder.writeUInt8(Byte); + } + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) { + return writeRecord(Builder.str()); +} + +TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) { + // TODO: Split the list into multiple records if it's longer than 64KB, using + // a subrecord of TypeRecordKind::Index to chain the records together. + return writeRecord(FieldList.str()); +} + +TypeIndex +TypeTableBuilder::writeMethodList(MethodListRecordBuilder &MethodList) { + // TODO: Split the list into multiple records if it's longer than 64KB, using + // a subrecord of TypeRecordKind::Index to chain the records together. + return writeRecord(MethodList.str()); +} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index 96bcf15..a4195b7 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" @@ -126,6 +127,11 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { getDebugFrame()->dump(OS); } + if (DumpType == DIDT_All || DumpType == DIDT_Macro) { + OS << "\n.debug_macinfo contents:\n"; + getDebugMacro()->dump(OS); + } + uint32_t offset = 0; if (DumpType == DIDT_All || DumpType == DIDT_Aranges) { OS << "\n.debug_aranges contents:\n"; @@ -155,6 +161,16 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { } } + if (DumpType == DIDT_All || DumpType == DIDT_CUIndex) { + OS << "\n.debug_cu_index contents:\n"; + getCUIndex().dump(OS); + } + + if (DumpType == DIDT_All || DumpType == DIDT_TUIndex) { + OS << "\n.debug_tu_index contents:\n"; + getTUIndex().dump(OS); + } + if (DumpType == DIDT_All || DumpType == DIDT_LineDwo) { OS << "\n.debug_line.dwo contents:\n"; unsigned stmtOffset = 0; @@ -250,6 +266,28 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { getStringSection(), isLittleEndian()); } +const DWARFUnitIndex &DWARFContext::getCUIndex() { + if (CUIndex) + return *CUIndex; + + DataExtractor CUIndexData(getCUIndexSection(), isLittleEndian(), 0); + + CUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_INFO); + CUIndex->parse(CUIndexData); + return *CUIndex; +} + +const DWARFUnitIndex &DWARFContext::getTUIndex() { + if (TUIndex) + return *TUIndex; + + DataExtractor TUIndexData(getTUIndexSection(), isLittleEndian(), 0); + + TUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_TYPES); + TUIndex->parse(TUIndexData); + return *TUIndex; +} + const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() { if (Abbrev) return Abbrev.get(); @@ -322,24 +360,37 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() { return DebugFrame.get(); } +const DWARFDebugMacro *DWARFContext::getDebugMacro() { + if (Macro) + return Macro.get(); + + DataExtractor MacinfoData(getMacinfoSection(), isLittleEndian(), 0); + Macro.reset(new DWARFDebugMacro()); + Macro->parse(MacinfoData); + return Macro.get(); +} + const DWARFLineTable * DWARFContext::getLineTableForUnit(DWARFUnit *U) { if (!Line) Line.reset(new DWARFDebugLine(&getLineSection().Relocs)); + const auto *UnitDIE = U->getUnitDIE(); if (UnitDIE == nullptr) return nullptr; + unsigned stmtOffset = UnitDIE->getAttributeValueAsSectionOffset(U, DW_AT_stmt_list, -1U); if (stmtOffset == -1U) return nullptr; // No line table for this compile unit. + stmtOffset += U->getLineTableOffset(); // See if the line table is cached. if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset)) return lt; // We have to parse it first. - DataExtractor lineData(getLineSection().Data, isLittleEndian(), + DataExtractor lineData(U->getLineSection(), isLittleEndian(), U->getAddressByteSize()); return Line->getOrParseLineTable(lineData, stmtOffset); } @@ -556,10 +607,11 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, continue; StringRef data; + section_iterator RelocatedSection = Section.getRelocatedSection(); // Try to obtain an already relocated version of this section. // Else use the unrelocated section from the object file. We'll have to // apply relocations ourselves later. - if (!L || !L->getLoadedSectionContents(name,data)) + if (!L || !L->getLoadedSectionContents(*RelocatedSection,data)) Section.getContents(data); name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. @@ -591,6 +643,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, .Case("debug_frame", &DebugFrameSection) .Case("debug_str", &StringSection) .Case("debug_ranges", &RangeSection) + .Case("debug_macinfo", &MacinfoSection) .Case("debug_pubnames", &PubNamesSection) .Case("debug_pubtypes", &PubTypesSection) .Case("debug_gnu_pubnames", &GnuPubNamesSection) @@ -607,6 +660,8 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, .Case("apple_namespaces", &AppleNamespacesSection.Data) .Case("apple_namespac", &AppleNamespacesSection.Data) .Case("apple_objc", &AppleObjCSection.Data) + .Case("debug_cu_index", &CUIndexSection) + .Case("debug_tu_index", &TUIndexSection) // Any more debug info sections go here. .Default(nullptr); if (SectionData) { @@ -623,7 +678,6 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, TypesDWOSections[Section].Data = data; } - section_iterator RelocatedSection = Section.getRelocatedSection(); if (RelocatedSection == Obj.section_end()) continue; @@ -634,7 +688,15 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, // If the section we're relocating was relocated already by the JIT, // then we used the relocated version above, so we do not need to process // relocations for it now. - if (L && L->getLoadedSectionContents(RelSecName,RelSecData)) + if (L && L->getLoadedSectionContents(*RelocatedSection,RelSecData)) + continue; + + // In Mach-o files, the relocations do not need to be applied if + // there is no load offset to apply. The value read at the + // relocation point already factors in the section address + // (actually applying the relocations will produce wrong results + // as the section address will be added twice). + if (!L && isa<MachOObjectFile>(&Obj)) continue; RelSecName = RelSecName.substr( @@ -685,13 +747,19 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, } SymAddr = *SymAddrOrErr; // Also remember what section this symbol is in for later - Sym->getSection(RSec); + RSec = *Sym->getSection(); } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { // MachO also has relocations that point to sections and // scattered relocations. - // FIXME: We are not handling scattered relocations, do we have to? - RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); - SymAddr = RSec->getAddress(); + auto RelocInfo = MObj->getRelocation(Reloc.getRawDataRefImpl()); + if (MObj->isRelocationScattered(RelocInfo)) { + // FIXME: it's not clear how to correctly handle scattered + // relocations. + continue; + } else { + RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); + SymAddr = RSec->getAddress(); + } } // If we are given load addresses for the sections, we need to adjust: @@ -699,12 +767,15 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, // (Address of Section in File) + // (Load Address of Section) if (L != nullptr && RSec != Obj.section_end()) { - // RSec is now either the section being targetted or the section - // containing the symbol being targetted. In either case, + // RSec is now either the section being targeted or the section + // containing the symbol being targeted. In either case, // we need to perform the same computation. StringRef SecName; RSec->getName(SecName); - SectionLoadAddress = L->getSectionLoadAddress(SecName); +// llvm::dbgs() << "Name: '" << SecName +// << "', RSec: " << RSec->getRawDataRefImpl() +// << ", Section: " << Section.getRawDataRefImpl() << "\n"; + SectionLoadAddress = L->getSectionLoadAddress(*RSec); if (SectionLoadAddress != 0) SymAddr += SectionLoadAddress - RSec->getAddress(); } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp index 5abbde4..62d5e66 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -139,7 +139,7 @@ void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS, std::string File; auto Color = syntax::Enumerator; if (attr == DW_AT_decl_file || attr == DW_AT_call_file) { - Color = syntax::String; + Color = syntax::String; if (const auto *LT = u->getContext().getLineTableForUnit(u)) if (LT->getFileNameByIndex( formValue.getAsUnsignedConstant().getValue(), diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp new file mode 100644 index 0000000..b6555fa --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp @@ -0,0 +1,103 @@ +//===-- DWARFDebugMacro.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SyntaxHighlighting.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace dwarf;
+using namespace syntax;
+
+void DWARFDebugMacro::dump(raw_ostream &OS) const {
+ unsigned IndLevel = 0;
+ for (const Entry &E : Macros) {
+ // There should not be DW_MACINFO_end_file when IndLevel is Zero. However,
+ // this check handles the case of corrupted ".debug_macinfo" section.
+ if (IndLevel > 0)
+ IndLevel -= (E.Type == DW_MACINFO_end_file);
+ // Print indentation.
+ for (unsigned I = 0; I < IndLevel; I++)
+ OS << " ";
+ IndLevel += (E.Type == DW_MACINFO_start_file);
+
+ WithColor(OS, syntax::Macro).get() << MacinfoString(E.Type);
+ switch (E.Type) {
+ default:
+ // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ OS << " - lineno: " << E.Line;
+ OS << " macro: " << E.MacroStr;
+ break;
+ case DW_MACINFO_start_file:
+ OS << " - lineno: " << E.Line;
+ OS << " filenum: " << E.File;
+ break;
+ case DW_MACINFO_end_file:
+ break;
+ case DW_MACINFO_vendor_ext:
+ OS << " - constant: " << E.ExtConstant;
+ OS << " string: " << E.ExtStr;
+ break;
+ }
+ OS << "\n";
+ }
+}
+
+void DWARFDebugMacro::parse(DataExtractor data) {
+ uint32_t Offset = 0;
+ while (data.isValidOffset(Offset)) {
+ // A macro list entry consists of:
+ Entry E;
+ // 1. Macinfo type
+ E.Type = data.getULEB128(&Offset);
+
+ if (E.Type == 0) {
+ // Reached end of ".debug_macinfo" section.
+ return;
+ }
+
+ switch (E.Type) {
+ default:
+ // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
+ // Push the corrupted entry to the list and halt parsing.
+ E.Type = DW_MACINFO_invalid;
+ Macros.push_back(E);
+ return;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ // 2. Source line
+ E.Line = data.getULEB128(&Offset);
+ // 3. Macro string
+ E.MacroStr = data.getCStr(&Offset);
+ break;
+ case DW_MACINFO_start_file:
+ // 2. Source line
+ E.Line = data.getULEB128(&Offset);
+ // 3. Source file id
+ E.File = data.getULEB128(&Offset);
+ break;
+ case DW_MACINFO_end_file:
+ break;
+ case DW_MACINFO_vendor_ext:
+ // 2. Vendor extension constant
+ E.ExtConstant = data.getULEB128(&Offset);
+ // 3. Vendor extension string
+ E.ExtStr = data.getCStr(&Offset);
+ break;
+ }
+
+ Macros.push_back(E);
+ }
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp index 53a676e..3dc5842 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -18,7 +18,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include <cassert> -#include <climits> +#include <limits> using namespace llvm; using namespace dwarf; using namespace syntax; @@ -110,7 +110,7 @@ static const DWARFFormValue::FormClass DWARF4FormClasses[] = { bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { // First, check DWARF4 form classes. - if (Form < ArrayRef<FormClass>(DWARF4FormClasses).size() && + if (Form < makeArrayRef(DWARF4FormClasses).size() && DWARF4FormClasses[Form] == FC) return true; // Check more forms from DWARF4 and DWARF5 proposals. @@ -261,6 +261,12 @@ DWARFFormValue::skipValue(DataExtractor debug_info_data, uint32_t* offset_ptr, bool DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, uint32_t *offset_ptr, const DWARFUnit *cu) { + return skipValue(form, debug_info_data, offset_ptr, cu->getVersion(), + cu->getAddressByteSize()); +} +bool DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, + uint32_t *offset_ptr, uint16_t Version, + uint8_t AddrSize) { bool indirect = false; do { switch (form) { @@ -295,10 +301,10 @@ DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, // Compile unit address sized values case DW_FORM_addr: - *offset_ptr += cu->getAddressByteSize(); + *offset_ptr += AddrSize; return true; case DW_FORM_ref_addr: - *offset_ptr += getRefAddrSize(cu->getAddressByteSize(), cu->getVersion()); + *offset_ptr += getRefAddrSize(AddrSize, Version); return true; // 0 byte values - implied from the form. @@ -565,7 +571,7 @@ Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const { Optional<int64_t> DWARFFormValue::getAsSignedConstant() const { if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) || - (Form == DW_FORM_udata && uint64_t(LLONG_MAX) < Value.uval)) + (Form == DW_FORM_udata && uint64_t(std::numeric_limits<int64_t>::max()) < Value.uval)) return None; switch (Form) { case DW_FORM_data4: @@ -584,6 +590,6 @@ Optional<int64_t> DWARFFormValue::getAsSignedConstant() const { Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const { if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc)) return None; - return ArrayRef<uint8_t>(Value.data, Value.uval); + return makeArrayRef(Value.data, Value.uval); } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index 348476d..92ca2d4 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -14,29 +14,37 @@ #include "llvm/Support/Path.h" #include <cstdio> -using namespace llvm; +namespace llvm { using namespace dwarf; void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) { parseImpl(C, Section, C.getDebugAbbrev(), C.getRangeSection(), C.getStringSection(), StringRef(), C.getAddrSection(), - C.isLittleEndian()); + C.getLineSection().Data, C.isLittleEndian()); } void DWARFUnitSectionBase::parseDWO(DWARFContext &C, - const DWARFSection &DWOSection) { + const DWARFSection &DWOSection, + DWARFUnitIndex *Index) { parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), C.getRangeDWOSection(), C.getStringDWOSection(), C.getStringOffsetDWOSection(), - C.getAddrSection(), C.isLittleEndian()); + C.getAddrSection(), C.getLineDWOSection().Data, C.isLittleEndian()); } DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, bool LE, - const DWARFUnitSectionBase &UnitSection) + StringRef SOS, StringRef AOS, StringRef LS, bool LE, + const DWARFUnitSectionBase &UnitSection, + const DWARFUnitIndex::Entry *IndexEntry) : Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS), - StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS), - isLittleEndian(LE), UnitSection(UnitSection) { + LineSection(LS), StringSection(SS), StringOffsetSection([&]() { + if (IndexEntry) + if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) + return SOS.slice(C->Offset, C->Offset + C->Length); + return SOS; + }()), + AddrOffsetSection(AOS), isLittleEndian(LE), UnitSection(UnitSection), + IndexEntry(IndexEntry) { clear(); } @@ -69,6 +77,17 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); Version = debug_info.getU16(offset_ptr); uint64_t AbbrOffset = debug_info.getU32(offset_ptr); + if (IndexEntry) { + if (AbbrOffset) + return false; + auto *UnitContrib = IndexEntry->getOffset(); + if (!UnitContrib || UnitContrib->Length != (Length + 4)) + return false; + auto *AbbrEntry = IndexEntry->getOffset(DW_SECT_ABBREV); + if (!AbbrEntry) + return false; + AbbrOffset = AbbrEntry->Offset; + } AddrSize = debug_info.getU8(offset_ptr); bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); @@ -375,3 +394,12 @@ DWARFUnit::getInlinedChainForAddress(uint64_t Address) { return DWARFDebugInfoEntryInlinedChain(); return SubprogramDIE->getInlinedChainForAddress(ChainCU, Address); } + +const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, + DWARFSectionKind Kind) { + if (Kind == DW_SECT_INFO) + return Context.getCUIndex(); + assert(Kind == DW_SECT_TYPES); + return Context.getTUIndex(); +} +} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp new file mode 100644 index 0000000..96b3169 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp @@ -0,0 +1,168 @@ +//===-- DWARFUnitIndex.cpp ------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +bool DWARFUnitIndex::Header::parse(DataExtractor IndexData, + uint32_t *OffsetPtr) { + if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16)) + return false; + Version = IndexData.getU32(OffsetPtr); + NumColumns = IndexData.getU32(OffsetPtr); + NumUnits = IndexData.getU32(OffsetPtr); + NumBuckets = IndexData.getU32(OffsetPtr); + return Version <= 2; +} + +void DWARFUnitIndex::Header::dump(raw_ostream &OS) const { + OS << format("version = %u slots = %u\n\n", Version, NumBuckets); +} + +bool DWARFUnitIndex::parse(DataExtractor IndexData) { + bool b = parseImpl(IndexData); + if (!b) { + // Make sure we don't try to dump anything + Header.NumBuckets = 0; + // Release any partially initialized data. + ColumnKinds.reset(); + Rows.reset(); + } + return b; +} + +bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) { + uint32_t Offset = 0; + if (!Header.parse(IndexData, &Offset)) + return false; + + if (!IndexData.isValidOffsetForDataOfSize( + Offset, Header.NumBuckets * (8 + 4) + + (2 * Header.NumUnits + 1) * 4 * Header.NumColumns)) + return false; + + Rows = llvm::make_unique<Entry[]>(Header.NumBuckets); + auto Contribs = + llvm::make_unique<Entry::SectionContribution *[]>(Header.NumUnits); + ColumnKinds = llvm::make_unique<DWARFSectionKind[]>(Header.NumColumns); + + // Read Hash Table of Signatures + for (unsigned i = 0; i != Header.NumBuckets; ++i) + Rows[i].Signature = IndexData.getU64(&Offset); + + // Read Parallel Table of Indexes + for (unsigned i = 0; i != Header.NumBuckets; ++i) { + auto Index = IndexData.getU32(&Offset); + if (!Index) + continue; + Rows[i].Index = this; + Rows[i].Contributions = + llvm::make_unique<Entry::SectionContribution[]>(Header.NumColumns); + Contribs[Index - 1] = Rows[i].Contributions.get(); + } + + // Read the Column Headers + for (unsigned i = 0; i != Header.NumColumns; ++i) { + ColumnKinds[i] = static_cast<DWARFSectionKind>(IndexData.getU32(&Offset)); + if (ColumnKinds[i] == InfoColumnKind) { + if (InfoColumn != -1) + return false; + InfoColumn = i; + } + } + + if (InfoColumn == -1) + return false; + + // Read Table of Section Offsets + for (unsigned i = 0; i != Header.NumUnits; ++i) { + auto *Contrib = Contribs[i]; + for (unsigned i = 0; i != Header.NumColumns; ++i) + Contrib[i].Offset = IndexData.getU32(&Offset); + } + + // Read Table of Section Sizes + for (unsigned i = 0; i != Header.NumUnits; ++i) { + auto *Contrib = Contribs[i]; + for (unsigned i = 0; i != Header.NumColumns; ++i) + Contrib[i].Length = IndexData.getU32(&Offset); + } + + return true; +} + +StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) { +#define CASE(DS) \ + case DW_SECT_##DS: \ + return #DS; + switch (DS) { + CASE(INFO); + CASE(TYPES); + CASE(ABBREV); + CASE(LINE); + CASE(LOC); + CASE(STR_OFFSETS); + CASE(MACINFO); + CASE(MACRO); + } + llvm_unreachable("unknown DWARFSectionKind"); +} + +void DWARFUnitIndex::dump(raw_ostream &OS) const { + if (!Header.NumBuckets) + return; + + Header.dump(OS); + OS << "Index Signature "; + for (unsigned i = 0; i != Header.NumColumns; ++i) + OS << ' ' << left_justify(getColumnHeader(ColumnKinds[i]), 24); + OS << "\n----- ------------------"; + for (unsigned i = 0; i != Header.NumColumns; ++i) + OS << " ------------------------"; + OS << '\n'; + for (unsigned i = 0; i != Header.NumBuckets; ++i) { + auto &Row = Rows[i]; + if (auto *Contribs = Row.Contributions.get()) { + OS << format("%5u 0x%016" PRIx64 " ", i + 1, Row.Signature); + for (unsigned i = 0; i != Header.NumColumns; ++i) { + auto &Contrib = Contribs[i]; + OS << format("[0x%08x, 0x%08x) ", Contrib.Offset, + Contrib.Offset + Contrib.Length); + } + OS << '\n'; + } + } +} + +const DWARFUnitIndex::Entry::SectionContribution * +DWARFUnitIndex::Entry::getOffset(DWARFSectionKind Sec) const { + uint32_t i = 0; + for (; i != Index->Header.NumColumns; ++i) + if (Index->ColumnKinds[i] == Sec) + return &Contributions[i]; + return nullptr; +} +const DWARFUnitIndex::Entry::SectionContribution * +DWARFUnitIndex::Entry::getOffset() const { + return &Contributions[Index->InfoColumn]; +} + +const DWARFUnitIndex::Entry * +DWARFUnitIndex::getFromOffset(uint32_t Offset) const { + for (uint32_t i = 0; i != Header.NumBuckets; ++i) + if (const auto &Contribs = Rows[i].Contributions) + if (Contribs[InfoColumn].Offset == Offset) + return &Rows[i]; + return nullptr; +} +} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp index a6b4c65..4f561d0 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp @@ -27,6 +27,7 @@ WithColor::WithColor(llvm::raw_ostream &OS, enum HighlightColor Type) : OS(OS) { case Tag: OS.changeColor(llvm::raw_ostream::BLUE); break; case Attribute: OS.changeColor(llvm::raw_ostream::CYAN); break; case Enumerator: OS.changeColor(llvm::raw_ostream::MAGENTA); break; + case Macro: OS.changeColor(llvm::raw_ostream::RED); break; } } } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h index 946a313..16e6835 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h +++ b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h @@ -17,7 +17,7 @@ namespace dwarf { namespace syntax { // Symbolic names for various syntax elements. -enum HighlightColor { Address, String, Tag, Attribute, Enumerator }; +enum HighlightColor { Address, String, Tag, Attribute, Enumerator, Macro }; /// An RAII object that temporarily switches an output stream to a /// specific color. diff --git a/contrib/llvm/lib/DebugInfo/PDB/PDB.cpp b/contrib/llvm/lib/DebugInfo/PDB/PDB.cpp index 13201bb..613407e 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/PDB.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/PDB.cpp @@ -31,7 +31,7 @@ PDB_ErrorCode llvm::loadDataForPDB(PDB_ReaderType Type, StringRef Path, PDB_ErrorCode llvm::loadDataForEXE(PDB_ReaderType Type, StringRef Path, std::unique_ptr<IPDBSession> &Session) { -// Create the correct concrete instance type based on the value of Type. + // Create the correct concrete instance type based on the value of Type. #if HAVE_DIA_SDK return DIASession::createFromExe(Path, Session); #endif diff --git a/contrib/llvm/lib/DebugInfo/PDB/PDBContext.cpp b/contrib/llvm/lib/DebugInfo/PDB/PDBContext.cpp index 83f27c7..ca2ae66 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/PDBContext.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/PDBContext.cpp @@ -21,24 +21,11 @@ using namespace llvm; using namespace llvm::object; PDBContext::PDBContext(const COFFObjectFile &Object, - std::unique_ptr<IPDBSession> PDBSession, - bool RelativeAddress) + std::unique_ptr<IPDBSession> PDBSession) : DIContext(CK_PDB), Session(std::move(PDBSession)) { - if (!RelativeAddress) { - uint64_t ImageBase = 0; - if (Object.is64()) { - const pe32plus_header *Header = nullptr; - Object.getPE32PlusHeader(Header); - if (Header) - ImageBase = Header->ImageBase; - } else { - const pe32_header *Header = nullptr; - Object.getPE32Header(Header); - if (Header) - ImageBase = static_cast<uint64_t>(Header->ImageBase); - } - Session->setLoadAddress(ImageBase); - } + ErrorOr<uint64_t> ImageBase = Object.getImageBase(); + if (ImageBase) + Session->setLoadAddress(ImageBase.get()); } void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType) {} diff --git a/contrib/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/contrib/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp new file mode 100644 index 0000000..c6bfbc0 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp @@ -0,0 +1,69 @@ +//===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DIPrinter class, which is responsible for printing +// structures defined in DebugInfo/DIContext.h +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/Symbolize/DIPrinter.h" + +#include "llvm/DebugInfo/DIContext.h" + +namespace llvm { +namespace symbolize { + +// By default, DILineInfo contains "<invalid>" for function/filename it +// cannot fetch. We replace it to "??" to make our output closer to addr2line. +static const char kDILineInfoBadString[] = "<invalid>"; +static const char kBadString[] = "??"; + +void DIPrinter::printName(const DILineInfo &Info, bool Inlined) { + if (PrintFunctionNames) { + std::string FunctionName = Info.FunctionName; + if (FunctionName == kDILineInfoBadString) + FunctionName = kBadString; + + StringRef Delimiter = (PrintPretty == true) ? " at " : "\n"; + StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : ""; + OS << Prefix << FunctionName << Delimiter; + } + std::string Filename = Info.FileName; + if (Filename == kDILineInfoBadString) + Filename = kBadString; + OS << Filename << ":" << Info.Line << ":" << Info.Column << "\n"; +} + +DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) { + printName(Info, false); + return *this; +} + +DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) { + uint32_t FramesNum = Info.getNumberOfFrames(); + if (FramesNum == 0) { + printName(DILineInfo(), false); + return *this; + } + for (uint32_t i = 0; i < FramesNum; i++) + printName(Info.getFrame(i), i > 0); + return *this; +} + +DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) { + std::string Name = Global.Name; + if (Name == kDILineInfoBadString) + Name = kBadString; + OS << Name << "\n"; + OS << Global.Start << " " << Global.Size << "\n"; + return *this; +} + +} +} diff --git a/contrib/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/contrib/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp new file mode 100644 index 0000000..e314624 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp @@ -0,0 +1,254 @@ +//===-- SymbolizableObjectFile.cpp ----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of SymbolizableObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "SymbolizableObjectFile.h" +#include "llvm/Object/SymbolSize.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" + +namespace llvm { +namespace symbolize { + +using namespace object; + +static DILineInfoSpecifier +getDILineInfoSpecifier(FunctionNameKind FNKind) { + return DILineInfoSpecifier( + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FNKind); +} + +ErrorOr<std::unique_ptr<SymbolizableObjectFile>> +SymbolizableObjectFile::create(object::ObjectFile *Obj, + std::unique_ptr<DIContext> DICtx) { + std::unique_ptr<SymbolizableObjectFile> res( + new SymbolizableObjectFile(Obj, std::move(DICtx))); + std::unique_ptr<DataExtractor> OpdExtractor; + uint64_t OpdAddress = 0; + // Find the .opd (function descriptor) section if any, for big-endian + // PowerPC64 ELF. + if (Obj->getArch() == Triple::ppc64) { + for (section_iterator Section : Obj->sections()) { + StringRef Name; + StringRef Data; + if (auto EC = Section->getName(Name)) + return EC; + if (Name == ".opd") { + if (auto EC = Section->getContents(Data)) + return EC; + OpdExtractor.reset(new DataExtractor(Data, Obj->isLittleEndian(), + Obj->getBytesInAddress())); + OpdAddress = Section->getAddress(); + break; + } + } + } + std::vector<std::pair<SymbolRef, uint64_t>> Symbols = + computeSymbolSizes(*Obj); + for (auto &P : Symbols) + res->addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress); + + // If this is a COFF object and we didn't find any symbols, try the export + // table. + if (Symbols.empty()) { + if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj)) + if (auto EC = res->addCoffExportSymbols(CoffObj)) + return EC; + } + return std::move(res); +} + +SymbolizableObjectFile::SymbolizableObjectFile(ObjectFile *Obj, + std::unique_ptr<DIContext> DICtx) + : Module(Obj), DebugInfoContext(std::move(DICtx)) {} + +namespace { +struct OffsetNamePair { + uint32_t Offset; + StringRef Name; + bool operator<(const OffsetNamePair &R) const { + return Offset < R.Offset; + } +}; +} + +std::error_code SymbolizableObjectFile::addCoffExportSymbols( + const COFFObjectFile *CoffObj) { + // Get all export names and offsets. + std::vector<OffsetNamePair> ExportSyms; + for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) { + StringRef Name; + uint32_t Offset; + if (auto EC = Ref.getSymbolName(Name)) + return EC; + if (auto EC = Ref.getExportRVA(Offset)) + return EC; + ExportSyms.push_back(OffsetNamePair{Offset, Name}); + } + if (ExportSyms.empty()) + return std::error_code(); + + // Sort by ascending offset. + array_pod_sort(ExportSyms.begin(), ExportSyms.end()); + + // Approximate the symbol sizes by assuming they run to the next symbol. + // FIXME: This assumes all exports are functions. + uint64_t ImageBase = CoffObj->getImageBase(); + for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) { + OffsetNamePair &Export = *I; + // FIXME: The last export has a one byte size now. + uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1; + uint64_t SymbolStart = ImageBase + Export.Offset; + uint64_t SymbolSize = NextOffset - Export.Offset; + SymbolDesc SD = {SymbolStart, SymbolSize}; + Functions.insert(std::make_pair(SD, Export.Name)); + } + return std::error_code(); +} + +std::error_code SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol, + uint64_t SymbolSize, + DataExtractor *OpdExtractor, + uint64_t OpdAddress) { + SymbolRef::Type SymbolType = Symbol.getType(); + if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data) + return std::error_code(); + ErrorOr<uint64_t> SymbolAddressOrErr = Symbol.getAddress(); + if (auto EC = SymbolAddressOrErr.getError()) + return EC; + uint64_t SymbolAddress = *SymbolAddressOrErr; + if (OpdExtractor) { + // For big-endian PowerPC64 ELF, symbols in the .opd section refer to + // function descriptors. The first word of the descriptor is a pointer to + // the function's code. + // For the purposes of symbolization, pretend the symbol's address is that + // of the function's code, not the descriptor. + uint64_t OpdOffset = SymbolAddress - OpdAddress; + uint32_t OpdOffset32 = OpdOffset; + if (OpdOffset == OpdOffset32 && + OpdExtractor->isValidOffsetForAddress(OpdOffset32)) + SymbolAddress = OpdExtractor->getAddress(&OpdOffset32); + } + ErrorOr<StringRef> SymbolNameOrErr = Symbol.getName(); + if (auto EC = SymbolNameOrErr.getError()) + return EC; + StringRef SymbolName = *SymbolNameOrErr; + // Mach-O symbol table names have leading underscore, skip it. + if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_') + SymbolName = SymbolName.drop_front(); + // FIXME: If a function has alias, there are two entries in symbol table + // with same address size. Make sure we choose the correct one. + auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; + SymbolDesc SD = { SymbolAddress, SymbolSize }; + M.insert(std::make_pair(SD, SymbolName)); + return std::error_code(); +} + +// Return true if this is a 32-bit x86 PE COFF module. +bool SymbolizableObjectFile::isWin32Module() const { + auto *CoffObject = dyn_cast<COFFObjectFile>(Module); + return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386; +} + +uint64_t SymbolizableObjectFile::getModulePreferredBase() const { + if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module)) + return CoffObject->getImageBase(); + return 0; +} + +bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type, + uint64_t Address, + std::string &Name, + uint64_t &Addr, + uint64_t &Size) const { + const auto &SymbolMap = Type == SymbolRef::ST_Function ? Functions : Objects; + if (SymbolMap.empty()) + return false; + SymbolDesc SD = { Address, Address }; + auto SymbolIterator = SymbolMap.upper_bound(SD); + if (SymbolIterator == SymbolMap.begin()) + return false; + --SymbolIterator; + if (SymbolIterator->first.Size != 0 && + SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address) + return false; + Name = SymbolIterator->second.str(); + Addr = SymbolIterator->first.Addr; + Size = SymbolIterator->first.Size; + return true; +} + +bool SymbolizableObjectFile::shouldOverrideWithSymbolTable( + FunctionNameKind FNKind, bool UseSymbolTable) const { + // When DWARF is used with -gline-tables-only / -gmlt, the symbol table gives + // better answers for linkage names than the DIContext. Otherwise, we are + // probably using PEs and PDBs, and we shouldn't do the override. PE files + // generally only contain the names of exported symbols. + return FNKind == FunctionNameKind::LinkageName && UseSymbolTable && + isa<DWARFContext>(DebugInfoContext.get()); +} + +DILineInfo SymbolizableObjectFile::symbolizeCode(uint64_t ModuleOffset, + FunctionNameKind FNKind, + bool UseSymbolTable) const { + DILineInfo LineInfo; + if (DebugInfoContext) { + LineInfo = DebugInfoContext->getLineInfoForAddress( + ModuleOffset, getDILineInfoSpecifier(FNKind)); + } + // Override function name from symbol table if necessary. + if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) { + std::string FunctionName; + uint64_t Start, Size; + if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, + FunctionName, Start, Size)) { + LineInfo.FunctionName = FunctionName; + } + } + return LineInfo; +} + +DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode( + uint64_t ModuleOffset, FunctionNameKind FNKind, bool UseSymbolTable) const { + DIInliningInfo InlinedContext; + + if (DebugInfoContext) + InlinedContext = DebugInfoContext->getInliningInfoForAddress( + ModuleOffset, getDILineInfoSpecifier(FNKind)); + // Make sure there is at least one frame in context. + if (InlinedContext.getNumberOfFrames() == 0) + InlinedContext.addFrame(DILineInfo()); + + // Override the function name in lower frame with name from symbol table. + if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) { + std::string FunctionName; + uint64_t Start, Size; + if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, + FunctionName, Start, Size)) { + InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1) + ->FunctionName = FunctionName; + } + } + + return InlinedContext; +} + +DIGlobal SymbolizableObjectFile::symbolizeData(uint64_t ModuleOffset) const { + DIGlobal Res; + getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Res.Name, Res.Start, + Res.Size); + return Res; +} + +} // namespace symbolize +} // namespace llvm + diff --git a/contrib/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h b/contrib/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h new file mode 100644 index 0000000..8583b6a --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h @@ -0,0 +1,82 @@ +//===-- SymbolizableObjectFile.h -------------------------------- C++ -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the SymbolizableObjectFile class. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H +#define LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H + +#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" +#include <map> + +namespace llvm { +class DataExtractor; +} + +namespace llvm { +namespace symbolize { + +class SymbolizableObjectFile : public SymbolizableModule { +public: + static ErrorOr<std::unique_ptr<SymbolizableObjectFile>> + create(object::ObjectFile *Obj, std::unique_ptr<DIContext> DICtx); + + DILineInfo symbolizeCode(uint64_t ModuleOffset, FunctionNameKind FNKind, + bool UseSymbolTable) const override; + DIInliningInfo symbolizeInlinedCode(uint64_t ModuleOffset, + FunctionNameKind FNKind, + bool UseSymbolTable) const override; + DIGlobal symbolizeData(uint64_t ModuleOffset) const override; + + // Return true if this is a 32-bit x86 PE COFF module. + bool isWin32Module() const override; + + // Returns the preferred base of the module, i.e. where the loader would place + // it in memory assuming there were no conflicts. + uint64_t getModulePreferredBase() const override; + +private: + bool shouldOverrideWithSymbolTable(FunctionNameKind FNKind, + bool UseSymbolTable) const; + + bool getNameFromSymbolTable(object::SymbolRef::Type Type, uint64_t Address, + std::string &Name, uint64_t &Addr, + uint64_t &Size) const; + // For big-endian PowerPC64 ELF, OpdAddress is the address of the .opd + // (function descriptor) section and OpdExtractor refers to its contents. + std::error_code addSymbol(const object::SymbolRef &Symbol, + uint64_t SymbolSize, + DataExtractor *OpdExtractor = nullptr, + uint64_t OpdAddress = 0); + std::error_code addCoffExportSymbols(const object::COFFObjectFile *CoffObj); + + object::ObjectFile *Module; + std::unique_ptr<DIContext> DebugInfoContext; + + struct SymbolDesc { + uint64_t Addr; + // If size is 0, assume that symbol occupies the whole memory range up to + // the following symbol. + uint64_t Size; + friend bool operator<(const SymbolDesc &s1, const SymbolDesc &s2) { + return s1.Addr < s2.Addr; + } + }; + std::map<SymbolDesc, StringRef> Functions; + std::map<SymbolDesc, StringRef> Objects; + + SymbolizableObjectFile(object::ObjectFile *Obj, + std::unique_ptr<DIContext> DICtx); +}; + +} // namespace symbolize +} // namespace llvm + +#endif // LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H diff --git a/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp new file mode 100644 index 0000000..3da1963 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -0,0 +1,456 @@ +//===-- LLVMSymbolize.cpp -------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation for LLVM symbolization library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/Symbolize/Symbolize.h" + +#include "SymbolizableObjectFile.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Config/config.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/DebugInfo/PDB/PDBContext.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include <stdlib.h> + +#if defined(_MSC_VER) +#include <Windows.h> +#include <DbgHelp.h> +#pragma comment(lib, "dbghelp.lib") + +// Windows.h conflicts with our COFF header definitions. +#ifdef IMAGE_FILE_MACHINE_I386 +#undef IMAGE_FILE_MACHINE_I386 +#endif +#endif + +namespace llvm { +namespace symbolize { + +ErrorOr<DILineInfo> LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, + uint64_t ModuleOffset) { + auto InfoOrErr = getOrCreateModuleInfo(ModuleName); + if (auto EC = InfoOrErr.getError()) + return EC; + SymbolizableModule *Info = InfoOrErr.get(); + + // If the user is giving us relative addresses, add the preferred base of the + // object to the offset before we do the query. It's what DIContext expects. + if (Opts.RelativeAddresses) + ModuleOffset += Info->getModulePreferredBase(); + + DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts.PrintFunctions, + Opts.UseSymbolTable); + if (Opts.Demangle) + LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info); + return LineInfo; +} + +ErrorOr<DIInliningInfo> +LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName, + uint64_t ModuleOffset) { + auto InfoOrErr = getOrCreateModuleInfo(ModuleName); + if (auto EC = InfoOrErr.getError()) + return EC; + SymbolizableModule *Info = InfoOrErr.get(); + + // If the user is giving us relative addresses, add the preferred base of the + // object to the offset before we do the query. It's what DIContext expects. + if (Opts.RelativeAddresses) + ModuleOffset += Info->getModulePreferredBase(); + + DIInliningInfo InlinedContext = Info->symbolizeInlinedCode( + ModuleOffset, Opts.PrintFunctions, Opts.UseSymbolTable); + if (Opts.Demangle) { + for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { + auto *Frame = InlinedContext.getMutableFrame(i); + Frame->FunctionName = DemangleName(Frame->FunctionName, Info); + } + } + return InlinedContext; +} + +ErrorOr<DIGlobal> LLVMSymbolizer::symbolizeData(const std::string &ModuleName, + uint64_t ModuleOffset) { + auto InfoOrErr = getOrCreateModuleInfo(ModuleName); + if (auto EC = InfoOrErr.getError()) + return EC; + SymbolizableModule *Info = InfoOrErr.get(); + + // If the user is giving us relative addresses, add the preferred base of + // the object to the offset before we do the query. It's what DIContext + // expects. + if (Opts.RelativeAddresses) + ModuleOffset += Info->getModulePreferredBase(); + + DIGlobal Global = Info->symbolizeData(ModuleOffset); + if (Opts.Demangle) + Global.Name = DemangleName(Global.Name, Info); + return Global; +} + +void LLVMSymbolizer::flush() { + ObjectForUBPathAndArch.clear(); + BinaryForPath.clear(); + ObjectPairForPathArch.clear(); + Modules.clear(); +} + +// For Path="/path/to/foo" and Basename="foo" assume that debug info is in +// /path/to/foo.dSYM/Contents/Resources/DWARF/foo. +// For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in +// /path/to/bar.dSYM/Contents/Resources/DWARF/foo. +static +std::string getDarwinDWARFResourceForPath( + const std::string &Path, const std::string &Basename) { + SmallString<16> ResourceName = StringRef(Path); + if (sys::path::extension(Path) != ".dSYM") { + ResourceName += ".dSYM"; + } + sys::path::append(ResourceName, "Contents", "Resources", "DWARF"); + sys::path::append(ResourceName, Basename); + return ResourceName.str(); +} + +static bool checkFileCRC(StringRef Path, uint32_t CRCHash) { + ErrorOr<std::unique_ptr<MemoryBuffer>> MB = + MemoryBuffer::getFileOrSTDIN(Path); + if (!MB) + return false; + return !zlib::isAvailable() || CRCHash == zlib::crc32(MB.get()->getBuffer()); +} + +static bool findDebugBinary(const std::string &OrigPath, + const std::string &DebuglinkName, uint32_t CRCHash, + std::string &Result) { + std::string OrigRealPath = OrigPath; +#if defined(HAVE_REALPATH) + if (char *RP = realpath(OrigPath.c_str(), nullptr)) { + OrigRealPath = RP; + free(RP); + } +#endif + SmallString<16> OrigDir(OrigRealPath); + llvm::sys::path::remove_filename(OrigDir); + SmallString<16> DebugPath = OrigDir; + // Try /path/to/original_binary/debuglink_name + llvm::sys::path::append(DebugPath, DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = DebugPath.str(); + return true; + } + // Try /path/to/original_binary/.debug/debuglink_name + DebugPath = OrigRealPath; + llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = DebugPath.str(); + return true; + } + // Try /usr/lib/debug/path/to/original_binary/debuglink_name + DebugPath = "/usr/lib/debug"; + llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), + DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = DebugPath.str(); + return true; + } + return false; +} + +static bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName, + uint32_t &CRCHash) { + if (!Obj) + return false; + for (const SectionRef &Section : Obj->sections()) { + StringRef Name; + Section.getName(Name); + Name = Name.substr(Name.find_first_not_of("._")); + if (Name == "gnu_debuglink") { + StringRef Data; + Section.getContents(Data); + DataExtractor DE(Data, Obj->isLittleEndian(), 0); + uint32_t Offset = 0; + if (const char *DebugNameStr = DE.getCStr(&Offset)) { + // 4-byte align the offset. + Offset = (Offset + 3) & ~0x3; + if (DE.isValidOffsetForDataOfSize(Offset, 4)) { + DebugName = DebugNameStr; + CRCHash = DE.getU32(&Offset); + return true; + } + } + break; + } + } + return false; +} + +static +bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj, + const MachOObjectFile *Obj) { + ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid(); + ArrayRef<uint8_t> bin_uuid = Obj->getUuid(); + if (dbg_uuid.empty() || bin_uuid.empty()) + return false; + return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size()); +} + +ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, + const MachOObjectFile *MachExeObj, const std::string &ArchName) { + // On Darwin we may find DWARF in separate object file in + // resource directory. + std::vector<std::string> DsymPaths; + StringRef Filename = sys::path::filename(ExePath); + DsymPaths.push_back(getDarwinDWARFResourceForPath(ExePath, Filename)); + for (const auto &Path : Opts.DsymHints) { + DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename)); + } + for (const auto &Path : DsymPaths) { + auto DbgObjOrErr = getOrCreateObject(Path, ArchName); + if (!DbgObjOrErr) + continue; + ObjectFile *DbgObj = DbgObjOrErr.get(); + const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj); + if (!MachDbgObj) + continue; + if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) + return DbgObj; + } + return nullptr; +} + +ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path, + const ObjectFile *Obj, + const std::string &ArchName) { + std::string DebuglinkName; + uint32_t CRCHash; + std::string DebugBinaryPath; + if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash)) + return nullptr; + if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) + return nullptr; + auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); + if (!DbgObjOrErr) + return nullptr; + return DbgObjOrErr.get(); +} + +ErrorOr<LLVMSymbolizer::ObjectPair> +LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path, + const std::string &ArchName) { + const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName)); + if (I != ObjectPairForPathArch.end()) + return I->second; + + auto ObjOrErr = getOrCreateObject(Path, ArchName); + if (auto EC = ObjOrErr.getError()) { + ObjectPairForPathArch.insert( + std::make_pair(std::make_pair(Path, ArchName), EC)); + return EC; + } + + ObjectFile *Obj = ObjOrErr.get(); + assert(Obj != nullptr); + ObjectFile *DbgObj = nullptr; + + if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj)) + DbgObj = lookUpDsymFile(Path, MachObj, ArchName); + if (!DbgObj) + DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName); + if (!DbgObj) + DbgObj = Obj; + ObjectPair Res = std::make_pair(Obj, DbgObj); + ObjectPairForPathArch.insert( + std::make_pair(std::make_pair(Path, ArchName), Res)); + return Res; +} + +ErrorOr<ObjectFile *> +LLVMSymbolizer::getOrCreateObject(const std::string &Path, + const std::string &ArchName) { + const auto &I = BinaryForPath.find(Path); + Binary *Bin = nullptr; + if (I == BinaryForPath.end()) { + ErrorOr<OwningBinary<Binary>> BinOrErr = createBinary(Path); + if (auto EC = BinOrErr.getError()) { + BinaryForPath.insert(std::make_pair(Path, EC)); + return EC; + } + Bin = BinOrErr->getBinary(); + BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get()))); + } else if (auto EC = I->second.getError()) { + return EC; + } else { + Bin = I->second->getBinary(); + } + + assert(Bin != nullptr); + + if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) { + const auto &I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName)); + if (I != ObjectForUBPathAndArch.end()) { + if (auto EC = I->second.getError()) + return EC; + return I->second->get(); + } + ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = + UB->getObjectForArch(ArchName); + if (auto EC = ObjOrErr.getError()) { + ObjectForUBPathAndArch.insert( + std::make_pair(std::make_pair(Path, ArchName), EC)); + return EC; + } + ObjectFile *Res = ObjOrErr->get(); + ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName), + std::move(ObjOrErr.get()))); + return Res; + } + if (Bin->isObject()) { + return cast<ObjectFile>(Bin); + } + return object_error::arch_not_found; +} + +ErrorOr<SymbolizableModule *> +LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { + const auto &I = Modules.find(ModuleName); + if (I != Modules.end()) { + auto &InfoOrErr = I->second; + if (auto EC = InfoOrErr.getError()) + return EC; + return InfoOrErr->get(); + } + std::string BinaryName = ModuleName; + std::string ArchName = Opts.DefaultArch; + size_t ColonPos = ModuleName.find_last_of(':'); + // Verify that substring after colon form a valid arch name. + if (ColonPos != std::string::npos) { + std::string ArchStr = ModuleName.substr(ColonPos + 1); + if (Triple(ArchStr).getArch() != Triple::UnknownArch) { + BinaryName = ModuleName.substr(0, ColonPos); + ArchName = ArchStr; + } + } + auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName); + if (auto EC = ObjectsOrErr.getError()) { + // Failed to find valid object file. + Modules.insert(std::make_pair(ModuleName, EC)); + return EC; + } + ObjectPair Objects = ObjectsOrErr.get(); + + std::unique_ptr<DIContext> Context; + if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) { + // If this is a COFF object, assume it contains PDB debug information. If + // we don't find any we will fall back to the DWARF case. + std::unique_ptr<IPDBSession> Session; + PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA, + Objects.first->getFileName(), Session); + if (Error == PDB_ErrorCode::Success) { + Context.reset(new PDBContext(*CoffObject, std::move(Session))); + } + } + if (!Context) + Context.reset(new DWARFContextInMemory(*Objects.second)); + assert(Context); + auto InfoOrErr = + SymbolizableObjectFile::create(Objects.first, std::move(Context)); + auto InsertResult = + Modules.insert(std::make_pair(ModuleName, std::move(InfoOrErr))); + assert(InsertResult.second); + if (auto EC = InsertResult.first->second.getError()) + return EC; + return InsertResult.first->second->get(); +} + +// Undo these various manglings for Win32 extern "C" functions: +// cdecl - _foo +// stdcall - _foo@12 +// fastcall - @foo@12 +// vectorcall - foo@@12 +// These are all different linkage names for 'foo'. +static StringRef demanglePE32ExternCFunc(StringRef SymbolName) { + // Remove any '_' or '@' prefix. + char Front = SymbolName.empty() ? '\0' : SymbolName[0]; + if (Front == '_' || Front == '@') + SymbolName = SymbolName.drop_front(); + + // Remove any '@[0-9]+' suffix. + if (Front != '?') { + size_t AtPos = SymbolName.rfind('@'); + if (AtPos != StringRef::npos && + std::all_of(SymbolName.begin() + AtPos + 1, SymbolName.end(), + [](char C) { return C >= '0' && C <= '9'; })) { + SymbolName = SymbolName.substr(0, AtPos); + } + } + + // Remove any ending '@' for vectorcall. + if (SymbolName.endswith("@")) + SymbolName = SymbolName.drop_back(); + + return SymbolName; +} + +#if !defined(_MSC_VER) +// Assume that __cxa_demangle is provided by libcxxabi (except for Windows). +extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, + size_t *length, int *status); +#endif + +std::string LLVMSymbolizer::DemangleName(const std::string &Name, + const SymbolizableModule *ModInfo) { +#if !defined(_MSC_VER) + // We can spoil names of symbols with C linkage, so use an heuristic + // approach to check if the name should be demangled. + if (Name.substr(0, 2) == "_Z") { + int status = 0; + char *DemangledName = __cxa_demangle(Name.c_str(), nullptr, nullptr, &status); + if (status != 0) + return Name; + std::string Result = DemangledName; + free(DemangledName); + return Result; + } +#else + if (!Name.empty() && Name.front() == '?') { + // Only do MSVC C++ demangling on symbols starting with '?'. + char DemangledName[1024] = {0}; + DWORD result = ::UnDecorateSymbolName( + Name.c_str(), DemangledName, 1023, + UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected + UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc + UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications + UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers + UNDNAME_NO_MS_KEYWORDS | // Strip all MS extension keywords + UNDNAME_NO_FUNCTION_RETURNS); // Strip function return types + return (result == 0) ? Name : std::string(DemangledName); + } +#endif + if (ModInfo && ModInfo->isWin32Module()) + return std::string(demanglePE32ExternCFunc(Name)); + return Name; +} + +} // namespace symbolize +} // namespace llvm |