[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
diff --git a/llvm/lib/MC/MCCodeView.cpp b/llvm/lib/MC/MCCodeView.cpp
index a876470..ea226f7 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 @@
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());
+}
- const MCCVLineEntry *LastLoc = nullptr;
- unsigned LastFileId = SourceFileId;
- unsigned LastLineNum = SourceLineNum;
+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);
+}
+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() != LastLoc->getFileNum()) {
+ compressAnnotation(ChangeFile, Buffer);
+ compressAnnotation(Loc.getFileNum(), Buffer);
}
- if (Loc.getFileNum() != LastFileId)
- Annotations.push_back({ChangeFile, Loc.getFileNum()});
+ int LineDelta = Loc.getLine() - LastLoc->getLine();
+ if (LineDelta == 0)
+ continue;
- if (Loc.getLine() != LastLineNum)
- Annotations.push_back(
- {ChangeLineOffset, encodeSignedNumber(Loc.getLine() - LastLineNum)});
+ 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);
}
//