summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2016-02-02 17:41:18 +0000
committerReid Kleckner <rnk@google.com>2016-02-02 17:41:18 +0000
commit617bba8af8b0582948a04c2c93db81226204ba25 (patch)
tree146f0ae7de74477f0a1ad82ca8ede476821001ec /lib
parent27751b528767b68b886e31af3a28b88e17e22be1 (diff)
[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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@259535 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/AsmPrinter/CodeViewDebug.cpp60
-rw-r--r--lib/CodeGen/AsmPrinter/CodeViewDebug.h11
-rw-r--r--lib/MC/MCAsmStreamer.cpp9
-rw-r--r--lib/MC/MCAssembler.cpp19
-rw-r--r--lib/MC/MCCodeView.cpp121
-rw-r--r--lib/MC/MCFragment.cpp14
-rw-r--r--lib/MC/MCObjectStreamer.cpp7
-rw-r--r--lib/MC/MCParser/AsmParser.cpp13
-rw-r--r--lib/MC/MCStreamer.cpp2
9 files changed, 215 insertions, 41 deletions
diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index e3c48296f34..de12fc38138 100644
--- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/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/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/lib/CodeGen/AsmPrinter/CodeViewDebug.h
index 4883905e907..d9f38f3eaf8 100644
--- a/lib/CodeGen/AsmPrinter/CodeViewDebug.h
+++ b/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/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index 1bac42a8d09..712b7a938be 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/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/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp
index 6965b1b037f..9a55ef3931e 100644
--- a/lib/MC/MCAssembler.cpp
+++ b/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/lib/MC/MCCodeView.cpp b/lib/MC/MCCodeView.cpp
index a876470b826..ea226f7769e 100644
--- a/lib/MC/MCCodeView.cpp
+++ b/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/lib/MC/MCFragment.cpp b/lib/MC/MCFragment.cpp
index 67f57a5c8fe..bfadfda47f2 100644
--- a/lib/MC/MCFragment.cpp
+++ b/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/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp
index 4f0b597b434..4d849049f60 100644
--- a/lib/MC/MCObjectStreamer.cpp
+++ b/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/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index 621618a5666..9f8027a381e 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/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/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp
index 1f445ca5893..dcb01b4d119 100644
--- a/lib/MC/MCStreamer.cpp
+++ b/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) {