diff options
author | Reid Kleckner <rnk@google.com> | 2016-02-02 17:41:18 +0000 |
---|---|---|
committer | Reid Kleckner <rnk@google.com> | 2016-02-02 17:41:18 +0000 |
commit | 1fcd610c9499d8f1eb42f339926ed17ec6d98ddd (patch) | |
tree | b80a02a7939d74d6657ce1523b272f81ea84b403 | |
parent | 7d6b924df841faff6893207044cc57b02464b255 (diff) | |
download | bcm5719-llvm-1fcd610c9499d8f1eb42f339926ed17ec6d98ddd.tar.gz bcm5719-llvm-1fcd610c9499d8f1eb42f339926ed17ec6d98ddd.zip |
[codeview] Wire up the .cv_inline_linetable directive
This directive emits the binary annotations that describe line and code
deltas in inlined call sites. Single-stepping through inlined frames in
windbg now works.
llvm-svn: 259535
-rw-r--r-- | llvm/include/llvm/MC/MCAssembler.h | 2 | ||||
-rw-r--r-- | llvm/include/llvm/MC/MCCodeView.h | 34 | ||||
-rw-r--r-- | llvm/include/llvm/MC/MCFragment.h | 42 | ||||
-rw-r--r-- | llvm/include/llvm/MC/MCObjectStreamer.h | 1 | ||||
-rw-r--r-- | llvm/include/llvm/MC/MCStreamer.h | 7 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 60 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h | 11 | ||||
-rw-r--r-- | llvm/lib/MC/MCAsmStreamer.cpp | 9 | ||||
-rw-r--r-- | llvm/lib/MC/MCAssembler.cpp | 19 | ||||
-rw-r--r-- | llvm/lib/MC/MCCodeView.cpp | 121 | ||||
-rw-r--r-- | llvm/lib/MC/MCFragment.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/MC/MCObjectStreamer.cpp | 7 | ||||
-rw-r--r-- | llvm/lib/MC/MCParser/AsmParser.cpp | 13 | ||||
-rw-r--r-- | llvm/lib/MC/MCStreamer.cpp | 2 | ||||
-rw-r--r-- | llvm/test/DebugInfo/COFF/asm.ll | 6 | ||||
-rw-r--r-- | llvm/test/DebugInfo/COFF/inlining.ll | 123 | ||||
-rw-r--r-- | llvm/test/DebugInfo/COFF/multifile.ll | 6 | ||||
-rw-r--r-- | llvm/test/DebugInfo/COFF/multifunction.ll | 18 | ||||
-rw-r--r-- | llvm/test/DebugInfo/COFF/simple.ll | 6 | ||||
-rw-r--r-- | llvm/test/MC/COFF/cv-inline-linetable.s | 25 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/COFFDumper.cpp | 2 |
21 files changed, 410 insertions, 118 deletions
diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h index ff069a8273a..3ad31dca22c 100644 --- a/llvm/include/llvm/MC/MCAssembler.h +++ b/llvm/include/llvm/MC/MCAssembler.h @@ -189,6 +189,8 @@ private: bool relaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF); bool relaxDwarfCallFrameFragment(MCAsmLayout &Layout, MCDwarfCallFrameFragment &DF); + bool relaxCVInlineLineTable(MCAsmLayout &Layout, + MCCVInlineLineTableFragment &DF); /// finishLayout - Finalize a layout, including fragment lowering. void finishLayout(MCAsmLayout &Layout); diff --git a/llvm/include/llvm/MC/MCCodeView.h b/llvm/include/llvm/MC/MCCodeView.h index 713c3b5af5c..71096bc1a5c 100644 --- a/llvm/include/llvm/MC/MCCodeView.h +++ b/llvm/include/llvm/MC/MCCodeView.h @@ -85,7 +85,7 @@ public: /// created at the current address in the current section and the info from /// the last .cv_loc directive seen as stored in the context. class MCCVLineEntry : public MCCVLoc { - MCSymbol *Label; + const MCSymbol *Label; private: // Allow the default copy constructor and assignment operator to be used @@ -93,10 +93,10 @@ private: public: // Constructor to create an MCCVLineEntry given a symbol and the dwarf loc. - MCCVLineEntry(MCSymbol *label, const MCCVLoc loc) - : MCCVLoc(loc), Label(label) {} + MCCVLineEntry(const MCSymbol *Label, const MCCVLoc loc) + : MCCVLoc(loc), Label(Label) {} - MCSymbol *getLabel() const { return Label; } + const MCSymbol *getLabel() const { return Label; } // This is called when an instruction is assembled into the specified // section and if there is information from the last .cv_loc directive that @@ -117,10 +117,10 @@ public: /// \brief Add a line entry. void addLineEntry(const MCCVLineEntry &LineEntry) { size_t Offset = MCCVLines.size(); - auto I = - MCCVLineStartStop.insert({LineEntry.getFunctionId(), {Offset, Offset}}); + auto I = MCCVLineStartStop.insert( + {LineEntry.getFunctionId(), {Offset, Offset + 1}}); if (!I.second) - I.first->second.second = Offset; + I.first->second.second = Offset + 1; MCCVLines.push_back(LineEntry); } @@ -129,13 +129,26 @@ public: auto I = MCCVLineStartStop.find(FuncId); if (I != MCCVLineStartStop.end()) - for (size_t Idx = I->second.first, End = I->second.second + 1; Idx != End; + for (size_t Idx = I->second.first, End = I->second.second; Idx != End; ++Idx) if (MCCVLines[Idx].getFunctionId() == FuncId) FilteredLines.push_back(MCCVLines[Idx]); return FilteredLines; } + std::pair<size_t, size_t> getLineExtent(unsigned FuncId) { + auto I = MCCVLineStartStop.find(FuncId); + // Return an empty extent if there are no cv_locs for this function id. + if (I == MCCVLineStartStop.end()) + return {~0ULL, 0}; + return I->second; + } + + ArrayRef<MCCVLineEntry> getLinesForExtent(size_t L, size_t R) { + size_t S = std::min(R, MCCVLines.size()) - L; + return makeArrayRef(&MCCVLines[L], S); + } + /// Emits a line table substream. void emitLineTableForFunction(MCObjectStreamer &OS, unsigned FuncId, const MCSymbol *FuncBegin, @@ -145,8 +158,13 @@ public: unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, + const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds); + /// Encodes the binary annotations once we have a layout. + void encodeInlineLineTable(MCAsmLayout &Layout, + MCCVInlineLineTableFragment &F); + /// Emits the string table substream. void emitStringTable(MCObjectStreamer &OS); diff --git a/llvm/include/llvm/MC/MCFragment.h b/llvm/include/llvm/MC/MCFragment.h index e51ee90e3e6..3d7d1b84a00 100644 --- a/llvm/include/llvm/MC/MCFragment.h +++ b/llvm/include/llvm/MC/MCFragment.h @@ -40,6 +40,7 @@ public: FT_DwarfFrame, FT_LEB, FT_SafeSEH, + FT_CVInlineLines, FT_Dummy }; @@ -484,6 +485,47 @@ public: } }; +/// Fragment representing the binary annotations produced by the +/// .cv_inline_linetable directive. +class MCCVInlineLineTableFragment : public MCFragment { + unsigned SiteFuncId; + unsigned StartFileId; + unsigned StartLineNum; + const MCSymbol *FnStartSym; + SmallVector<unsigned, 3> SecondaryFuncs; + SmallString<8> Contents; + + /// CodeViewContext has the real knowledge about this format, so let it access + /// our members. + friend class CodeViewContext; + +public: + MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId, + unsigned StartLineNum, const MCSymbol *FnStartSym, + ArrayRef<unsigned> SecondaryFuncs, + MCSection *Sec = nullptr) + : MCFragment(FT_CVInlineLines, false, 0, Sec), SiteFuncId(SiteFuncId), + StartFileId(StartFileId), StartLineNum(StartLineNum), + FnStartSym(FnStartSym), + SecondaryFuncs(SecondaryFuncs.begin(), SecondaryFuncs.end()) { + Contents.push_back(0); + } + + /// \name Accessors + /// @{ + + const MCSymbol *getFnStartSym() const { return FnStartSym; } + + SmallString<8> &getContents() { return Contents; } + const SmallString<8> &getContents() const { return Contents; } + + /// @} + + static bool classof(const MCFragment *F) { + return F->getKind() == MCFragment::FT_CVInlineLines; + } +}; + } // end namespace llvm #endif diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h index 8eb60f4693f..cf0ee5d4a42 100644 --- a/llvm/include/llvm/MC/MCObjectStreamer.h +++ b/llvm/include/llvm/MC/MCObjectStreamer.h @@ -129,6 +129,7 @@ public: const MCSymbol *End) override; void EmitCVInlineLinetableDirective( unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, + const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds) override; void EmitCVStringTableDirective() override; void EmitCVFileChecksumsDirective() override; diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index 9aa33747249..7fd4277f753 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -657,10 +657,9 @@ public: /// \brief This implements the CodeView '.cv_inline_linetable' assembler /// directive. - virtual void - EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, - unsigned SourceFileId, unsigned SourceLineNum, - ArrayRef<unsigned> SecondaryFunctionIds); + virtual void EmitCVInlineLinetableDirective( + unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, + const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds); /// \brief This implements the CodeView '.cv_stringtable' assembler directive. virtual void EmitCVStringTableDirective() {} diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index e3c48296f34..de12fc38138 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -96,6 +96,7 @@ CodeViewDebug::InlineSite &CodeViewDebug::getInlineSite(const DILocation *Loc) { InlineSite &Site = Insertion.first->second; Site.SiteFuncId = NextFuncId++; Site.Inlinee = Loc->getScope()->getSubprogram(); + InlinedSubprograms.insert(Loc->getScope()->getSubprogram()); } return Insertion.first->second; } @@ -188,6 +189,9 @@ void CodeViewDebug::endModule() { // of the payload followed by the payload itself. The subsections are 4-byte // aligned. + // Make a subsection for all the inlined subprograms. + emitInlineeLinesSubsection(); + // Emit per-function debug information. for (auto &P : FnDebugInfo) emitDebugInfoForFunction(P.first, P.second); @@ -257,6 +261,39 @@ void CodeViewDebug::emitTypeInformation() { } } +void CodeViewDebug::emitInlineeLinesSubsection() { + if (InlinedSubprograms.empty()) + return; + + MCStreamer &OS = *Asm->OutStreamer; + MCSymbol *InlineBegin = Asm->MMI->getContext().createTempSymbol(), + *InlineEnd = Asm->MMI->getContext().createTempSymbol(); + + OS.AddComment("Inlinee lines subsection"); + OS.EmitIntValue(unsigned(ModuleSubstreamKind::InlineeLines), 4); + OS.emitAbsoluteSymbolDiff(InlineEnd, InlineBegin, 4); + OS.EmitLabel(InlineBegin); + + // We don't provide any extra file info. + // FIXME: Find out if debuggers use this info. + OS.EmitIntValue(unsigned(InlineeLinesSignature::Normal), 4); + + for (const DISubprogram *SP : InlinedSubprograms) { + TypeIndex TypeId = SubprogramToFuncId[SP]; + unsigned FileId = maybeRecordFile(SP->getFile()); + OS.AddComment("Inlined function " + SP->getDisplayName() + " starts at " + + SP->getFilename() + Twine(':') + Twine(SP->getLine())); + // The filechecksum table uses 8 byte entries for now, and file ids start at + // 1. + unsigned FileOffset = (FileId - 1) * 8; + OS.EmitIntValue(TypeId.getIndex(), 4); + OS.EmitIntValue(FileOffset, 4); + OS.EmitIntValue(SP->getLine(), 4); + } + + OS.EmitLabel(InlineEnd); +} + static void EmitLabelDiff(MCStreamer &Streamer, const MCSymbol *From, const MCSymbol *To, unsigned int Size = 4) { @@ -269,6 +306,18 @@ static void EmitLabelDiff(MCStreamer &Streamer, Streamer.EmitValue(AddrDelta, Size); } +void CodeViewDebug::collectInlineSiteChildren( + SmallVectorImpl<unsigned> &Children, const FunctionInfo &FI, + const InlineSite &Site) { + for (const DILocation *ChildSiteLoc : Site.ChildSites) { + auto I = FI.InlineSites.find(ChildSiteLoc); + assert(I != FI.InlineSites.end()); + const InlineSite &ChildSite = I->second; + Children.push_back(ChildSite.SiteFuncId); + collectInlineSiteChildren(Children, FI, ChildSite); + } +} + void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt, const InlineSite &Site) { @@ -290,7 +339,13 @@ void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI, Asm->OutStreamer->EmitBytes( StringRef(reinterpret_cast<const char *>(&SiteBytes), sizeof(SiteBytes))); - // FIXME: annotations + unsigned FileId = maybeRecordFile(Site.Inlinee->getFile()); + unsigned StartLineNum = Site.Inlinee->getLine(); + SmallVector<unsigned, 3> SecondaryFuncIds; + collectInlineSiteChildren(SecondaryFuncIds, FI, Site); + + OS.EmitCVInlineLinetableDirective(Site.SiteFuncId, FileId, StartLineNum, + FI.Begin, SecondaryFuncIds); OS.EmitLabel(InlineEnd); @@ -367,7 +422,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, } Asm->OutStreamer->EmitLabel(SymbolsEnd); // Every subsection must be aligned to a 4-byte boundary. - Asm->OutStreamer->EmitFill((-FuncName.size()) % 4, 0); + Asm->OutStreamer->EmitValueToAlignment(4); // We have an assembler directive that takes care of the whole line table. Asm->OutStreamer->EmitCVLinetableDirective(FI.FuncId, Fn, FI.End); @@ -383,6 +438,7 @@ void CodeViewDebug::beginFunction(const MachineFunction *MF) { assert(FnDebugInfo.count(GV) == false); CurFn = &FnDebugInfo[GV]; CurFn->FuncId = NextFuncId++; + CurFn->Begin = Asm->getFunctionBegin(); // Find the end of the function prolog. // FIXME: is there a simpler a way to do this? Can we just search diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index 4883905e907..d9f38f3eaf8 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -48,7 +48,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public AsmPrinterHandler { MapVector<const DILocation *, InlineSite> InlineSites; DebugLoc LastLoc; - MCSymbol *End = nullptr; + const MCSymbol *Begin = nullptr; + const MCSymbol *End = nullptr; unsigned FuncId = 0; unsigned LastFileId = 0; bool HaveLineInfo = false; @@ -59,6 +60,10 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public AsmPrinterHandler { InlineSite &getInlineSite(const DILocation *Loc); + static void collectInlineSiteChildren(SmallVectorImpl<unsigned> &Children, + const FunctionInfo &FI, + const InlineSite &Site); + /// Remember some debug info about each function. Keep it in a stable order to /// emit at the end of the TU. MapVector<const Function *, FunctionInfo> FnDebugInfo; @@ -66,6 +71,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public AsmPrinterHandler { /// Map from DIFile to .cv_file id. DenseMap<const DIFile *, unsigned> FileIdMap; + SmallSetVector<const DISubprogram *, 4> InlinedSubprograms; + DenseMap<const DISubprogram *, codeview::TypeIndex> SubprogramToFuncId; unsigned TypeCount = 0; @@ -93,6 +100,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public AsmPrinterHandler { void emitTypeInformation(); + void emitInlineeLinesSubsection(); + void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI); void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt, diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 1bac42a8d09..712b7a938be 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -207,6 +207,7 @@ public: const MCSymbol *FnEnd) override; void EmitCVInlineLinetableDirective( unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, + const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds) override; void EmitCVStringTableDirective() override; void EmitCVFileChecksumsDirective() override; @@ -1019,9 +1020,10 @@ void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId, void MCAsmStreamer::EmitCVInlineLinetableDirective( unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, - ArrayRef<unsigned> SecondaryFunctionIds) { + const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds) { OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId - << ' ' << SourceLineNum; + << ' ' << SourceLineNum << ' '; + FnStartSym->print(OS, MAI); if (!SecondaryFunctionIds.empty()) { OS << " contains"; for (unsigned SecondaryFunctionId : SecondaryFunctionIds) @@ -1029,7 +1031,8 @@ void MCAsmStreamer::EmitCVInlineLinetableDirective( } EmitEOL(); this->MCStreamer::EmitCVInlineLinetableDirective( - PrimaryFunctionId, SourceFileId, SourceLineNum, SecondaryFunctionIds); + PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, + SecondaryFunctionIds); } void MCAsmStreamer::EmitCVStringTableDirective() { diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index 6965b1b037f..9a55ef3931e 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -15,6 +15,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" @@ -300,6 +301,8 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, return cast<MCDwarfLineAddrFragment>(F).getContents().size(); case MCFragment::FT_DwarfFrame: return cast<MCDwarfCallFrameFragment>(F).getContents().size(); + case MCFragment::FT_CVInlineLines: + return cast<MCCVInlineLineTableFragment>(F).getContents().size(); case MCFragment::FT_Dummy: llvm_unreachable("Should not have been added"); } @@ -537,6 +540,11 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, OW->writeBytes(CF.getContents()); break; } + case MCFragment::FT_CVInlineLines: { + const auto &OF = cast<MCCVInlineLineTableFragment>(F); + OW->writeBytes(OF.getContents()); + break; + } case MCFragment::FT_Dummy: llvm_unreachable("Should not have been added"); } @@ -813,6 +821,13 @@ bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout, return OldSize != Data.size(); } +bool MCAssembler::relaxCVInlineLineTable(MCAsmLayout &Layout, + MCCVInlineLineTableFragment &F) { + unsigned OldSize = F.getContents().size(); + getContext().getCVContext().encodeInlineLineTable(Layout, F); + return OldSize != F.getContents().size(); +} + bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) { // Holds the first fragment which needed relaxing during this layout. It will // remain NULL if none were relaxed. @@ -844,6 +859,10 @@ bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) { case MCFragment::FT_LEB: RelaxedFrag = relaxLEB(Layout, *cast<MCLEBFragment>(I)); break; + case MCFragment::FT_CVInlineLines: + RelaxedFrag = + relaxCVInlineLineTable(Layout, *cast<MCCVInlineLineTableFragment>(I)); + break; } if (RelaxedFrag && !FirstRelaxedFragment) FirstRelaxedFragment = &*I; diff --git a/llvm/lib/MC/MCCodeView.cpp b/llvm/lib/MC/MCCodeView.cpp index a876470b826..ea226f7769e 100644 --- a/llvm/lib/MC/MCCodeView.cpp +++ b/llvm/lib/MC/MCCodeView.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCCodeView.h" +#include "llvm/MC/MCAsmLayout.h" #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" @@ -226,40 +227,110 @@ static uint32_t encodeSignedNumber(uint32_t Data) { void CodeViewContext::emitInlineLineTableForFunction( MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId, - unsigned SourceLineNum, ArrayRef<unsigned> SecondaryFunctionIds) { - std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(PrimaryFunctionId); - std::vector<std::pair<BinaryAnnotationsOpCode, uint32_t>> Annotations; + unsigned SourceLineNum, const MCSymbol *FnStartSym, + ArrayRef<unsigned> SecondaryFunctionIds) { + // Create and insert a fragment into the current section that will be encoded + // later. + new MCCVInlineLineTableFragment( + PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, + SecondaryFunctionIds, OS.getCurrentSectionOnly()); +} + +unsigned computeLabelDiff(MCAsmLayout &Layout, const MCSymbol *Begin, + const MCSymbol *End) { + MCContext &Ctx = Layout.getAssembler().getContext(); + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *BeginRef = MCSymbolRefExpr::create(Begin, Variant, Ctx), + *EndRef = MCSymbolRefExpr::create(End, Variant, Ctx); + const MCExpr *AddrDelta = + MCBinaryExpr::create(MCBinaryExpr::Sub, EndRef, BeginRef, Ctx); + int64_t Result; + bool Success = AddrDelta->evaluateKnownAbsolute(Result, Layout); + assert(Success && "failed to evaluate label difference as absolute"); + (void)Success; + assert(Result >= 0 && "negative label difference requested"); + assert(Result < UINT_MAX && "label difference greater than 2GB"); + return unsigned(Result); +} - const MCCVLineEntry *LastLoc = nullptr; - unsigned LastFileId = SourceFileId; - unsigned LastLineNum = SourceLineNum; +void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, + MCCVInlineLineTableFragment &Frag) { + size_t LocBegin; + size_t LocEnd; + std::tie(LocBegin, LocEnd) = getLineExtent(Frag.SiteFuncId); + for (unsigned SecondaryId : Frag.SecondaryFuncs) { + auto Extent = getLineExtent(SecondaryId); + LocBegin = std::min(LocBegin, Extent.first); + LocEnd = std::max(LocEnd, Extent.second); + } + if (LocBegin >= LocEnd) + return; + ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd + 1); + if (Locs.empty()) + return; + SmallSet<unsigned, 8> InlinedFuncIds; + InlinedFuncIds.insert(Frag.SiteFuncId); + InlinedFuncIds.insert(Frag.SecondaryFuncs.begin(), Frag.SecondaryFuncs.end()); + + // Make an artificial start location using the function start and the inlinee + // lines start location information. All deltas start relative to this + // location. + MCCVLineEntry StartLoc(Frag.getFnStartSym(), MCCVLoc(Locs.front())); + StartLoc.setFileNum(Frag.StartFileId); + StartLoc.setLine(Frag.StartLineNum); + const MCCVLineEntry *LastLoc = &StartLoc; + bool WithinFunction = true; + + SmallVectorImpl<char> &Buffer = Frag.getContents(); + Buffer.clear(); // Clear old contents if we went through relaxation. for (const MCCVLineEntry &Loc : Locs) { - if (!LastLoc) { - // TODO ChangeCodeOffset - // TODO ChangeCodeLength + if (!InlinedFuncIds.count(Loc.getFunctionId())) { + // We've hit a cv_loc not attributed to this inline call site. Use this + // label to end the PC range. + if (WithinFunction) { + unsigned Length = + computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel()); + compressAnnotation(ChangeCodeLength, Buffer); + compressAnnotation(Length, Buffer); + } + WithinFunction = false; + continue; } + WithinFunction = true; - if (Loc.getFileNum() != LastFileId) - Annotations.push_back({ChangeFile, Loc.getFileNum()}); + if (Loc.getFileNum() != LastLoc->getFileNum()) { + compressAnnotation(ChangeFile, Buffer); + compressAnnotation(Loc.getFileNum(), Buffer); + } - if (Loc.getLine() != LastLineNum) - Annotations.push_back( - {ChangeLineOffset, encodeSignedNumber(Loc.getLine() - LastLineNum)}); + int LineDelta = Loc.getLine() - LastLoc->getLine(); + if (LineDelta == 0) + continue; + + unsigned EncodedLineDelta = encodeSignedNumber(LineDelta); + unsigned CodeDelta = + computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel()); + if (CodeDelta == 0) { + compressAnnotation(ChangeLineOffset, Buffer); + compressAnnotation(EncodedLineDelta, Buffer); + } else if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) { + // The ChangeCodeOffsetAndLineOffset combination opcode is used when the + // encoded line delta uses 3 or fewer set bits and the code offset fits + // in one nibble. + unsigned Operand = (EncodedLineDelta << 4) | CodeDelta; + compressAnnotation(ChangeCodeOffsetAndLineOffset, Buffer); + compressAnnotation(Operand, Buffer); + } else { + // Otherwise use the separate line and code deltas. + compressAnnotation(ChangeLineOffset, Buffer); + compressAnnotation(EncodedLineDelta, Buffer); + compressAnnotation(ChangeCodeOffset, Buffer); + compressAnnotation(CodeDelta, Buffer); + } LastLoc = &Loc; - LastFileId = Loc.getFileNum(); - LastLineNum = Loc.getLine(); - } - - SmallString<32> Buffer; - for (auto Annotation : Annotations) { - BinaryAnnotationsOpCode Opcode = Annotation.first; - uint32_t Operand = Annotation.second; - compressAnnotation(Opcode, Buffer); - compressAnnotation(Operand, Buffer); } - OS.EmitBytes(Buffer); } // diff --git a/llvm/lib/MC/MCFragment.cpp b/llvm/lib/MC/MCFragment.cpp index 67f57a5c8fe..bfadfda47f2 100644 --- a/llvm/lib/MC/MCFragment.cpp +++ b/llvm/lib/MC/MCFragment.cpp @@ -289,6 +289,9 @@ void MCFragment::destroy() { case FT_SafeSEH: delete cast<MCSafeSEHFragment>(this); return; + case FT_CVInlineLines: + delete cast<MCCVInlineLineTableFragment>(this); + return; case FT_Dummy: delete cast<MCDummyFragment>(this); return; @@ -327,9 +330,8 @@ LLVM_DUMP_METHOD void MCFragment::dump() { case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break; case MCFragment::FT_LEB: OS << "MCLEBFragment"; break; case MCFragment::FT_SafeSEH: OS << "MCSafeSEHFragment"; break; - case MCFragment::FT_Dummy: - OS << "MCDummyFragment"; - break; + case MCFragment::FT_CVInlineLines: OS << "MCCVInlineLineTableFragment"; break; + case MCFragment::FT_Dummy: OS << "MCDummyFragment"; break; } OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder @@ -427,6 +429,12 @@ LLVM_DUMP_METHOD void MCFragment::dump() { OS << " Sym:" << F->getSymbol(); break; } + case MCFragment::FT_CVInlineLines: { + const auto *F = cast<MCCVInlineLineTableFragment>(this); + OS << "\n "; + OS << " Sym:" << *F->getFnStartSym(); + break; + } case MCFragment::FT_Dummy: break; } diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index 4f0b597b434..4d849049f60 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -386,12 +386,13 @@ void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId, void MCObjectStreamer::EmitCVInlineLinetableDirective( unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, - ArrayRef<unsigned> SecondaryFunctionIds) { + const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds) { getContext().getCVContext().emitInlineLineTableForFunction( - *this, PrimaryFunctionId, SourceFileId, SourceLineNum, + *this, PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, SecondaryFunctionIds); this->MCStreamer::EmitCVInlineLinetableDirective( - PrimaryFunctionId, SourceFileId, SourceLineNum, SecondaryFunctionIds); + PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, + SecondaryFunctionIds); } void MCObjectStreamer::EmitCVStringTableDirective() { diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 621618a5666..9f8027a381e 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -3229,7 +3229,7 @@ bool AsmParser::parseDirectiveCVLinetable() { } /// parseDirectiveCVInlineLinetable -/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum +/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart /// ("contains" SecondaryFunctionId+)? bool AsmParser::parseDirectiveCVInlineLinetable() { int64_t PrimaryFunctionId = getTok().getIntVal(); @@ -3250,6 +3250,12 @@ bool AsmParser::parseDirectiveCVInlineLinetable() { "Line number less than zero in '.cv_inline_linetable' directive"); Lex(); + SMLoc Loc = getLexer().getLoc(); + StringRef FnStartName; + if (parseIdentifier(FnStartName)) + return Error(Loc, "expected identifier in directive"); + MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName); + SmallVector<unsigned, 8> SecondaryFunctionIds; if (getLexer().is(AsmToken::Identifier)) { if (getTok().getIdentifier() != "contains") @@ -3268,8 +3274,9 @@ bool AsmParser::parseDirectiveCVInlineLinetable() { } } - getStreamer().EmitCVInlineLinetableDirective( - PrimaryFunctionId, SourceFileId, SourceLineNum, SecondaryFunctionIds); + getStreamer().EmitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId, + SourceLineNum, FnStartSym, + SecondaryFunctionIds); return false; } diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index 1f445ca5893..dcb01b4d119 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -198,7 +198,7 @@ void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId, void MCStreamer::EmitCVInlineLinetableDirective( unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, - ArrayRef<unsigned> SecondaryFunctionIds) {} + const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds) {} void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol) { diff --git a/llvm/test/DebugInfo/COFF/asm.ll b/llvm/test/DebugInfo/COFF/asm.ll index 33d80a72450..ef0737a80a0 100644 --- a/llvm/test/DebugInfo/COFF/asm.ll +++ b/llvm/test/DebugInfo/COFF/asm.ll @@ -42,8 +42,7 @@ ; X86-NEXT: .short 2 ; X86-NEXT: .short 4431 ; X86-NEXT: [[F1_END]]: -; Padding -; X86-NEXT: .zero 3 +; X86-NEXT: .p2align 2 ; Line table ; X86-NEXT: .cv_linetable 0, _f, [[END_OF_F]] ; File index to string table offset subsection @@ -131,8 +130,7 @@ ; X64-NEXT: .short 2 ; X64-NEXT: .short 4431 ; X64-NEXT: [[F1_END]]: -; Padding -; X64-NEXT: .zero 3 +; X64-NEXT: .p2align 2 ; Line table ; X64-NEXT: .cv_linetable 0, f, [[END_OF_F]] ; File index to string table offset subsection diff --git a/llvm/test/DebugInfo/COFF/inlining.ll b/llvm/test/DebugInfo/COFF/inlining.ll index 08e26c789a2..fafc224022e 100644 --- a/llvm/test/DebugInfo/COFF/inlining.ll +++ b/llvm/test/DebugInfo/COFF/inlining.ll @@ -39,40 +39,95 @@ ; ASM: addl $7, "?x@@3HC" ; ASM: .cv_loc 0 1 17 1 # t.cpp:17:1 -; OBJ: ProcStart { -; OBJ: PtrParent: 0x0 -; OBJ: PtrEnd: 0x0 -; OBJ: PtrNext: 0x0 -; OBJ: CodeSize: 0x3D -; OBJ: DbgStart: 0x0 -; OBJ: DbgEnd: 0x0 -; OBJ: FunctionType: 0x0 -; OBJ: CodeOffset: ?baz@@YAXXZ+0x0 -; OBJ: Segment: 0x0 -; OBJ: Flags [ (0x0) -; OBJ: ] -; OBJ: DisplayName: baz -; OBJ: LinkageName: ?baz@@YAXXZ -; OBJ: } -; OBJ: InlineSite { -; OBJ: PtrParent: 0x0 -; OBJ: PtrEnd: 0x0 -; OBJ: Inlinee: bar (0x1003) -; OBJ: BinaryAnnotations [ -; OBJ: ] -; OBJ: } -; OBJ: InlineSite { -; OBJ: PtrParent: 0x0 -; OBJ: PtrEnd: 0x0 -; OBJ: Inlinee: foo (0x1004) -; OBJ: BinaryAnnotations [ -; OBJ: ] -; OBJ: } -; OBJ: InlineSiteEnd { -; OBJ: } -; OBJ: InlineSiteEnd { -; OBJ: } -; OBJ: ProcEnd +; ASM: .section .debug$S,"dr" +; ASM: .long 246 # Inlinee lines subsection +; ASM: .long [[inline_end:.*]]-[[inline_beg:.*]] +; ASM: [[inline_beg]]: +; ASM: .long 0 +; ASM: .long 4099 # Inlined function bar starts at t.cpp:8 +; ASM: .long 0 +; ASM: .long 8 +; ASM: .long 4100 # Inlined function foo starts at t.cpp:2 +; ASM: .long 0 +; ASM: .long 2 +; ASM: [[inline_end]]: + +; ASM: .long 241 # Symbol subsection for baz +; ASM: .long Ltmp3-Ltmp2 +; ASM: .short 4429 +; ASM: .asciz +; ASM: .cv_inline_linetable 1 1 8 Lfunc_begin0 contains 2 +; ASM: .short 4429 +; ASM: .asciz +; ASM: .cv_inline_linetable 2 1 2 Lfunc_begin0 +; ASM: .short 4430 +; ASM: .short 4430 + +; OBJ: Subsection [ +; OBJ: SubSectionType: InlineeLines (0xF6) +; OBJ: SubSectionSize: 0x1C +; OBJ: InlineeSourceLine { +; OBJ: Inlinee: bar (0x1003) +; OBJ: FileID: D:\src\llvm\build\t.cpp (0x0) +; OBJ: SourceLineNum: 8 +; OBJ: } +; OBJ: InlineeSourceLine { +; OBJ: Inlinee: foo (0x1004) +; OBJ: FileID: D:\src\llvm\build\t.cpp (0x0) +; OBJ: SourceLineNum: 2 +; OBJ: } +; OBJ: ] +; OBJ: Subsection [ +; OBJ: SubSectionType: Symbols (0xF1) +; OBJ: ProcStart { +; OBJ: PtrParent: 0x0 +; OBJ: PtrEnd: 0x0 +; OBJ: PtrNext: 0x0 +; OBJ: CodeSize: 0x3D +; OBJ: DbgStart: 0x0 +; OBJ: DbgEnd: 0x0 +; OBJ: FunctionType: 0x0 +; OBJ: CodeOffset: ?baz@@YAXXZ+0x0 +; OBJ: Segment: 0x0 +; OBJ: Flags [ (0x0) +; OBJ: ] +; OBJ: DisplayName: baz +; OBJ: LinkageName: ?baz@@YAXXZ +; OBJ: } +; OBJ: InlineSite { +; OBJ: PtrParent: 0x0 +; OBJ: PtrEnd: 0x0 +; OBJ: Inlinee: bar (0x1003) +; OBJ: BinaryAnnotations [ +; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x8, LineOffset: 1} +; OBJ-NEXT: ChangeLineOffset: -6 +; OBJ-NEXT: ChangeCodeOffset: 0x7 +; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xA, LineOffset: 1} +; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1} +; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1} +; OBJ-NEXT: ChangeLineOffset: 5 +; OBJ-NEXT: ChangeCodeOffset: 0x7 +; OBJ-NEXT: ChangeCodeLength: 0x7 +; OBJ: ] +; OBJ: } +; OBJ: InlineSite { +; OBJ: PtrParent: 0x0 +; OBJ: PtrEnd: 0x0 +; OBJ: Inlinee: foo (0x1004) +; OBJ: BinaryAnnotations [ +; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xF, LineOffset: 1} +; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xA, LineOffset: 1} +; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1} +; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1} +; OBJ-NEXT: ChangeCodeLength: 0x7 +; OBJ: ] +; OBJ: } +; OBJ: InlineSiteEnd { +; OBJ: } +; OBJ: InlineSiteEnd { +; OBJ: } +; OBJ: ProcEnd +; OBJ: ] ; ModuleID = 't.cpp' target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" diff --git a/llvm/test/DebugInfo/COFF/multifile.ll b/llvm/test/DebugInfo/COFF/multifile.ll index f1b68b654ba..b8055f1d310 100644 --- a/llvm/test/DebugInfo/COFF/multifile.ll +++ b/llvm/test/DebugInfo/COFF/multifile.ll @@ -51,8 +51,7 @@ ; X86-NEXT: .short 2 ; X86-NEXT: .short 4431 ; X86-NEXT: [[F1_END]]: -; Padding -; X86-NEXT: .zero 3 +; X86-NEXT: .p2align 2 ; Line table ; X86-NEXT: .cv_linetable 0, _f, [[END_OF_F]] ; File index to string table offset subsection @@ -155,8 +154,7 @@ ; X64-NEXT: .short 2 ; X64-NEXT: .short 4431 ; X64-NEXT: [[F1_END]]: -; Padding -; X64-NEXT: .zero 3 +; X64-NEXT: .p2align 2 ; X64: .cv_linetable 0, f, [[END_OF_F]] ; X64: .cv_filechecksums ; X64: .cv_stringtable diff --git a/llvm/test/DebugInfo/COFF/multifunction.ll b/llvm/test/DebugInfo/COFF/multifunction.ll index 2e6b3b7a5cb..152e4acc61a 100644 --- a/llvm/test/DebugInfo/COFF/multifunction.ll +++ b/llvm/test/DebugInfo/COFF/multifunction.ll @@ -72,8 +72,7 @@ ; X86-NEXT: .short 2 ; X86-NEXT: .short 4431 ; X86-NEXT: [[F1_END]]: -; Padding -; X86-NEXT: .zero 3 +; X86-NEXT: .p2align 2 ; Line table subsection for x ; X86: .cv_linetable 0, _x, [[END_OF_X]] ; Symbol subsection for y @@ -95,8 +94,7 @@ ; X86-NEXT: .short 2 ; X86-NEXT: .short 4431 ; X86-NEXT: [[F1_END]]: -; Padding -; X86-NEXT: .zero 3 +; X86-NEXT: .p2align 2 ; Line table subsection for y ; X86: .cv_linetable 1, _y, [[END_OF_Y]] ; Symbol subsection for f @@ -118,8 +116,7 @@ ; X86-NEXT: .short 2 ; X86-NEXT: .short 4431 ; X86-NEXT: [[F1_END]]: -; Padding -; X86-NEXT: .zero 3 +; X86-NEXT: .p2align 2 ; Line table subsection for f ; X86: .cv_linetable 2, _f, [[END_OF_F]] ; X86: .cv_filechecksums @@ -326,8 +323,7 @@ ; X64-NEXT: .short 2 ; X64-NEXT: .short 4431 ; X64-NEXT: [[F1_END]]: -; Padding -; X64-NEXT: .zero 3 +; X64-NEXT: .p2align 2 ; Line table subsection for x ; X64: .cv_linetable 0, x, [[END_OF_X]] ; Symbol subsection for y @@ -349,8 +345,7 @@ ; X64-NEXT: .short 2 ; X64-NEXT: .short 4431 ; X64-NEXT: [[F1_END]]: -; Padding -; X64-NEXT: .zero 3 +; X64-NEXT: .p2align 2 ; Line table subsection for y ; X64: .cv_linetable 1, y, [[END_OF_Y]] ; Symbol subsection for f @@ -372,8 +367,7 @@ ; X64-NEXT: .short 2 ; X64-NEXT: .short 4431 ; X64-NEXT: [[F1_END]]: -; Padding -; X64-NEXT: .zero 3 +; X64-NEXT: .p2align 2 ; Line table subsection for f ; X64: .cv_linetable 2, f, [[END_OF_F]] ; File index to string table offset subsection diff --git a/llvm/test/DebugInfo/COFF/simple.ll b/llvm/test/DebugInfo/COFF/simple.ll index 6612a3393e4..3438c775cbf 100644 --- a/llvm/test/DebugInfo/COFF/simple.ll +++ b/llvm/test/DebugInfo/COFF/simple.ll @@ -41,8 +41,7 @@ ; X86-NEXT: .short 2 ; X86-NEXT: .short 4431 ; X86-NEXT: [[F1_END]]: -; Padding -; X86-NEXT: .zero 3 +; X86-NEXT: .p2align 2 ; Line table ; X86-NEXT: .cv_linetable 0, _f, [[END_OF_F]] ; File index to string table offset subsection @@ -127,8 +126,7 @@ ; X64-NEXT: .short 2 ; X64-NEXT: .short 4431 ; X64-NEXT: [[F1_END]]: -; Padding -; X64-NEXT: .zero 3 +; X64-NEXT: .p2align 2 ; Line table ; X64-NEXT: .cv_linetable 0, f, [[END_OF_F]] ; File index to string table offset subsection diff --git a/llvm/test/MC/COFF/cv-inline-linetable.s b/llvm/test/MC/COFF/cv-inline-linetable.s index db83de97ac8..222a0859db5 100644 --- a/llvm/test/MC/COFF/cv-inline-linetable.s +++ b/llvm/test/MC/COFF/cv-inline-linetable.s @@ -84,13 +84,20 @@ Ltmp3: Ltmp4: .short 4429 .asciz "\000\000\000\000\000\000\000\000\003\020\000" - .cv_inline_linetable 1 1 9 contains 2 + .cv_inline_linetable 1 1 9 Lfunc_begin0 contains 2 # CHECK: InlineSite { # CHECK: PtrParent: 0x0 # CHECK: PtrEnd: 0x0 # CHECK: Inlinee: bar (0x1003) # CHECK: BinaryAnnotations [ -# CHECK: ChangeLineOffset: 2 +# CHECK: ChangeLineOffset: -6 +# CHECK: ChangeCodeOffset: 0xF +# CHECK: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xA, LineOffset: 1} +# CHECK: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1} +# CHECK: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1} +# CHECK: ChangeLineOffset: 5 +# CHECK: ChangeCodeOffset: 0x7 +# CHECK: ChangeCodeLength: 0x7 # CHECK: ] # CHECK: } Ltmp5: @@ -98,26 +105,32 @@ Ltmp5: Ltmp6: .short 4429 .asciz "\000\000\000\000\000\000\000\000\004\020\000" - .cv_inline_linetable 2 1 3 + .cv_inline_linetable 2 1 3 Lfunc_begin0 # CHECK: InlineSite { # CHECK: PtrParent: 0x0 # CHECK: PtrEnd: 0x0 # CHECK: Inlinee: foo (0x1004) # CHECK: BinaryAnnotations [ # CHECK: ChangeLineOffset: 1 -# CHECK: ChangeLineOffset: 1 -# CHECK: ChangeLineOffset: 1 +# CHECK: ChangeCodeOffset: 0x19 +# CHECK: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1} +# CHECK: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1} +# CHECK: ChangeCodeLength: 0x7 # CHECK: ] # CHECK: } Ltmp7: .short 2 .short 4430 +# CHECK: InlineSiteEnd { +# CHECK: } .short 2 .short 4430 +# CHECK: InlineSiteEnd { +# CHECK: } .short 2 .short 4431 Ltmp1: - .zero 1 + .p2align 2 .cv_linetable 0, "?baz@@YAXXZ", Lfunc_end0 .cv_filechecksums # File index to string table offset subsection .cv_stringtable # String table diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index 09eca62ee59..8c308f60592 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -1423,7 +1423,7 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, W.printHex("ChangeCodeOffset", GetCompressedAnnotation()); break; case ChangeCodeLength: - W.printNumber("ChangeCodeLength", GetCompressedAnnotation()); + W.printHex("ChangeCodeLength", GetCompressedAnnotation()); break; case ChangeFile: printFileNameForOffset("ChangeFile", GetCompressedAnnotation()); |