diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
| commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
| tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /include/llvm/DebugInfo | |
| parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) | |
Notes
Diffstat (limited to 'include/llvm/DebugInfo')
72 files changed, 2849 insertions, 741 deletions
diff --git a/include/llvm/DebugInfo/CodeView/CVDebugRecord.h b/include/llvm/DebugInfo/CodeView/CVDebugRecord.h deleted file mode 100644 index 5a0bb4266ba2..000000000000 --- a/include/llvm/DebugInfo/CodeView/CVDebugRecord.h +++ /dev/null @@ -1,55 +0,0 @@ -//===- CVDebugRecord.h ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_CVDEBUGRECORD_H -#define LLVM_DEBUGINFO_CODEVIEW_CVDEBUGRECORD_H - -#include "llvm/Support/Endian.h" - -namespace llvm { -namespace OMF { -struct Signature { - enum ID : uint32_t { - PDB70 = 0x53445352, // RSDS - PDB20 = 0x3031424e, // NB10 - CV50 = 0x3131424e, // NB11 - CV41 = 0x3930424e, // NB09 - }; - - support::ulittle32_t CVSignature; - support::ulittle32_t Offset; -}; -} - -namespace codeview { -struct PDB70DebugInfo { - support::ulittle32_t CVSignature; - uint8_t Signature[16]; - support::ulittle32_t Age; - // char PDBFileName[]; -}; - -struct PDB20DebugInfo { - support::ulittle32_t CVSignature; - support::ulittle32_t Offset; - support::ulittle32_t Signature; - support::ulittle32_t Age; - // char PDBFileName[]; -}; - -union DebugInfo { - struct OMF::Signature Signature; - struct PDB20DebugInfo PDB20; - struct PDB70DebugInfo PDB70; -}; -} -} - -#endif - diff --git a/include/llvm/DebugInfo/CodeView/CVRecord.h b/include/llvm/DebugInfo/CodeView/CVRecord.h index 9f3a753ad1ae..9dbeb438f4ae 100644 --- a/include/llvm/DebugInfo/CodeView/CVRecord.h +++ b/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -61,6 +61,30 @@ template <typename Kind> struct RemappedRecord { SmallVector<std::pair<uint32_t, TypeIndex>, 8> Mappings; }; +template <typename Record, typename Func> +Error forEachCodeViewRecord(ArrayRef<uint8_t> StreamBuffer, Func F) { + while (!StreamBuffer.empty()) { + if (StreamBuffer.size() < sizeof(RecordPrefix)) + return make_error<CodeViewError>(cv_error_code::corrupt_record); + + const RecordPrefix *Prefix = + reinterpret_cast<const RecordPrefix *>(StreamBuffer.data()); + + size_t RealLen = Prefix->RecordLen + 2; + if (StreamBuffer.size() < RealLen) + return make_error<CodeViewError>(cv_error_code::corrupt_record); + + ArrayRef<uint8_t> Data = StreamBuffer.take_front(RealLen); + StreamBuffer = StreamBuffer.drop_front(RealLen); + + Record R(static_cast<decltype(Record::Type)>((uint16_t)Prefix->RecordKind), + Data); + if (auto EC = F(R)) + return EC; + } + return Error::success(); +} + /// Read a complete record from a stream at a random offset. template <typename Kind> inline Expected<CVRecord<Kind>> readCVRecordFromStream(BinaryStreamRef Stream, diff --git a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h index df55e181364c..b765ba1abb4d 100644 --- a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -20,7 +20,7 @@ class TypeCollection; class TypeVisitorCallbacks; enum VisitorDataSource { - VDS_BytesPresent, // The record bytes are passed into the the visitation + VDS_BytesPresent, // The record bytes are passed into the visitation // function. The algorithm should first deserialize them // before passing them on through the pipeline. VDS_BytesExternal // The record bytes are not present, and it is the diff --git a/include/llvm/DebugInfo/CodeView/CodeView.h b/include/llvm/DebugInfo/CodeView/CodeView.h index 1a4f510c24ab..4ce9f68cffd9 100644 --- a/include/llvm/DebugInfo/CodeView/CodeView.h +++ b/include/llvm/DebugInfo/CodeView/CodeView.h @@ -22,8 +22,8 @@ namespace llvm { namespace codeview { -/// Distinguishes individual records in .debug$T section or PDB type stream. The -/// documentation and headers talk about this as the "leaf" type. +/// Distinguishes individual records in .debug$T or .debug$P section or PDB type +/// stream. The documentation and headers talk about this as the "leaf" type. enum class TypeRecordKind : uint16_t { #define TYPE_RECORD(lf_ename, value, name) name = value, #include "CodeViewTypes.def" @@ -531,7 +531,7 @@ enum LineFlags : uint16_t { LF_HaveColumns = 1, // CV_LINES_HAVE_COLUMNS }; -/// Data in the the SUBSEC_FRAMEDATA subection. +/// Data in the SUBSEC_FRAMEDATA subection. struct FrameData { support::ulittle32_t RvaStart; support::ulittle32_t CodeSize; diff --git a/include/llvm/DebugInfo/CodeView/CodeViewRegisters.def b/include/llvm/DebugInfo/CodeView/CodeViewRegisters.def index 3f0660294866..6da8893bd61a 100644 --- a/include/llvm/DebugInfo/CodeView/CodeViewRegisters.def +++ b/include/llvm/DebugInfo/CodeView/CodeViewRegisters.def @@ -15,254 +15,254 @@ #define CV_REGISTER(name, value) #endif -// This currently only contains the "register subset shraed by all processor +// This currently only contains the "register subset shared by all processor // types" (ERR etc.) and the x86 registers. -CV_REGISTER(ERR, 30000) -CV_REGISTER(TEB, 30001) -CV_REGISTER(TIMER, 30002) -CV_REGISTER(EFAD1, 30003) -CV_REGISTER(EFAD2, 30004) -CV_REGISTER(EFAD3, 30005) -CV_REGISTER(VFRAME, 30006) -CV_REGISTER(HANDLE, 30007) -CV_REGISTER(PARAMS, 30008) -CV_REGISTER(LOCALS, 30009) -CV_REGISTER(TID, 30010) -CV_REGISTER(ENV, 30011) -CV_REGISTER(CMDLN, 30012) +CV_REGISTER(CVRegERR, 30000) +CV_REGISTER(CVRegTEB, 30001) +CV_REGISTER(CVRegTIMER, 30002) +CV_REGISTER(CVRegEFAD1, 30003) +CV_REGISTER(CVRegEFAD2, 30004) +CV_REGISTER(CVRegEFAD3, 30005) +CV_REGISTER(CVRegVFRAME, 30006) +CV_REGISTER(CVRegHANDLE, 30007) +CV_REGISTER(CVRegPARAMS, 30008) +CV_REGISTER(CVRegLOCALS, 30009) +CV_REGISTER(CVRegTID, 30010) +CV_REGISTER(CVRegENV, 30011) +CV_REGISTER(CVRegCMDLN, 30012) -CV_REGISTER(NONE, 0) -CV_REGISTER(AL, 1) -CV_REGISTER(CL, 2) -CV_REGISTER(DL, 3) -CV_REGISTER(BL, 4) -CV_REGISTER(AH, 5) -CV_REGISTER(CH, 6) -CV_REGISTER(DH, 7) -CV_REGISTER(BH, 8) -CV_REGISTER(AX, 9) -CV_REGISTER(CX, 10) -CV_REGISTER(DX, 11) -CV_REGISTER(BX, 12) -CV_REGISTER(SP, 13) -CV_REGISTER(BP, 14) -CV_REGISTER(SI, 15) -CV_REGISTER(DI, 16) -CV_REGISTER(EAX, 17) -CV_REGISTER(ECX, 18) -CV_REGISTER(EDX, 19) -CV_REGISTER(EBX, 20) -CV_REGISTER(ESP, 21) -CV_REGISTER(EBP, 22) -CV_REGISTER(ESI, 23) -CV_REGISTER(EDI, 24) -CV_REGISTER(ES, 25) -CV_REGISTER(CS, 26) -CV_REGISTER(SS, 27) -CV_REGISTER(DS, 28) -CV_REGISTER(FS, 29) -CV_REGISTER(GS, 30) -CV_REGISTER(IP, 31) -CV_REGISTER(FLAGS, 32) -CV_REGISTER(EIP, 33) -CV_REGISTER(EFLAGS, 34) -CV_REGISTER(TEMP, 40) -CV_REGISTER(TEMPH, 41) -CV_REGISTER(QUOTE, 42) -CV_REGISTER(PCDR3, 43) -CV_REGISTER(PCDR4, 44) -CV_REGISTER(PCDR5, 45) -CV_REGISTER(PCDR6, 46) -CV_REGISTER(PCDR7, 47) -CV_REGISTER(CR0, 80) -CV_REGISTER(CR1, 81) -CV_REGISTER(CR2, 82) -CV_REGISTER(CR3, 83) -CV_REGISTER(CR4, 84) -CV_REGISTER(DR0, 90) -CV_REGISTER(DR1, 91) -CV_REGISTER(DR2, 92) -CV_REGISTER(DR3, 93) -CV_REGISTER(DR4, 94) -CV_REGISTER(DR5, 95) -CV_REGISTER(DR6, 96) -CV_REGISTER(DR7, 97) -CV_REGISTER(GDTR, 110) -CV_REGISTER(GDTL, 111) -CV_REGISTER(IDTR, 112) -CV_REGISTER(IDTL, 113) -CV_REGISTER(LDTR, 114) -CV_REGISTER(TR, 115) +CV_REGISTER(CVRegNONE, 0) +CV_REGISTER(CVRegAL, 1) +CV_REGISTER(CVRegCL, 2) +CV_REGISTER(CVRegDL, 3) +CV_REGISTER(CVRegBL, 4) +CV_REGISTER(CVRegAH, 5) +CV_REGISTER(CVRegCH, 6) +CV_REGISTER(CVRegDH, 7) +CV_REGISTER(CVRegBH, 8) +CV_REGISTER(CVRegAX, 9) +CV_REGISTER(CVRegCX, 10) +CV_REGISTER(CVRegDX, 11) +CV_REGISTER(CVRegBX, 12) +CV_REGISTER(CVRegSP, 13) +CV_REGISTER(CVRegBP, 14) +CV_REGISTER(CVRegSI, 15) +CV_REGISTER(CVRegDI, 16) +CV_REGISTER(CVRegEAX, 17) +CV_REGISTER(CVRegECX, 18) +CV_REGISTER(CVRegEDX, 19) +CV_REGISTER(CVRegEBX, 20) +CV_REGISTER(CVRegESP, 21) +CV_REGISTER(CVRegEBP, 22) +CV_REGISTER(CVRegESI, 23) +CV_REGISTER(CVRegEDI, 24) +CV_REGISTER(CVRegES, 25) +CV_REGISTER(CVRegCS, 26) +CV_REGISTER(CVRegSS, 27) +CV_REGISTER(CVRegDS, 28) +CV_REGISTER(CVRegFS, 29) +CV_REGISTER(CVRegGS, 30) +CV_REGISTER(CVRegIP, 31) +CV_REGISTER(CVRegFLAGS, 32) +CV_REGISTER(CVRegEIP, 33) +CV_REGISTER(CVRegEFLAGS, 34) +CV_REGISTER(CVRegTEMP, 40) +CV_REGISTER(CVRegTEMPH, 41) +CV_REGISTER(CVRegQUOTE, 42) +CV_REGISTER(CVRegPCDR3, 43) +CV_REGISTER(CVRegPCDR4, 44) +CV_REGISTER(CVRegPCDR5, 45) +CV_REGISTER(CVRegPCDR6, 46) +CV_REGISTER(CVRegPCDR7, 47) +CV_REGISTER(CVRegCR0, 80) +CV_REGISTER(CVRegCR1, 81) +CV_REGISTER(CVRegCR2, 82) +CV_REGISTER(CVRegCR3, 83) +CV_REGISTER(CVRegCR4, 84) +CV_REGISTER(CVRegDR0, 90) +CV_REGISTER(CVRegDR1, 91) +CV_REGISTER(CVRegDR2, 92) +CV_REGISTER(CVRegDR3, 93) +CV_REGISTER(CVRegDR4, 94) +CV_REGISTER(CVRegDR5, 95) +CV_REGISTER(CVRegDR6, 96) +CV_REGISTER(CVRegDR7, 97) +CV_REGISTER(CVRegGDTR, 110) +CV_REGISTER(CVRegGDTL, 111) +CV_REGISTER(CVRegIDTR, 112) +CV_REGISTER(CVRegIDTL, 113) +CV_REGISTER(CVRegLDTR, 114) +CV_REGISTER(CVRegTR, 115) -CV_REGISTER(PSEUDO1, 116) -CV_REGISTER(PSEUDO2, 117) -CV_REGISTER(PSEUDO3, 118) -CV_REGISTER(PSEUDO4, 119) -CV_REGISTER(PSEUDO5, 120) -CV_REGISTER(PSEUDO6, 121) -CV_REGISTER(PSEUDO7, 122) -CV_REGISTER(PSEUDO8, 123) -CV_REGISTER(PSEUDO9, 124) +CV_REGISTER(CVRegPSEUDO1, 116) +CV_REGISTER(CVRegPSEUDO2, 117) +CV_REGISTER(CVRegPSEUDO3, 118) +CV_REGISTER(CVRegPSEUDO4, 119) +CV_REGISTER(CVRegPSEUDO5, 120) +CV_REGISTER(CVRegPSEUDO6, 121) +CV_REGISTER(CVRegPSEUDO7, 122) +CV_REGISTER(CVRegPSEUDO8, 123) +CV_REGISTER(CVRegPSEUDO9, 124) -CV_REGISTER(ST0, 128) -CV_REGISTER(ST1, 129) -CV_REGISTER(ST2, 130) -CV_REGISTER(ST3, 131) -CV_REGISTER(ST4, 132) -CV_REGISTER(ST5, 133) -CV_REGISTER(ST6, 134) -CV_REGISTER(ST7, 135) -CV_REGISTER(CTRL, 136) -CV_REGISTER(STAT, 137) -CV_REGISTER(TAG, 138) -CV_REGISTER(FPIP, 139) -CV_REGISTER(FPCS, 140) -CV_REGISTER(FPDO, 141) -CV_REGISTER(FPDS, 142) -CV_REGISTER(ISEM, 143) -CV_REGISTER(FPEIP, 144) -CV_REGISTER(FPEDO, 145) +CV_REGISTER(CVRegST0, 128) +CV_REGISTER(CVRegST1, 129) +CV_REGISTER(CVRegST2, 130) +CV_REGISTER(CVRegST3, 131) +CV_REGISTER(CVRegST4, 132) +CV_REGISTER(CVRegST5, 133) +CV_REGISTER(CVRegST6, 134) +CV_REGISTER(CVRegST7, 135) +CV_REGISTER(CVRegCTRL, 136) +CV_REGISTER(CVRegSTAT, 137) +CV_REGISTER(CVRegTAG, 138) +CV_REGISTER(CVRegFPIP, 139) +CV_REGISTER(CVRegFPCS, 140) +CV_REGISTER(CVRegFPDO, 141) +CV_REGISTER(CVRegFPDS, 142) +CV_REGISTER(CVRegISEM, 143) +CV_REGISTER(CVRegFPEIP, 144) +CV_REGISTER(CVRegFPEDO, 145) -CV_REGISTER(MM0, 146) -CV_REGISTER(MM1, 147) -CV_REGISTER(MM2, 148) -CV_REGISTER(MM3, 149) -CV_REGISTER(MM4, 150) -CV_REGISTER(MM5, 151) -CV_REGISTER(MM6, 152) -CV_REGISTER(MM7, 153) +CV_REGISTER(CVRegMM0, 146) +CV_REGISTER(CVRegMM1, 147) +CV_REGISTER(CVRegMM2, 148) +CV_REGISTER(CVRegMM3, 149) +CV_REGISTER(CVRegMM4, 150) +CV_REGISTER(CVRegMM5, 151) +CV_REGISTER(CVRegMM6, 152) +CV_REGISTER(CVRegMM7, 153) -CV_REGISTER(XMM0, 154) -CV_REGISTER(XMM1, 155) -CV_REGISTER(XMM2, 156) -CV_REGISTER(XMM3, 157) -CV_REGISTER(XMM4, 158) -CV_REGISTER(XMM5, 159) -CV_REGISTER(XMM6, 160) -CV_REGISTER(XMM7, 161) +CV_REGISTER(CVRegXMM0, 154) +CV_REGISTER(CVRegXMM1, 155) +CV_REGISTER(CVRegXMM2, 156) +CV_REGISTER(CVRegXMM3, 157) +CV_REGISTER(CVRegXMM4, 158) +CV_REGISTER(CVRegXMM5, 159) +CV_REGISTER(CVRegXMM6, 160) +CV_REGISTER(CVRegXMM7, 161) -CV_REGISTER(MXCSR, 211) +CV_REGISTER(CVRegMXCSR, 211) -CV_REGISTER(EDXEAX, 212) +CV_REGISTER(CVRegEDXEAX, 212) -CV_REGISTER(EMM0L, 220) -CV_REGISTER(EMM1L, 221) -CV_REGISTER(EMM2L, 222) -CV_REGISTER(EMM3L, 223) -CV_REGISTER(EMM4L, 224) -CV_REGISTER(EMM5L, 225) -CV_REGISTER(EMM6L, 226) -CV_REGISTER(EMM7L, 227) +CV_REGISTER(CVRegEMM0L, 220) +CV_REGISTER(CVRegEMM1L, 221) +CV_REGISTER(CVRegEMM2L, 222) +CV_REGISTER(CVRegEMM3L, 223) +CV_REGISTER(CVRegEMM4L, 224) +CV_REGISTER(CVRegEMM5L, 225) +CV_REGISTER(CVRegEMM6L, 226) +CV_REGISTER(CVRegEMM7L, 227) -CV_REGISTER(EMM0H, 228) -CV_REGISTER(EMM1H, 229) -CV_REGISTER(EMM2H, 230) -CV_REGISTER(EMM3H, 231) -CV_REGISTER(EMM4H, 232) -CV_REGISTER(EMM5H, 233) -CV_REGISTER(EMM6H, 234) -CV_REGISTER(EMM7H, 235) +CV_REGISTER(CVRegEMM0H, 228) +CV_REGISTER(CVRegEMM1H, 229) +CV_REGISTER(CVRegEMM2H, 230) +CV_REGISTER(CVRegEMM3H, 231) +CV_REGISTER(CVRegEMM4H, 232) +CV_REGISTER(CVRegEMM5H, 233) +CV_REGISTER(CVRegEMM6H, 234) +CV_REGISTER(CVRegEMM7H, 235) -CV_REGISTER(MM00, 236) -CV_REGISTER(MM01, 237) -CV_REGISTER(MM10, 238) -CV_REGISTER(MM11, 239) -CV_REGISTER(MM20, 240) -CV_REGISTER(MM21, 241) -CV_REGISTER(MM30, 242) -CV_REGISTER(MM31, 243) -CV_REGISTER(MM40, 244) -CV_REGISTER(MM41, 245) -CV_REGISTER(MM50, 246) -CV_REGISTER(MM51, 247) -CV_REGISTER(MM60, 248) -CV_REGISTER(MM61, 249) -CV_REGISTER(MM70, 250) -CV_REGISTER(MM71, 251) +CV_REGISTER(CVRegMM00, 236) +CV_REGISTER(CVRegMM01, 237) +CV_REGISTER(CVRegMM10, 238) +CV_REGISTER(CVRegMM11, 239) +CV_REGISTER(CVRegMM20, 240) +CV_REGISTER(CVRegMM21, 241) +CV_REGISTER(CVRegMM30, 242) +CV_REGISTER(CVRegMM31, 243) +CV_REGISTER(CVRegMM40, 244) +CV_REGISTER(CVRegMM41, 245) +CV_REGISTER(CVRegMM50, 246) +CV_REGISTER(CVRegMM51, 247) +CV_REGISTER(CVRegMM60, 248) +CV_REGISTER(CVRegMM61, 249) +CV_REGISTER(CVRegMM70, 250) +CV_REGISTER(CVRegMM71, 251) -CV_REGISTER(BND0, 396) -CV_REGISTER(BND1, 397) -CV_REGISTER(BND2, 398) +CV_REGISTER(CVRegBND0, 396) +CV_REGISTER(CVRegBND1, 397) +CV_REGISTER(CVRegBND2, 398) -CV_REGISTER(XMM8, 252) -CV_REGISTER(XMM9, 253) -CV_REGISTER(XMM10, 254) -CV_REGISTER(XMM11, 255) -CV_REGISTER(XMM12, 256) -CV_REGISTER(XMM13, 257) -CV_REGISTER(XMM14, 258) -CV_REGISTER(XMM15, 259) +CV_REGISTER(CVRegXMM8, 252) +CV_REGISTER(CVRegXMM9, 253) +CV_REGISTER(CVRegXMM10, 254) +CV_REGISTER(CVRegXMM11, 255) +CV_REGISTER(CVRegXMM12, 256) +CV_REGISTER(CVRegXMM13, 257) +CV_REGISTER(CVRegXMM14, 258) +CV_REGISTER(CVRegXMM15, 259) -CV_REGISTER(SIL, 324) -CV_REGISTER(DIL, 325) -CV_REGISTER(BPL, 326) -CV_REGISTER(SPL, 327) +CV_REGISTER(CVRegSIL, 324) +CV_REGISTER(CVRegDIL, 325) +CV_REGISTER(CVRegBPL, 326) +CV_REGISTER(CVRegSPL, 327) -CV_REGISTER(RAX, 328) -CV_REGISTER(RBX, 329) -CV_REGISTER(RCX, 330) -CV_REGISTER(RDX, 331) -CV_REGISTER(RSI, 332) -CV_REGISTER(RDI, 333) -CV_REGISTER(RBP, 334) -CV_REGISTER(RSP, 335) +CV_REGISTER(CVRegRAX, 328) +CV_REGISTER(CVRegRBX, 329) +CV_REGISTER(CVRegRCX, 330) +CV_REGISTER(CVRegRDX, 331) +CV_REGISTER(CVRegRSI, 332) +CV_REGISTER(CVRegRDI, 333) +CV_REGISTER(CVRegRBP, 334) +CV_REGISTER(CVRegRSP, 335) -CV_REGISTER(R8, 336) -CV_REGISTER(R9, 337) -CV_REGISTER(R10, 338) -CV_REGISTER(R11, 339) -CV_REGISTER(R12, 340) -CV_REGISTER(R13, 341) -CV_REGISTER(R14, 342) -CV_REGISTER(R15, 343) +CV_REGISTER(CVRegR8, 336) +CV_REGISTER(CVRegR9, 337) +CV_REGISTER(CVRegR10, 338) +CV_REGISTER(CVRegR11, 339) +CV_REGISTER(CVRegR12, 340) +CV_REGISTER(CVRegR13, 341) +CV_REGISTER(CVRegR14, 342) +CV_REGISTER(CVRegR15, 343) -CV_REGISTER(R8B, 344) -CV_REGISTER(R9B, 345) -CV_REGISTER(R10B, 346) -CV_REGISTER(R11B, 347) -CV_REGISTER(R12B, 348) -CV_REGISTER(R13B, 349) -CV_REGISTER(R14B, 350) -CV_REGISTER(R15B, 351) +CV_REGISTER(CVRegR8B, 344) +CV_REGISTER(CVRegR9B, 345) +CV_REGISTER(CVRegR10B, 346) +CV_REGISTER(CVRegR11B, 347) +CV_REGISTER(CVRegR12B, 348) +CV_REGISTER(CVRegR13B, 349) +CV_REGISTER(CVRegR14B, 350) +CV_REGISTER(CVRegR15B, 351) -CV_REGISTER(R8W, 352) -CV_REGISTER(R9W, 353) -CV_REGISTER(R10W, 354) -CV_REGISTER(R11W, 355) -CV_REGISTER(R12W, 356) -CV_REGISTER(R13W, 357) -CV_REGISTER(R14W, 358) -CV_REGISTER(R15W, 359) +CV_REGISTER(CVRegR8W, 352) +CV_REGISTER(CVRegR9W, 353) +CV_REGISTER(CVRegR10W, 354) +CV_REGISTER(CVRegR11W, 355) +CV_REGISTER(CVRegR12W, 356) +CV_REGISTER(CVRegR13W, 357) +CV_REGISTER(CVRegR14W, 358) +CV_REGISTER(CVRegR15W, 359) -CV_REGISTER(R8D, 360) -CV_REGISTER(R9D, 361) -CV_REGISTER(R10D, 362) -CV_REGISTER(R11D, 363) -CV_REGISTER(R12D, 364) -CV_REGISTER(R13D, 365) -CV_REGISTER(R14D, 366) -CV_REGISTER(R15D, 367) +CV_REGISTER(CVRegR8D, 360) +CV_REGISTER(CVRegR9D, 361) +CV_REGISTER(CVRegR10D, 362) +CV_REGISTER(CVRegR11D, 363) +CV_REGISTER(CVRegR12D, 364) +CV_REGISTER(CVRegR13D, 365) +CV_REGISTER(CVRegR14D, 366) +CV_REGISTER(CVRegR15D, 367) // cvconst.h defines both CV_REG_YMM0 (252) and CV_AMD64_YMM0 (368). Keep the // original prefix to distinguish them. -CV_REGISTER(AMD64_YMM0, 368) -CV_REGISTER(AMD64_YMM1, 369) -CV_REGISTER(AMD64_YMM2, 370) -CV_REGISTER(AMD64_YMM3, 371) -CV_REGISTER(AMD64_YMM4, 372) -CV_REGISTER(AMD64_YMM5, 373) -CV_REGISTER(AMD64_YMM6, 374) -CV_REGISTER(AMD64_YMM7, 375) -CV_REGISTER(AMD64_YMM8, 376) -CV_REGISTER(AMD64_YMM9, 377) -CV_REGISTER(AMD64_YMM10, 378) -CV_REGISTER(AMD64_YMM11, 379) -CV_REGISTER(AMD64_YMM12, 380) -CV_REGISTER(AMD64_YMM13, 381) -CV_REGISTER(AMD64_YMM14, 382) -CV_REGISTER(AMD64_YMM15, 383) +CV_REGISTER(CVRegAMD64_YMM0, 368) +CV_REGISTER(CVRegAMD64_YMM1, 369) +CV_REGISTER(CVRegAMD64_YMM2, 370) +CV_REGISTER(CVRegAMD64_YMM3, 371) +CV_REGISTER(CVRegAMD64_YMM4, 372) +CV_REGISTER(CVRegAMD64_YMM5, 373) +CV_REGISTER(CVRegAMD64_YMM6, 374) +CV_REGISTER(CVRegAMD64_YMM7, 375) +CV_REGISTER(CVRegAMD64_YMM8, 376) +CV_REGISTER(CVRegAMD64_YMM9, 377) +CV_REGISTER(CVRegAMD64_YMM10, 378) +CV_REGISTER(CVRegAMD64_YMM11, 379) +CV_REGISTER(CVRegAMD64_YMM12, 380) +CV_REGISTER(CVRegAMD64_YMM13, 381) +CV_REGISTER(CVRegAMD64_YMM14, 382) +CV_REGISTER(CVRegAMD64_YMM15, 383) diff --git a/include/llvm/DebugInfo/CodeView/CodeViewTypes.def b/include/llvm/DebugInfo/CodeView/CodeViewTypes.def index 69ce9606a670..e9a479dba496 100644 --- a/include/llvm/DebugInfo/CodeView/CodeViewTypes.def +++ b/include/llvm/DebugInfo/CodeView/CodeViewTypes.def @@ -87,6 +87,8 @@ TYPE_RECORD(LF_UDT_MOD_SRC_LINE, 0x1607, UdtModSourceLine) TYPE_RECORD(LF_METHODLIST, 0x1206, MethodOverloadList) +TYPE_RECORD(LF_PRECOMP, 0x1509, Precomp) +TYPE_RECORD(LF_ENDPRECOMP, 0x0014, EndPrecomp) // 16 bit type records. CV_TYPE(LF_MODIFIER_16t, 0x0001) @@ -106,7 +108,6 @@ CV_TYPE(LF_NOTTRAN, 0x0010) CV_TYPE(LF_DIMARRAY_16t, 0x0011) CV_TYPE(LF_VFTPATH_16t, 0x0012) CV_TYPE(LF_PRECOMP_16t, 0x0013) -CV_TYPE(LF_ENDPRECOMP, 0x0014) CV_TYPE(LF_OEM_16t, 0x0015) CV_TYPE(LF_TYPESERVER_ST, 0x0016) @@ -181,7 +182,6 @@ CV_TYPE(LF_MANAGED_ST, 0x140f) CV_TYPE(LF_ST_MAX, 0x1500) CV_TYPE(LF_TYPESERVER, 0x1501) CV_TYPE(LF_DIMARRAY, 0x1508) -CV_TYPE(LF_PRECOMP, 0x1509) CV_TYPE(LF_ALIAS, 0x150a) CV_TYPE(LF_DEFARG, 0x150b) CV_TYPE(LF_FRIENDFCN, 0x150c) diff --git a/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h b/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h index 7f0f10e4fbfa..bebc960223cc 100644 --- a/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h +++ b/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_DEBUGSTRINGTABLESUBSECTION_H #define LLVM_DEBUGINFO_CODEVIEW_DEBUGSTRINGTABLESUBSECTION_H +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" @@ -66,19 +67,26 @@ public: uint32_t insert(StringRef S); // Return the ID for string S. Assumes S exists in the table. - uint32_t getStringId(StringRef S) const; + uint32_t getIdForString(StringRef S) const; + + StringRef getStringForId(uint32_t Id) const; uint32_t calculateSerializedSize() const override; Error commit(BinaryStreamWriter &Writer) const override; uint32_t size() const; - StringMap<uint32_t>::const_iterator begin() const { return Strings.begin(); } + StringMap<uint32_t>::const_iterator begin() const { + return StringToId.begin(); + } + + StringMap<uint32_t>::const_iterator end() const { return StringToId.end(); } - StringMap<uint32_t>::const_iterator end() const { return Strings.end(); } + std::vector<uint32_t> sortedIds() const; private: - StringMap<uint32_t> Strings; + DenseMap<uint32_t, StringRef> IdToString; + StringMap<uint32_t> StringToId; uint32_t StringSize = 1; }; diff --git a/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h index d8ac3343c15f..c4704168ed34 100644 --- a/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h +++ b/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h @@ -69,9 +69,22 @@ public: ArrayRef<ArrayRef<uint8_t>> records() const; ArrayRef<GloballyHashedType> hashes() const; - using CreateRecord = llvm::function_ref<ArrayRef<uint8_t>()>; + template <typename CreateFunc> + TypeIndex insertRecordAs(GloballyHashedType Hash, size_t RecordSize, + CreateFunc Create) { + auto Result = HashedRecords.try_emplace(Hash, nextTypeIndex()); + + if (LLVM_UNLIKELY(Result.second)) { + uint8_t *Stable = RecordStorage.Allocate<uint8_t>(RecordSize); + MutableArrayRef<uint8_t> Data(Stable, RecordSize); + SeenRecords.push_back(Create(Data)); + SeenHashes.push_back(Hash); + } + + // Update the caller's copy of Record to point a stable copy. + return Result.first->second; + } - TypeIndex insertRecordAs(GloballyHashedType Hash, CreateRecord Create); TypeIndex insertRecordBytes(ArrayRef<uint8_t> Data); TypeIndex insertRecord(ContinuationRecordBuilder &Builder); diff --git a/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h b/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h index 16d78692c839..383f7dd9fb6a 100644 --- a/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h +++ b/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h @@ -26,7 +26,7 @@ namespace llvm { namespace codeview { -/// \brief Provides amortized O(1) random access to a CodeView type stream. +/// Provides amortized O(1) random access to a CodeView type stream. /// Normally to access a type from a type stream, you must know its byte /// offset into the type stream, because type records are variable-lengthed. /// However, this is not the way we prefer to access them. For example, given diff --git a/include/llvm/DebugInfo/CodeView/TypeHashing.h b/include/llvm/DebugInfo/CodeView/TypeHashing.h index 741337533701..1f732d29a538 100644 --- a/include/llvm/DebugInfo/CodeView/TypeHashing.h +++ b/include/llvm/DebugInfo/CodeView/TypeHashing.h @@ -58,7 +58,10 @@ struct LocallyHashedType { } }; -enum class GlobalTypeHashAlg : uint16_t { SHA1 = 0 }; +enum class GlobalTypeHashAlg : uint16_t { + SHA1 = 0, // standard 20-byte SHA1 hash + SHA1_8 // last 8-bytes of standard SHA1 hash +}; /// A globally hashed type represents a hash value that is sufficient to /// uniquely identify a record across multiple type streams or type sequences. @@ -77,10 +80,10 @@ struct GloballyHashedType { GloballyHashedType(StringRef H) : GloballyHashedType(ArrayRef<uint8_t>(H.bytes_begin(), H.bytes_end())) {} GloballyHashedType(ArrayRef<uint8_t> H) { - assert(H.size() == 20); - ::memcpy(Hash.data(), H.data(), 20); + assert(H.size() == 8); + ::memcpy(Hash.data(), H.data(), 8); } - std::array<uint8_t, 20> Hash; + std::array<uint8_t, 8> Hash; /// Given a sequence of bytes representing a record, compute a global hash for /// this record. Due to the nature of global hashes incorporating the hashes diff --git a/include/llvm/DebugInfo/CodeView/TypeRecord.h b/include/llvm/DebugInfo/CodeView/TypeRecord.h index 508bdd395f74..61ebdf878ce7 100644 --- a/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ b/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -330,6 +330,10 @@ public: return !!(Attrs & uint32_t(PointerOptions::Unaligned)); } + bool isRestrict() const { + return !!(Attrs & uint32_t(PointerOptions::Restrict)); + } + TypeIndex ReferentType; uint32_t Attrs; Optional<MemberPointerInfo> MemberInfo; @@ -892,6 +896,33 @@ public: TypeIndex ContinuationIndex; }; +// LF_PRECOMP +class PrecompRecord : public TypeRecord { +public: + PrecompRecord() = default; + explicit PrecompRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} + + uint32_t getStartTypeIndex() const { return StartTypeIndex; } + uint32_t getTypesCount() const { return TypesCount; } + uint32_t getSignature() const { return Signature; } + StringRef getPrecompFilePath() const { return PrecompFilePath; } + + uint32_t StartTypeIndex; + uint32_t TypesCount; + uint32_t Signature; + StringRef PrecompFilePath; +}; + +// LF_ENDPRECOMP +class EndPrecompRecord : public TypeRecord { +public: + EndPrecompRecord() = default; + explicit EndPrecompRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} + + uint32_t getSignature() const { return Signature; } + + uint32_t Signature; +}; } // end namespace codeview } // end namespace llvm diff --git a/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h index 59e216abcb11..583740d2eb4b 100644 --- a/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h +++ b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h @@ -23,7 +23,7 @@ struct GloballyHashedType; class GlobalTypeTableBuilder; class MergingTypeTableBuilder; -/// \brief Merge one set of type records into another. This method assumes +/// Merge one set of type records into another. This method assumes /// that all records are type records, and there are no Id records present. /// /// \param Dest The table to store the re-written type records into. @@ -40,7 +40,7 @@ Error mergeTypeRecords(MergingTypeTableBuilder &Dest, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &Types); -/// \brief Merge one set of id records into another. This method assumes +/// Merge one set of id records into another. This method assumes /// that all records are id records, and there are no Type records present. /// However, since Id records can refer back to Type records, this method /// assumes that the referenced type records have also been merged into @@ -65,7 +65,7 @@ Error mergeIdRecords(MergingTypeTableBuilder &Dest, ArrayRef<TypeIndex> Types, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &Ids); -/// \brief Merge a unified set of type and id records, splitting them into +/// Merge a unified set of type and id records, splitting them into /// separate output streams. /// /// \param DestIds The table to store the re-written id records into. diff --git a/include/llvm/DebugInfo/DIContext.h b/include/llvm/DebugInfo/DIContext.h index abace9378607..f89eb34fdd77 100644 --- a/include/llvm/DebugInfo/DIContext.h +++ b/include/llvm/DebugInfo/DIContext.h @@ -31,6 +31,7 @@ namespace llvm { struct DILineInfo { std::string FileName; std::string FunctionName; + Optional<StringRef> Source; uint32_t Line = 0; uint32_t Column = 0; uint32_t StartLine = 0; @@ -159,6 +160,7 @@ struct DIDumpOptions { bool ShowForm = false; bool SummarizeTypes = false; bool Verbose = false; + bool DisplayRawContents = false; /// Return default option set for printing a single DIE without children. static DIDumpOptions getForSingleDIE() { diff --git a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index 0bade10f6201..1d448728338f 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H #define LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" @@ -20,18 +21,76 @@ namespace llvm { class raw_ostream; +class ScopedPrinter; + +/// The accelerator tables are designed to allow efficient random access +/// (using a symbol name as a key) into debug info by providing an index of the +/// debug info DIEs. This class implements the common functionality of Apple and +/// DWARF 5 accelerator tables. +/// TODO: Generalize the rest of the AppleAcceleratorTable interface and move it +/// to this class. +class DWARFAcceleratorTable { +protected: + DWARFDataExtractor AccelSection; + DataExtractor StringSection; + +public: + /// An abstract class representing a single entry in the accelerator tables. + class Entry { + protected: + SmallVector<DWARFFormValue, 3> Values; + + Entry() = default; + + // Make these protected so only (final) subclasses can be copied around. + Entry(const Entry &) = default; + Entry(Entry &&) = default; + Entry &operator=(const Entry &) = default; + Entry &operator=(Entry &&) = default; + ~Entry() = default; + + + public: + /// Returns the Offset of the Compilation Unit associated with this + /// Accelerator Entry or None if the Compilation Unit offset is not recorded + /// in this Accelerator Entry. + virtual Optional<uint64_t> getCUOffset() const = 0; + + /// Returns the Tag of the Debug Info Entry associated with this + /// Accelerator Entry or None if the Tag is not recorded in this + /// Accelerator Entry. + virtual Optional<dwarf::Tag> getTag() const = 0; + + /// Returns the raw values of fields in the Accelerator Entry. In general, + /// these can only be interpreted with the help of the metadata in the + /// owning Accelerator Table. + ArrayRef<DWARFFormValue> getValues() const { return Values; } + }; + + DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection, + DataExtractor StringSection) + : AccelSection(AccelSection), StringSection(StringSection) {} + virtual ~DWARFAcceleratorTable(); + + virtual llvm::Error extract() = 0; + virtual void dump(raw_ostream &OS) const = 0; + + DWARFAcceleratorTable(const DWARFAcceleratorTable &) = delete; + void operator=(const DWARFAcceleratorTable &) = delete; +}; /// This implements the Apple accelerator table format, a precursor of the /// DWARF 5 accelerator table format. -/// TODO: Factor out a common base class for both formats. -class DWARFAcceleratorTable { +class AppleAcceleratorTable : public DWARFAcceleratorTable { struct Header { uint32_t Magic; uint16_t Version; uint16_t HashFunction; - uint32_t NumBuckets; - uint32_t NumHashes; + uint32_t BucketCount; + uint32_t HashCount; uint32_t HeaderDataLength; + + void dump(ScopedPrinter &W) const; }; struct HeaderData { @@ -40,22 +99,51 @@ class DWARFAcceleratorTable { uint32_t DIEOffsetBase; SmallVector<std::pair<AtomType, Form>, 3> Atoms; + + Optional<uint64_t> extractOffset(Optional<DWARFFormValue> Value) const; }; struct Header Hdr; struct HeaderData HdrData; - DWARFDataExtractor AccelSection; - DataExtractor StringSection; bool IsValid = false; + /// Returns true if we should continue scanning for entries or false if we've + /// reached the last (sentinel) entry of encountered a parsing error. + bool dumpName(ScopedPrinter &W, SmallVectorImpl<DWARFFormValue> &AtomForms, + uint32_t *DataOffset) const; + public: - /// An iterator for the entries associated with one key. Each entry can have - /// multiple DWARFFormValues. - class ValueIterator : public std::iterator<std::input_iterator_tag, - ArrayRef<DWARFFormValue>> { - const DWARFAcceleratorTable *AccelTable = nullptr; - SmallVector<DWARFFormValue, 3> AtomForms; ///< The decoded data entry. + /// Apple-specific implementation of an Accelerator Entry. + class Entry final : public DWARFAcceleratorTable::Entry { + const HeaderData *HdrData = nullptr; + + Entry(const HeaderData &Data); + Entry() = default; + + void extract(const AppleAcceleratorTable &AccelTable, uint32_t *Offset); + + public: + Optional<uint64_t> getCUOffset() const override; + + /// Returns the Section Offset of the Debug Info Entry associated with this + /// Accelerator Entry or None if the DIE offset is not recorded in this + /// Accelerator Entry. The returned offset is relative to the start of the + /// Section containing the DIE. + Optional<uint64_t> getDIESectionOffset() const; + Optional<dwarf::Tag> getTag() const override; + + /// Returns the value of the Atom in this Accelerator Entry, if the Entry + /// contains such Atom. + Optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const; + + friend class AppleAcceleratorTable; + friend class ValueIterator; + }; + + class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> { + const AppleAcceleratorTable *AccelTable = nullptr; + Entry Current; ///< The current entry. unsigned DataOffset = 0; ///< Offset into the section. unsigned Data = 0; ///< Current data entry. unsigned NumData = 0; ///< Number of data entries. @@ -64,13 +152,11 @@ public: void Next(); public: /// Construct a new iterator for the entries at \p DataOffset. - ValueIterator(const DWARFAcceleratorTable &AccelTable, unsigned DataOffset); + ValueIterator(const AppleAcceleratorTable &AccelTable, unsigned DataOffset); /// End marker. ValueIterator() = default; - const ArrayRef<DWARFFormValue> operator*() const { - return AtomForms; - } + const Entry &operator*() const { return Current; } ValueIterator &operator++() { Next(); return *this; } ValueIterator operator++(int) { ValueIterator I = *this; @@ -85,16 +171,18 @@ public: } }; - - DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection, + AppleAcceleratorTable(const DWARFDataExtractor &AccelSection, DataExtractor StringSection) - : AccelSection(AccelSection), StringSection(StringSection) {} + : DWARFAcceleratorTable(AccelSection, StringSection) {} - llvm::Error extract(); + llvm::Error extract() override; uint32_t getNumBuckets(); uint32_t getNumHashes(); uint32_t getSizeHdr(); uint32_t getHeaderDataLength(); + + /// Return the Atom description, which can be used to interpret the raw values + /// of the Accelerator Entries in this table. ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc(); bool validateForms(); @@ -107,10 +195,404 @@ public: /// related to the input hash data offset. /// DieTag is the tag of the DIE std::pair<uint32_t, dwarf::Tag> readAtoms(uint32_t &HashDataOffset); - void dump(raw_ostream &OS) const; + void dump(raw_ostream &OS) const override; + + /// Look up all entries in the accelerator table matching \c Key. + iterator_range<ValueIterator> equal_range(StringRef Key) const; +}; + +/// .debug_names section consists of one or more units. Each unit starts with a +/// header, which is followed by a list of compilation units, local and foreign +/// type units. +/// +/// These may be followed by an (optional) hash lookup table, which consists of +/// an array of buckets and hashes similar to the apple tables above. The only +/// difference is that the hashes array is 1-based, and consequently an empty +/// bucket is denoted by 0 and not UINT32_MAX. +/// +/// Next is the name table, which consists of an array of names and array of +/// entry offsets. This is different from the apple tables, which store names +/// next to the actual entries. +/// +/// The structure of the entries is described by an abbreviations table, which +/// comes after the name table. Unlike the apple tables, which have a uniform +/// entry structure described in the header, each .debug_names entry may have +/// different index attributes (DW_IDX_???) attached to it. +/// +/// The last segment consists of a list of entries, which is a 0-terminated list +/// referenced by the name table and interpreted with the help of the +/// abbreviation table. +class DWARFDebugNames : public DWARFAcceleratorTable { + /// The fixed-size part of a Dwarf 5 Name Index header + struct HeaderPOD { + uint32_t UnitLength; + uint16_t Version; + uint16_t Padding; + uint32_t CompUnitCount; + uint32_t LocalTypeUnitCount; + uint32_t ForeignTypeUnitCount; + uint32_t BucketCount; + uint32_t NameCount; + uint32_t AbbrevTableSize; + uint32_t AugmentationStringSize; + }; + +public: + class NameIndex; + class NameIterator; + class ValueIterator; + + /// Dwarf 5 Name Index header. + struct Header : public HeaderPOD { + SmallString<8> AugmentationString; + + Error extract(const DWARFDataExtractor &AS, uint32_t *Offset); + void dump(ScopedPrinter &W) const; + }; + + /// Index attribute and its encoding. + struct AttributeEncoding { + dwarf::Index Index; + dwarf::Form Form; + + constexpr AttributeEncoding(dwarf::Index Index, dwarf::Form Form) + : Index(Index), Form(Form) {} + + friend bool operator==(const AttributeEncoding &LHS, + const AttributeEncoding &RHS) { + return LHS.Index == RHS.Index && LHS.Form == RHS.Form; + } + }; + + /// Abbreviation describing the encoding of Name Index entries. + struct Abbrev { + uint32_t Code; ///< Abbreviation code + dwarf::Tag Tag; ///< Dwarf Tag of the described entity. + std::vector<AttributeEncoding> Attributes; ///< List of index attributes. + + Abbrev(uint32_t Code, dwarf::Tag Tag, + std::vector<AttributeEncoding> Attributes) + : Code(Code), Tag(Tag), Attributes(std::move(Attributes)) {} + + void dump(ScopedPrinter &W) const; + }; + + /// DWARF v5-specific implementation of an Accelerator Entry. + class Entry final : public DWARFAcceleratorTable::Entry { + const NameIndex *NameIdx; + const Abbrev *Abbr; + + Entry(const NameIndex &NameIdx, const Abbrev &Abbr); + + public: + Optional<uint64_t> getCUOffset() const override; + Optional<dwarf::Tag> getTag() const override { return tag(); } + + /// Returns the Index into the Compilation Unit list of the owning Name + /// Index or None if this Accelerator Entry does not have an associated + /// Compilation Unit. It is up to the user to verify that the returned Index + /// is valid in the owning NameIndex (or use getCUOffset(), which will + /// handle that check itself). Note that entries in NameIndexes which index + /// just a single Compilation Unit are implicitly associated with that unit, + /// so this function will return 0 even without an explicit + /// DW_IDX_compile_unit attribute. + Optional<uint64_t> getCUIndex() const; + + /// .debug_names-specific getter, which always succeeds (DWARF v5 index + /// entries always have a tag). + dwarf::Tag tag() const { return Abbr->Tag; } + + /// Returns the Offset of the DIE within the containing CU or TU. + Optional<uint64_t> getDIEUnitOffset() const; + + /// Return the Abbreviation that can be used to interpret the raw values of + /// this Accelerator Entry. + const Abbrev &getAbbrev() const { return *Abbr; } + + /// Returns the value of the Index Attribute in this Accelerator Entry, if + /// the Entry contains such Attribute. + Optional<DWARFFormValue> lookup(dwarf::Index Index) const; + + void dump(ScopedPrinter &W) const; + + friend class NameIndex; + friend class ValueIterator; + }; + + /// Error returned by NameIndex::getEntry to report it has reached the end of + /// the entry list. + class SentinelError : public ErrorInfo<SentinelError> { + public: + static char ID; + + void log(raw_ostream &OS) const override { OS << "Sentinel"; } + std::error_code convertToErrorCode() const override; + }; + +private: + /// DenseMapInfo for struct Abbrev. + struct AbbrevMapInfo { + static Abbrev getEmptyKey(); + static Abbrev getTombstoneKey(); + static unsigned getHashValue(uint32_t Code) { + return DenseMapInfo<uint32_t>::getHashValue(Code); + } + static unsigned getHashValue(const Abbrev &Abbr) { + return getHashValue(Abbr.Code); + } + static bool isEqual(uint32_t LHS, const Abbrev &RHS) { + return LHS == RHS.Code; + } + static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) { + return LHS.Code == RHS.Code; + } + }; + +public: + /// A single entry in the Name Table (Dwarf 5 sect. 6.1.1.4.6) of the Name + /// Index. + class NameTableEntry { + DataExtractor StrData; + + uint32_t Index; + uint32_t StringOffset; + uint32_t EntryOffset; + + public: + NameTableEntry(const DataExtractor &StrData, uint32_t Index, + uint32_t StringOffset, uint32_t EntryOffset) + : StrData(StrData), Index(Index), StringOffset(StringOffset), + EntryOffset(EntryOffset) {} + + /// Return the index of this name in the parent Name Index. + uint32_t getIndex() const { return Index; } + + /// Returns the offset of the name of the described entities. + uint32_t getStringOffset() const { return StringOffset; } + + /// Return the string referenced by this name table entry or nullptr if the + /// string offset is not valid. + const char *getString() const { + uint32_t Off = StringOffset; + return StrData.getCStr(&Off); + } + + /// Returns the offset of the first Entry in the list. + uint32_t getEntryOffset() const { return EntryOffset; } + }; + + /// Represents a single accelerator table within the Dwarf 5 .debug_names + /// section. + class NameIndex { + DenseSet<Abbrev, AbbrevMapInfo> Abbrevs; + struct Header Hdr; + const DWARFDebugNames &Section; + + // Base of the whole unit and of various important tables, as offsets from + // the start of the section. + uint32_t Base; + uint32_t CUsBase; + uint32_t BucketsBase; + uint32_t HashesBase; + uint32_t StringOffsetsBase; + uint32_t EntryOffsetsBase; + uint32_t EntriesBase; + + void dumpCUs(ScopedPrinter &W) const; + void dumpLocalTUs(ScopedPrinter &W) const; + void dumpForeignTUs(ScopedPrinter &W) const; + void dumpAbbreviations(ScopedPrinter &W) const; + bool dumpEntry(ScopedPrinter &W, uint32_t *Offset) const; + void dumpName(ScopedPrinter &W, const NameTableEntry &NTE, + Optional<uint32_t> Hash) const; + void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const; + + Expected<AttributeEncoding> extractAttributeEncoding(uint32_t *Offset); + + Expected<std::vector<AttributeEncoding>> + extractAttributeEncodings(uint32_t *Offset); + + Expected<Abbrev> extractAbbrev(uint32_t *Offset); + + public: + NameIndex(const DWARFDebugNames &Section, uint32_t Base) + : Section(Section), Base(Base) {} + + /// Reads offset of compilation unit CU. CU is 0-based. + uint32_t getCUOffset(uint32_t CU) const; + uint32_t getCUCount() const { return Hdr.CompUnitCount; } + + /// Reads offset of local type unit TU, TU is 0-based. + uint32_t getLocalTUOffset(uint32_t TU) const; + uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; } + + /// Reads signature of foreign type unit TU. TU is 0-based. + uint64_t getForeignTUSignature(uint32_t TU) const; + uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; } + + /// Reads an entry in the Bucket Array for the given Bucket. The returned + /// value is a (1-based) index into the Names, StringOffsets and + /// EntryOffsets arrays. The input Bucket index is 0-based. + uint32_t getBucketArrayEntry(uint32_t Bucket) const; + uint32_t getBucketCount() const { return Hdr.BucketCount; } + + /// Reads an entry in the Hash Array for the given Index. The input Index + /// is 1-based. + uint32_t getHashArrayEntry(uint32_t Index) const; + + /// Reads an entry in the Name Table for the given Index. The Name Table + /// consists of two arrays -- String Offsets and Entry Offsets. The returned + /// offsets are relative to the starts of respective sections. Input Index + /// is 1-based. + NameTableEntry getNameTableEntry(uint32_t Index) const; + + uint32_t getNameCount() const { return Hdr.NameCount; } + + const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const { + return Abbrevs; + } + + Expected<Entry> getEntry(uint32_t *Offset) const; + + /// Look up all entries in this Name Index matching \c Key. + iterator_range<ValueIterator> equal_range(StringRef Key) const; + + NameIterator begin() const { return NameIterator(this, 1); } + NameIterator end() const { return NameIterator(this, getNameCount() + 1); } + + llvm::Error extract(); + uint32_t getUnitOffset() const { return Base; } + uint32_t getNextUnitOffset() const { return Base + 4 + Hdr.UnitLength; } + void dump(ScopedPrinter &W) const; + + friend class DWARFDebugNames; + }; + + class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> { + + /// The Name Index we are currently iterating through. The implementation + /// relies on the fact that this can also be used as an iterator into the + /// "NameIndices" vector in the Accelerator section. + const NameIndex *CurrentIndex = nullptr; + + /// Whether this is a local iterator (searches in CurrentIndex only) or not + /// (searches all name indices). + bool IsLocal; + + Optional<Entry> CurrentEntry; + unsigned DataOffset = 0; ///< Offset into the section. + std::string Key; ///< The Key we are searching for. + Optional<uint32_t> Hash; ///< Hash of Key, if it has been computed. + + bool getEntryAtCurrentOffset(); + Optional<uint32_t> findEntryOffsetInCurrentIndex(); + bool findInCurrentIndex(); + void searchFromStartOfCurrentIndex(); + void next(); + + /// Set the iterator to the "end" state. + void setEnd() { *this = ValueIterator(); } + + public: + /// Create a "begin" iterator for looping over all entries in the + /// accelerator table matching Key. The iterator will run through all Name + /// Indexes in the section in sequence. + ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key); + + /// Create a "begin" iterator for looping over all entries in a specific + /// Name Index. Other indices in the section will not be visited. + ValueIterator(const NameIndex &NI, StringRef Key); + + /// End marker. + ValueIterator() = default; + + const Entry &operator*() const { return *CurrentEntry; } + ValueIterator &operator++() { + next(); + return *this; + } + ValueIterator operator++(int) { + ValueIterator I = *this; + next(); + return I; + } + + friend bool operator==(const ValueIterator &A, const ValueIterator &B) { + return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset; + } + friend bool operator!=(const ValueIterator &A, const ValueIterator &B) { + return !(A == B); + } + }; + + class NameIterator { + + /// The Name Index we are iterating through. + const NameIndex *CurrentIndex; + + /// The current name in the Name Index. + uint32_t CurrentName; + + void next() { + assert(CurrentName <= CurrentIndex->getNameCount()); + ++CurrentName; + } + + public: + using iterator_category = std::input_iterator_tag; + using value_type = NameTableEntry; + using difference_type = uint32_t; + using pointer = NameTableEntry *; + using reference = NameTableEntry; // We return entries by value. + + /// Creates an iterator whose initial position is name CurrentName in + /// CurrentIndex. + NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName) + : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {} + + NameTableEntry operator*() const { + return CurrentIndex->getNameTableEntry(CurrentName); + } + NameIterator &operator++() { + next(); + return *this; + } + NameIterator operator++(int) { + NameIterator I = *this; + next(); + return I; + } + + friend bool operator==(const NameIterator &A, const NameIterator &B) { + return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName; + } + friend bool operator!=(const NameIterator &A, const NameIterator &B) { + return !(A == B); + } + }; + +private: + SmallVector<NameIndex, 0> NameIndices; + DenseMap<uint32_t, const NameIndex *> CUToNameIndex; + +public: + DWARFDebugNames(const DWARFDataExtractor &AccelSection, + DataExtractor StringSection) + : DWARFAcceleratorTable(AccelSection, StringSection) {} + + llvm::Error extract() override; + void dump(raw_ostream &OS) const override; /// Look up all entries in the accelerator table matching \c Key. iterator_range<ValueIterator> equal_range(StringRef Key) const; + + using const_iterator = SmallVector<NameIndex, 0>::const_iterator; + const_iterator begin() const { return NameIndices.begin(); } + const_iterator end() const { return NameIndices.end(); } + + /// Return the Name Index covering the compile unit at CUOffset, or nullptr if + /// there is no Name Index covering that unit. + const NameIndex *getCUNameIndex(uint32_t CUOffset); }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h b/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h new file mode 100644 index 000000000000..5a7df5c353e8 --- /dev/null +++ b/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h @@ -0,0 +1,68 @@ +//===- DWARFAddressRange.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H +#define LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H + +#include "llvm/DebugInfo/DIContext.h" +#include <cstdint> +#include <tuple> +#include <vector> + +namespace llvm { + +class raw_ostream; + +struct DWARFAddressRange { + uint64_t LowPC; + uint64_t HighPC; + uint64_t SectionIndex; + + DWARFAddressRange() = default; + + /// Used for unit testing. + DWARFAddressRange(uint64_t LowPC, uint64_t HighPC, uint64_t SectionIndex = 0) + : LowPC(LowPC), HighPC(HighPC), SectionIndex(SectionIndex) {} + + /// Returns true if LowPC is smaller or equal to HighPC. This accounts for + /// dead-stripped ranges. + bool valid() const { return LowPC <= HighPC; } + + /// Returns true if [LowPC, HighPC) intersects with [RHS.LowPC, RHS.HighPC). + bool intersects(const DWARFAddressRange &RHS) const { + assert(valid() && RHS.valid()); + // Empty ranges can't intersect. + if (LowPC == HighPC || RHS.LowPC == RHS.HighPC) + return false; + return LowPC < RHS.HighPC && RHS.LowPC < HighPC; + } + + /// Returns true if [LowPC, HighPC) fully contains [RHS.LowPC, RHS.HighPC). + bool contains(const DWARFAddressRange &RHS) const { + assert(valid() && RHS.valid()); + return LowPC <= RHS.LowPC && RHS.HighPC <= HighPC; + } + + void dump(raw_ostream &OS, uint32_t AddressSize, + DIDumpOptions DumpOpts = {}) const; +}; + +static inline bool operator<(const DWARFAddressRange &LHS, + const DWARFAddressRange &RHS) { + return std::tie(LHS.LowPC, LHS.HighPC) < std::tie(RHS.LowPC, RHS.HighPC); +} + +raw_ostream &operator<<(raw_ostream &OS, const DWARFAddressRange &R); + +/// DWARFAddressRangesVector - represents a set of absolute address ranges. +using DWARFAddressRangesVector = std::vector<DWARFAddressRange>; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h index a18adf87bf8e..c219ca75e640 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h @@ -18,13 +18,13 @@ namespace llvm { class DWARFCompileUnit : public DWARFUnit { public: DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, - bool IsDWO, const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, - UnitSection, Entry) {} + bool IsDWO, const DWARFUnitSectionBase &UnitSection) + : DWARFUnit(Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection) {} // VTable anchor. ~DWARFCompileUnit() override; diff --git a/include/llvm/DebugInfo/DWARF/DWARFContext.h b/include/llvm/DebugInfo/DWARF/DWARFContext.h index 2ddbc4b91ba2..fe7430c9f04c 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -34,6 +34,7 @@ #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Error.h" #include "llvm/Support/Host.h" #include <cstdint> @@ -43,7 +44,6 @@ namespace llvm { -class DataExtractor; class MCRegisterInfo; class MemoryBuffer; class raw_ostream; @@ -69,10 +69,11 @@ class DWARFContext : public DIContext { std::unique_ptr<DWARFDebugFrame> DebugFrame; std::unique_ptr<DWARFDebugFrame> EHFrame; std::unique_ptr<DWARFDebugMacro> Macro; - std::unique_ptr<DWARFAcceleratorTable> AppleNames; - std::unique_ptr<DWARFAcceleratorTable> AppleTypes; - std::unique_ptr<DWARFAcceleratorTable> AppleNamespaces; - std::unique_ptr<DWARFAcceleratorTable> AppleObjC; + std::unique_ptr<DWARFDebugNames> Names; + std::unique_ptr<AppleAcceleratorTable> AppleNames; + std::unique_ptr<AppleAcceleratorTable> AppleTypes; + std::unique_ptr<AppleAcceleratorTable> AppleNamespaces; + std::unique_ptr<AppleAcceleratorTable> AppleObjC; DWARFUnitSection<DWARFCompileUnit> DWOCUs; std::deque<DWARFUnitSection<DWARFTypeUnit>> DWOTUs; @@ -204,6 +205,9 @@ public: DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash); + /// Return the compile unit that includes an offset (relative to .debug_info). + DWARFCompileUnit *getCompileUnitForOffset(uint32_t Offset); + /// Get a DIE given an exact offset. DWARFDie getDIEForOffset(uint32_t Offset); @@ -243,19 +247,36 @@ public: const DWARFDebugMacro *getDebugMacro(); /// Get a reference to the parsed accelerator table object. - const DWARFAcceleratorTable &getAppleNames(); + const DWARFDebugNames &getDebugNames(); /// Get a reference to the parsed accelerator table object. - const DWARFAcceleratorTable &getAppleTypes(); + const AppleAcceleratorTable &getAppleNames(); /// Get a reference to the parsed accelerator table object. - const DWARFAcceleratorTable &getAppleNamespaces(); + const AppleAcceleratorTable &getAppleTypes(); /// Get a reference to the parsed accelerator table object. - const DWARFAcceleratorTable &getAppleObjC(); + const AppleAcceleratorTable &getAppleNamespaces(); + + /// Get a reference to the parsed accelerator table object. + const AppleAcceleratorTable &getAppleObjC(); + + /// Get a pointer to a parsed line table corresponding to a compile unit. + /// Report any parsing issues as warnings on stderr. + const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *U); /// Get a pointer to a parsed line table corresponding to a compile unit. - const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *cu); + /// Report any recoverable parsing problems using the callback. + Expected<const DWARFDebugLine::LineTable *> + getLineTableForUnit(DWARFUnit *U, + std::function<void(Error)> RecoverableErrorCallback); + + DataExtractor getStringExtractor() const { + return DataExtractor(DObj->getStringSection(), false, 0); + } + DataExtractor getLineStringExtractor() const { + return DataExtractor(DObj->getLineStringSection(), false, 0); + } /// Wraps the returned DIEs for a given address. struct DIEsForAddress { @@ -303,9 +324,6 @@ public: Error loadRegisterInfo(const object::ObjectFile &Obj); private: - /// Return the compile unit that includes an offset (relative to .debug_info). - DWARFCompileUnit *getCompileUnitForOffset(uint32_t Offset); - /// Return the compile unit which contains instruction with provided /// address. DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); diff --git a/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h index a379d9c85b38..10e146b70ec7 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h @@ -44,6 +44,13 @@ public: uint64_t getRelocatedAddress(uint32_t *Off, uint64_t *SecIx = nullptr) const { return getRelocatedValue(getAddressSize(), Off, SecIx); } + + /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding. + /// There is a DWARF encoding that uses a PC-relative adjustment. + /// For these values, \p AbsPosOffset is used to fix them, which should + /// reflect the absolute address of this pointer. + Optional<uint64_t> getEncodedPointer(uint32_t *Offset, uint8_t Encoding, + uint64_t AbsPosOffset = 0) const; }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h b/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h index dfbbb95076e8..ab46fac39f7c 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h @@ -43,6 +43,7 @@ public: uint64_t Length; uint64_t getEndAddress() const { return Address + Length; } + void dump(raw_ostream &OS, uint32_t AddressSize) const; }; private: diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h index a711fb295444..ff1c7fb38389 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -10,40 +10,290 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H -#include "llvm/Support/DataExtractor.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/Support/Error.h" #include <memory> #include <vector> namespace llvm { -class FrameEntry; class raw_ostream; -/// \brief A parsed .debug_frame or .eh_frame section -/// +namespace dwarf { + +/// Represent a sequence of Call Frame Information instructions that, when read +/// in order, construct a table mapping PC to frame state. This can also be +/// referred to as "CFI rules" in DWARF literature to avoid confusion with +/// computer programs in the broader sense, and in this context each instruction +/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5 +/// manual, "6.4.1 Structure of Call Frame Information". +class CFIProgram { +public: + typedef SmallVector<uint64_t, 2> Operands; + + /// An instruction consists of a DWARF CFI opcode and an optional sequence of + /// operands. If it refers to an expression, then this expression has its own + /// sequence of operations and operands handled separately by DWARFExpression. + struct Instruction { + Instruction(uint8_t Opcode) : Opcode(Opcode) {} + + uint8_t Opcode; + Operands Ops; + // Associated DWARF expression in case this instruction refers to one + Optional<DWARFExpression> Expression; + }; + + using InstrList = std::vector<Instruction>; + using iterator = InstrList::iterator; + using const_iterator = InstrList::const_iterator; + + iterator begin() { return Instructions.begin(); } + const_iterator begin() const { return Instructions.begin(); } + iterator end() { return Instructions.end(); } + const_iterator end() const { return Instructions.end(); } + + unsigned size() const { return (unsigned)Instructions.size(); } + bool empty() const { return Instructions.empty(); } + + CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor) + : CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor) {} + + /// Parse and store a sequence of CFI instructions from Data, + /// starting at *Offset and ending at EndOffset. *Offset is updated + /// to EndOffset upon successful parsing, or indicates the offset + /// where a problem occurred in case an error is returned. + Error parse(DataExtractor Data, uint32_t *Offset, uint32_t EndOffset); + + void dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH, + unsigned IndentLevel = 1) const; + +private: + std::vector<Instruction> Instructions; + const uint64_t CodeAlignmentFactor; + const int64_t DataAlignmentFactor; + + /// Convenience method to add a new instruction with the given opcode. + void addInstruction(uint8_t Opcode) { + Instructions.push_back(Instruction(Opcode)); + } + + /// Add a new single-operand instruction. + void addInstruction(uint8_t Opcode, uint64_t Operand1) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + } + + /// Add a new instruction that has two operands. + void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + Instructions.back().Ops.push_back(Operand2); + } + + /// Types of operands to CFI instructions + /// In DWARF, this type is implicitly tied to a CFI instruction opcode and + /// thus this type doesn't need to be explictly written to the file (this is + /// not a DWARF encoding). The relationship of instrs to operand types can + /// be obtained from getOperandTypes() and is only used to simplify + /// instruction printing. + enum OperandType { + OT_Unset, + OT_None, + OT_Address, + OT_Offset, + OT_FactoredCodeOffset, + OT_SignedFactDataOffset, + OT_UnsignedFactDataOffset, + OT_Register, + OT_Expression + }; + + /// Retrieve the array describing the types of operands according to the enum + /// above. This is indexed by opcode. + static ArrayRef<OperandType[2]> getOperandTypes(); + + /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. + void printOperand(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH, + const Instruction &Instr, unsigned OperandIdx, + uint64_t Operand) const; +}; + +/// An entry in either debug_frame or eh_frame. This entry can be a CIE or an +/// FDE. +class FrameEntry { +public: + enum FrameKind { FK_CIE, FK_FDE }; + + FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length, uint64_t CodeAlign, + int64_t DataAlign) + : Kind(K), Offset(Offset), Length(Length), CFIs(CodeAlign, DataAlign) {} + + virtual ~FrameEntry() {} + + FrameKind getKind() const { return Kind; } + uint64_t getOffset() const { return Offset; } + uint64_t getLength() const { return Length; } + const CFIProgram &cfis() const { return CFIs; } + CFIProgram &cfis() { return CFIs; } + + /// Dump the instructions in this CFI fragment + virtual void dump(raw_ostream &OS, const MCRegisterInfo *MRI, + bool IsEH) const = 0; + +protected: + const FrameKind Kind; + + /// Offset of this entry in the section. + const uint64_t Offset; + + /// Entry length as specified in DWARF. + const uint64_t Length; + + CFIProgram CFIs; +}; + +/// DWARF Common Information Entry (CIE) +class CIE : public FrameEntry { +public: + // CIEs (and FDEs) are simply container classes, so the only sensible way to + // create them is by providing the full parsed contents in the constructor. + 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, + SmallString<8> AugmentationData, uint32_t FDEPointerEncoding, + uint32_t LSDAPointerEncoding, Optional<uint64_t> Personality, + Optional<uint32_t> PersonalityEnc) + : FrameEntry(FK_CIE, Offset, Length, CodeAlignmentFactor, + DataAlignmentFactor), + Version(Version), Augmentation(std::move(Augmentation)), + AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize), + CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor), + ReturnAddressRegister(ReturnAddressRegister), + AugmentationData(std::move(AugmentationData)), + FDEPointerEncoding(FDEPointerEncoding), + LSDAPointerEncoding(LSDAPointerEncoding), Personality(Personality), + PersonalityEnc(PersonalityEnc) {} + + static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; } + + StringRef getAugmentationString() const { return Augmentation; } + uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; } + int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; } + uint8_t getVersion() const { return Version; } + uint64_t getReturnAddressRegister() const { return ReturnAddressRegister; } + Optional<uint64_t> getPersonalityAddress() const { return Personality; } + Optional<uint32_t> getPersonalityEncoding() const { return PersonalityEnc; } + + uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; } + + uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; } + + void dump(raw_ostream &OS, const MCRegisterInfo *MRI, + bool IsEH) const override; + +private: + /// The following fields are defined in section 6.4.1 of the DWARF standard v4 + const uint8_t Version; + const SmallString<8> Augmentation; + const uint8_t AddressSize; + const uint8_t SegmentDescriptorSize; + const uint64_t CodeAlignmentFactor; + const int64_t DataAlignmentFactor; + const uint64_t ReturnAddressRegister; + + // The following are used when the CIE represents an EH frame entry. + const SmallString<8> AugmentationData; + const uint32_t FDEPointerEncoding; + const uint32_t LSDAPointerEncoding; + const Optional<uint64_t> Personality; + const Optional<uint32_t> PersonalityEnc; +}; + +/// DWARF Frame Description Entry (FDE) +class FDE : public FrameEntry { +public: + // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with + // an offset to the CIE (provided by parsing the FDE header). The CIE itself + // is obtained lazily once it's actually required. + FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset, + uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie, + Optional<uint64_t> LSDAAddress) + : FrameEntry(FK_FDE, Offset, Length, + Cie ? Cie->getCodeAlignmentFactor() : 0, + Cie ? Cie->getDataAlignmentFactor() : 0), + LinkedCIEOffset(LinkedCIEOffset), InitialLocation(InitialLocation), + AddressRange(AddressRange), LinkedCIE(Cie), LSDAAddress(LSDAAddress) {} + + ~FDE() override = default; + + const CIE *getLinkedCIE() const { return LinkedCIE; } + uint64_t getInitialLocation() const { return InitialLocation; } + uint64_t getAddressRange() const { return AddressRange; } + Optional<uint64_t> getLSDAAddress() const { return LSDAAddress; } + + void dump(raw_ostream &OS, const MCRegisterInfo *MRI, + bool IsEH) const override; + + static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_FDE; } + +private: + /// The following fields are defined in section 6.4.1 of the DWARF standard v3 + const uint64_t LinkedCIEOffset; + const uint64_t InitialLocation; + const uint64_t AddressRange; + const CIE *LinkedCIE; + const Optional<uint64_t> LSDAAddress; +}; + +} // end namespace dwarf + +/// A parsed .debug_frame or .eh_frame section class DWARFDebugFrame { // True if this is parsing an eh_frame section. - bool IsEH; + const bool IsEH; + // Not zero for sane pointer values coming out of eh_frame + const uint64_t EHFrameAddress; + + std::vector<std::unique_ptr<dwarf::FrameEntry>> Entries; + using iterator = pointee_iterator<decltype(Entries)::const_iterator>; + + /// Return the entry at the given offset or nullptr. + dwarf::FrameEntry *getEntryAtOffset(uint64_t Offset) const; public: - DWARFDebugFrame(bool IsEH); + // If IsEH is true, assume it is a .eh_frame section. Otherwise, + // it is a .debug_frame section. EHFrameAddress should be different + // than zero for correct parsing of .eh_frame addresses when they + // use a PC-relative encoding. + DWARFDebugFrame(bool IsEH = false, uint64_t EHFrameAddress = 0); ~DWARFDebugFrame(); /// Dump the section data into the given stream. - void dump(raw_ostream &OS, Optional<uint64_t> Offset) const; + void dump(raw_ostream &OS, const MCRegisterInfo *MRI, + Optional<uint64_t> Offset) const; - /// \brief Parse the section from raw data. - /// data is assumed to be pointing to the beginning of the section. - void parse(DataExtractor Data); + /// Parse the section from raw data. \p Data is assumed to contain the whole + /// frame section contents to be parsed. + void parse(DWARFDataExtractor Data); /// Return whether the section has any entries. bool empty() const { return Entries.empty(); } - /// Return the entry at the given offset or nullptr. - FrameEntry *getEntryAtOffset(uint64_t Offset) const; + /// DWARF Frame entries accessors + iterator begin() const { return Entries.begin(); } + iterator end() const { return Entries.end(); } + iterator_range<iterator> entries() const { + return iterator_range<iterator>(Entries.begin(), Entries.end()); + } -private: - std::vector<std::unique_ptr<FrameEntry>> Entries; + uint64_t getEHFrameAddress() const { return EHFrameAddress; } }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h index de8ad4e5ef3c..5b2af34bbcf5 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -10,11 +10,14 @@ #ifndef LLVM_DEBUGINFO_DWARFDEBUGLINE_H #define LLVM_DEBUGINFO_DWARFDEBUGLINE_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" #include "llvm/Support/MD5.h" #include <cstdint> #include <map> @@ -31,11 +34,30 @@ public: struct FileNameEntry { FileNameEntry() = default; - StringRef Name; + DWARFFormValue Name; uint64_t DirIdx = 0; uint64_t ModTime = 0; uint64_t Length = 0; MD5::MD5Result Checksum; + DWARFFormValue Source; + }; + + /// Tracks which optional content types are present in a DWARF file name + /// entry format. + struct ContentTypeTracker { + ContentTypeTracker() = default; + + /// Whether filename entries provide a modification timestamp. + bool HasModTime = false; + /// Whether filename entries provide a file size. + bool HasLength = false; + /// For v5, whether filename entries provide an MD5 checksum. + bool HasMD5 = false; + /// For v5, whether filename entries provide source text. + bool HasSource = false; + + /// Update tracked content types with \p ContentType. + void trackContentType(dwarf::LineNumberEntryFormat ContentType); }; struct Prologue { @@ -47,7 +69,7 @@ public: /// Version, address size (starting in v5), and DWARF32/64 format; these /// parameters affect interpretation of forms (used in the directory and /// file tables starting with v5). - DWARFFormParams FormParams; + dwarf::FormParams FormParams; /// The number of bytes following the prologue_length field to the beginning /// of the first byte of the statement program itself. uint64_t PrologueLength; @@ -68,13 +90,13 @@ public: uint8_t LineRange; /// The number assigned to the first special opcode. uint8_t OpcodeBase; - /// For v5, whether filename entries provide an MD5 checksum. - bool HasMD5; + /// This tracks which optional file format content types are present. + ContentTypeTracker ContentTypes; std::vector<uint8_t> StandardOpcodeLengths; - std::vector<StringRef> IncludeDirectories; + std::vector<DWARFFormValue> IncludeDirectories; std::vector<FileNameEntry> FileNames; - const DWARFFormParams getFormParams() const { return FormParams; } + const dwarf::FormParams getFormParams() const { return FormParams; } uint16_t getVersion() const { return FormParams.Version; } uint8_t getAddressSize() const { return FormParams.AddrSize; } bool isDWARF64() const { return FormParams.Format == dwarf::DWARF64; } @@ -83,6 +105,8 @@ public: uint32_t sizeofPrologueLength() const { return isDWARF64() ? 8 : 4; } + bool totalLengthIsValid() const; + /// Length of the prologue in bytes. uint32_t getLength() const { return PrologueLength + sizeofTotalLength() + sizeof(getVersion()) + @@ -99,9 +123,9 @@ public: } void clear(); - void dump(raw_ostream &OS) const; - bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, - const DWARFUnit *U = nullptr); + void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const; + Error parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + const DWARFContext &Ctx, const DWARFUnit *U = nullptr); }; /// Standard .debug_line state machine structure. @@ -219,12 +243,14 @@ public: DILineInfoSpecifier::FileLineInfoKind Kind, DILineInfo &Result) const; - void dump(raw_ostream &OS) const; + void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const; void clear(); /// Parse prologue and all rows. - bool parse(DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, - const DWARFUnit *U, raw_ostream *OS = nullptr); + Error parse(DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + const DWARFContext &Ctx, const DWARFUnit *U, + std::function<void(Error)> RecoverableErrorCallback = warn, + raw_ostream *OS = nullptr); using RowVector = std::vector<Row>; using RowIter = RowVector::const_iterator; @@ -238,11 +264,75 @@ public: private: uint32_t findRowInSeq(const DWARFDebugLine::Sequence &Seq, uint64_t Address) const; + Optional<StringRef> + getSourceByIndex(uint64_t FileIndex, + DILineInfoSpecifier::FileLineInfoKind Kind) const; }; const LineTable *getLineTable(uint32_t Offset) const; - const LineTable *getOrParseLineTable(DWARFDataExtractor &DebugLineData, - uint32_t Offset, const DWARFUnit *U); + Expected<const LineTable *> getOrParseLineTable( + DWARFDataExtractor &DebugLineData, uint32_t Offset, + const DWARFContext &Ctx, const DWARFUnit *U, + std::function<void(Error)> RecoverableErrorCallback = warn); + + /// Helper to allow for parsing of an entire .debug_line section in sequence. + class SectionParser { + public: + using cu_range = DWARFUnitSection<DWARFCompileUnit>::iterator_range; + using tu_range = + iterator_range<std::deque<DWARFUnitSection<DWARFTypeUnit>>::iterator>; + using LineToUnitMap = std::map<uint64_t, DWARFUnit *>; + + SectionParser(DWARFDataExtractor &Data, const DWARFContext &C, cu_range CUs, + tu_range TUs); + + /// Get the next line table from the section. Report any issues via the + /// callbacks. + /// + /// \param RecoverableErrorCallback - any issues that don't prevent further + /// parsing of the table will be reported through this callback. + /// \param UnrecoverableErrorCallback - any issues that prevent further + /// parsing of the table will be reported through this callback. + /// \param OS - if not null, the parser will print information about the + /// table as it parses it. + LineTable + parseNext(function_ref<void(Error)> RecoverableErrorCallback = warn, + function_ref<void(Error)> UnrecoverableErrorCallback = warn, + raw_ostream *OS = nullptr); + + /// Skip the current line table and go to the following line table (if + /// present) immediately. + /// + /// \param ErrorCallback - report any prologue parsing issues via this + /// callback. + void skip(function_ref<void(Error)> ErrorCallback = warn); + + /// Indicates if the parser has parsed as much as possible. + /// + /// \note Certain problems with the line table structure might mean that + /// parsing stops before the end of the section is reached. + bool done() const { return Done; } + + /// Get the offset the parser has reached. + uint32_t getOffset() const { return Offset; } + + private: + DWARFUnit *prepareToParse(uint32_t Offset); + void moveToNextTable(uint32_t OldOffset, const Prologue &P); + + LineToUnitMap LineToUnit; + + DWARFDataExtractor &DebugLineData; + const DWARFContext &Context; + uint32_t Offset = 0; + bool Done = false; + }; + + /// Helper function for DWARFDebugLine parse functions, to report issues + /// identified during parsing. + /// + /// \param Err The Error to report. + static void warn(Error Err); private: struct ParsingState { diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h index a6d319a90457..9a73745fb6b4 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -42,7 +42,8 @@ public: SmallVector<Entry, 2> Entries; /// Dump this list on OS. void dump(raw_ostream &OS, bool IsLittleEndian, unsigned AddressSize, - const MCRegisterInfo *MRI, unsigned Indent) const; + const MCRegisterInfo *MRI, uint64_t BaseAddress, + unsigned Indent) const; }; private: diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h b/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h index 761871dc6255..cae4804e61d3 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h @@ -32,7 +32,7 @@ public: /// The name of the object as given by the DW_AT_name attribute of the /// referenced DIE. - const char *Name; + StringRef Name; }; /// Each table consists of sets of variable length entries. Each set describes diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h b/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h index f9ec96366a53..ce7436d9faa3 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h @@ -10,8 +10,8 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include <cassert> #include <cstdint> #include <vector> @@ -21,47 +21,6 @@ namespace llvm { struct BaseAddress; class raw_ostream; -struct DWARFAddressRange { - uint64_t LowPC; - uint64_t HighPC; - uint64_t SectionIndex; - - DWARFAddressRange() = default; - - /// Used for unit testing. - DWARFAddressRange(uint64_t LowPC, uint64_t HighPC, uint64_t SectionIndex = 0) - : LowPC(LowPC), HighPC(HighPC), SectionIndex(SectionIndex) {} - - /// Returns true if LowPC is smaller or equal to HighPC. This accounts for - /// dead-stripped ranges. - bool valid() const { return LowPC <= HighPC; } - - /// Returns true if [LowPC, HighPC) intersects with [RHS.LowPC, RHS.HighPC). - bool intersects(const DWARFAddressRange &RHS) const { - // Empty ranges can't intersect. - if (LowPC == HighPC || RHS.LowPC == RHS.HighPC) - return false; - return (LowPC < RHS.HighPC) && (HighPC > RHS.LowPC); - } - - /// Returns true if [LowPC, HighPC) fully contains [RHS.LowPC, RHS.HighPC). - bool contains(const DWARFAddressRange &RHS) const { - if (LowPC <= RHS.LowPC && RHS.LowPC <= HighPC) - return LowPC <= RHS.HighPC && RHS.HighPC <= HighPC; - return false; - } -}; - -static inline bool operator<(const DWARFAddressRange &LHS, - const DWARFAddressRange &RHS) { - return std::tie(LHS.LowPC, LHS.HighPC) < std::tie(RHS.LowPC, RHS.HighPC); -} - -raw_ostream &operator<<(raw_ostream &OS, const DWARFAddressRange &R); - -/// DWARFAddressRangesVector - represents a set of absolute address ranges. -using DWARFAddressRangesVector = std::vector<DWARFAddressRange>; - class DWARFDebugRangeList { public: struct RangeListEntry { @@ -112,7 +71,7 @@ public: void clear(); void dump(raw_ostream &OS) const; - bool extract(const DWARFDataExtractor &data, uint32_t *offset_ptr); + Error extract(const DWARFDataExtractor &data, uint32_t *offset_ptr); const std::vector<RangeListEntry> &getEntries() { return Entries; } /// getAbsoluteRanges - Returns absolute address ranges defined by this range diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h b/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h new file mode 100644 index 000000000000..e2e8ab5ed219 --- /dev/null +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h @@ -0,0 +1,60 @@ +//===- DWARFDebugRnglists.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H +#define LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H + +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFListTable.h" +#include <cstdint> +#include <map> +#include <vector> + +namespace llvm { + +class Error; +class raw_ostream; + +/// A class representing a single range list entry. +struct RangeListEntry : public DWARFListEntryBase { + /// The values making up the range list entry. Most represent a range with + /// a start and end address or a start address and a length. Others are + /// single value base addresses or end-of-list with no values. The unneeded + /// values are semantically undefined, but initialized to 0. + uint64_t Value0; + uint64_t Value1; + + Error extract(DWARFDataExtractor Data, uint32_t End, uint32_t *OffsetPtr); + void dump(raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength, + uint64_t &CurrentBase, DIDumpOptions DumpOpts) const; + bool isSentinel() const { return EntryKind == dwarf::DW_RLE_end_of_list; } +}; + +/// A class representing a single rangelist. +class DWARFDebugRnglist : public DWARFListType<RangeListEntry> { +public: + /// Build a DWARFAddressRangesVector from a rangelist. + DWARFAddressRangesVector + getAbsoluteRanges(llvm::Optional<BaseAddress> BaseAddr) const; +}; + +class DWARFDebugRnglistTable : public DWARFListTableBase<DWARFDebugRnglist> { +public: + DWARFDebugRnglistTable() + : DWARFListTableBase(/* SectionName = */ ".debug_rnglists", + /* HeaderString = */ "ranges:", + /* ListTypeString = */ "range") {} +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDie.h b/include/llvm/DebugInfo/DWARF/DWARFDie.h index 75fc5995c5b2..6e6b57cbcbd4 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -16,9 +16,9 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFAttribute.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include <cassert> #include <cstdint> #include <iterator> @@ -104,12 +104,24 @@ public: /// invalid DWARFDie instance if it doesn't. DWARFDie getSibling() const; + /// Get the previous sibling of this DIE object. + /// + /// \returns a valid DWARFDie instance if this object has a sibling or an + /// invalid DWARFDie instance if it doesn't. + DWARFDie getPreviousSibling() const; + /// Get the first child of this DIE object. /// /// \returns a valid DWARFDie instance if this object has children or an /// invalid DWARFDie instance if it doesn't. DWARFDie getFirstChild() const; + /// Get the last child of this DIE object. + /// + /// \returns a valid null DWARFDie instance if this object has children or an + /// invalid DWARFDie instance if it doesn't. + DWARFDie getLastChild() const; + /// Dump the DIE and all of its attributes to the supplied stream. /// /// \param OS the stream to use for output. @@ -207,7 +219,7 @@ public: /// /// \returns a address range vector that might be empty if no address range /// information is available. - DWARFAddressRangesVector getAddressRanges() const; + Expected<DWARFAddressRangesVector> getAddressRanges() const; /// Get all address ranges for any DW_TAG_subprogram DIEs in this DIE or any /// of its children. @@ -288,6 +300,7 @@ public: explicit attribute_iterator(DWARFDie D, bool End); attribute_iterator &operator++(); + attribute_iterator &operator--(); explicit operator bool() const { return AttrValue.isValid(); } const DWARFAttribute &operator*() const { return AttrValue; } bool operator==(const attribute_iterator &X) const { return Index == X.Index; } @@ -306,26 +319,23 @@ inline bool operator<(const DWARFDie &LHS, const DWARFDie &RHS) { return LHS.getOffset() < RHS.getOffset(); } -class DWARFDie::iterator : public iterator_facade_base<iterator, - std::forward_iterator_tag, - const DWARFDie> { +class DWARFDie::iterator + : public iterator_facade_base<iterator, std::bidirectional_iterator_tag, + const DWARFDie> { DWARFDie Die; - void skipNull() { - if (Die && Die.isNULL()) - Die = DWARFDie(); - } public: iterator() = default; explicit iterator(DWARFDie D) : Die(D) { - // If we start out with only a Null DIE then invalidate. - skipNull(); } iterator &operator++() { Die = Die.getSibling(); - // Don't include the NULL die when iterating. - skipNull(); + return *this; + } + + iterator &operator--() { + Die = Die.getPreviousSibling(); return *this; } @@ -341,7 +351,7 @@ inline DWARFDie::iterator DWARFDie::begin() const { } inline DWARFDie::iterator DWARFDie::end() const { - return iterator(); + return iterator(getLastChild()); } inline iterator_range<DWARFDie::iterator> DWARFDie::children() const { diff --git a/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/include/llvm/DebugInfo/DWARF/DWARFExpression.h index dcd486f3fb13..3fad68a9b48b 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFExpression.h +++ b/include/llvm/DebugInfo/DWARF/DWARFExpression.h @@ -93,12 +93,13 @@ public: /// An iterator to go through the expression operations. class iterator - : public iterator_facade_base<iterator, std::forward_iterator_tag, Operation> { + : public iterator_facade_base<iterator, std::forward_iterator_tag, + Operation> { friend class DWARFExpression; - DWARFExpression *Expr; + const DWARFExpression *Expr; uint32_t Offset; Operation Op; - iterator(DWARFExpression *Expr, uint32_t Offset) + iterator(const DWARFExpression *Expr, uint32_t Offset) : Expr(Expr), Offset(Offset) { Op.Error = Offset >= Expr->Data.getData().size() || @@ -127,10 +128,11 @@ public: assert(AddressSize == 8 || AddressSize == 4); } - iterator begin() { return iterator(this, 0); } - iterator end() { return iterator(this, Data.getData().size()); } + iterator begin() const { return iterator(this, 0); } + iterator end() const { return iterator(this, Data.getData().size()); } - void print(raw_ostream &OS, const MCRegisterInfo *RegInfo); + void print(raw_ostream &OS, const MCRegisterInfo *RegInfo, + bool IsEH = false) const; private: DataExtractor Data; diff --git a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index d32053519ec4..1b5f71c946f9 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -20,38 +20,10 @@ namespace llvm { +class DWARFContext; class DWARFUnit; class raw_ostream; -/// A helper struct for DWARFFormValue methods, providing information that -/// allows it to know the byte size of DW_FORM values that vary in size -/// depending on the DWARF version, address byte size, or DWARF32/DWARF64. -struct DWARFFormParams { - uint16_t Version; - uint8_t AddrSize; - dwarf::DwarfFormat Format; - - /// The definition of the size of form DW_FORM_ref_addr depends on the - /// version. In DWARF v2 it's the size of an address; after that, it's the - /// size of a reference. - uint8_t getRefAddrByteSize() const { - if (Version == 2) - return AddrSize; - return getDwarfOffsetByteSize(); - } - - /// The size of a reference is determined by the DWARF 32/64-bit format. - uint8_t getDwarfOffsetByteSize() const { - switch (Format) { - case dwarf::DwarfFormat::DWARF32: - return 4; - case dwarf::DwarfFormat::DWARF64: - return 8; - } - llvm_unreachable("Invalid Format value"); - } -}; - class DWARFFormValue { public: enum FormClass { @@ -83,7 +55,7 @@ private: dwarf::Form Form; /// Form for this value. ValueType Value; /// Contains all data for the form. const DWARFUnit *U = nullptr; /// Remember the DWARFUnit at extract time. - + const DWARFContext *C = nullptr; /// Context for extract time. public: DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {} @@ -106,10 +78,17 @@ public: /// Extracts a value in \p Data at offset \p *OffsetPtr. The information /// in \p FormParams is needed to interpret some forms. The optional - /// \p Unit allows extracting information if the form refers to other - /// sections (e.g., .debug_str). + /// \p Context and \p Unit allows extracting information if the form refers + /// to other sections (e.g., .debug_str). bool extractValue(const DWARFDataExtractor &Data, uint32_t *OffsetPtr, - DWARFFormParams FormParams, const DWARFUnit *U = nullptr); + dwarf::FormParams FormParams, + const DWARFContext *Context = nullptr, + const DWARFUnit *Unit = nullptr); + + bool extractValue(const DWARFDataExtractor &Data, uint32_t *OffsetPtr, + dwarf::FormParams FormParams, const DWARFUnit *U) { + return extractValue(Data, OffsetPtr, FormParams, nullptr, U); + } bool isInlinedCStr() const { return Value.data != nullptr && Value.data == (const uint8_t *)Value.cstr; @@ -127,19 +106,6 @@ public: Optional<uint64_t> getAsCStringOffset() const; Optional<uint64_t> getAsReferenceUVal() const; - /// Get the fixed byte size for a given form. - /// - /// If the form has a fixed byte size, then an Optional with a value will be - /// returned. If the form is always encoded using a variable length storage - /// format (ULEB or SLEB numbers or blocks) then None will be returned. - /// - /// \param Form DWARF form to get the fixed byte size for. - /// \param FormParams DWARF parameters to help interpret forms. - /// \returns Optional<uint8_t> value with the fixed byte size or None if - /// \p Form doesn't have a fixed byte size. - static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, - const DWARFFormParams FormParams); - /// Skip a form's value in \p DebugInfoData at the offset specified by /// \p OffsetPtr. /// @@ -150,7 +116,7 @@ public: /// \param Params DWARF parameters to help interpret forms. /// \returns true on success, false if the form was not skipped. bool skipValue(DataExtractor DebugInfoData, uint32_t *OffsetPtr, - const DWARFFormParams Params) const { + const dwarf::FormParams Params) const { return DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, Params); } @@ -165,7 +131,8 @@ public: /// \param FormParams DWARF parameters to help interpret forms. /// \returns true on success, false if the form was not skipped. static bool skipValue(dwarf::Form Form, DataExtractor DebugInfoData, - uint32_t *OffsetPtr, const DWARFFormParams FormParams); + uint32_t *OffsetPtr, + const dwarf::FormParams FormParams); private: void dumpString(raw_ostream &OS) const; diff --git a/include/llvm/DebugInfo/DWARF/DWARFListTable.h b/include/llvm/DebugInfo/DWARF/DWARFListTable.h new file mode 100644 index 000000000000..ab12f3bc08b0 --- /dev/null +++ b/include/llvm/DebugInfo/DWARF/DWARFListTable.h @@ -0,0 +1,278 @@ +//===- DWARFListTable.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFLISTTABLE_H +#define LLVM_DEBUGINFO_DWARFLISTTABLE_H + +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdint> +#include <map> +#include <vector> + +namespace llvm { + +/// A base class for DWARF list entries, such as range or location list +/// entries. +struct DWARFListEntryBase { + /// The offset at which the entry is located in the section. + uint32_t Offset; + /// The DWARF encoding (DW_RLE_* or DW_LLE_*). + uint8_t EntryKind; + /// The index of the section this entry belongs to. + uint64_t SectionIndex; +}; + +/// A base class for lists of entries that are extracted from a particular +/// section, such as range lists or location lists. +template <typename ListEntryType> class DWARFListType { + using EntryType = ListEntryType; + using ListEntries = std::vector<EntryType>; + +protected: + ListEntries Entries; + +public: + // FIXME: We need to consolidate the various verions of "createError" + // that are used in the DWARF consumer. Until then, this is a workaround. + Error createError(const char *, const char *, uint32_t); + + const ListEntries &getEntries() const { return Entries; } + bool empty() const { return Entries.empty(); } + void clear() { Entries.clear(); } + Error extract(DWARFDataExtractor Data, uint32_t HeaderOffset, uint32_t End, + uint32_t *OffsetPtr, StringRef SectionName, + StringRef ListStringName); +}; + +/// A class representing the header of a list table such as the range list +/// table in the .debug_rnglists section. +class DWARFListTableHeader { + struct Header { + /// The total length of the entries for this table, not including the length + /// field itself. + uint32_t Length = 0; + /// The DWARF version number. + uint16_t Version; + /// The size in bytes of an address on the target architecture. For + /// segmented addressing, this is the size of the offset portion of the + /// address. + uint8_t AddrSize; + /// The size in bytes of a segment selector on the target architecture. + /// If the target system uses a flat address space, this value is 0. + uint8_t SegSize; + /// The number of offsets that follow the header before the range lists. + uint32_t OffsetEntryCount; + }; + + Header HeaderData; + /// The offset table, which contains offsets to the individual list entries. + /// It is used by forms such as DW_FORM_rnglistx. + /// FIXME: Generate the table and use the appropriate forms. + std::vector<uint32_t> Offsets; + /// The table's format, either DWARF32 or DWARF64. + dwarf::DwarfFormat Format; + /// The offset at which the header (and hence the table) is located within + /// its section. + uint32_t HeaderOffset; + /// The name of the section the list is located in. + StringRef SectionName; + /// A characterization of the list for dumping purposes, e.g. "range" or + /// "location". + StringRef ListTypeString; + +public: + DWARFListTableHeader(StringRef SectionName, StringRef ListTypeString) + : SectionName(SectionName), ListTypeString(ListTypeString) {} + + void clear() { + HeaderData = {}; + Offsets.clear(); + } + uint32_t getHeaderOffset() const { return HeaderOffset; } + uint8_t getAddrSize() const { return HeaderData.AddrSize; } + uint32_t getLength() const { return HeaderData.Length; } + StringRef getSectionName() const { return SectionName; } + StringRef getListTypeString() const { return ListTypeString; } + dwarf::DwarfFormat getFormat() const { return Format; } + + void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const; + Optional<uint32_t> getOffsetEntry(uint32_t Index) const { + if (Index < Offsets.size()) + return Offsets[Index]; + return None; + } + + /// Extract the table header and the array of offsets. + Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr); + + /// Returns the length of the table, including the length field, or 0 if the + /// length has not been determined (e.g. because the table has not yet been + /// parsed, or there was a problem in parsing). + uint32_t length() const; +}; + +/// A class representing a table of lists as specified in the DWARF v5 +/// standard for location lists and range lists. The table consists of a header +/// followed by an array of offsets into a DWARF section, followed by zero or +/// more list entries. The list entries are kept in a map where the keys are +/// the lists' section offsets. +template <typename DWARFListType> class DWARFListTableBase { + DWARFListTableHeader Header; + /// A mapping between file offsets and lists. It is used to find a particular + /// list based on an offset (obtained from DW_AT_ranges, for example). + std::map<uint32_t, DWARFListType> ListMap; + /// This string is displayed as a heading before the list is dumped + /// (e.g. "ranges:"). + StringRef HeaderString; + +protected: + DWARFListTableBase(StringRef SectionName, StringRef HeaderString, + StringRef ListTypeString) + : Header(SectionName, ListTypeString), HeaderString(HeaderString) {} + +public: + void clear() { + Header.clear(); + ListMap.clear(); + } + /// Extract the table header and the array of offsets. + Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t *OffsetPtr) { + return Header.extract(Data, OffsetPtr); + } + /// Extract an entire table, including all list entries. + Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr); + /// Look up a list based on a given offset. Extract it and enter it into the + /// list map if necessary. + Expected<DWARFListType> findList(DWARFDataExtractor Data, uint32_t Offset); + + uint32_t getHeaderOffset() const { return Header.getHeaderOffset(); } + uint8_t getAddrSize() const { return Header.getAddrSize(); } + + void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const; + + /// Return the contents of the offset entry designated by a given index. + Optional<uint32_t> getOffsetEntry(uint32_t Index) const { + return Header.getOffsetEntry(Index); + } + /// Return the size of the table header including the length but not including + /// the offsets. This is dependent on the table format, which is unambiguously + /// derived from parsing the table. + uint8_t getHeaderSize() const { + switch (Header.getFormat()) { + case dwarf::DwarfFormat::DWARF32: + return 12; + case dwarf::DwarfFormat::DWARF64: + return 20; + } + llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64"); + } + + uint32_t length() { return Header.length(); } +}; + +template <typename DWARFListType> +Error DWARFListTableBase<DWARFListType>::extract(DWARFDataExtractor Data, + uint32_t *OffsetPtr) { + clear(); + if (Error E = extractHeaderAndOffsets(Data, OffsetPtr)) + return E; + + Data.setAddressSize(Header.getAddrSize()); + uint32_t End = getHeaderOffset() + Header.length(); + while (*OffsetPtr < End) { + DWARFListType CurrentList; + uint32_t Off = *OffsetPtr; + if (Error E = CurrentList.extract(Data, getHeaderOffset(), End, OffsetPtr, + Header.getSectionName(), + Header.getListTypeString())) + return E; + ListMap[Off] = CurrentList; + } + + assert(*OffsetPtr == End && + "mismatch between expected length of table and length " + "of extracted data"); + return Error::success(); +} + +template <typename ListEntryType> +Error DWARFListType<ListEntryType>::extract(DWARFDataExtractor Data, + uint32_t HeaderOffset, uint32_t End, + uint32_t *OffsetPtr, + StringRef SectionName, + StringRef ListTypeString) { + if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End) + return createError("invalid %s list offset 0x%" PRIx32, + ListTypeString.data(), *OffsetPtr); + Entries.clear(); + while (*OffsetPtr < End) { + ListEntryType Entry; + if (Error E = Entry.extract(Data, End, OffsetPtr)) + return E; + Entries.push_back(Entry); + if (Entry.isSentinel()) + return Error::success(); + } + return createError("no end of list marker detected at end of %s table " + "starting at offset 0x%" PRIx32, + SectionName.data(), HeaderOffset); +} + +template <typename DWARFListType> +void DWARFListTableBase<DWARFListType>::dump(raw_ostream &OS, + DIDumpOptions DumpOpts) const { + Header.dump(OS, DumpOpts); + OS << HeaderString << "\n"; + + // Determine the length of the longest encoding string we have in the table, + // so we can align the output properly. We only need this in verbose mode. + size_t MaxEncodingStringLength = 0; + if (DumpOpts.Verbose) { + for (const auto &List : ListMap) + for (const auto &Entry : List.second.getEntries()) + MaxEncodingStringLength = + std::max(MaxEncodingStringLength, + dwarf::RangeListEncodingString(Entry.EntryKind).size()); + } + + uint64_t CurrentBase = 0; + for (const auto &List : ListMap) + for (const auto &Entry : List.second.getEntries()) + Entry.dump(OS, getAddrSize(), MaxEncodingStringLength, CurrentBase, + DumpOpts); +} + +template <typename DWARFListType> +Expected<DWARFListType> +DWARFListTableBase<DWARFListType>::findList(DWARFDataExtractor Data, + uint32_t Offset) { + auto Entry = ListMap.find(Offset); + if (Entry != ListMap.end()) + return Entry->second; + + // Extract the list from the section and enter it into the list map. + DWARFListType List; + uint32_t End = getHeaderOffset() + Header.length(); + uint32_t StartingOffset = Offset; + if (Error E = + List.extract(Data, getHeaderOffset(), End, &Offset, + Header.getSectionName(), Header.getListTypeString())) + return std::move(E); + ListMap[StartingOffset] = List; + return List; +} + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFLISTTABLE_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFObject.h b/include/llvm/DebugInfo/DWARF/DWARFObject.h index 167eb2da5ba0..6e8f370f4aea 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFObject.h +++ b/include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -42,8 +42,10 @@ public: virtual StringRef getDebugFrameSection() const { return ""; } virtual StringRef getEHFrameSection() const { return ""; } virtual const DWARFSection &getLineSection() const { return Dummy; } + virtual StringRef getLineStringSection() const { return ""; } virtual StringRef getStringSection() const { return ""; } virtual const DWARFSection &getRangeSection() const { return Dummy; } + virtual const DWARFSection &getRnglistsSection() const { return Dummy; } virtual StringRef getMacinfoSection() const { return ""; } virtual StringRef getPubNamesSection() const { return ""; } virtual StringRef getPubTypesSection() const { return ""; } @@ -61,12 +63,14 @@ public: return Dummy; } virtual const DWARFSection &getRangeDWOSection() const { return Dummy; } + virtual const DWARFSection &getRnglistsDWOSection() const { return Dummy; } virtual const DWARFSection &getAddrSection() const { return Dummy; } virtual const DWARFSection &getAppleNamesSection() const { return Dummy; } virtual const DWARFSection &getAppleTypesSection() const { return Dummy; } virtual const DWARFSection &getAppleNamespacesSection() const { return Dummy; } + virtual const DWARFSection &getDebugNamesSection() const { return Dummy; } virtual const DWARFSection &getAppleObjCSection() const { return Dummy; } virtual StringRef getCUIndexSection() const { return ""; } virtual StringRef getGdbIndexSection() const { return ""; } diff --git a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h index a7842454f435..cb5a78ee3dbf 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -24,29 +24,21 @@ struct DWARFSection; class raw_ostream; class DWARFTypeUnit : public DWARFUnit { -private: - uint64_t TypeHash; - uint32_t TypeOffset; - public: DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, - const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, - UnitSection, Entry) {} + const DWARFUnitSectionBase &UnitSection) + : DWARFUnit(Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection) {} - uint32_t getHeaderSize() const override { - return DWARFUnit::getHeaderSize() + 12; - } + uint64_t getTypeHash() const { return getHeader().getTypeHash(); } + uint32_t getTypeOffset() const { return getHeader().getTypeOffset(); } void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}); static const DWARFSectionKind Section = DW_SECT_TYPES; - -protected: - bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) override; }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h index 3cec58383f87..988a7958184c 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -18,6 +18,7 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" @@ -40,6 +41,66 @@ class DWARFContext; class DWARFDebugAbbrev; class DWARFUnit; +/// Base class describing the header of any kind of "unit." Some information +/// is specific to certain unit types. We separate this class out so we can +/// parse the header before deciding what specific kind of unit to construct. +class DWARFUnitHeader { + // Offset within section. + uint32_t Offset = 0; + // Version, address size, and DWARF format. + dwarf::FormParams FormParams; + uint32_t Length = 0; + uint64_t AbbrOffset = 0; + + // For DWO units only. + const DWARFUnitIndex::Entry *IndexEntry = nullptr; + + // For type units only. + uint64_t TypeHash = 0; + uint32_t TypeOffset = 0; + + // For v5 split or skeleton compile units only. + Optional<uint64_t> DWOId; + + // Unit type as parsed, or derived from the section kind. + uint8_t UnitType = 0; + + // Size as parsed. uint8_t for compactness. + uint8_t Size = 0; + +public: + /// Parse a unit header from \p debug_info starting at \p offset_ptr. + bool extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, + uint32_t *offset_ptr, DWARFSectionKind Kind = DW_SECT_INFO, + const DWARFUnitIndex *Index = nullptr); + uint32_t getOffset() const { return Offset; } + const dwarf::FormParams &getFormParams() const { return FormParams; } + uint16_t getVersion() const { return FormParams.Version; } + dwarf::DwarfFormat getFormat() const { return FormParams.Format; } + uint8_t getAddressByteSize() const { return FormParams.AddrSize; } + uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); } + uint8_t getDwarfOffsetByteSize() const { + return FormParams.getDwarfOffsetByteSize(); + } + uint32_t getLength() const { return Length; } + uint64_t getAbbrOffset() const { return AbbrOffset; } + Optional<uint64_t> getDWOId() const { return DWOId; } + void setDWOId(uint64_t Id) { + assert((!DWOId || *DWOId == Id) && "setting DWOId to a different value"); + DWOId = Id; + } + const DWARFUnitIndex::Entry *getIndexEntry() const { return IndexEntry; } + uint64_t getTypeHash() const { return TypeHash; } + uint32_t getTypeOffset() const { return TypeOffset; } + uint8_t getUnitType() const { return UnitType; } + bool isTypeUnit() const { + return UnitType == dwarf::DW_UT_type || UnitType == dwarf::DW_UT_split_type; + } + uint8_t getSize() const { return Size; } + // FIXME: Support DWARF64. + uint32_t getNextUnitOffset() const { return Offset + Length + 4; } +}; + /// Base class for all DWARFUnitSection classes. This provides the /// functionality common to all unit types. class DWARFUnitSectionBase { @@ -56,7 +117,8 @@ public: protected: ~DWARFUnitSectionBase() = default; - virtual void parseImpl(DWARFContext &Context, const DWARFSection &Section, + virtual void parseImpl(DWARFContext &Context, const DWARFObject &Obj, + const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, @@ -116,14 +178,14 @@ public: } private: - void parseImpl(DWARFContext &Context, const DWARFSection &Section, - const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, - const DWARFSection &LS, bool LE, bool IsDWO, - bool Lazy) override { + void parseImpl(DWARFContext &Context, const DWARFObject &Obj, + const DWARFSection &Section, const DWARFDebugAbbrev *DA, + const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, const DWARFSection &LS, bool LE, + bool IsDWO, bool Lazy) override { if (Parsed) return; - DataExtractor Data(Section.Data, LE, 0); + DWARFDataExtractor Data(Obj, Section, LE, 0); if (!Parser) { const DWARFUnitIndex *Index = nullptr; if (IsDWO) @@ -132,11 +194,12 @@ private: &LS](uint32_t Offset) -> std::unique_ptr<UnitType> { if (!Data.isValidOffset(Offset)) return nullptr; - auto U = llvm::make_unique<UnitType>( - Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, *this, - Index ? Index->getFromOffset(Offset) : nullptr); - if (!U->extract(Data, &Offset)) + DWARFUnitHeader Header; + if (!Header.extract(Context, Data, &Offset, UnitType::Section, Index)) return nullptr; + auto U = llvm::make_unique<UnitType>( + Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + *this); return U; }; } @@ -168,9 +231,10 @@ struct BaseAddress { /// Represents a unit's contribution to the string offsets table. struct StrOffsetsContributionDescriptor { uint64_t Base = 0; + /// The contribution size not including the header. uint64_t Size = 0; /// Format and version. - DWARFFormParams FormParams = {0, 0, dwarf::DwarfFormat::DWARF32}; + dwarf::FormParams FormParams = {0, 0, dwarf::DwarfFormat::DWARF32}; StrOffsetsContributionDescriptor(uint64_t Base, uint64_t Size, uint8_t Version, dwarf::DwarfFormat Format) @@ -193,6 +257,7 @@ class DWARFUnit { /// Section containing this DWARFUnit. const DWARFSection &InfoSection; + DWARFUnitHeader Header; const DWARFDebugAbbrev *Abbrev; const DWARFSection *RangeSection; uint32_t RangeSectionBase; @@ -205,63 +270,28 @@ class DWARFUnit { bool isDWO; const DWARFUnitSectionBase &UnitSection; - // Version, address size, and DWARF format. - DWARFFormParams FormParams; /// Start, length, and DWARF format of the unit's contribution to the string /// offsets table (DWARF v5). Optional<StrOffsetsContributionDescriptor> StringOffsetsTableContribution; - uint32_t Offset; - uint32_t Length; + /// A table of range lists (DWARF v5 and later). + Optional<DWARFDebugRnglistTable> RngListTable; + mutable const DWARFAbbreviationDeclarationSet *Abbrevs; - uint64_t AbbrOffset; - uint8_t UnitType; llvm::Optional<BaseAddress> BaseAddr; /// The compile unit debug information entry items. std::vector<DWARFDebugInfoEntry> DieArray; - /// The vector of inlined subroutine DIEs that we can map directly to from - /// their subprogram below. - std::vector<DWARFDie> InlinedSubroutineDIEs; - - /// A type representing a subprogram DIE and a map (built using a sorted - /// vector) into that subprogram's inlined subroutine DIEs. - struct SubprogramDIEAddrInfo { - DWARFDie SubprogramDIE; - - uint64_t SubprogramBasePC; - - /// A vector sorted to allow mapping from a relative PC to the inlined - /// subroutine DIE with the most specific address range covering that PC. - /// - /// The PCs are relative to the `SubprogramBasePC`. - /// - /// The vector is sorted in ascending order of the first int which - /// represents the relative PC for an interval in the map. The second int - /// represents the index into the `InlinedSubroutineDIEs` vector of the DIE - /// that interval maps to. An index of '-1` indicates an empty mapping. The - /// interval covered is from the `.first` relative PC to the next entry's - /// `.first` relative PC. - std::vector<std::pair<uint32_t, int32_t>> InlinedSubroutineDIEAddrMap; - }; - - /// Vector of the subprogram DIEs and their subroutine address maps. - std::vector<SubprogramDIEAddrInfo> SubprogramDIEAddrInfos; - - /// A vector sorted to allow mapping from a PC to the subprogram DIE (and - /// associated addr map) index. Subprograms with overlapping PC ranges aren't - /// supported here. Nothing will crash, but the mapping may be inaccurate. - /// This vector may also contain "empty" ranges marked by an address with - /// a DIE index of '-1'. - std::vector<std::pair<uint64_t, int64_t>> SubprogramDIEAddrMap; + /// Map from range's start address to end address and corresponding DIE. + /// IntervalMap does not support range removal, as a result, we use the + /// std::map::upper_bound for address range lookup. + std::map<uint64_t, std::pair<uint64_t, DWARFDie>> AddrDieMap; using die_iterator_range = iterator_range<std::vector<DWARFDebugInfoEntry>::iterator>; std::shared_ptr<DWARFUnit> DWO; - const DWARFUnitIndex::Entry *IndexEntry; - uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) { auto First = DieArray.data(); assert(Die >= First && Die < First + DieArray.size()); @@ -269,10 +299,10 @@ class DWARFUnit { } protected: - virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr); + const DWARFUnitHeader &getHeader() const { return Header; } - /// Size in bytes of the unit header. - virtual uint32_t getHeaderSize() const { return getVersion() <= 4 ? 11 : 12; } + /// Size in bytes of the parsed unit header. + uint32_t getHeaderSize() const { return Header.getSize(); } /// Find the unit's contribution to the string offsets table and determine its /// length and form. The given offset is expected to be derived from the unit @@ -291,16 +321,28 @@ protected: public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, - const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *IndexEntry = nullptr); + const DWARFUnitSectionBase &UnitSection); virtual ~DWARFUnit(); DWARFContext& getContext() const { return Context; } - + uint32_t getOffset() const { return Header.getOffset(); } + const dwarf::FormParams &getFormParams() const { + return Header.getFormParams(); + } + uint16_t getVersion() const { return Header.getVersion(); } + uint8_t getAddressByteSize() const { return Header.getAddressByteSize(); } + uint8_t getRefAddrByteSize() const { return Header.getRefAddrByteSize(); } + uint8_t getDwarfOffsetByteSize() const { + return Header.getDwarfOffsetByteSize(); + } + uint32_t getLength() const { return Header.getLength(); } + uint8_t getUnitType() const { return Header.getUnitType(); } + uint32_t getNextUnitOffset() const { return Header.getNextUnitOffset(); } const DWARFSection &getLineSection() const { return LineSection; } StringRef getStringSection() const { return StringSection; } const DWARFSection &getStringOffsetSection() const { @@ -312,6 +354,9 @@ public: AddrOffsetSectionBase = Base; } + /// Recursively update address to Die map. + void updateAddressDieMap(DWARFDie Die); + void setRangesSection(const DWARFSection *RS, uint32_t Base) { RangeSection = RS; RangeSectionBase = Base; @@ -326,31 +371,18 @@ public: return DataExtractor(StringSection, false, 0); } - - bool extract(DataExtractor debug_info, uint32_t* offset_ptr); - - /// extractRangeList - extracts the range list referenced by this compile - /// unit from .debug_ranges section. Returns true on success. - /// Requires that compile unit is already extracted. - bool extractRangeList(uint32_t RangeListOffset, - DWARFDebugRangeList &RangeList) const; + /// Extract the range list referenced by this compile unit from the + /// .debug_ranges section. If the extraction is unsuccessful, an error + /// is returned. Successful extraction requires that the compile unit + /// has already been extracted. + Error extractRangeList(uint32_t RangeListOffset, + DWARFDebugRangeList &RangeList) const; void clear(); - uint32_t getOffset() const { return Offset; } - uint32_t getNextUnitOffset() const { return Offset + Length + 4; } - uint32_t getLength() const { return Length; } const Optional<StrOffsetsContributionDescriptor> & getStringOffsetsTableContribution() const { return StringOffsetsTableContribution; } - const DWARFFormParams &getFormParams() const { return FormParams; } - uint16_t getVersion() const { return FormParams.Version; } - dwarf::DwarfFormat getFormat() const { return FormParams.Format; } - uint8_t getAddressByteSize() const { return FormParams.AddrSize; } - uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); } - uint8_t getDwarfOffsetByteSize() const { - return FormParams.getDwarfOffsetByteSize(); - } uint8_t getDwarfStringOffsetsByteSize() const { assert(StringOffsetsTableContribution); @@ -364,8 +396,6 @@ public: const DWARFAbbreviationDeclarationSet *getAbbreviations() const; - uint8_t getUnitType() const { return UnitType; } - static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) { switch (UnitType) { case dwarf::DW_UT_compile: @@ -383,7 +413,7 @@ public: return false; } - /// \brief Return the number of bytes for the header of a unit of + /// Return the number of bytes for the header of a unit of /// UnitType type. /// /// This function must be called with a valid unit type which in @@ -403,9 +433,7 @@ public: llvm_unreachable("Invalid UnitType."); } - llvm::Optional<BaseAddress> getBaseAddress() const { return BaseAddr; } - - void setBaseAddress(BaseAddress BaseAddr) { this->BaseAddr = BaseAddr; } + llvm::Optional<BaseAddress> getBaseAddress(); DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) { extractDIEsIfNeeded(ExtractUnitDIEOnly); @@ -415,7 +443,29 @@ public: } const char *getCompilationDir(); - Optional<uint64_t> getDWOId(); + Optional<uint64_t> getDWOId() { + extractDIEsIfNeeded(/*CUDieOnly*/ true); + return getHeader().getDWOId(); + } + void setDWOId(uint64_t NewID) { Header.setDWOId(NewID); } + + /// Return a vector of address ranges resulting from a (possibly encoded) + /// range list starting at a given offset in the appropriate ranges section. + Expected<DWARFAddressRangesVector> findRnglistFromOffset(uint32_t Offset); + + /// Return a vector of address ranges retrieved from an encoded range + /// list whose offset is found via a table lookup given an index (DWARF v5 + /// and later). + Expected<DWARFAddressRangesVector> findRnglistFromIndex(uint32_t Index); + + /// Return a rangelist's offset based on an index. The index designates + /// an entry in the rangelist table's offset array and is supplied by + /// DW_FORM_rnglistx. + Optional<uint32_t> getRnglistOffset(uint32_t Index) { + if (RngListTable) + return RngListTable->getOffsetEntry(Index); + return None; + } void collectAddressRanges(DWARFAddressRangesVector &CURanges); @@ -433,14 +483,14 @@ public: /// getUnitSection - Return the DWARFUnitSection containing this unit. const DWARFUnitSectionBase &getUnitSection() const { return UnitSection; } - /// \brief Returns the number of DIEs in the unit. Parses the unit + /// Returns the number of DIEs in the unit. Parses the unit /// if necessary. unsigned getNumDIEs() { extractDIEsIfNeeded(false); return DieArray.size(); } - /// \brief Return the index of a DIE inside the unit's DIE vector. + /// Return the index of a DIE inside the unit's DIE vector. /// /// It is illegal to call this method with a DIE that hasn't be /// created by this unit. In other word, it's illegal to call this @@ -450,7 +500,7 @@ public: return getDIEIndex(D.getDebugInfoEntry()); } - /// \brief Return the DIE object at the given index. + /// Return the DIE object at the given index. DWARFDie getDIEAtIndex(unsigned Index) { assert(Index < DieArray.size()); return DWARFDie(this, &DieArray[Index]); @@ -458,9 +508,11 @@ public: DWARFDie getParent(const DWARFDebugInfoEntry *Die); DWARFDie getSibling(const DWARFDebugInfoEntry *Die); + DWARFDie getPreviousSibling(const DWARFDebugInfoEntry *Die); DWARFDie getFirstChild(const DWARFDebugInfoEntry *Die); + DWARFDie getLastChild(const DWARFDebugInfoEntry *Die); - /// \brief Return the DIE object for a given offset inside the + /// Return the DIE object for a given offset inside the /// unit's DIE vector. /// /// The unit needs to have its DIEs extracted for this method to work. @@ -478,7 +530,7 @@ public: } uint32_t getLineTableOffset() const { - if (IndexEntry) + if (auto IndexEntry = Header.getIndexEntry()) if (const auto *Contrib = IndexEntry->getOffset(DW_SECT_LINE)) return Contrib->Offset; return 0; @@ -491,7 +543,9 @@ public: private: /// Size in bytes of the .debug_info data associated with this compile unit. - size_t getDebugInfoSize() const { return Length + 4 - getHeaderSize(); } + size_t getDebugInfoSize() const { + return Header.getLength() + 4 - getHeaderSize(); + } /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it /// hasn't already been done. Returns the number of DIEs parsed at this call. @@ -507,9 +561,6 @@ private: /// parseDWO - Parses .dwo file for current compile unit. Returns true if /// it was actually constructed. bool parseDWO(); - - void buildSubprogramDIEAddrMap(); - void buildInlinedSubroutineDIEAddrMap(SubprogramDIEAddrInfo &SPInfo); }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h index 0d920abe3231..a829510a219d 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -11,7 +11,8 @@ #define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H #include "llvm/DebugInfo/DIContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include <cstdint> @@ -24,7 +25,7 @@ struct DWARFAttribute; class DWARFContext; class DWARFDie; class DWARFUnit; -class DWARFAcceleratorTable; +class DWARFCompileUnit; class DWARFDataExtractor; class DWARFDebugAbbrev; class DataExtractor; @@ -109,7 +110,7 @@ private: /// \param Abbrev Pointer to the abbreviations section we are verifying /// Abbrev can be a pointer to either .debug_abbrev or debug_abbrev.dwo. /// - /// \returns The number of errors that occured during verification. + /// \returns The number of errors that occurred during verification. unsigned verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev); /// Verifies the header of a unit in the .debug_info section. @@ -151,14 +152,14 @@ private: /// type of the unit DIE. /// /// \returns true if the content is verified successfully, false otherwise. - bool verifyUnitContents(DWARFUnit Unit, uint8_t UnitType = 0); + bool verifyUnitContents(DWARFUnit &Unit, uint8_t UnitType = 0); /// Verify that all Die ranges are valid. /// /// This function currently checks for: /// - cases in which lowPC >= highPC /// - /// \returns Number of errors that occured during verification. + /// \returns Number of errors that occurred during verification. unsigned verifyDieRanges(const DWARFDie &Die, DieRangeInfo &ParentRI); /// Verifies the attribute's DWARF attribute and its value. @@ -170,7 +171,7 @@ private: /// \param Die The DWARF DIE that owns the attribute value /// \param AttrValue The DWARF attribute value to check /// - /// \returns NumErrors The number of errors occured during verification of + /// \returns NumErrors The number of errors occurred during verification of /// attributes' values in a .debug_info section unit unsigned verifyDebugInfoAttribute(const DWARFDie &Die, DWARFAttribute &AttrValue); @@ -185,7 +186,7 @@ private: /// \param Die The DWARF DIE that owns the attribute value /// \param AttrValue The DWARF attribute value to check /// - /// \returns NumErrors The number of errors occured during verification of + /// \returns NumErrors The number of errors occurred during verification of /// attributes' forms in a .debug_info section unit unsigned verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue); @@ -197,11 +198,11 @@ private: /// around, that it doesn't create invalid references by failing to relocate /// CU relative and absolute references. /// - /// \returns NumErrors The number of errors occured during verification of + /// \returns NumErrors The number of errors occurred during verification of /// references for the .debug_info section unsigned verifyDebugInfoReferences(); - /// Verify the the DW_AT_stmt_list encoding and value and ensure that no + /// Verify the DW_AT_stmt_list encoding and value and ensure that no /// compile units that have the same DW_AT_stmt_list value. void verifyDebugLineStmtOffsets(); @@ -228,9 +229,42 @@ private: /// \param StrData pointer to the string section /// \param SectionName the name of the table we're verifying /// - /// \returns The number of errors occured during verification - unsigned verifyAccelTable(const DWARFSection *AccelSection, - DataExtractor *StrData, const char *SectionName); + /// \returns The number of errors occurred during verification + unsigned verifyAppleAccelTable(const DWARFSection *AccelSection, + DataExtractor *StrData, + const char *SectionName); + + unsigned verifyDebugNamesCULists(const DWARFDebugNames &AccelTable); + unsigned verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI, + const DataExtractor &StrData); + unsigned verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI); + unsigned verifyNameIndexAttribute(const DWARFDebugNames::NameIndex &NI, + const DWARFDebugNames::Abbrev &Abbr, + DWARFDebugNames::AttributeEncoding AttrEnc); + unsigned verifyNameIndexEntries(const DWARFDebugNames::NameIndex &NI, + const DWARFDebugNames::NameTableEntry &NTE); + unsigned verifyNameIndexCompleteness(const DWARFDie &Die, + const DWARFDebugNames::NameIndex &NI); + + /// Verify that the DWARF v5 accelerator table is valid. + /// + /// This function currently checks that: + /// - Headers individual Name Indices fit into the section and can be parsed. + /// - Abbreviation tables can be parsed and contain valid index attributes + /// with correct form encodings. + /// - The CU lists reference existing compile units. + /// - The buckets have a valid index, or they are empty. + /// - All names are reachable via the hash table (they have the correct hash, + /// and the hash is in the correct bucket). + /// - Information in the index entries is complete (all required entries are + /// present) and consistent with the debug_info section DIEs. + /// + /// \param AccelSection section containing the acceleration table + /// \param StrData string section + /// + /// \returns The number of errors occurred during verification + unsigned verifyDebugNames(const DWARFSection &AccelSection, + const DataExtractor &StrData); public: DWARFVerifier(raw_ostream &S, DWARFContext &D, diff --git a/include/llvm/DebugInfo/MSF/MSFBuilder.h b/include/llvm/DebugInfo/MSF/MSFBuilder.h index 19e5c31b3076..3de98c4ecba8 100644 --- a/include/llvm/DebugInfo/MSF/MSFBuilder.h +++ b/include/llvm/DebugInfo/MSF/MSFBuilder.h @@ -20,11 +20,13 @@ #include <vector> namespace llvm { +class FileBufferByteStream; +class WritableBinaryStream; namespace msf { class MSFBuilder { public: - /// \brief Create a new `MSFBuilder`. + /// Create a new `MSFBuilder`. /// /// \param BlockSize The internal block size used by the PDB file. See /// isValidBlockSize() for a list of valid block sizes. @@ -109,7 +111,10 @@ public: /// Finalize the layout and build the headers and structures that describe the /// MSF layout and can be written directly to the MSF file. - Expected<MSFLayout> build(); + Expected<MSFLayout> generateLayout(); + + /// Write the MSF layout to the underlying file. + Expected<FileBufferByteStream> commit(StringRef Path, MSFLayout &Layout); BumpPtrAllocator &getAllocator() { return Allocator; } diff --git a/include/llvm/DebugInfo/MSF/MSFCommon.h b/include/llvm/DebugInfo/MSF/MSFCommon.h index f28415d4e603..2db2b71df4a7 100644 --- a/include/llvm/DebugInfo/MSF/MSFCommon.h +++ b/include/llvm/DebugInfo/MSF/MSFCommon.h @@ -52,6 +52,16 @@ struct SuperBlock { struct MSFLayout { MSFLayout() = default; + uint32_t mainFpmBlock() const { + assert(SB->FreeBlockMapBlock == 1 || SB->FreeBlockMapBlock == 2); + return SB->FreeBlockMapBlock; + } + + uint32_t alternateFpmBlock() const { + // If mainFpmBlock is 1, this is 2. If mainFpmBlock is 2, this is 1. + return 3U - mainFpmBlock(); + } + const SuperBlock *SB = nullptr; BitVector FreePageMap; ArrayRef<support::ulittle32_t> DirectoryBlocks; @@ -59,7 +69,7 @@ struct MSFLayout { std::vector<ArrayRef<support::ulittle32_t>> StreamMap; }; -/// \brief Describes the layout of a stream in an MSF layout. A "stream" here +/// Describes the layout of a stream in an MSF layout. A "stream" here /// is defined as any logical unit of data which may be arranged inside the MSF /// file as a sequence of (possibly discontiguous) blocks. When we want to read /// from a particular MSF Stream, we fill out a stream layout structure and the @@ -71,7 +81,7 @@ public: std::vector<support::ulittle32_t> Blocks; }; -/// \brief Determine the layout of the FPM stream, given the MSF layout. An FPM +/// Determine the layout of the FPM stream, given the MSF layout. An FPM /// stream spans 1 or more blocks, each at equally spaced intervals throughout /// the file. MSFStreamLayout getFpmStreamLayout(const MSFLayout &Msf, @@ -108,14 +118,40 @@ inline uint32_t getFpmIntervalLength(const MSFLayout &L) { return L.SB->BlockSize; } -inline uint32_t getNumFpmIntervals(const MSFLayout &L, - bool IncludeUnusedFpmData = false) { - if (IncludeUnusedFpmData) - return divideCeil(L.SB->NumBlocks, L.SB->BlockSize); +/// Given an MSF with the specified block size and number of blocks, determine +/// how many pieces the specified Fpm is split into. +/// \p BlockSize - the block size of the MSF +/// \p NumBlocks - the total number of blocks in the MSF +/// \p IncludeUnusedFpmData - When true, this will count every block that is +/// both in the file and matches the form of an FPM block, even if some of +/// those FPM blocks are unused (a single FPM block can describe the +/// allocation status of up to 32,767 blocks, although one appears only +/// every 4,096 blocks). So there are 8x as many blocks that match the +/// form as there are blocks that are necessary to describe the allocation +/// status of the file. When this parameter is false, these extraneous +/// trailing blocks are not counted. +inline uint32_t getNumFpmIntervals(uint32_t BlockSize, uint32_t NumBlocks, + bool IncludeUnusedFpmData, int FpmNumber) { + assert(FpmNumber == 1 || FpmNumber == 2); + if (IncludeUnusedFpmData) { + // This calculation determines how many times a number of the form + // BlockSize * k + N appears in the range [0, NumBlocks). We only need to + // do this when unused data is included, since the number of blocks dwarfs + // the number of fpm blocks. + return divideCeil(NumBlocks - FpmNumber, BlockSize); + } // We want the minimum number of intervals required, where each interval can // represent BlockSize * 8 blocks. - return divideCeil(L.SB->NumBlocks, 8 * L.SB->BlockSize); + return divideCeil(NumBlocks, 8 * BlockSize); +} + +inline uint32_t getNumFpmIntervals(const MSFLayout &L, + bool IncludeUnusedFpmData = false, + bool AltFpm = false) { + return getNumFpmIntervals(L.SB->BlockSize, L.SB->NumBlocks, + IncludeUnusedFpmData, + AltFpm ? L.alternateFpmBlock() : L.mainFpmBlock()); } Error validateSuperBlock(const SuperBlock &SB); diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumInjectedSources.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumInjectedSources.h new file mode 100644 index 000000000000..39490a4b2209 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumInjectedSources.h @@ -0,0 +1,40 @@ +//==- DIAEnumInjectedSources.h - DIA Injected Sources Enumerator -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_DIA_DIAENUMINJECTEDSOURCES_H +#define LLVM_DEBUGINFO_PDB_DIA_DIAENUMINJECTEDSOURCES_H + +#include "DIASupport.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h" + +namespace llvm { +namespace pdb { +class DIASession; + +class DIAEnumInjectedSources : public IPDBEnumChildren<IPDBInjectedSource> { +public: + explicit DIAEnumInjectedSources( + const DIASession &PDBSession, + CComPtr<IDiaEnumInjectedSources> DiaEnumerator); + + uint32_t getChildCount() const override; + ChildTypePtr getChildAtIndex(uint32_t Index) const override; + ChildTypePtr getNext() override; + void reset() override; + DIAEnumInjectedSources *clone() const override; + +private: + const DIASession &Session; + CComPtr<IDiaEnumInjectedSources> Enumerator; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_DIA_DIAENUMINJECTEDSOURCES_H diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSectionContribs.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSectionContribs.h new file mode 100644 index 000000000000..52c9563b5d5f --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSectionContribs.h @@ -0,0 +1,40 @@ +//==- DIAEnumSectionContribs.h --------------------------------- -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_DIA_DIAENUMSECTIONCONTRIBS_H +#define LLVM_DEBUGINFO_PDB_DIA_DIAENUMSECTIONCONTRIBS_H + +#include "DIASupport.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" + +namespace llvm { +namespace pdb { +class DIASession; + +class DIAEnumSectionContribs : public IPDBEnumChildren<IPDBSectionContrib> { +public: + explicit DIAEnumSectionContribs( + const DIASession &PDBSession, + CComPtr<IDiaEnumSectionContribs> DiaEnumerator); + + uint32_t getChildCount() const override; + ChildTypePtr getChildAtIndex(uint32_t Index) const override; + ChildTypePtr getNext() override; + void reset() override; + DIAEnumSectionContribs *clone() const override; + +private: + const DIASession &Session; + CComPtr<IDiaEnumSectionContribs> Enumerator; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_DIA_DIAENUMSECTIONCONTRIBS_H diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAInjectedSource.h b/include/llvm/DebugInfo/PDB/DIA/DIAInjectedSource.h new file mode 100644 index 000000000000..635508da84ea --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIAInjectedSource.h @@ -0,0 +1,38 @@ +//===- DIAInjectedSource.h - DIA impl for IPDBInjectedSource ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_DIA_DIAINJECTEDSOURCE_H +#define LLVM_DEBUGINFO_PDB_DIA_DIAINJECTEDSOURCE_H + +#include "DIASupport.h" +#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h" + +namespace llvm { +namespace pdb { +class DIASession; + +class DIAInjectedSource : public IPDBInjectedSource { +public: + explicit DIAInjectedSource(CComPtr<IDiaInjectedSource> DiaSourceFile); + + uint32_t getCrc32() const override; + uint64_t getCodeByteSize() const override; + std::string getFileName() const override; + std::string getObjectFileName() const override; + std::string getVirtualFileName() const override; + PDB_SourceCompression getCompression() const override; + std::string getCode() const override; + +private: + CComPtr<IDiaInjectedSource> SourceFile; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_DIA_DIAINJECTEDSOURCE_H diff --git a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h index 2d6c44905ce0..dfb35647055a 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h @@ -30,10 +30,31 @@ public: findChildren(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags) const override; std::unique_ptr<IPDBEnumSymbols> + findChildrenByAddr(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, + uint32_t Section, uint32_t Offset) const override; + std::unique_ptr<IPDBEnumSymbols> + findChildrenByVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, + uint64_t VA) const override; + std::unique_ptr<IPDBEnumSymbols> findChildrenByRVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, uint32_t RVA) const override; + + std::unique_ptr<IPDBEnumSymbols> + findInlineFramesByAddr(uint32_t Section, uint32_t Offset) const override; std::unique_ptr<IPDBEnumSymbols> findInlineFramesByRVA(uint32_t RVA) const override; + std::unique_ptr<IPDBEnumSymbols> + findInlineFramesByVA(uint64_t VA) const override; + + std::unique_ptr<IPDBEnumLineNumbers> findInlineeLines() const override; + std::unique_ptr<IPDBEnumLineNumbers> + findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, + uint32_t Length) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findInlineeLinesByVA(uint64_t VA, uint32_t Length) const override; void getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) const override; void getFrontEndVersion(VersionInfo &Version) const override; @@ -82,6 +103,7 @@ public: uint32_t getSizeInUdt() const override; uint32_t getSlot() const override; std::string getSourceFileName() const override; + std::unique_ptr<IPDBLineNumber> getSrcLineOnTypeDefn() const override; uint32_t getStride() const override; uint32_t getSubTypeId() const override; std::string getSymbolsFileName() const override; diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASectionContrib.h b/include/llvm/DebugInfo/PDB/DIA/DIASectionContrib.h new file mode 100644 index 000000000000..4688f1f91a89 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIASectionContrib.h @@ -0,0 +1,55 @@ +//===- DIASectionContrib.h - DIA Impl. of IPDBSectionContrib ------ C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_DIA_DIASECTIONCONTRIB_H +#define LLVM_DEBUGINFO_PDB_DIA_DIASECTIONCONTRIB_H + +#include "DIASupport.h" +#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" + +namespace llvm { +namespace pdb { +class DIASession; + +class DIASectionContrib : public IPDBSectionContrib { +public: + explicit DIASectionContrib(const DIASession &PDBSession, + CComPtr<IDiaSectionContrib> DiaSection); + + std::unique_ptr<PDBSymbolCompiland> getCompiland() const override; + uint32_t getAddressSection() const override; + uint32_t getAddressOffset() const override; + uint32_t getRelativeVirtualAddress() const override; + uint64_t getVirtualAddress() const override; + uint32_t getLength() const override; + bool isNotPaged() const override; + bool hasCode() const override; + bool hasCode16Bit() const override; + bool hasInitializedData() const override; + bool hasUninitializedData() const override; + bool isRemoved() const override; + bool hasComdat() const override; + bool isDiscardable() const override; + bool isNotCached() const override; + bool isShared() const override; + bool isExecutable() const override; + bool isReadable() const override; + bool isWritable() const override; + uint32_t getDataCrc32() const override; + uint32_t getRelocationsCrc32() const override; + uint32_t getCompilandId() const override; + +private: + const DIASession &Session; + CComPtr<IDiaSectionContrib> Section; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_DIA_DIASECTIONCONTRIB_H diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASession.h b/include/llvm/DebugInfo/PDB/DIA/DIASession.h index 66bd7a7e9c4e..a63659439389 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASession.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASession.h @@ -30,18 +30,33 @@ public: std::unique_ptr<IPDBSession> &Session); uint64_t getLoadAddress() const override; - void setLoadAddress(uint64_t Address) override; + bool setLoadAddress(uint64_t Address) override; std::unique_ptr<PDBSymbolExe> getGlobalScope() override; std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const override; + bool addressForVA(uint64_t VA, uint32_t &Section, + uint32_t &Offset) const override; + bool addressForRVA(uint32_t RVA, uint32_t &Section, + uint32_t &Offset) const override; + std::unique_ptr<PDBSymbol> findSymbolByAddress(uint64_t Address, PDB_SymType Type) const override; + std::unique_ptr<PDBSymbol> findSymbolByRVA(uint32_t RVA, + PDB_SymType Type) const override; + std::unique_ptr<PDBSymbol> + findSymbolBySectOffset(uint32_t Section, uint32_t Offset, + PDB_SymType Type) const override; std::unique_ptr<IPDBEnumLineNumbers> findLineNumbers(const PDBSymbolCompiland &Compiland, const IPDBSourceFile &File) const override; std::unique_ptr<IPDBEnumLineNumbers> findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, + uint32_t Length) const override; std::unique_ptr<IPDBEnumSourceFiles> findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, @@ -65,9 +80,14 @@ public: std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const override; std::unique_ptr<IPDBEnumTables> getEnumTables() const override; + + std::unique_ptr<IPDBEnumInjectedSources> getInjectedSources() const override; + + std::unique_ptr<IPDBEnumSectionContribs> getSectionContribs() const override; + private: CComPtr<IDiaSession> Session; }; -} -} +} // namespace pdb +} // namespace llvm #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASupport.h b/include/llvm/DebugInfo/PDB/DIA/DIASupport.h index 3b4a348289df..92ebc04ae5a4 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASupport.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASupport.h @@ -22,14 +22,6 @@ #define NOMINMAX #endif -// llvm/Support/Debug.h unconditionally #defines DEBUG as a macro. -// DIA headers #define it if it is not already defined, so we have -// an order of includes problem. The real fix is to make LLVM use -// something less generic than DEBUG, such as LLVM_DEBUG(), but it's -// fairly prevalent. So for now, we save the definition state and -// restore it. -#pragma push_macro("DEBUG") - // atlbase.h has to come before windows.h #include <atlbase.h> #include <windows.h> @@ -39,6 +31,4 @@ #include <dia2.h> #include <diacreate.h> -#pragma pop_macro("DEBUG") - #endif // LLVM_DEBUGINFO_PDB_DIA_DIASUPPORT_H diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAUtils.h b/include/llvm/DebugInfo/PDB/DIA/DIAUtils.h new file mode 100644 index 000000000000..aa843e05de70 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIAUtils.h @@ -0,0 +1,31 @@ +//===- DIAUtils.h - Utility functions for working with DIA ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_DIA_DIAUTILS_H +#define LLVM_DEBUGINFO_PDB_DIA_DIAUTILS_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/ConvertUTF.h" + +template <typename Obj> +std::string invokeBstrMethod(Obj &Object, + HRESULT (__stdcall Obj::*Func)(BSTR *)) { + CComBSTR Str16; + HRESULT Result = (Object.*Func)(&Str16); + if (S_OK != Result) + return std::string(); + + std::string Str8; + llvm::ArrayRef<char> StrBytes(reinterpret_cast<char *>(Str16.m_str), + Str16.ByteLength()); + llvm::convertUTF16ToUTF8String(StrBytes, Str8); + return Str8; +} + +#endif // LLVM_DEBUGINFO_PDB_DIA_DIAUTILS_H diff --git a/include/llvm/DebugInfo/PDB/IPDBInjectedSource.h b/include/llvm/DebugInfo/PDB/IPDBInjectedSource.h new file mode 100644 index 000000000000..e75d64af92bb --- /dev/null +++ b/include/llvm/DebugInfo/PDB/IPDBInjectedSource.h @@ -0,0 +1,42 @@ +//===- IPDBInjectedSource.h - base class for PDB injected file --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_IPDBINJECTEDSOURCE_H +#define LLVM_DEBUGINFO_PDB_IPDBINJECTEDSOURCE_H + +#include "PDBTypes.h" +#include "llvm/Support/raw_ostream.h" +#include <memory> +#include <string> + +namespace llvm { +class raw_ostream; + +namespace pdb { + +/// IPDBInjectedSource defines an interface used to represent source files +/// which were injected directly into the PDB file during the compilation +/// process. This is used, for example, to add natvis files to a PDB, but +/// in theory could be used to add arbitrary source code. +class IPDBInjectedSource { +public: + virtual ~IPDBInjectedSource(); + + virtual uint32_t getCrc32() const = 0; + virtual uint64_t getCodeByteSize() const = 0; + virtual std::string getFileName() const = 0; + virtual std::string getObjectFileName() const = 0; + virtual std::string getVirtualFileName() const = 0; + virtual PDB_SourceCompression getCompression() const = 0; + virtual std::string getCode() const = 0; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_IPDBINJECTEDSOURCE_H diff --git a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h index 18b9423378a0..bcb2eaa35630 100644 --- a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h @@ -42,10 +42,31 @@ public: findChildren(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags) const = 0; virtual std::unique_ptr<IPDBEnumSymbols> + findChildrenByAddr(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, + uint32_t Section, uint32_t Offset) const = 0; + virtual std::unique_ptr<IPDBEnumSymbols> + findChildrenByVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, + uint64_t VA) const = 0; + virtual std::unique_ptr<IPDBEnumSymbols> findChildrenByRVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, uint32_t RVA) const = 0; + + virtual std::unique_ptr<IPDBEnumSymbols> + findInlineFramesByAddr(uint32_t Section, uint32_t Offset) const = 0; virtual std::unique_ptr<IPDBEnumSymbols> findInlineFramesByRVA(uint32_t RVA) const = 0; + virtual std::unique_ptr<IPDBEnumSymbols> + findInlineFramesByVA(uint64_t VA) const = 0; + + virtual std::unique_ptr<IPDBEnumLineNumbers> findInlineeLines() const = 0; + virtual std::unique_ptr<IPDBEnumLineNumbers> + findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, + uint32_t Length) const = 0; + virtual std::unique_ptr<IPDBEnumLineNumbers> + findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const = 0; + virtual std::unique_ptr<IPDBEnumLineNumbers> + findInlineeLinesByVA(uint64_t VA, uint32_t Length) const = 0; virtual void getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) const = 0; virtual void getBackEndVersion(VersionInfo &Version) const = 0; @@ -94,6 +115,8 @@ public: virtual uint32_t getSizeInUdt() const = 0; virtual uint32_t getSlot() const = 0; virtual std::string getSourceFileName() const = 0; + virtual std::unique_ptr<IPDBLineNumber> + getSrcLineOnTypeDefn() const = 0; virtual uint32_t getStride() const = 0; virtual uint32_t getSubTypeId() const = 0; virtual std::string getSymbolsFileName() const = 0; diff --git a/include/llvm/DebugInfo/PDB/IPDBSectionContrib.h b/include/llvm/DebugInfo/PDB/IPDBSectionContrib.h new file mode 100644 index 000000000000..4fda62404672 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/IPDBSectionContrib.h @@ -0,0 +1,50 @@ +//==- IPDBSectionContrib.h - Interfaces for PDB SectionContribs --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_IPDBSECTIONCONTRIB_H +#define LLVM_DEBUGINFO_PDB_IPDBSECTIONCONTRIB_H + +#include "PDBTypes.h" + +namespace llvm { +namespace pdb { + +/// IPDBSectionContrib defines an interface used to represent section +/// contributions whose information are stored in the PDB. +class IPDBSectionContrib { +public: + virtual ~IPDBSectionContrib(); + + virtual std::unique_ptr<PDBSymbolCompiland> getCompiland() const = 0; + virtual uint32_t getAddressSection() const = 0; + virtual uint32_t getAddressOffset() const = 0; + virtual uint32_t getRelativeVirtualAddress() const = 0; + virtual uint64_t getVirtualAddress() const = 0; + virtual uint32_t getLength() const = 0; + virtual bool isNotPaged() const = 0; + virtual bool hasCode() const = 0; + virtual bool hasCode16Bit() const = 0; + virtual bool hasInitializedData() const = 0; + virtual bool hasUninitializedData() const = 0; + virtual bool isRemoved() const = 0; + virtual bool hasComdat() const = 0; + virtual bool isDiscardable() const = 0; + virtual bool isNotCached() const = 0; + virtual bool isShared() const = 0; + virtual bool isExecutable() const = 0; + virtual bool isReadable() const = 0; + virtual bool isWritable() const = 0; + virtual uint32_t getDataCrc32() const = 0; + virtual uint32_t getRelocationsCrc32() const = 0; + virtual uint32_t getCompilandId() const = 0; +}; +} +} + +#endif // LLVM_DEBUGINFO_PDB_IPDBSECTIONCONTRIB_H diff --git a/include/llvm/DebugInfo/PDB/IPDBSession.h b/include/llvm/DebugInfo/PDB/IPDBSession.h index 6291289de5bf..88ec517bc4a5 100644 --- a/include/llvm/DebugInfo/PDB/IPDBSession.h +++ b/include/llvm/DebugInfo/PDB/IPDBSession.h @@ -28,10 +28,15 @@ public: virtual ~IPDBSession(); virtual uint64_t getLoadAddress() const = 0; - virtual void setLoadAddress(uint64_t Address) = 0; + virtual bool setLoadAddress(uint64_t Address) = 0; virtual std::unique_ptr<PDBSymbolExe> getGlobalScope() = 0; virtual std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const = 0; + virtual bool addressForVA(uint64_t VA, uint32_t &Section, + uint32_t &Offset) const = 0; + virtual bool addressForRVA(uint32_t RVA, uint32_t &Section, + uint32_t &Offset) const = 0; + template <typename T> std::unique_ptr<T> getConcreteSymbolById(uint32_t SymbolId) const { return unique_dyn_cast_or_null<T>(getSymbolById(SymbolId)); @@ -39,12 +44,22 @@ public: virtual std::unique_ptr<PDBSymbol> findSymbolByAddress(uint64_t Address, PDB_SymType Type) const = 0; + virtual std::unique_ptr<PDBSymbol> + findSymbolByRVA(uint32_t RVA, PDB_SymType Type) const = 0; + virtual std::unique_ptr<PDBSymbol> + findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, + PDB_SymType Type) const = 0; virtual std::unique_ptr<IPDBEnumLineNumbers> findLineNumbers(const PDBSymbolCompiland &Compiland, const IPDBSourceFile &File) const = 0; virtual std::unique_ptr<IPDBEnumLineNumbers> findLineNumbersByAddress(uint64_t Address, uint32_t Length) const = 0; + virtual std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const = 0; + virtual std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, + uint32_t Length) const = 0; virtual std::unique_ptr<IPDBEnumSourceFiles> findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, @@ -69,8 +84,14 @@ public: virtual std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const = 0; virtual std::unique_ptr<IPDBEnumTables> getEnumTables() const = 0; + + virtual std::unique_ptr<IPDBEnumInjectedSources> + getInjectedSources() const = 0; + + virtual std::unique_ptr<IPDBEnumSectionContribs> + getSectionContribs() const = 0; }; -} -} +} // namespace pdb +} // namespace llvm #endif diff --git a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h b/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h index 8200f51e3da9..9eef4041d0a1 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h @@ -47,6 +47,8 @@ public: uint32_t getRecordLength() const; + const SectionContrib &getSectionContrib() const; + private: StringRef ModuleName; StringRef ObjFileName; diff --git a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h b/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h index c918a5d5e976..ce4d07917755 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h @@ -49,6 +49,7 @@ public: void setPdbFilePathNI(uint32_t NI); void setObjFileName(StringRef Name); + void setFirstSectionContrib(const SectionContrib &SC); void addSymbol(codeview::CVSymbol Symbol); void diff --git a/include/llvm/DebugInfo/PDB/Native/DbiStream.h b/include/llvm/DebugInfo/PDB/Native/DbiStream.h index 4be113f28d6f..280615bdb507 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiStream.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiStream.h @@ -38,9 +38,9 @@ class DbiStream { friend class DbiStreamBuilder; public: - DbiStream(PDBFile &File, std::unique_ptr<msf::MappedBlockStream> Stream); + explicit DbiStream(std::unique_ptr<BinaryStream> Stream); ~DbiStream(); - Error reload(); + Error reload(PDBFile *Pdb); PdbRaw_DbiVer getDbiVersion() const; uint32_t getAge() const; @@ -63,6 +63,8 @@ public: PDB_Machine getMachineType() const; + const DbiStreamHeader *getHeader() const { return Header; } + BinarySubstreamRef getSectionContributionData() const; BinarySubstreamRef getSecMapSubstreamData() const; BinarySubstreamRef getModiSubstreamData() const; @@ -87,12 +89,11 @@ public: private: Error initializeSectionContributionData(); - Error initializeSectionHeadersData(); + Error initializeSectionHeadersData(PDBFile *Pdb); Error initializeSectionMapData(); - Error initializeFpoRecords(); + Error initializeFpoRecords(PDBFile *Pdb); - PDBFile &Pdb; - std::unique_ptr<msf::MappedBlockStream> Stream; + std::unique_ptr<BinaryStream> Stream; PDBStringTable ECNames; diff --git a/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h index ad4a0d1bcb6b..51befcdac775 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -12,6 +12,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSet.h" +#include "llvm/BinaryFormat/COFF.h" #include "llvm/Support/Error.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" @@ -46,10 +47,12 @@ public: void setVersionHeader(PdbRaw_DbiVer V); void setAge(uint32_t A); void setBuildNumber(uint16_t B); + void setBuildNumber(uint8_t Major, uint8_t Minor); void setPdbDllVersion(uint16_t V); void setPdbDllRbld(uint16_t R); void setFlags(uint16_t F); void setMachineType(PDB_Machine M); + void setMachineType(COFF::MachineTypes M); void setSectionMap(ArrayRef<SecMapEntry> SecMap); // Add given bytes as a new stream. @@ -121,7 +124,7 @@ private: MutableBinaryByteStream FileInfoBuffer; std::vector<SectionContrib> SectionContribs; ArrayRef<SecMapEntry> SectionMap; - llvm::SmallVector<DebugStream, (int)DbgHeaderType::Max> DbgStreams; + std::array<Optional<DebugStream>, (int)DbgHeaderType::Max> DbgStreams; }; } } diff --git a/include/llvm/DebugInfo/PDB/Native/HashTable.h b/include/llvm/DebugInfo/PDB/Native/HashTable.h index 05c70c4f2175..34cc6179688b 100644 --- a/include/llvm/DebugInfo/PDB/Native/HashTable.h +++ b/include/llvm/DebugInfo/PDB/Native/HashTable.h @@ -12,6 +12,9 @@ #include "llvm/ADT/SparseBitVector.h" #include "llvm/ADT/iterator.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <cstdint> @@ -26,80 +29,303 @@ class BinaryStreamWriter; namespace pdb { -class HashTableIterator; +Error readSparseBitVector(BinaryStreamReader &Stream, SparseBitVector<> &V); +Error writeSparseBitVector(BinaryStreamWriter &Writer, SparseBitVector<> &Vec); +template <typename ValueT, typename TraitsT> class HashTable; + +template <typename ValueT, typename TraitsT> +class HashTableIterator + : public iterator_facade_base<HashTableIterator<ValueT, TraitsT>, + std::forward_iterator_tag, + std::pair<uint32_t, ValueT>> { + friend HashTable<ValueT, TraitsT>; + + HashTableIterator(const HashTable<ValueT, TraitsT> &Map, uint32_t Index, + bool IsEnd) + : Map(&Map), Index(Index), IsEnd(IsEnd) {} + +public: + HashTableIterator(const HashTable<ValueT, TraitsT> &Map) : Map(&Map) { + int I = Map.Present.find_first(); + if (I == -1) { + Index = 0; + IsEnd = true; + } else { + Index = static_cast<uint32_t>(I); + IsEnd = false; + } + } + + HashTableIterator &operator=(const HashTableIterator &R) { + Map = R.Map; + return *this; + } + bool operator==(const HashTableIterator &R) const { + if (IsEnd && R.IsEnd) + return true; + if (IsEnd != R.IsEnd) + return false; + + return (Map == R.Map) && (Index == R.Index); + } + const std::pair<uint32_t, ValueT> &operator*() const { + assert(Map->Present.test(Index)); + return Map->Buckets[Index]; + } + HashTableIterator &operator++() { + while (Index < Map->Buckets.size()) { + ++Index; + if (Map->Present.test(Index)) + return *this; + } + + IsEnd = true; + return *this; + } + +private: + bool isEnd() const { return IsEnd; } + uint32_t index() const { return Index; } + + const HashTable<ValueT, TraitsT> *Map; + uint32_t Index; + bool IsEnd; +}; + +template <typename T> struct PdbHashTraits {}; + +template <> struct PdbHashTraits<uint32_t> { + uint32_t hashLookupKey(uint32_t N) const { return N; } + uint32_t storageKeyToLookupKey(uint32_t N) const { return N; } + uint32_t lookupKeyToStorageKey(uint32_t N) { return N; } +}; + +template <typename ValueT, typename TraitsT = PdbHashTraits<ValueT>> class HashTable { - friend class HashTableIterator; + using iterator = HashTableIterator<ValueT, TraitsT>; + friend iterator; struct Header { support::ulittle32_t Size; support::ulittle32_t Capacity; }; - using BucketList = std::vector<std::pair<uint32_t, uint32_t>>; + using BucketList = std::vector<std::pair<uint32_t, ValueT>>; public: - HashTable(); - explicit HashTable(uint32_t Capacity); + HashTable() { Buckets.resize(8); } + + explicit HashTable(TraitsT Traits) : HashTable(8, std::move(Traits)) {} + HashTable(uint32_t Capacity, TraitsT Traits) : Traits(Traits) { + Buckets.resize(Capacity); + } + + Error load(BinaryStreamReader &Stream) { + const Header *H; + if (auto EC = Stream.readObject(H)) + return EC; + if (H->Capacity == 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid Hash Table Capacity"); + if (H->Size > maxLoad(H->Capacity)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid Hash Table Size"); + + Buckets.resize(H->Capacity); + + if (auto EC = readSparseBitVector(Stream, Present)) + return EC; + if (Present.count() != H->Size) + return make_error<RawError>(raw_error_code::corrupt_file, + "Present bit vector does not match size!"); + + if (auto EC = readSparseBitVector(Stream, Deleted)) + return EC; + if (Present.intersects(Deleted)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Present bit vector interesects deleted!"); - Error load(BinaryStreamReader &Stream); + for (uint32_t P : Present) { + if (auto EC = Stream.readInteger(Buckets[P].first)) + return EC; + const ValueT *Value; + if (auto EC = Stream.readObject(Value)) + return EC; + Buckets[P].second = *Value; + } - uint32_t calculateSerializedLength() const; - Error commit(BinaryStreamWriter &Writer) const; + return Error::success(); + } - void clear(); + uint32_t calculateSerializedLength() const { + uint32_t Size = sizeof(Header); - uint32_t capacity() const; - uint32_t size() const; + constexpr int BitsPerWord = 8 * sizeof(uint32_t); - HashTableIterator begin() const; - HashTableIterator end() const; - HashTableIterator find(uint32_t K); + int NumBitsP = Present.find_last() + 1; + int NumBitsD = Deleted.find_last() + 1; - void set(uint32_t K, uint32_t V); - void remove(uint32_t K); - uint32_t get(uint32_t K); + uint32_t NumWordsP = alignTo(NumBitsP, BitsPerWord) / BitsPerWord; + uint32_t NumWordsD = alignTo(NumBitsD, BitsPerWord) / BitsPerWord; + + // Present bit set number of words (4 bytes), followed by that many actual + // words (4 bytes each). + Size += sizeof(uint32_t); + Size += NumWordsP * sizeof(uint32_t); + + // Deleted bit set number of words (4 bytes), followed by that many actual + // words (4 bytes each). + Size += sizeof(uint32_t); + Size += NumWordsD * sizeof(uint32_t); + + // One (Key, ValueT) pair for each entry Present. + Size += (sizeof(uint32_t) + sizeof(ValueT)) * size(); + + return Size; + } + + Error commit(BinaryStreamWriter &Writer) const { + Header H; + H.Size = size(); + H.Capacity = capacity(); + if (auto EC = Writer.writeObject(H)) + return EC; + + if (auto EC = writeSparseBitVector(Writer, Present)) + return EC; + + if (auto EC = writeSparseBitVector(Writer, Deleted)) + return EC; + + for (const auto &Entry : *this) { + if (auto EC = Writer.writeInteger(Entry.first)) + return EC; + if (auto EC = Writer.writeObject(Entry.second)) + return EC; + } + return Error::success(); + } + + void clear() { + Buckets.resize(8); + Present.clear(); + Deleted.clear(); + } + + bool empty() const { return size() == 0; } + uint32_t capacity() const { return Buckets.size(); } + uint32_t size() const { return Present.count(); } + + iterator begin() const { return iterator(*this); } + iterator end() const { return iterator(*this, 0, true); } + + /// Find the entry whose key has the specified hash value, using the specified + /// traits defining hash function and equality. + template <typename Key> iterator find_as(const Key &K) const { + uint32_t H = Traits.hashLookupKey(K) % capacity(); + uint32_t I = H; + Optional<uint32_t> FirstUnused; + do { + if (isPresent(I)) { + if (Traits.storageKeyToLookupKey(Buckets[I].first) == K) + return iterator(*this, I, false); + } else { + if (!FirstUnused) + FirstUnused = I; + // Insertion occurs via linear probing from the slot hint, and will be + // inserted at the first empty / deleted location. Therefore, if we are + // probing and find a location that is neither present nor deleted, then + // nothing must have EVER been inserted at this location, and thus it is + // not possible for a matching value to occur later. + if (!isDeleted(I)) + break; + } + I = (I + 1) % capacity(); + } while (I != H); + + // The only way FirstUnused would not be set is if every single entry in the + // table were Present. But this would violate the load factor constraints + // that we impose, so it should never happen. + assert(FirstUnused); + return iterator(*this, *FirstUnused, true); + } + + /// Set the entry using a key type that the specified Traits can convert + /// from a real key to an internal key. + template <typename Key> bool set_as(const Key &K, ValueT V) { + return set_as_internal(K, std::move(V), None); + } + + template <typename Key> ValueT get(const Key &K) const { + auto Iter = find_as(K); + assert(Iter != end()); + return (*Iter).second; + } protected: bool isPresent(uint32_t K) const { return Present.test(K); } bool isDeleted(uint32_t K) const { return Deleted.test(K); } + TraitsT Traits; BucketList Buckets; mutable SparseBitVector<> Present; mutable SparseBitVector<> Deleted; private: - static uint32_t maxLoad(uint32_t capacity); - void grow(); + /// Set the entry using a key type that the specified Traits can convert + /// from a real key to an internal key. + template <typename Key> + bool set_as_internal(const Key &K, ValueT V, Optional<uint32_t> InternalKey) { + auto Entry = find_as(K); + if (Entry != end()) { + assert(isPresent(Entry.index())); + assert(Traits.storageKeyToLookupKey(Buckets[Entry.index()].first) == K); + // We're updating, no need to do anything special. + Buckets[Entry.index()].second = V; + return false; + } - static Error readSparseBitVector(BinaryStreamReader &Stream, - SparseBitVector<> &V); - static Error writeSparseBitVector(BinaryStreamWriter &Writer, - SparseBitVector<> &Vec); -}; + auto &B = Buckets[Entry.index()]; + assert(!isPresent(Entry.index())); + assert(Entry.isEnd()); + B.first = InternalKey ? *InternalKey : Traits.lookupKeyToStorageKey(K); + B.second = V; + Present.set(Entry.index()); + Deleted.reset(Entry.index()); -class HashTableIterator - : public iterator_facade_base<HashTableIterator, std::forward_iterator_tag, - std::pair<uint32_t, uint32_t>> { - friend class HashTable; + grow(); - HashTableIterator(const HashTable &Map, uint32_t Index, bool IsEnd); + assert((find_as(K)) != end()); + return true; + } -public: - HashTableIterator(const HashTable &Map); + static uint32_t maxLoad(uint32_t capacity) { return capacity * 2 / 3 + 1; } - HashTableIterator &operator=(const HashTableIterator &R); - bool operator==(const HashTableIterator &R) const; - const std::pair<uint32_t, uint32_t> &operator*() const; - HashTableIterator &operator++(); + void grow() { + uint32_t S = size(); + uint32_t MaxLoad = maxLoad(capacity()); + if (S < maxLoad(capacity())) + return; + assert(capacity() != UINT32_MAX && "Can't grow Hash table!"); -private: - bool isEnd() const { return IsEnd; } - uint32_t index() const { return Index; } + uint32_t NewCapacity = (capacity() <= INT32_MAX) ? MaxLoad * 2 : UINT32_MAX; - const HashTable *Map; - uint32_t Index; - bool IsEnd; + // Growing requires rebuilding the table and re-hashing every item. Make a + // copy with a larger capacity, insert everything into the copy, then swap + // it in. + HashTable NewMap(NewCapacity, Traits); + for (auto I : Present) { + auto LookupKey = Traits.storageKeyToLookupKey(Buckets[I].first); + NewMap.set_as_internal(LookupKey, Buckets[I].second, Buckets[I].first); + } + + Buckets.swap(NewMap.Buckets); + std::swap(Present, NewMap.Present); + std::swap(Deleted, NewMap.Deleted); + assert(capacity() == NewCapacity); + assert(size() == S); + } }; } // end namespace pdb diff --git a/include/llvm/DebugInfo/PDB/Native/InfoStream.h b/include/llvm/DebugInfo/PDB/Native/InfoStream.h index fb8271cb5ebc..8c52b042f289 100644 --- a/include/llvm/DebugInfo/PDB/Native/InfoStream.h +++ b/include/llvm/DebugInfo/PDB/Native/InfoStream.h @@ -30,12 +30,14 @@ class InfoStream { friend class InfoStreamBuilder; public: - InfoStream(std::unique_ptr<msf::MappedBlockStream> Stream); + InfoStream(std::unique_ptr<BinaryStream> Stream); Error reload(); uint32_t getStreamSize() const; + const InfoStreamHeader *getHeader() const { return Header; } + bool containsIdStream() const; PdbRaw_ImplVer getVersion() const; uint32_t getSignature() const; @@ -50,29 +52,13 @@ public: BinarySubstreamRef getNamedStreamsBuffer() const; - uint32_t getNamedStreamIndex(llvm::StringRef Name) const; - iterator_range<StringMapConstIterator<uint32_t>> named_streams() const; + Expected<uint32_t> getNamedStreamIndex(llvm::StringRef Name) const; + StringMap<uint32_t> named_streams() const; private: - std::unique_ptr<msf::MappedBlockStream> Stream; - - // PDB file format version. We only support VC70. See the enumeration - // `PdbRaw_ImplVer` for the other possible values. - uint32_t Version; - - // A 32-bit signature unique across all PDBs. This is generated with - // a call to time() when the PDB is written, but obviously this is not - // universally unique. - uint32_t Signature; - - // The number of times the PDB has been written. Might also be used to - // ensure that the PDB matches the executable. - uint32_t Age; + std::unique_ptr<BinaryStream> Stream; - // Due to the aforementioned limitations with `Signature`, this is a new - // signature present on VC70 and higher PDBs which is guaranteed to be - // universally unique. - codeview::GUID Guid; + const InfoStreamHeader *Header; BinarySubstreamRef SubNamedStreams; diff --git a/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h index c6cb0e221e70..419e8ada06f7 100644 --- a/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h @@ -40,6 +40,10 @@ public: void setGuid(codeview::GUID G); void addFeature(PdbRaw_FeatureSig Sig); + uint32_t getAge() const { return Age; } + codeview::GUID getGuid() const { return Guid; } + Optional<uint32_t> getSignature() const { return Signature; } + uint32_t finalize(); Error finalizeMsfLayout(); @@ -52,8 +56,8 @@ private: std::vector<PdbRaw_FeatureSig> Features; PdbRaw_ImplVer Ver; - uint32_t Sig; uint32_t Age; + Optional<uint32_t> Signature; codeview::GUID Guid; NamedStreamMap &NamedStreams; diff --git a/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h b/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h index 17a82b7ce12d..01b8f1b5da56 100644 --- a/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h +++ b/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h @@ -25,32 +25,45 @@ class BinaryStreamWriter; namespace pdb { +class NamedStreamMap; + +struct NamedStreamMapTraits { + NamedStreamMap *NS; + + explicit NamedStreamMapTraits(NamedStreamMap &NS); + uint16_t hashLookupKey(StringRef S) const; + StringRef storageKeyToLookupKey(uint32_t Offset) const; + uint32_t lookupKeyToStorageKey(StringRef S); +}; + class NamedStreamMap { friend class NamedStreamMapBuilder; - struct FinalizationInfo { - uint32_t StringDataBytes = 0; - uint32_t SerializedLength = 0; - }; - public: NamedStreamMap(); Error load(BinaryStreamReader &Stream); Error commit(BinaryStreamWriter &Writer) const; - uint32_t finalize(); + uint32_t calculateSerializedLength() const; uint32_t size() const; bool get(StringRef Stream, uint32_t &StreamNo) const; void set(StringRef Stream, uint32_t StreamNo); - void remove(StringRef Stream); - const StringMap<uint32_t> &getStringMap() const { return Mapping; } - iterator_range<StringMapConstIterator<uint32_t>> entries() const; + + uint32_t appendStringData(StringRef S); + StringRef getString(uint32_t Offset) const; + uint32_t hashString(uint32_t Offset) const; + + StringMap<uint32_t> entries() const; private: - Optional<FinalizationInfo> FinalizedInfo; - HashTable FinalizedHashTable; - StringMap<uint32_t> Mapping; + NamedStreamMapTraits HashTraits; + /// Closed hash table from Offset -> StreamNumber, where Offset is the offset + /// of the stream name in NamesBuffer. + HashTable<support::ulittle32_t, NamedStreamMapTraits> OffsetIndexMap; + + /// Buffer of string data. + std::vector<char> NamesBuffer; }; } // end namespace pdb diff --git a/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h b/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h index 931b93fb7266..5b70ecfa2056 100644 --- a/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h @@ -35,10 +35,31 @@ public: findChildren(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags) const override; std::unique_ptr<IPDBEnumSymbols> + findChildrenByAddr(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, + uint32_t Section, uint32_t Offset) const override; + std::unique_ptr<IPDBEnumSymbols> + findChildrenByVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, + uint64_t VA) const override; + std::unique_ptr<IPDBEnumSymbols> findChildrenByRVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, uint32_t RVA) const override; + + std::unique_ptr<IPDBEnumSymbols> + findInlineFramesByAddr(uint32_t Section, uint32_t Offset) const override; std::unique_ptr<IPDBEnumSymbols> findInlineFramesByRVA(uint32_t RVA) const override; + std::unique_ptr<IPDBEnumSymbols> + findInlineFramesByVA(uint64_t VA) const override; + + std::unique_ptr<IPDBEnumLineNumbers> findInlineeLines() const override; + std::unique_ptr<IPDBEnumLineNumbers> + findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, + uint32_t Length) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findInlineeLinesByVA(uint64_t VA, uint32_t Length) const override; void getDataBytes(SmallVector<uint8_t, 32> &Bytes) const override; void getFrontEndVersion(VersionInfo &Version) const override; @@ -87,6 +108,7 @@ public: uint32_t getSizeInUdt() const override; uint32_t getSlot() const override; std::string getSourceFileName() const override; + std::unique_ptr<IPDBLineNumber> getSrcLineOnTypeDefn() const override; uint32_t getStride() const override; uint32_t getSubTypeId() const override; std::string getSymbolsFileName() const override; diff --git a/include/llvm/DebugInfo/PDB/Native/NativeSession.h b/include/llvm/DebugInfo/PDB/Native/NativeSession.h index 2e68ced46bfe..aff7ef2f8f21 100644 --- a/include/llvm/DebugInfo/PDB/Native/NativeSession.h +++ b/include/llvm/DebugInfo/PDB/Native/NativeSession.h @@ -49,18 +49,33 @@ public: SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI); uint64_t getLoadAddress() const override; - void setLoadAddress(uint64_t Address) override; + bool setLoadAddress(uint64_t Address) override; std::unique_ptr<PDBSymbolExe> getGlobalScope() override; std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const override; + bool addressForVA(uint64_t VA, uint32_t &Section, + uint32_t &Offset) const override; + bool addressForRVA(uint32_t RVA, uint32_t &Section, + uint32_t &Offset) const override; + std::unique_ptr<PDBSymbol> findSymbolByAddress(uint64_t Address, PDB_SymType Type) const override; + std::unique_ptr<PDBSymbol> findSymbolByRVA(uint32_t RVA, + PDB_SymType Type) const override; + std::unique_ptr<PDBSymbol> + findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, + PDB_SymType Type) const override; std::unique_ptr<IPDBEnumLineNumbers> findLineNumbers(const PDBSymbolCompiland &Compiland, const IPDBSourceFile &File) const override; std::unique_ptr<IPDBEnumLineNumbers> findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, + uint32_t Length) const override; std::unique_ptr<IPDBEnumSourceFiles> findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, @@ -85,6 +100,10 @@ public: std::unique_ptr<IPDBEnumTables> getEnumTables() const override; + std::unique_ptr<IPDBEnumInjectedSources> getInjectedSources() const override; + + std::unique_ptr<IPDBEnumSectionContribs> getSectionContribs() const override; + PDBFile &getPDBFile() { return *Pdb; } const PDBFile &getPDBFile() const { return *Pdb; } @@ -94,7 +113,7 @@ private: std::vector<std::unique_ptr<NativeRawSymbol>> SymbolCache; DenseMap<codeview::TypeIndex, SymIndexId> TypeIndexToSymbolId; }; -} -} +} // namespace pdb +} // namespace llvm #endif diff --git a/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h b/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h index 7ed164bee9ee..7f9c4cf9fa83 100644 --- a/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h @@ -17,9 +17,11 @@ #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" #include <memory> #include <vector> @@ -54,12 +56,34 @@ public: Error commit(StringRef Filename); Expected<uint32_t> getNamedStreamIndex(StringRef Name) const; - Error addNamedStream(StringRef Name, uint32_t Size); + Error addNamedStream(StringRef Name, StringRef Data); + void addInjectedSource(StringRef Name, std::unique_ptr<MemoryBuffer> Buffer); private: - Expected<msf::MSFLayout> finalizeMsfLayout(); + struct InjectedSourceDescriptor { + // The full name of the stream that contains the contents of this injected + // source. This is built as a concatenation of the literal "/src/files" + // plus the "vname". + std::string StreamName; + + // The exact name of the file name as specified by the user. + uint32_t NameIndex; + + // The string table index of the "vname" of the file. As far as we + // understand, this is the same as the name, except it is lowercased and + // forward slashes are converted to backslashes. + uint32_t VNameIndex; + std::unique_ptr<MemoryBuffer> Content; + }; + + Error finalizeMsfLayout(); + Expected<uint32_t> allocateNamedStream(StringRef Name, uint32_t Size); void commitFpm(WritableBinaryStream &MsfBuffer, const msf::MSFLayout &Layout); + void commitInjectedSources(WritableBinaryStream &MsfBuffer, + const msf::MSFLayout &Layout); + void commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer, + const msf::MSFLayout &Layout); BumpPtrAllocator &Allocator; @@ -71,7 +95,13 @@ private: std::unique_ptr<TpiStreamBuilder> Ipi; PDBStringTableBuilder Strings; + StringTableHashTraits InjectedSourceHashTraits; + HashTable<SrcHeaderBlockEntry, StringTableHashTraits> InjectedSourceTable; + + SmallVector<InjectedSourceDescriptor, 2> InjectedSources; + NamedStreamMap NamedStreams; + DenseMap<uint32_t, std::string> NamedStreamData; }; } } diff --git a/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h b/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h index b57707ee7923..0f81c18eafe6 100644 --- a/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h @@ -31,6 +31,16 @@ struct MSFLayout; namespace pdb { class PDBFileBuilder; +class PDBStringTableBuilder; + +struct StringTableHashTraits { + PDBStringTableBuilder *Table; + + explicit StringTableHashTraits(PDBStringTableBuilder &Table); + uint32_t hashLookupKey(StringRef S) const; + StringRef storageKeyToLookupKey(uint32_t Offset) const; + uint32_t lookupKeyToStorageKey(StringRef S); +}; class PDBStringTableBuilder { public: @@ -38,6 +48,9 @@ public: // Returns the ID for S. uint32_t insert(StringRef S); + uint32_t getIdForString(StringRef S) const; + StringRef getStringForId(uint32_t Id) const; + uint32_t calculateSerializedSize() const; Error commit(BinaryStreamWriter &Writer) const; diff --git a/include/llvm/DebugInfo/PDB/Native/RawConstants.h b/include/llvm/DebugInfo/PDB/Native/RawConstants.h index bb1d097b5123..fbbd3318d958 100644 --- a/include/llvm/DebugInfo/PDB/Native/RawConstants.h +++ b/include/llvm/DebugInfo/PDB/Native/RawConstants.h @@ -32,6 +32,8 @@ enum PdbRaw_ImplVer : uint32_t { PdbImplVC140 = 20140508, }; +enum class PdbRaw_SrcHeaderBlockVer : uint32_t { SrcVerOne = 19980827 }; + enum class PdbRaw_FeatureSig : uint32_t { VC110 = PdbImplVC110, VC140 = PdbImplVC140, diff --git a/include/llvm/DebugInfo/PDB/Native/RawTypes.h b/include/llvm/DebugInfo/PDB/Native/RawTypes.h index 8cc083685265..19f592d562e4 100644 --- a/include/llvm/DebugInfo/PDB/Native/RawTypes.h +++ b/include/llvm/DebugInfo/PDB/Native/RawTypes.h @@ -112,6 +112,8 @@ struct DbiBuildNo { static const uint16_t BuildMajorMask = 0x7F00; static const uint16_t BuildMajorShift = 8; + + static const uint16_t NewVersionFormatMask = 0x8000; }; /// The fixed size header that appears at the beginning of the DBI Stream. @@ -175,18 +177,6 @@ struct DbiStreamHeader { }; static_assert(sizeof(DbiStreamHeader) == 64, "Invalid DbiStreamHeader size!"); -struct SectionContribEntry { - support::ulittle16_t Section; - char Padding1[2]; - support::little32_t Offset; - support::little32_t Size; - support::ulittle32_t Characteristics; - support::ulittle16_t ModuleIndex; - char Padding2[2]; - support::ulittle32_t DataCrc; - support::ulittle32_t RelocCrc; -}; - /// The header preceeding the File Info Substream of the DBI stream. struct FileInfoSubstreamHeader { /// Total # of modules, should match number of records in the ModuleInfo @@ -228,7 +218,7 @@ struct ModuleInfoHeader { support::ulittle32_t Mod; /// First section contribution of this module. - SectionContribEntry SC; + SectionContrib SC; /// See ModInfoFlags definition. support::ulittle16_t Flags; @@ -328,6 +318,34 @@ struct PDBStringTableHeader { const uint32_t PDBStringTableSignature = 0xEFFEEFFE; +/// The header preceding the /src/headerblock stream. +struct SrcHeaderBlockHeader { + support::ulittle32_t Version; // PdbRaw_SrcHeaderBlockVer enumeration. + support::ulittle32_t Size; // Size of entire stream. + uint64_t FileTime; // Time stamp (Windows FILETIME format). + support::ulittle32_t Age; // Age + uint8_t Padding[44]; // Pad to 64 bytes. +}; +static_assert(sizeof(SrcHeaderBlockHeader) == 64, "Incorrect struct size!"); + +/// A single file record entry within the /src/headerblock stream. +struct SrcHeaderBlockEntry { + support::ulittle32_t Size; // Record Length. + support::ulittle32_t Version; // PdbRaw_SrcHeaderBlockVer enumeration. + support::ulittle32_t CRC; // CRC of the original file contents. + support::ulittle32_t FileSize; // Size of original source file. + support::ulittle32_t FileNI; // String table index of file name. + support::ulittle32_t ObjNI; // String table index of object name. + support::ulittle32_t VFileNI; // String table index of virtual file name. + uint8_t Compression; // PDB_SourceCompression enumeration. + uint8_t IsVirtual; // Is this a virtual file (injected)? + short Padding; // Pad to 4 bytes. + char Reserved[8]; +}; + +constexpr int I = sizeof(SrcHeaderBlockEntry); +static_assert(sizeof(SrcHeaderBlockEntry) == 40, "Incorrect struct size!"); + } // namespace pdb } // namespace llvm diff --git a/include/llvm/DebugInfo/PDB/Native/TpiStream.h b/include/llvm/DebugInfo/PDB/Native/TpiStream.h index d3475205a6c2..b77939929ecf 100644 --- a/include/llvm/DebugInfo/PDB/Native/TpiStream.h +++ b/include/llvm/DebugInfo/PDB/Native/TpiStream.h @@ -51,7 +51,7 @@ public: uint32_t getNumHashBuckets() const; FixedStreamArray<support::ulittle32_t> getHashValues() const; FixedStreamArray<codeview::TypeIndexOffset> getTypeIndexOffsets() const; - HashTable &getHashAdjusters(); + HashTable<support::ulittle32_t> &getHashAdjusters(); codeview::CVTypeRange types(bool *HadError) const; const codeview::CVTypeArray &typeArray() const { return TypeRecords; } @@ -75,7 +75,7 @@ private: std::unique_ptr<BinaryStream> HashStream; FixedStreamArray<support::ulittle32_t> HashValues; FixedStreamArray<codeview::TypeIndexOffset> TypeIndexOffsets; - HashTable HashAdjusters; + HashTable<support::ulittle32_t> HashAdjusters; const TpiStreamHeader *Header; }; diff --git a/include/llvm/DebugInfo/PDB/PDBExtras.h b/include/llvm/DebugInfo/PDB/PDBExtras.h index 778121c8eb79..3c9a19801f89 100644 --- a/include/llvm/DebugInfo/PDB/PDBExtras.h +++ b/include/llvm/DebugInfo/PDB/PDBExtras.h @@ -34,6 +34,8 @@ raw_ostream &operator<<(raw_ostream &OS, const PDB_SymType &Tag); raw_ostream &operator<<(raw_ostream &OS, const PDB_MemberAccess &Access); raw_ostream &operator<<(raw_ostream &OS, const PDB_UdtType &Type); raw_ostream &operator<<(raw_ostream &OS, const PDB_Machine &Machine); +raw_ostream &operator<<(raw_ostream &OS, + const PDB_SourceCompression &Compression); raw_ostream &operator<<(raw_ostream &OS, const Variant &Value); raw_ostream &operator<<(raw_ostream &OS, const VersionInfo &Version); diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h index 26788017cf32..9549089c7eb4 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h @@ -34,6 +34,7 @@ public: FORWARD_SYMBOL_METHOD(getName) std::string getSourceFileName() const; + std::string getSourceFileFullPath() const; }; } } diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolData.h b/include/llvm/DebugInfo/PDB/PDBSymbolData.h index ad4285df4d44..76b14bf17784 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolData.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolData.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_PDB_PDBSYMBOLDATA_H #define LLVM_DEBUGINFO_PDB_PDBSYMBOLDATA_H +#include "IPDBLineNumber.h" #include "PDBSymbol.h" #include "PDBTypes.h" @@ -53,9 +54,11 @@ public: FORWARD_SYMBOL_METHOD(getValue) FORWARD_SYMBOL_METHOD(getVirtualAddress) FORWARD_SYMBOL_METHOD(isVolatileType) -}; + std::unique_ptr<IPDBEnumLineNumbers> getLineNumbers() const; + uint32_t getCompilandId() const; +}; +} // namespace pdb } // namespace llvm -} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLDATA_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h index c2f02ea6f126..05d585d25763 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNC_H #define LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNC_H +#include "IPDBLineNumber.h" #include "PDBSymbol.h" #include "PDBSymbolTypeFunctionSig.h" #include "PDBTypes.h" @@ -38,7 +39,9 @@ public: FORWARD_SYMBOL_METHOD(getAddressSection) FORWARD_SYMBOL_ID_METHOD(getClassParent) FORWARD_SYMBOL_METHOD(isCompilerGenerated) + FORWARD_SYMBOL_METHOD(isConstructorVirtualBase) FORWARD_SYMBOL_METHOD(isConstType) + FORWARD_SYMBOL_METHOD(isCxxReturnUdt) FORWARD_SYMBOL_METHOD(hasCustomCallingConvention) FORWARD_SYMBOL_METHOD(hasFarReturn) FORWARD_SYMBOL_METHOD(hasAlloca) @@ -76,6 +79,9 @@ public: FORWARD_SYMBOL_METHOD(getVirtualAddress) FORWARD_SYMBOL_METHOD(getVirtualBaseOffset) FORWARD_SYMBOL_METHOD(isVolatileType) + + std::unique_ptr<IPDBEnumLineNumbers> getLineNumbers() const; + uint32_t getCompilandId() const; }; } // namespace llvm diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h index c5ae3c51162c..ddbe7e58f183 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEENUM_H #define LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEENUM_H +#include "IPDBLineNumber.h" #include "PDBSymbol.h" #include "PDBSymbolTypeBuiltin.h" #include "PDBTypes.h" @@ -38,6 +39,7 @@ public: FORWARD_SYMBOL_METHOD(getLength) FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getName) + FORWARD_SYMBOL_METHOD(getSrcLineOnTypeDefn) FORWARD_SYMBOL_METHOD(isNested) FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h index 8de54e70701d..abd4cf5effa2 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h @@ -31,6 +31,8 @@ public: void dumpRight(PDBSymDumper &Dumper) const override; void dumpArgList(raw_ostream &OS) const; + bool isCVarArgs() const; + FORWARD_SYMBOL_METHOD(getCallingConvention) FORWARD_SYMBOL_ID_METHOD(getClassParent) FORWARD_SYMBOL_ID_METHOD(getUnmodifiedType) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h index c502d4e77afe..7612ebac31dd 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h @@ -32,7 +32,11 @@ public: FORWARD_SYMBOL_METHOD(getLength) FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(isReference) + FORWARD_SYMBOL_METHOD(isRValueReference) + FORWARD_SYMBOL_METHOD(isPointerToDataMember) + FORWARD_SYMBOL_METHOD(isPointerToMemberFunction) FORWARD_SYMBOL_ID_METHOD_WITH_NAME(getType, getPointeeType) + FORWARD_SYMBOL_METHOD(isRestrictedType) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h index e9e7fe8c9865..e259b6dca3d5 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H #define LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H +#include "IPDBLineNumber.h" #include "IPDBSession.h" #include "PDBSymbol.h" #include "PDBSymbolTypeBaseClass.h" @@ -45,6 +46,7 @@ public: FORWARD_SYMBOL_METHOD(getLength) FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getName) + FORWARD_SYMBOL_METHOD(getSrcLineOnTypeDefn) FORWARD_SYMBOL_METHOD(isNested) FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) @@ -53,6 +55,7 @@ public: FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_ID_METHOD(getVirtualTableShape) FORWARD_SYMBOL_METHOD(isVolatileType) + FORWARD_SYMBOL_METHOD(getAccess) }; } } // namespace llvm diff --git a/include/llvm/DebugInfo/PDB/PDBTypes.h b/include/llvm/DebugInfo/PDB/PDBTypes.h index a6c6da37d1cc..da6cb1d26771 100644 --- a/include/llvm/DebugInfo/PDB/PDBTypes.h +++ b/include/llvm/DebugInfo/PDB/PDBTypes.h @@ -23,7 +23,9 @@ namespace llvm { namespace pdb { class IPDBDataStream; +class IPDBInjectedSource; class IPDBLineNumber; +class IPDBSectionContrib; class IPDBSourceFile; class IPDBTable; class PDBSymDumper; @@ -65,6 +67,8 @@ using IPDBEnumSourceFiles = IPDBEnumChildren<IPDBSourceFile>; using IPDBEnumDataStreams = IPDBEnumChildren<IPDBDataStream>; using IPDBEnumLineNumbers = IPDBEnumChildren<IPDBLineNumber>; using IPDBEnumTables = IPDBEnumChildren<IPDBTable>; +using IPDBEnumInjectedSources = IPDBEnumChildren<IPDBInjectedSource>; +using IPDBEnumSectionContribs = IPDBEnumChildren<IPDBSectionContrib>; /// Specifies which PDB reader implementation is to be used. Only a value /// of PDB_ReaderType::DIA is currently supported, but Native is in the works. @@ -96,13 +100,18 @@ enum PDB_NameSearchFlags { NS_CaseInsensitive = 0x2, NS_FileNameExtMatch = 0x4, NS_Regex = 0x8, - NS_UndecoratedName = 0x10 + NS_UndecoratedName = 0x10, + + // For backward compatibility. + NS_CaseInFileNameExt = NS_CaseInsensitive | NS_FileNameExtMatch, + NS_CaseRegex = NS_Regex | NS_CaseSensitive, + NS_CaseInRex = NS_Regex | NS_CaseInsensitive }; /// Specifies the hash algorithm that a source file from a PDB was hashed with. /// This corresponds to the CV_SourceChksum_t enumeration and are documented /// here: https://msdn.microsoft.com/en-us/library/e96az21x.aspx -enum class PDB_Checksum { None = 0, MD5 = 1, SHA1 = 2 }; +enum class PDB_Checksum { None = 0, MD5 = 1, SHA1 = 2, SHA256 = 3 }; /// These values correspond to the CV_CPU_TYPE_e enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx @@ -133,6 +142,13 @@ enum class PDB_Machine { WceMipsV2 = 0x169 }; +enum class PDB_SourceCompression { + None, + RunLengthEncoded, + Huffman, + LZ, +}; + /// These values correspond to the CV_call_e enumeration, and are documented /// at the following locations: /// https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx @@ -209,6 +225,7 @@ enum class PDB_LocType { IlRel, MetaData, Constant, + RegRelAliasIndir, Max }; @@ -218,11 +235,24 @@ enum class PDB_UdtType { Struct, Class, Union, Interface }; /// These values correspond to the StackFrameTypeEnum enumeration, and are /// documented here: https://msdn.microsoft.com/en-us/library/bc5207xw.aspx. -enum class PDB_StackFrameType { FPO, KernelTrap, KernelTSS, EBP, FrameData }; +enum class PDB_StackFrameType : uint16_t { + FPO, + KernelTrap, + KernelTSS, + EBP, + FrameData, + Unknown = 0xffff +}; -/// These values correspond to the StackFrameTypeEnum enumeration, and are -/// documented here: https://msdn.microsoft.com/en-us/library/bc5207xw.aspx. -enum class PDB_MemoryType { Code, Data, Stack, HeapCode }; +/// These values correspond to the MemoryTypeEnum enumeration, and are +/// documented here: https://msdn.microsoft.com/en-us/library/ms165609.aspx. +enum class PDB_MemoryType : uint16_t { + Code, + Data, + Stack, + HeapCode, + Any = 0xffff +}; /// These values correspond to the Basictype enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/4szdtzc3.aspx @@ -244,13 +274,15 @@ enum class PDB_BuiltinType { Complex = 28, Bitfield = 29, BSTR = 30, - HResult = 31 + HResult = 31, + Char16 = 32, + Char32 = 33 }; /// These values correspond to the flags that can be combined to control the /// return of an undecorated name for a C++ decorated name, and are documented /// here: https://msdn.microsoft.com/en-us/library/kszfk0fs.aspx -enum PDB_UndnameFlags: uint32_t { +enum PDB_UndnameFlags : uint32_t { Undname_Complete = 0x0, Undname_NoLeadingUnderscores = 0x1, Undname_NoMsKeywords = 0x2, diff --git a/include/llvm/DebugInfo/Symbolize/Symbolize.h b/include/llvm/DebugInfo/Symbolize/Symbolize.h index 6480aef109c6..289148f569db 100644 --- a/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ b/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -90,11 +90,11 @@ private: const ObjectFile *Obj, const std::string &ArchName); - /// \brief Returns pair of pointers to object and debug object. + /// Returns pair of pointers to object and debug object. Expected<ObjectPair> getOrCreateObjectPair(const std::string &Path, const std::string &ArchName); - /// \brief Return a pointer to object file at specified path, for a specified + /// Return a pointer to object file at specified path, for a specified /// architecture (e.g. if path refers to a Mach-O universal binary, only one /// object file from it will be returned). Expected<ObjectFile *> getOrCreateObject(const std::string &Path, @@ -102,14 +102,14 @@ private: std::map<std::string, std::unique_ptr<SymbolizableModule>> Modules; - /// \brief Contains cached results of getOrCreateObjectPair(). + /// Contains cached results of getOrCreateObjectPair(). std::map<std::pair<std::string, std::string>, ObjectPair> ObjectPairForPathArch; - /// \brief Contains parsed binary for each path, or parsing error. + /// Contains parsed binary for each path, or parsing error. std::map<std::string, OwningBinary<Binary>> BinaryForPath; - /// \brief Parsed object file for path/architecture pair, where "path" refers + /// Parsed object file for path/architecture pair, where "path" refers /// to Mach-O universal binary. std::map<std::pair<std::string, std::string>, std::unique_ptr<ObjectFile>> ObjectForUBPathAndArch; |
