summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/MC/MCCodeView.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/MC/MCCodeView.cpp')
-rw-r--r--contrib/llvm/lib/MC/MCCodeView.cpp228
1 files changed, 168 insertions, 60 deletions
diff --git a/contrib/llvm/lib/MC/MCCodeView.cpp b/contrib/llvm/lib/MC/MCCodeView.cpp
index 65cff41..99a5c11 100644
--- a/contrib/llvm/lib/MC/MCCodeView.cpp
+++ b/contrib/llvm/lib/MC/MCCodeView.cpp
@@ -65,6 +65,50 @@ bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) {
return true;
}
+bool CodeViewContext::recordFunctionId(unsigned FuncId) {
+ if (FuncId >= Functions.size())
+ Functions.resize(FuncId + 1);
+
+ // Return false if this function info was already allocated.
+ if (!Functions[FuncId].isUnallocatedFunctionInfo())
+ return false;
+
+ // Mark this as an allocated normal function, and leave the rest alone.
+ Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel;
+ return true;
+}
+
+bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
+ unsigned IAFile, unsigned IALine,
+ unsigned IACol) {
+ if (FuncId >= Functions.size())
+ Functions.resize(FuncId + 1);
+
+ // Return false if this function info was already allocated.
+ if (!Functions[FuncId].isUnallocatedFunctionInfo())
+ return false;
+
+ MCCVFunctionInfo::LineInfo InlinedAt;
+ InlinedAt.File = IAFile;
+ InlinedAt.Line = IALine;
+ InlinedAt.Col = IACol;
+
+ // Mark this as an inlined call site and record call site line info.
+ MCCVFunctionInfo *Info = &Functions[FuncId];
+ Info->ParentFuncIdPlusOne = IAFunc + 1;
+ Info->InlinedAt = InlinedAt;
+
+ // Walk up the call chain adding this function id to the InlinedAtMap of all
+ // transitive callers until we hit a real function.
+ while (Info->isInlinedCallSite()) {
+ InlinedAt = Info->InlinedAt;
+ Info = getCVFunctionInfo(Info->getParentFuncId());
+ Info->InlinedAtMap[FuncId] = InlinedAt;
+ }
+
+ return true;
+}
+
MCDataFragment *CodeViewContext::getStringTableFragment() {
if (!StrTabFragment) {
StrTabFragment = new MCDataFragment();
@@ -156,7 +200,7 @@ void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
OS.EmitIntValue(unsigned(ModuleSubstreamKind::Lines), 4);
OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4);
OS.EmitLabel(LineBegin);
- OS.EmitCOFFSecRel32(FuncBegin);
+ OS.EmitCOFFSecRel32(FuncBegin, /*Offset=*/0);
OS.EmitCOFFSectionIndex(FuncBegin);
// Actual line info.
@@ -237,15 +281,17 @@ static uint32_t encodeSignedNumber(uint32_t Data) {
return Data << 1;
}
-void CodeViewContext::emitInlineLineTableForFunction(
- MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId,
- unsigned SourceLineNum, const MCSymbol *FnStartSym,
- const MCSymbol *FnEndSym, ArrayRef<unsigned> SecondaryFunctionIds) {
+void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS,
+ unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) {
// Create and insert a fragment into the current section that will be encoded
// later.
- new MCCVInlineLineTableFragment(
- PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym,
- SecondaryFunctionIds, OS.getCurrentSectionOnly());
+ new MCCVInlineLineTableFragment(PrimaryFunctionId, SourceFileId,
+ SourceLineNum, FnStartSym, FnEndSym,
+ OS.getCurrentSectionOnly());
}
void CodeViewContext::emitDefRange(
@@ -280,69 +326,92 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
size_t LocBegin;
size_t LocEnd;
std::tie(LocBegin, LocEnd) = getLineExtent(Frag.SiteFuncId);
- for (unsigned SecondaryId : Frag.SecondaryFuncs) {
- auto Extent = getLineExtent(SecondaryId);
+
+ // Include all child inline call sites in our .cv_loc extent.
+ MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId);
+ for (auto &KV : SiteInfo->InlinedAtMap) {
+ unsigned ChildId = KV.first;
+ auto Extent = getLineExtent(ChildId);
LocBegin = std::min(LocBegin, Extent.first);
LocEnd = std::max(LocEnd, Extent.second);
}
+
if (LocBegin >= LocEnd)
return;
ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd);
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 HaveOpenRange = false;
+ const MCSymbol *LastLabel = Frag.getFnStartSym();
+ MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc;
+ LastSourceLoc.File = Frag.StartFileId;
+ LastSourceLoc.Line = Frag.StartLineNum;
+
SmallVectorImpl<char> &Buffer = Frag.getContents();
Buffer.clear(); // Clear old contents if we went through relaxation.
for (const MCCVLineEntry &Loc : Locs) {
- 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 (HaveOpenRange) {
- unsigned Length =
- computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel());
- compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
- compressAnnotation(Length, Buffer);
+ // Exit early if our line table would produce an oversized InlineSiteSym
+ // record. Account for the ChangeCodeLength annotation emitted after the
+ // loop ends.
+ constexpr uint32_t InlineSiteSize = 12;
+ constexpr uint32_t AnnotationSize = 8;
+ size_t MaxBufferSize = MaxRecordLength - InlineSiteSize - AnnotationSize;
+ if (Buffer.size() >= MaxBufferSize)
+ break;
+
+ if (Loc.getFunctionId() == Frag.SiteFuncId) {
+ CurSourceLoc.File = Loc.getFileNum();
+ CurSourceLoc.Line = Loc.getLine();
+ } else {
+ auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId());
+ if (I != SiteInfo->InlinedAtMap.end()) {
+ // This .cv_loc is from a child inline call site. Use the source
+ // location of the inlined call site instead of the .cv_loc directive
+ // source location.
+ CurSourceLoc = I->second;
+ } else {
+ // We've hit a cv_loc not attributed to this inline call site. Use this
+ // label to end the PC range.
+ if (HaveOpenRange) {
+ unsigned Length = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
+ compressAnnotation(Length, Buffer);
+ LastLabel = Loc.getLabel();
+ }
+ HaveOpenRange = false;
+ continue;
}
- HaveOpenRange = false;
- continue;
}
- // If we've already opened the function and we're at an indirectly inlined
- // location, continue until the next directly inlined location.
- bool DirectlyInlined = Loc.getFunctionId() == Frag.SiteFuncId;
- if (!DirectlyInlined && HaveOpenRange)
+ // Skip this .cv_loc if we have an open range and this isn't a meaningful
+ // source location update. The current table format does not support column
+ // info, so we can skip updates for those.
+ if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File &&
+ CurSourceLoc.Line == LastSourceLoc.Line)
continue;
+
HaveOpenRange = true;
- if (Loc.getFileNum() != LastLoc->getFileNum()) {
+ if (CurSourceLoc.File != LastSourceLoc.File) {
// File ids are 1 based, and each file checksum table entry is 8 bytes
// long. See emitFileChecksums above.
- unsigned FileOffset = 8 * (Loc.getFileNum() - 1);
+ unsigned FileOffset = 8 * (CurSourceLoc.File - 1);
compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer);
compressAnnotation(FileOffset, Buffer);
}
- int LineDelta = Loc.getLine() - LastLoc->getLine();
- if (LineDelta == 0)
- continue;
-
+ int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line;
unsigned EncodedLineDelta = encodeSignedNumber(LineDelta);
- unsigned CodeDelta =
- computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel());
- if (CodeDelta == 0) {
+ unsigned CodeDelta = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
+ if (CodeDelta == 0 && LineDelta != 0) {
compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
compressAnnotation(EncodedLineDelta, Buffer);
} else if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) {
@@ -355,29 +424,29 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
compressAnnotation(Operand, Buffer);
} else {
// Otherwise use the separate line and code deltas.
- compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
- compressAnnotation(EncodedLineDelta, Buffer);
+ if (LineDelta != 0) {
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
+ compressAnnotation(EncodedLineDelta, Buffer);
+ }
compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer);
compressAnnotation(CodeDelta, Buffer);
}
- LastLoc = &Loc;
+ LastLabel = Loc.getLabel();
+ LastSourceLoc = CurSourceLoc;
}
assert(HaveOpenRange);
unsigned EndSymLength =
- computeLabelDiff(Layout, LastLoc->getLabel(), Frag.getFnEndSym());
+ computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym());
unsigned LocAfterLength = ~0U;
ArrayRef<MCCVLineEntry> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1);
if (!LocAfter.empty()) {
// Only try to compute this difference if we're in the same section.
const MCCVLineEntry &Loc = LocAfter[0];
- if (&Loc.getLabel()->getSection(false) ==
- &LastLoc->getLabel()->getSection(false)) {
- LocAfterLength =
- computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel());
- }
+ if (&Loc.getLabel()->getSection(false) == &LastLabel->getSection(false))
+ LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
}
compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
@@ -393,16 +462,41 @@ void CodeViewContext::encodeDefRange(MCAsmLayout &Layout,
Fixups.clear();
raw_svector_ostream OS(Contents);
- // Write down each range where the variable is defined.
+ // Compute all the sizes up front.
+ SmallVector<std::pair<unsigned, unsigned>, 4> GapAndRangeSizes;
+ const MCSymbol *LastLabel = nullptr;
for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) {
+ unsigned GapSize =
+ LastLabel ? computeLabelDiff(Layout, LastLabel, Range.first) : 0;
unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second);
+ GapAndRangeSizes.push_back({GapSize, RangeSize});
+ LastLabel = Range.second;
+ }
+
+ // Write down each range where the variable is defined.
+ for (size_t I = 0, E = Frag.getRanges().size(); I != E;) {
+ // If the range size of multiple consecutive ranges is under the max,
+ // combine the ranges and emit some gaps.
+ const MCSymbol *RangeBegin = Frag.getRanges()[I].first;
+ unsigned RangeSize = GapAndRangeSizes[I].second;
+ size_t J = I + 1;
+ for (; J != E; ++J) {
+ unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second;
+ if (RangeSize + GapAndRangeSize > MaxDefRange)
+ break;
+ RangeSize += GapAndRangeSize;
+ }
+ unsigned NumGaps = J - I - 1;
+
+ support::endian::Writer<support::little> LEWriter(OS);
+
unsigned Bias = 0;
// We must split the range into chunks of MaxDefRange, this is a fundamental
// limitation of the file format.
do {
uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize);
- const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Range.first, Ctx);
+ const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx);
const MCBinaryExpr *BE =
MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx);
MCValue Res;
@@ -413,26 +507,39 @@ void CodeViewContext::encodeDefRange(MCAsmLayout &Layout,
StringRef FixedSizePortion = Frag.getFixedSizePortion();
// Our record is a fixed sized prefix and a LocalVariableAddrRange that we
// are artificially constructing.
- size_t RecordSize =
- FixedSizePortion.size() + sizeof(LocalVariableAddrRange);
- // Write out the recrod size.
- support::endian::Writer<support::little>(OS).write<uint16_t>(RecordSize);
+ size_t RecordSize = FixedSizePortion.size() +
+ sizeof(LocalVariableAddrRange) + 4 * NumGaps;
+ // Write out the record size.
+ LEWriter.write<uint16_t>(RecordSize);
// Write out the fixed size prefix.
OS << FixedSizePortion;
// Make space for a fixup that will eventually have a section relative
// relocation pointing at the offset where the variable becomes live.
Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4));
- Contents.resize(Contents.size() + 4); // Fixup for code start.
+ LEWriter.write<uint32_t>(0); // Fixup for code start.
// Make space for a fixup that will record the section index for the code.
Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2));
- Contents.resize(Contents.size() + 2); // Fixup for section index.
+ LEWriter.write<uint16_t>(0); // Fixup for section index.
// Write down the range's extent.
- support::endian::Writer<support::little>(OS).write<uint16_t>(Chunk);
+ LEWriter.write<uint16_t>(Chunk);
// Move on to the next range.
Bias += Chunk;
RangeSize -= Chunk;
} while (RangeSize > 0);
+
+ // Emit the gaps afterwards.
+ assert((NumGaps == 0 || Bias <= MaxDefRange) &&
+ "large ranges should not have gaps");
+ unsigned GapStartOffset = GapAndRangeSizes[I].second;
+ for (++I; I != J; ++I) {
+ unsigned GapSize, RangeSize;
+ assert(I < GapAndRangeSizes.size());
+ std::tie(GapSize, RangeSize) = GapAndRangeSizes[I];
+ LEWriter.write<uint16_t>(GapStartOffset);
+ LEWriter.write<uint16_t>(GapSize);
+ GapStartOffset += GapSize + RangeSize;
+ }
}
}
@@ -442,7 +549,8 @@ void CodeViewContext::encodeDefRange(MCAsmLayout &Layout,
// a line entry made for it is made.
//
void MCCVLineEntry::Make(MCObjectStreamer *MCOS) {
- if (!MCOS->getContext().getCVLocSeen())
+ CodeViewContext &CVC = MCOS->getContext().getCVContext();
+ if (!CVC.getCVLocSeen())
return;
// Create a symbol at in the current section for use in the line entry.
@@ -451,14 +559,14 @@ void MCCVLineEntry::Make(MCObjectStreamer *MCOS) {
MCOS->EmitLabel(LineSym);
// Get the current .loc info saved in the context.
- const MCCVLoc &CVLoc = MCOS->getContext().getCurrentCVLoc();
+ const MCCVLoc &CVLoc = CVC.getCurrentCVLoc();
// Create a (local) line entry with the symbol and the current .loc info.
MCCVLineEntry LineEntry(LineSym, CVLoc);
// clear CVLocSeen saying the current .loc info is now used.
- MCOS->getContext().clearCVLocSeen();
+ CVC.clearCVLocSeen();
// Add the line entry to this section's entries.
- MCOS->getContext().getCVContext().addLineEntry(LineEntry);
+ CVC.addLineEntry(LineEntry);
}
OpenPOWER on IntegriCloud