forked from OSchip/llvm-project
Improve DWARFDebugFrame::parse to also handle __eh_frame.
LLVM MC has single methods which can handle the output of EH frame and DWARF CIE's and FDE's. This code improves DWARFDebugFrame::parse to do the same for parsing. This also allows llvm-objdump to support the --dwarf=frames option which objdump supports. This option dumps the .eh_frame section using the new code in DWARFDebugFrame::parse. http://reviews.llvm.org/D15535 Reviewed by Rafael Espindola. llvm-svn: 256008
This commit is contained in:
parent
a45c0e0d4e
commit
6c97f4c7d7
|
@ -140,7 +140,8 @@ public:
|
|||
DIContext(DIContextKind K) : Kind(K) {}
|
||||
virtual ~DIContext() {}
|
||||
|
||||
virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) = 0;
|
||||
virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
||||
bool DumpEH = false) = 0;
|
||||
|
||||
virtual DILineInfo getLineInfoForAddress(uint64_t Address,
|
||||
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
|
||||
|
|
|
@ -48,6 +48,7 @@ class DWARFContext : public DIContext {
|
|||
std::unique_ptr<DWARFDebugAranges> Aranges;
|
||||
std::unique_ptr<DWARFDebugLine> Line;
|
||||
std::unique_ptr<DWARFDebugFrame> DebugFrame;
|
||||
std::unique_ptr<DWARFDebugFrame> EHFrame;
|
||||
std::unique_ptr<DWARFDebugMacro> Macro;
|
||||
|
||||
DWARFUnitSection<DWARFCompileUnit> DWOCUs;
|
||||
|
@ -81,7 +82,8 @@ public:
|
|||
return DICtx->getKind() == CK_DWARF;
|
||||
}
|
||||
|
||||
void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override;
|
||||
void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
||||
bool DumpEH = false) override;
|
||||
|
||||
typedef DWARFUnitSection<DWARFCompileUnit>::iterator_range cu_iterator_range;
|
||||
typedef DWARFUnitSection<DWARFTypeUnit>::iterator_range tu_iterator_range;
|
||||
|
@ -168,6 +170,9 @@ public:
|
|||
/// Get a pointer to the parsed frame information object.
|
||||
const DWARFDebugFrame *getDebugFrame();
|
||||
|
||||
/// Get a pointer to the parsed eh frame information object.
|
||||
const DWARFDebugFrame *getEHFrame();
|
||||
|
||||
/// Get a pointer to the parsed DebugMacro object.
|
||||
const DWARFDebugMacro *getDebugMacro();
|
||||
|
||||
|
@ -191,6 +196,7 @@ public:
|
|||
virtual const DWARFSection &getLocSection() = 0;
|
||||
virtual StringRef getARangeSection() = 0;
|
||||
virtual StringRef getDebugFrameSection() = 0;
|
||||
virtual StringRef getEHFrameSection() = 0;
|
||||
virtual const DWARFSection &getLineSection() = 0;
|
||||
virtual StringRef getStringSection() = 0;
|
||||
virtual StringRef getRangeSection() = 0;
|
||||
|
@ -242,6 +248,7 @@ class DWARFContextInMemory : public DWARFContext {
|
|||
DWARFSection LocSection;
|
||||
StringRef ARangeSection;
|
||||
StringRef DebugFrameSection;
|
||||
StringRef EHFrameSection;
|
||||
DWARFSection LineSection;
|
||||
StringRef StringSection;
|
||||
StringRef RangeSection;
|
||||
|
@ -281,6 +288,7 @@ public:
|
|||
const DWARFSection &getLocSection() override { return LocSection; }
|
||||
StringRef getARangeSection() override { return ARangeSection; }
|
||||
StringRef getDebugFrameSection() override { return DebugFrameSection; }
|
||||
StringRef getEHFrameSection() override { return EHFrameSection; }
|
||||
const DWARFSection &getLineSection() override { return LineSection; }
|
||||
StringRef getStringSection() override { return StringSection; }
|
||||
StringRef getRangeSection() override { return RangeSection; }
|
||||
|
|
|
@ -19,11 +19,13 @@ namespace llvm {
|
|||
|
||||
class FrameEntry;
|
||||
|
||||
/// \brief A parsed .debug_frame section
|
||||
/// \brief A parsed .debug_frame or .eh_frame section
|
||||
///
|
||||
class DWARFDebugFrame {
|
||||
// True if this is parsing an eh_frame section.
|
||||
bool IsEH;
|
||||
public:
|
||||
DWARFDebugFrame();
|
||||
DWARFDebugFrame(bool IsEH);
|
||||
~DWARFDebugFrame();
|
||||
|
||||
/// \brief Dump the section data into the given stream.
|
||||
|
|
|
@ -38,7 +38,8 @@ public:
|
|||
return DICtx->getKind() == CK_PDB;
|
||||
}
|
||||
|
||||
void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override;
|
||||
void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
||||
bool DumpEH = false) override;
|
||||
|
||||
DILineInfo getLineInfoForAddress(
|
||||
uint64_t Address,
|
||||
|
|
|
@ -72,7 +72,7 @@ static void dumpAccelSection(raw_ostream &OS, StringRef Name,
|
|||
Accel.dump(OS);
|
||||
}
|
||||
|
||||
void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
|
||||
void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) {
|
||||
if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
|
||||
OS << ".debug_abbrev contents:\n";
|
||||
getDebugAbbrev()->dump(OS);
|
||||
|
@ -125,6 +125,10 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
|
|||
if (DumpType == DIDT_All || DumpType == DIDT_Frames) {
|
||||
OS << "\n.debug_frame contents:\n";
|
||||
getDebugFrame()->dump(OS);
|
||||
if (DumpEH) {
|
||||
OS << "\n.eh_frame contents:\n";
|
||||
getEHFrame()->dump(OS);
|
||||
}
|
||||
}
|
||||
|
||||
if (DumpType == DIDT_All || DumpType == DIDT_Macro) {
|
||||
|
@ -355,7 +359,18 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
|
|||
// http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
|
||||
DataExtractor debugFrameData(getDebugFrameSection(), isLittleEndian(),
|
||||
getAddressSize());
|
||||
DebugFrame.reset(new DWARFDebugFrame());
|
||||
DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */));
|
||||
DebugFrame->parse(debugFrameData);
|
||||
return DebugFrame.get();
|
||||
}
|
||||
|
||||
const DWARFDebugFrame *DWARFContext::getEHFrame() {
|
||||
if (EHFrame)
|
||||
return EHFrame.get();
|
||||
|
||||
DataExtractor debugFrameData(getEHFrameSection(), isLittleEndian(),
|
||||
getAddressSize());
|
||||
DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */));
|
||||
DebugFrame->parse(debugFrameData);
|
||||
return DebugFrame.get();
|
||||
}
|
||||
|
@ -641,6 +656,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj,
|
|||
.Case("debug_line", &LineSection.Data)
|
||||
.Case("debug_aranges", &ARangeSection)
|
||||
.Case("debug_frame", &DebugFrameSection)
|
||||
.Case("eh_frame", &EHFrameSection)
|
||||
.Case("debug_str", &StringSection)
|
||||
.Case("debug_ranges", &RangeSection)
|
||||
.Case("debug_macinfo", &MacinfoSection)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
@ -191,19 +192,31 @@ public:
|
|||
CIE(uint64_t Offset, uint64_t Length, uint8_t Version,
|
||||
SmallString<8> Augmentation, uint8_t AddressSize,
|
||||
uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
|
||||
int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister)
|
||||
int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
|
||||
SmallString<8> AugmentationData, Optional<uint32_t> FDEPointerEncoding,
|
||||
Optional<uint32_t> LSDAPointerEncoding)
|
||||
: FrameEntry(FK_CIE, Offset, Length), Version(Version),
|
||||
Augmentation(std::move(Augmentation)),
|
||||
AddressSize(AddressSize),
|
||||
SegmentDescriptorSize(SegmentDescriptorSize),
|
||||
CodeAlignmentFactor(CodeAlignmentFactor),
|
||||
DataAlignmentFactor(DataAlignmentFactor),
|
||||
ReturnAddressRegister(ReturnAddressRegister) {}
|
||||
ReturnAddressRegister(ReturnAddressRegister),
|
||||
AugmentationData(AugmentationData),
|
||||
FDEPointerEncoding(FDEPointerEncoding),
|
||||
LSDAPointerEncoding(LSDAPointerEncoding) { }
|
||||
|
||||
~CIE() override {}
|
||||
|
||||
StringRef getAugmentationString() const { return Augmentation; }
|
||||
uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
|
||||
int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
|
||||
Optional<uint32_t> getFDEPointerEncoding() const {
|
||||
return FDEPointerEncoding;
|
||||
}
|
||||
Optional<uint32_t> getLSDAPointerEncoding() const {
|
||||
return LSDAPointerEncoding;
|
||||
}
|
||||
|
||||
void dumpHeader(raw_ostream &OS) const override {
|
||||
OS << format("%08x %08x %08x CIE",
|
||||
|
@ -223,6 +236,8 @@ public:
|
|||
(int32_t)DataAlignmentFactor);
|
||||
OS << format(" Return address column: %d\n",
|
||||
(int32_t)ReturnAddressRegister);
|
||||
if (!AugmentationData.empty())
|
||||
OS << " Augmentation data: " << AugmentationData << "\n";
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
|
@ -239,6 +254,11 @@ private:
|
|||
uint64_t CodeAlignmentFactor;
|
||||
int64_t DataAlignmentFactor;
|
||||
uint64_t ReturnAddressRegister;
|
||||
|
||||
// The following are used when the CIE represents an EH frame entry.
|
||||
SmallString<8> AugmentationData;
|
||||
Optional<uint32_t> FDEPointerEncoding;
|
||||
Optional<uint32_t> LSDAPointerEncoding;
|
||||
};
|
||||
|
||||
|
||||
|
@ -423,7 +443,7 @@ void FrameEntry::dumpInstructions(raw_ostream &OS) const {
|
|||
}
|
||||
}
|
||||
|
||||
DWARFDebugFrame::DWARFDebugFrame() {
|
||||
DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) {
|
||||
}
|
||||
|
||||
DWARFDebugFrame::~DWARFDebugFrame() {
|
||||
|
@ -439,6 +459,39 @@ static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
|
|||
errs() << "\n";
|
||||
}
|
||||
|
||||
static unsigned getSizeForEncoding(const DataExtractor &Data,
|
||||
unsigned symbolEncoding) {
|
||||
unsigned format = symbolEncoding & 0x0f;
|
||||
switch (format) {
|
||||
default: llvm_unreachable("Unknown Encoding");
|
||||
case dwarf::DW_EH_PE_absptr:
|
||||
case dwarf::DW_EH_PE_signed:
|
||||
return Data.getAddressSize();
|
||||
case dwarf::DW_EH_PE_udata2:
|
||||
case dwarf::DW_EH_PE_sdata2:
|
||||
return 2;
|
||||
case dwarf::DW_EH_PE_udata4:
|
||||
case dwarf::DW_EH_PE_sdata4:
|
||||
return 4;
|
||||
case dwarf::DW_EH_PE_udata8:
|
||||
case dwarf::DW_EH_PE_sdata8:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset,
|
||||
unsigned Encoding) {
|
||||
switch (getSizeForEncoding(Data, Encoding)) {
|
||||
case 2:
|
||||
return Data.getU16(&Offset);
|
||||
case 4:
|
||||
return Data.getU32(&Offset);
|
||||
case 8:
|
||||
return Data.getU64(&Offset);
|
||||
default:
|
||||
llvm_unreachable("Illegal data size");
|
||||
}
|
||||
}
|
||||
|
||||
void DWARFDebugFrame::parse(DataExtractor Data) {
|
||||
uint32_t Offset = 0;
|
||||
|
@ -447,6 +500,14 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
|
|||
while (Data.isValidOffset(Offset)) {
|
||||
uint32_t StartOffset = Offset;
|
||||
|
||||
auto ReportError = [StartOffset](const char *ErrorMsg) {
|
||||
std::string Str;
|
||||
raw_string_ostream OS(Str);
|
||||
OS << format(ErrorMsg, StartOffset);
|
||||
OS.flush();
|
||||
report_fatal_error(Str);
|
||||
};
|
||||
|
||||
bool IsDWARF64 = false;
|
||||
uint64_t Length = Data.getU32(&Offset);
|
||||
uint64_t Id;
|
||||
|
@ -465,47 +526,136 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
|
|||
// read).
|
||||
// TODO: For honest DWARF64 support, DataExtractor will have to treat
|
||||
// offset_ptr as uint64_t*
|
||||
uint32_t StartStructureOffset = Offset;
|
||||
uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);
|
||||
|
||||
// The Id field's size depends on the DWARF format
|
||||
Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4);
|
||||
bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID);
|
||||
Id = Data.getUnsigned(&Offset, (IsDWARF64 && !IsEH) ? 8 : 4);
|
||||
bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) ||
|
||||
Id == DW_CIE_ID ||
|
||||
(IsEH && !Id));
|
||||
|
||||
if (IsCIE) {
|
||||
uint8_t Version = Data.getU8(&Offset);
|
||||
const char *Augmentation = Data.getCStr(&Offset);
|
||||
uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : Data.getU8(&Offset);
|
||||
StringRef AugmentationString(Augmentation ? Augmentation : "");
|
||||
uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
|
||||
Data.getU8(&Offset);
|
||||
Data.setAddressSize(AddressSize);
|
||||
uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
|
||||
uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
|
||||
int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
|
||||
uint64_t ReturnAddressRegister = Data.getULEB128(&Offset);
|
||||
|
||||
// Parse the augmentation data for EH CIEs
|
||||
StringRef AugmentationData;
|
||||
Optional<uint32_t> FDEPointerEncoding;
|
||||
Optional<uint32_t> LSDAPointerEncoding;
|
||||
if (IsEH) {
|
||||
Optional<uint32_t> PersonalityEncoding;
|
||||
Optional<uint64_t> Personality;
|
||||
|
||||
uint64_t AugmentationLength = 0;
|
||||
uint32_t StartAugmentationOffset = 0;
|
||||
uint32_t EndAugmentationOffset = 0;
|
||||
|
||||
// Walk the augmentation string to get all the augmentation data.
|
||||
for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
|
||||
switch (AugmentationString[i]) {
|
||||
default:
|
||||
ReportError("Unknown augmentation character in entry at %lx");
|
||||
case 'L':
|
||||
if (LSDAPointerEncoding)
|
||||
ReportError("Duplicate LSDA encoding in entry at %lx");
|
||||
LSDAPointerEncoding = Data.getU8(&Offset);
|
||||
break;
|
||||
case 'P': {
|
||||
if (Personality)
|
||||
ReportError("Duplicate personality in entry at %lx");
|
||||
PersonalityEncoding = Data.getU8(&Offset);
|
||||
Personality = readPointer(Data, Offset, *PersonalityEncoding);
|
||||
break;
|
||||
}
|
||||
case 'R':
|
||||
if (FDEPointerEncoding)
|
||||
ReportError("Duplicate FDE encoding in entry at %lx");
|
||||
FDEPointerEncoding = Data.getU8(&Offset);
|
||||
break;
|
||||
case 'z':
|
||||
if (i)
|
||||
ReportError("'z' must be the first character at %lx");
|
||||
// Parse the augmentation length first. We only parse it if
|
||||
// the string contains a 'z'.
|
||||
AugmentationLength = Data.getULEB128(&Offset);
|
||||
StartAugmentationOffset = Offset;
|
||||
EndAugmentationOffset =
|
||||
Offset + static_cast<uint32_t>(AugmentationLength);
|
||||
}
|
||||
}
|
||||
|
||||
if (Offset != EndAugmentationOffset)
|
||||
ReportError("Parsing augmentation data at %lx failed");
|
||||
|
||||
AugmentationData = Data.getData().slice(StartAugmentationOffset,
|
||||
EndAugmentationOffset);
|
||||
}
|
||||
|
||||
auto Cie = make_unique<CIE>(StartOffset, Length, Version,
|
||||
StringRef(Augmentation), AddressSize,
|
||||
SegmentDescriptorSize, CodeAlignmentFactor,
|
||||
DataAlignmentFactor, ReturnAddressRegister);
|
||||
DataAlignmentFactor, ReturnAddressRegister,
|
||||
AugmentationData, FDEPointerEncoding,
|
||||
LSDAPointerEncoding);
|
||||
CIEs[StartOffset] = Cie.get();
|
||||
Entries.emplace_back(std::move(Cie));
|
||||
} else {
|
||||
// FDE
|
||||
uint64_t CIEPointer = Id;
|
||||
uint64_t InitialLocation = Data.getAddress(&Offset);
|
||||
uint64_t AddressRange = Data.getAddress(&Offset);
|
||||
uint64_t InitialLocation = 0;
|
||||
uint64_t AddressRange = 0;
|
||||
CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
|
||||
|
||||
if (IsEH) {
|
||||
// The address size is encoded in the CIE we reference.
|
||||
if (!Cie)
|
||||
ReportError("Parsing FDE data at %lx failed due to missing CIE");
|
||||
|
||||
Optional<uint32_t> FDEPointerEncoding = Cie->getFDEPointerEncoding();
|
||||
if (!FDEPointerEncoding)
|
||||
ReportError("Parsing at %lx failed due to missing pointer encoding");
|
||||
|
||||
InitialLocation = readPointer(Data, Offset, *FDEPointerEncoding);
|
||||
AddressRange = readPointer(Data, Offset, *FDEPointerEncoding);
|
||||
StringRef AugmentationString = Cie->getAugmentationString();
|
||||
if (!AugmentationString.empty()) {
|
||||
// Parse the augmentation length and data for this FDE.
|
||||
uint64_t AugmentationLength = Data.getULEB128(&Offset);
|
||||
|
||||
uint32_t EndAugmentationOffset =
|
||||
Offset + static_cast<uint32_t>(AugmentationLength);
|
||||
|
||||
// Decode the LSDA if the CIE augmentation string said we should.
|
||||
uint64_t LSDA = 0;
|
||||
if (Optional<uint32_t> Encoding = Cie->getLSDAPointerEncoding())
|
||||
LSDA = readPointer(Data, Offset, *Encoding);
|
||||
|
||||
if (Offset != EndAugmentationOffset)
|
||||
ReportError("Parsing augmentation data at %lx failed");
|
||||
}
|
||||
} else {
|
||||
InitialLocation = Data.getAddress(&Offset);
|
||||
AddressRange = Data.getAddress(&Offset);
|
||||
}
|
||||
|
||||
Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
|
||||
InitialLocation, AddressRange,
|
||||
CIEs[CIEPointer]));
|
||||
Cie));
|
||||
}
|
||||
|
||||
Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset);
|
||||
|
||||
if (Offset != EndStructureOffset) {
|
||||
std::string Str;
|
||||
raw_string_ostream OS(Str);
|
||||
OS << format("Parsing entry instructions at %lx failed", StartOffset);
|
||||
report_fatal_error(Str);
|
||||
}
|
||||
if (Offset != EndStructureOffset)
|
||||
ReportError("Parsing entry instructions at %lx failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ PDBContext::PDBContext(const COFFObjectFile &Object,
|
|||
Session->setLoadAddress(ImageBase.get());
|
||||
}
|
||||
|
||||
void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType) {}
|
||||
void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType,
|
||||
bool DumpEH) {}
|
||||
|
||||
DILineInfo PDBContext::getLineInfoForAddress(uint64_t Address,
|
||||
DILineInfoSpecifier Specifier) {
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
# RUN: llvm-objdump -unwind-info %p/Inputs/eh_frame.macho-arm64 2>/dev/null | FileCheck %s
|
||||
# RUN: llvm-objdump -dwarf=frames %p/Inputs/eh_frame.macho-arm64 2>/dev/null | FileCheck %s
|
||||
|
||||
# CHECK: Contents of __eh_frame section:
|
||||
# CHECK: CIE:
|
||||
# CHECK: Length: 16
|
||||
# CHECK: CIE ID: 0
|
||||
# CHECK: Version: 1
|
||||
# CHECK: Augmentation String: zR
|
||||
# CHECK: Code Alignment Factor: 1
|
||||
# CHECK: Data Alignment Factor: -8
|
||||
# CHECK: Return Address Register: 30
|
||||
# CHECK: Augmentation Data Length: 1
|
||||
# CHECK: FDE Address Pointer Encoding: 16
|
||||
# CHECK: Instructions:
|
||||
# CHECK: 0c 1f 00
|
||||
# CHECK: FDE:
|
||||
# CHECK: Length: 32
|
||||
# CHECK: CIE Offset: 0
|
||||
# CHECK: PC Begin: ffffffffffffffe4
|
||||
# CHECK: PC Range: 0000000000000020
|
||||
# CHECK: Augmentation Data Length: 0
|
||||
# CHECK: Instructions:
|
||||
# CHECK: 48 0e 10 9e 01 9d 02 00 00 00 00
|
||||
# CHECK: .eh_frame contents:
|
||||
|
||||
# CHECK: 00000000 00000010 ffffffff CIE
|
||||
# CHECK: Version: 1
|
||||
# CHECK: Augmentation: "zR"
|
||||
# CHECK: Code alignment factor: 1
|
||||
# CHECK: Data alignment factor: -8
|
||||
# CHECK: Return address column: 30
|
||||
# CHECK: Augmentation data:
|
||||
|
||||
# CHECK: DW_CFA_def_cfa: reg31 +0
|
||||
|
||||
# CHECK: 00000014 00000020 00000018 FDE cie=00000018 pc=ffffffe4...00000004
|
||||
# CHECK: DW_CFA_advance_loc: 8
|
||||
# CHECK: DW_CFA_def_cfa_offset: +16
|
||||
# CHECK: DW_CFA_offset: reg30 -8
|
||||
# CHECK: DW_CFA_offset: reg29 -16
|
||||
# CHECK: DW_CFA_nop:
|
||||
# CHECK: DW_CFA_nop:
|
||||
# CHECK: DW_CFA_nop:
|
||||
# CHECK: DW_CFA_nop:
|
||||
|
|
|
@ -1210,6 +1210,12 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
|
|||
printLazyBindTable(MachOOF);
|
||||
if (WeakBind)
|
||||
printWeakBindTable(MachOOF);
|
||||
|
||||
if (DwarfDumpType != DIDT_Null) {
|
||||
std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(*MachOOF));
|
||||
// Dump the complete DWARF structure.
|
||||
DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */);
|
||||
}
|
||||
}
|
||||
|
||||
// printUnknownCPUType() helps print_fat_headers for unknown CPU's.
|
||||
|
@ -6748,262 +6754,6 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned getSizeForEncoding(bool is64Bit,
|
||||
unsigned symbolEncoding) {
|
||||
unsigned format = symbolEncoding & 0x0f;
|
||||
switch (format) {
|
||||
default: llvm_unreachable("Unknown Encoding");
|
||||
case dwarf::DW_EH_PE_absptr:
|
||||
case dwarf::DW_EH_PE_signed:
|
||||
return is64Bit ? 8 : 4;
|
||||
case dwarf::DW_EH_PE_udata2:
|
||||
case dwarf::DW_EH_PE_sdata2:
|
||||
return 2;
|
||||
case dwarf::DW_EH_PE_udata4:
|
||||
case dwarf::DW_EH_PE_sdata4:
|
||||
return 4;
|
||||
case dwarf::DW_EH_PE_udata8:
|
||||
case dwarf::DW_EH_PE_sdata8:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t readPointer(const char *&Pos, bool is64Bit, unsigned Encoding) {
|
||||
switch (getSizeForEncoding(is64Bit, Encoding)) {
|
||||
case 2:
|
||||
return readNext<uint16_t>(Pos);
|
||||
break;
|
||||
case 4:
|
||||
return readNext<uint32_t>(Pos);
|
||||
break;
|
||||
case 8:
|
||||
return readNext<uint64_t>(Pos);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Illegal data size");
|
||||
}
|
||||
}
|
||||
|
||||
static void printMachOEHFrameSection(const MachOObjectFile *Obj,
|
||||
std::map<uint64_t, SymbolRef> &Symbols,
|
||||
const SectionRef &EHFrame) {
|
||||
if (!Obj->isLittleEndian()) {
|
||||
outs() << "warning: cannot handle big endian __eh_frame section\n";
|
||||
return;
|
||||
}
|
||||
|
||||
bool is64Bit = Obj->is64Bit();
|
||||
|
||||
outs() << "Contents of __eh_frame section:\n";
|
||||
|
||||
StringRef Contents;
|
||||
EHFrame.getContents(Contents);
|
||||
|
||||
/// A few fields of the CIE are used when decoding the FDE's. This struct
|
||||
/// will cache those fields we need so that we don't have to decode it
|
||||
/// repeatedly for each FDE that references it.
|
||||
struct DecodedCIE {
|
||||
Optional<uint32_t> FDEPointerEncoding;
|
||||
Optional<uint32_t> LSDAPointerEncoding;
|
||||
bool hasAugmentationLength;
|
||||
};
|
||||
|
||||
// Map from the start offset of the CIE to the cached data for that CIE.
|
||||
DenseMap<uint64_t, DecodedCIE> CachedCIEs;
|
||||
|
||||
for (const char *Pos = Contents.data(), *End = Contents.end(); Pos != End; ) {
|
||||
|
||||
const char *EntryStartPos = Pos;
|
||||
|
||||
uint64_t Length = readNext<uint32_t>(Pos);
|
||||
if (Length == 0xffffffff)
|
||||
Length = readNext<uint64_t>(Pos);
|
||||
|
||||
// Save the Pos so that we can check the length we encoded against what we
|
||||
// end up decoding.
|
||||
const char *PosAfterLength = Pos;
|
||||
const char *EntryEndPos = PosAfterLength + Length;
|
||||
|
||||
assert(EntryEndPos <= End &&
|
||||
"__eh_frame entry length exceeds section size");
|
||||
|
||||
uint32_t ID = readNext<uint32_t>(Pos);
|
||||
if (ID == 0) {
|
||||
// This is a CIE.
|
||||
|
||||
uint32_t Version = readNext<uint8_t>(Pos);
|
||||
|
||||
// Parse a null terminated augmentation string
|
||||
SmallString<8> AugmentationString;
|
||||
for (uint8_t Char = readNext<uint8_t>(Pos); Char;
|
||||
Char = readNext<uint8_t>(Pos))
|
||||
AugmentationString.push_back(Char);
|
||||
|
||||
// Optionally parse the EH data if the augmentation string says it's there.
|
||||
Optional<uint64_t> EHData;
|
||||
if (StringRef(AugmentationString).count("eh"))
|
||||
EHData = is64Bit ? readNext<uint64_t>(Pos) : readNext<uint32_t>(Pos);
|
||||
|
||||
unsigned ULEBByteCount;
|
||||
uint64_t CodeAlignmentFactor = decodeULEB128((const uint8_t *)Pos,
|
||||
&ULEBByteCount);
|
||||
Pos += ULEBByteCount;
|
||||
|
||||
int64_t DataAlignmentFactor = decodeSLEB128((const uint8_t *)Pos,
|
||||
&ULEBByteCount);
|
||||
Pos += ULEBByteCount;
|
||||
|
||||
uint32_t ReturnAddressRegister = readNext<uint8_t>(Pos);
|
||||
|
||||
Optional<uint64_t> AugmentationLength;
|
||||
Optional<uint32_t> LSDAPointerEncoding;
|
||||
Optional<uint32_t> PersonalityEncoding;
|
||||
Optional<uint64_t> Personality;
|
||||
Optional<uint32_t> FDEPointerEncoding;
|
||||
if (!AugmentationString.empty() && AugmentationString.front() == 'z') {
|
||||
AugmentationLength = decodeULEB128((const uint8_t *)Pos,
|
||||
&ULEBByteCount);
|
||||
Pos += ULEBByteCount;
|
||||
|
||||
// Walk the augmentation string to get all the augmentation data.
|
||||
for (unsigned i = 1, e = AugmentationString.size(); i != e; ++i) {
|
||||
char Char = AugmentationString[i];
|
||||
switch (Char) {
|
||||
case 'e':
|
||||
assert((i + 1) != e && AugmentationString[i + 1] == 'h' &&
|
||||
"Expected 'eh' in augmentation string");
|
||||
break;
|
||||
case 'L':
|
||||
assert(!LSDAPointerEncoding && "Duplicate LSDA encoding");
|
||||
LSDAPointerEncoding = readNext<uint8_t>(Pos);
|
||||
break;
|
||||
case 'P': {
|
||||
assert(!Personality && "Duplicate personality");
|
||||
PersonalityEncoding = readNext<uint8_t>(Pos);
|
||||
Personality = readPointer(Pos, is64Bit, *PersonalityEncoding);
|
||||
break;
|
||||
}
|
||||
case 'R':
|
||||
assert(!FDEPointerEncoding && "Duplicate FDE encoding");
|
||||
FDEPointerEncoding = readNext<uint8_t>(Pos);
|
||||
break;
|
||||
case 'z':
|
||||
llvm_unreachable("'z' must be first in the augmentation string");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outs() << "CIE:\n";
|
||||
outs() << " Length: " << Length << "\n";
|
||||
outs() << " CIE ID: " << ID << "\n";
|
||||
outs() << " Version: " << Version << "\n";
|
||||
outs() << " Augmentation String: " << AugmentationString << "\n";
|
||||
if (EHData)
|
||||
outs() << " EHData: " << *EHData << "\n";
|
||||
outs() << " Code Alignment Factor: " << CodeAlignmentFactor << "\n";
|
||||
outs() << " Data Alignment Factor: " << DataAlignmentFactor << "\n";
|
||||
outs() << " Return Address Register: " << ReturnAddressRegister << "\n";
|
||||
if (AugmentationLength) {
|
||||
outs() << " Augmentation Data Length: " << *AugmentationLength << "\n";
|
||||
if (LSDAPointerEncoding) {
|
||||
outs() << " FDE LSDA Pointer Encoding: "
|
||||
<< *LSDAPointerEncoding << "\n";
|
||||
}
|
||||
if (Personality) {
|
||||
outs() << " Personality Encoding: " << *PersonalityEncoding << "\n";
|
||||
outs() << " Personality: " << *Personality << "\n";
|
||||
}
|
||||
if (FDEPointerEncoding) {
|
||||
outs() << " FDE Address Pointer Encoding: "
|
||||
<< *FDEPointerEncoding << "\n";
|
||||
}
|
||||
}
|
||||
// FIXME: Handle instructions.
|
||||
// For now just emit some bytes
|
||||
outs() << " Instructions:\n ";
|
||||
dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos),
|
||||
outs());
|
||||
outs() << "\n";
|
||||
Pos = EntryEndPos;
|
||||
|
||||
// Cache this entry.
|
||||
uint64_t Offset = EntryStartPos - Contents.data();
|
||||
CachedCIEs[Offset] = { FDEPointerEncoding, LSDAPointerEncoding,
|
||||
AugmentationLength.hasValue() };
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is an FDE.
|
||||
// The CIE pointer for an FDE is the same location as the ID which we
|
||||
// already read.
|
||||
uint32_t CIEPointer = ID;
|
||||
|
||||
const char *CIEStart = PosAfterLength - CIEPointer;
|
||||
assert(CIEStart >= Contents.data() &&
|
||||
"FDE points to CIE before the __eh_frame start");
|
||||
|
||||
uint64_t CIEOffset = CIEStart - Contents.data();
|
||||
auto CIEIt = CachedCIEs.find(CIEOffset);
|
||||
if (CIEIt == CachedCIEs.end())
|
||||
llvm_unreachable("Couldn't find CIE at offset in to __eh_frame section");
|
||||
|
||||
const DecodedCIE &CIE = CIEIt->getSecond();
|
||||
assert(CIE.FDEPointerEncoding &&
|
||||
"FDE references CIE which did not set pointer encoding");
|
||||
|
||||
uint64_t PCPointerSize = getSizeForEncoding(is64Bit,
|
||||
*CIE.FDEPointerEncoding);
|
||||
|
||||
uint64_t PCBegin = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding);
|
||||
uint64_t PCRange = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding);
|
||||
|
||||
Optional<uint64_t> AugmentationLength;
|
||||
uint32_t LSDAPointerSize;
|
||||
Optional<uint64_t> LSDAPointer;
|
||||
if (CIE.hasAugmentationLength) {
|
||||
unsigned ULEBByteCount;
|
||||
AugmentationLength = decodeULEB128((const uint8_t *)Pos,
|
||||
&ULEBByteCount);
|
||||
Pos += ULEBByteCount;
|
||||
|
||||
// Decode the LSDA if the CIE augmentation string said we should.
|
||||
if (CIE.LSDAPointerEncoding) {
|
||||
LSDAPointerSize = getSizeForEncoding(is64Bit, *CIE.LSDAPointerEncoding);
|
||||
LSDAPointer = readPointer(Pos, is64Bit, *CIE.LSDAPointerEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
outs() << "FDE:\n";
|
||||
outs() << " Length: " << Length << "\n";
|
||||
outs() << " CIE Offset: " << CIEOffset << "\n";
|
||||
|
||||
if (PCPointerSize == 8) {
|
||||
outs() << format(" PC Begin: %016" PRIx64, PCBegin) << "\n";
|
||||
outs() << format(" PC Range: %016" PRIx64, PCRange) << "\n";
|
||||
} else {
|
||||
outs() << format(" PC Begin: %08" PRIx64, PCBegin) << "\n";
|
||||
outs() << format(" PC Range: %08" PRIx64, PCRange) << "\n";
|
||||
}
|
||||
if (AugmentationLength) {
|
||||
outs() << " Augmentation Data Length: " << *AugmentationLength << "\n";
|
||||
if (LSDAPointer) {
|
||||
if (LSDAPointerSize == 8)
|
||||
outs() << format(" LSDA Pointer: %016\n" PRIx64, *LSDAPointer);
|
||||
else
|
||||
outs() << format(" LSDA Pointer: %08\n" PRIx64, *LSDAPointer);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Handle instructions.
|
||||
// For now just emit some bytes
|
||||
outs() << " Instructions:\n ";
|
||||
dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos),
|
||||
outs());
|
||||
outs() << "\n";
|
||||
Pos = EntryEndPos;
|
||||
}
|
||||
}
|
||||
|
||||
void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
|
||||
std::map<uint64_t, SymbolRef> Symbols;
|
||||
for (const SymbolRef &SymRef : Obj->symbols()) {
|
||||
|
@ -7024,8 +6774,6 @@ void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
|
|||
printMachOCompactUnwindSection(Obj, Symbols, Section);
|
||||
else if (SectName == "__unwind_info")
|
||||
printMachOUnwindInfoSection(Obj, Symbols, Section);
|
||||
else if (SectName == "__eh_frame")
|
||||
printMachOEHFrameSection(Obj, Symbols, Section);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/CodeGen/FaultMaps.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCDisassembler.h"
|
||||
|
@ -176,6 +177,11 @@ cl::opt<bool>
|
|||
cl::opt<bool> PrintFaultMaps("fault-map-section",
|
||||
cl::desc("Display contents of faultmap section"));
|
||||
|
||||
cl::opt<DIDumpType> llvm::DwarfDumpType(
|
||||
"dwarf", cl::init(DIDT_Null), cl::desc("Dump of dwarf debug sections:"),
|
||||
cl::values(clEnumValN(DIDT_Frames, "frames", ".debug_frame"),
|
||||
clEnumValEnd));
|
||||
|
||||
static StringRef ToolName;
|
||||
|
||||
namespace {
|
||||
|
@ -1572,6 +1578,11 @@ static void DumpObject(const ObjectFile *o) {
|
|||
printRawClangAST(o);
|
||||
if (PrintFaultMaps)
|
||||
printFaultMaps(o);
|
||||
if (DwarfDumpType != DIDT_Null) {
|
||||
std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(*o));
|
||||
// Dump the complete DWARF structure.
|
||||
DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Dump each object file in \a a;
|
||||
|
@ -1664,7 +1675,8 @@ int main(int argc, char **argv) {
|
|||
&& !(DylibId && MachOOpt)
|
||||
&& !(ObjcMetaData && MachOOpt)
|
||||
&& !(FilterSections.size() != 0 && MachOOpt)
|
||||
&& !PrintFaultMaps) {
|
||||
&& !PrintFaultMaps
|
||||
&& DwarfDumpType == DIDT_Null) {
|
||||
cl::PrintHelpMessage();
|
||||
return 2;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define LLVM_TOOLS_LLVM_OBJDUMP_LLVM_OBJDUMP_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/DIContext.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
|
@ -53,6 +54,7 @@ extern cl::opt<bool> SectionContents;
|
|||
extern cl::opt<bool> SymbolTable;
|
||||
extern cl::opt<bool> UnwindInfo;
|
||||
extern cl::opt<bool> PrintImmHex;
|
||||
extern cl::opt<DIDumpType> DwarfDumpType;
|
||||
|
||||
// Various helper functions.
|
||||
void error(std::error_code ec);
|
||||
|
|
Loading…
Reference in New Issue