1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[codeview] Add new directives to record inlined call site line info

Summary:
Previously we were trying to represent this with the "contains" list of
the .cv_inline_linetable directive, which was not enough information.
Now we directly represent the chain of inlined call sites, so we know
what location to emit when we encounter a .cv_loc directive of an inner
inlined call site while emitting the line table of an outer function or
inlined call site. Fixes PR29146.

Also fixes PR29147, where we would crash when .cv_loc directives crossed
sections. Now we write down the section of the first .cv_loc directive,
and emit an error if any other .cv_loc directive for that function is in
a different section.

Also fixes issues with discontiguous inlined source locations, like in
this example:

  volatile int unlikely_cond = 0;
  extern void __declspec(noreturn) abort();
  __forceinline void f() {
    if (!unlikely_cond) abort();
  }
  int main() {
    unlikely_cond = 0;
    f();
    unlikely_cond = 0;
  }

Previously our tables gave bad location information for the 'abort'
call, and the debugger wouldn't snow the inlined stack frame for 'f'.
It is important to emit good line tables for this code pattern, because
it comes up whenever an asan bug occurs in an inlined function. The
__asan_report* stubs are generally placed after the normal function
epilogue, leading to discontiguous regions of inlined code.

Reviewers: majnemer, amccarth

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D24014

llvm-svn: 280822
This commit is contained in:
Reid Kleckner 2016-09-07 16:15:31 +00:00
parent 2f60815d8e
commit bdfdb24819
23 changed files with 741 additions and 176 deletions

View File

@ -105,6 +105,55 @@ public:
static void Make(MCObjectStreamer *MCOS);
};
/// Information describing a function or inlined call site introduced by
/// .cv_func_id or .cv_inline_site_id. Accumulates information from .cv_loc
/// directives used with this function's id or the id of an inlined call site
/// within this function or inlined call site.
struct MCCVFunctionInfo {
/// If this represents an inlined call site, then ParentFuncIdPlusOne will be
/// the parent function id plus one. If this represents a normal function,
/// then there is no parent, and ParentFuncIdPlusOne will be FunctionSentinel.
/// If this struct is an unallocated slot in the function info vector, then
/// ParentFuncIdPlusOne will be zero.
unsigned ParentFuncIdPlusOne = 0;
enum : unsigned { FunctionSentinel = ~0U };
struct LineInfo {
unsigned File;
unsigned Line;
unsigned Col;
};
LineInfo InlinedAt;
/// The section of the first .cv_loc directive used for this function, or null
/// if none has been seen yet.
MCSection *Section = nullptr;
/// Map from inlined call site id to the inlined at location to use for that
/// call site. Call chains are collapsed, so for the call chain 'f -> g -> h',
/// the InlinedAtMap of 'f' will contain entries for 'g' and 'h' that both
/// list the line info for the 'g' call site.
DenseMap<unsigned, LineInfo> InlinedAtMap;
/// Returns true if this is function info has not yet been used in a
/// .cv_func_id or .cv_inline_site_id directive.
bool isUnallocatedFunctionInfo() const { return ParentFuncIdPlusOne == 0; }
/// Returns true if this represents an inlined call site, meaning
/// ParentFuncIdPlusOne is neither zero nor ~0U.
bool isInlinedCallSite() const {
return !isUnallocatedFunctionInfo() &&
ParentFuncIdPlusOne != FunctionSentinel;
}
unsigned getParentFuncId() const {
assert(isInlinedCallSite());
return ParentFuncIdPlusOne - 1;
}
};
/// Holds state from .cv_file and .cv_loc directives for later emission.
class CodeViewContext {
public:
@ -115,6 +164,27 @@ public:
bool addFile(unsigned FileNumber, StringRef Filename);
ArrayRef<StringRef> getFilenames() { return Filenames; }
/// Records the function id of a normal function. Returns false if the
/// function id has already been used, and true otherwise.
bool recordFunctionId(unsigned FuncId);
/// Records the function id of an inlined call site. Records the "inlined at"
/// location info of the call site, including what function or inlined call
/// site it was inlined into. Returns false if the function id has already
/// been used, and true otherwise.
bool recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
unsigned IAFile, unsigned IALine,
unsigned IACol);
/// Retreive the function info if this is a valid function id, or nullptr.
MCCVFunctionInfo *getCVFunctionInfo(unsigned FuncId) {
if (FuncId >= Functions.size())
return nullptr;
if (Functions[FuncId].isUnallocatedFunctionInfo())
return nullptr;
return &Functions[FuncId];
}
/// Saves the information from the currently parsed .cv_loc directive
/// and sets CVLocSeen. When the next instruction is assembled an entry
/// in the line number table with this information and the address of the
@ -179,10 +249,12 @@ public:
const MCSymbol *FuncBegin,
const MCSymbol *FuncEnd);
void emitInlineLineTableForFunction(
MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId,
unsigned SourceLineNum, const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym, ArrayRef<unsigned> SecondaryFunctionIds);
void emitInlineLineTableForFunction(MCObjectStreamer &OS,
unsigned PrimaryFunctionId,
unsigned SourceFileId,
unsigned SourceLineNum,
const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym);
/// Encodes the binary annotations once we have a layout.
void encodeInlineLineTable(MCAsmLayout &Layout,
@ -230,6 +302,9 @@ private:
/// A collection of MCCVLineEntry for each section.
std::vector<MCCVLineEntry> MCCVLines;
/// All known functions and inlined call sites, indexed by function id.
std::vector<MCCVFunctionInfo> Functions;
};
} // end namespace llvm

View File

@ -491,7 +491,6 @@ class MCCVInlineLineTableFragment : public MCFragment {
unsigned StartLineNum;
const MCSymbol *FnStartSym;
const MCSymbol *FnEndSym;
SmallVector<unsigned, 3> SecondaryFuncs;
SmallString<8> Contents;
/// CodeViewContext has the real knowledge about this format, so let it access
@ -502,12 +501,10 @@ public:
MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId,
unsigned StartLineNum, const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFuncs,
MCSection *Sec = nullptr)
: MCFragment(FT_CVInlineLines, false, 0, Sec), SiteFuncId(SiteFuncId),
StartFileId(StartFileId), StartLineNum(StartLineNum),
FnStartSym(FnStartSym), FnEndSym(FnEndSym),
SecondaryFuncs(SecondaryFuncs.begin(), SecondaryFuncs.end()) {}
FnStartSym(FnStartSym), FnEndSym(FnEndSym) {}
/// \name Accessors
/// @{

View File

@ -124,13 +124,14 @@ public:
const MCSymbol *Label);
void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
unsigned Column, bool PrologueEnd, bool IsStmt,
StringRef FileName) override;
StringRef FileName, SMLoc Loc) override;
void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *Begin,
const MCSymbol *End) override;
void EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds) override;
void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
unsigned SourceFileId,
unsigned SourceLineNum,
const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym) override;
void EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) override;

View File

@ -713,11 +713,20 @@ public:
/// success.
virtual bool EmitCVFileDirective(unsigned FileNo, StringRef Filename);
/// \brief Introduces a function id for use with .cv_loc.
virtual bool EmitCVFuncIdDirective(unsigned FunctionId);
/// \brief Introduces an inline call site id for use with .cv_loc. Includes
/// extra information for inline line table generation.
virtual bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
unsigned IAFile, unsigned IALine,
unsigned IACol, SMLoc Loc);
/// \brief This implements the CodeView '.cv_loc' assembler directive.
virtual void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
unsigned Line, unsigned Column,
bool PrologueEnd, bool IsStmt,
StringRef FileName);
StringRef FileName, SMLoc Loc);
/// \brief This implements the CodeView '.cv_linetable' assembler directive.
virtual void EmitCVLinetableDirective(unsigned FunctionId,
@ -726,10 +735,11 @@ public:
/// \brief This implements the CodeView '.cv_inline_linetable' assembler
/// directive.
virtual void EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds);
virtual void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
unsigned SourceFileId,
unsigned SourceLineNum,
const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym);
/// \brief This implements the CodeView '.cv_def_range' assembler
/// directive.

View File

@ -124,7 +124,16 @@ CodeViewDebug::getInlineSite(const DILocation *InlinedAt,
auto SiteInsertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()});
InlineSite *Site = &SiteInsertion.first->second;
if (SiteInsertion.second) {
unsigned ParentFuncId = CurFn->FuncId;
if (const DILocation *OuterIA = InlinedAt->getInlinedAt())
ParentFuncId =
getInlineSite(OuterIA, InlinedAt->getScope()->getSubprogram())
.SiteFuncId;
Site->SiteFuncId = NextFuncId++;
OS.EmitCVInlineSiteIdDirective(
Site->SiteFuncId, ParentFuncId, maybeRecordFile(InlinedAt->getFile()),
InlinedAt->getLine(), InlinedAt->getColumn(), SMLoc());
Site->Inlinee = Inlinee;
InlinedSubprograms.insert(Inlinee);
getFuncIdForSubprogram(Inlinee);
@ -357,8 +366,8 @@ void CodeViewDebug::maybeRecordLocation(const DebugLoc &DL,
}
OS.EmitCVLocDirective(FuncId, FileId, DL.getLine(), DL.getCol(),
/*PrologueEnd=*/false,
/*IsStmt=*/false, DL->getFilename());
/*PrologueEnd=*/false, /*IsStmt=*/false,
DL->getFilename(), SMLoc());
}
void CodeViewDebug::emitCodeViewMagicVersion() {
@ -529,17 +538,6 @@ void CodeViewDebug::emitInlineeLinesSubsection() {
endCVSubsection(InlineEnd);
}
void CodeViewDebug::collectInlineSiteChildren(
SmallVectorImpl<unsigned> &Children, const FunctionInfo &FI,
const InlineSite &Site) {
for (const DILocation *ChildSiteLoc : Site.ChildSites) {
auto I = FI.InlineSites.find(ChildSiteLoc);
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) {
@ -565,11 +563,9 @@ void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
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, FI.End, SecondaryFuncIds);
FI.Begin, FI.End);
OS.EmitLabel(InlineEnd);
@ -877,6 +873,8 @@ void CodeViewDebug::beginFunction(const MachineFunction *MF) {
CurFn->FuncId = NextFuncId++;
CurFn->Begin = Asm->getFunctionBegin();
OS.EmitCVFuncIdDirective(CurFn->FuncId);
// Find the end of the function prolog. First known non-DBG_VALUE and
// non-frame setup location marks the beginning of the function body.
// FIXME: is there a simpler a way to do this? Can we just search

View File

@ -222,15 +222,20 @@ public:
MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;
bool EmitCVFileDirective(unsigned FileNo, StringRef Filename) override;
bool EmitCVFuncIdDirective(unsigned FuncId) override;
bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
unsigned IAFile, unsigned IALine,
unsigned IACol, SMLoc Loc) override;
void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
unsigned Column, bool PrologueEnd, bool IsStmt,
StringRef FileName) override;
StringRef FileName, SMLoc Loc) override;
void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,
const MCSymbol *FnEnd) override;
void EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds) override;
void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
unsigned SourceFileId,
unsigned SourceLineNum,
const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym) override;
void EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) override;
@ -1114,10 +1119,26 @@ bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) {
return true;
}
bool MCAsmStreamer::EmitCVFuncIdDirective(unsigned FuncId) {
OS << "\t.cv_func_id " << FuncId << '\n';
return MCStreamer::EmitCVFuncIdDirective(FuncId);
}
bool MCAsmStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId,
unsigned IAFunc,
unsigned IAFile,
unsigned IALine, unsigned IACol,
SMLoc Loc) {
OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc
<< " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n';
return MCStreamer::EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
IALine, IACol, Loc);
}
void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
unsigned Line, unsigned Column,
bool PrologueEnd, bool IsStmt,
StringRef FileName) {
StringRef FileName, SMLoc Loc) {
OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " "
<< Column;
if (PrologueEnd)
@ -1135,12 +1156,12 @@ void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
if (IsVerboseAsm) {
OS.PadToColumn(MAI->getCommentColumn());
OS << MAI->getCommentString() << ' ' << FileName << ':'
<< Line << ':' << Column;
OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':'
<< Column;
}
EmitEOL();
this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column,
PrologueEnd, IsStmt, FileName);
PrologueEnd, IsStmt, FileName, Loc);
}
void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId,
@ -1154,24 +1175,19 @@ void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId,
this->MCStreamer::EmitCVLinetableDirective(FunctionId, FnStart, FnEnd);
}
void MCAsmStreamer::EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds) {
void MCAsmStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
unsigned SourceFileId,
unsigned SourceLineNum,
const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym) {
OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId
<< ' ' << SourceLineNum << ' ';
FnStartSym->print(OS, MAI);
OS << ' ';
FnEndSym->print(OS, MAI);
if (!SecondaryFunctionIds.empty()) {
OS << " contains";
for (unsigned SecondaryFunctionId : SecondaryFunctionIds)
OS << ' ' << SecondaryFunctionId;
}
EmitEOL();
this->MCStreamer::EmitCVInlineLinetableDirective(
PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym,
SecondaryFunctionIds);
PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
}
void MCAsmStreamer::EmitCVDefRangeDirective(

View File

@ -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();
@ -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,83 @@ 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);
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 +415,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);

View File

@ -369,13 +369,13 @@ void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
void MCObjectStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
unsigned Line, unsigned Column,
bool PrologueEnd, bool IsStmt,
StringRef FileName) {
StringRef FileName, SMLoc Loc) {
// In case we see two .cv_loc directives in a row, make sure the
// first one gets a line entry.
MCCVLineEntry::Make(this);
this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column,
PrologueEnd, IsStmt, FileName);
PrologueEnd, IsStmt, FileName, Loc);
}
void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId,
@ -388,14 +388,12 @@ void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId,
void MCObjectStreamer::EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds) {
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) {
getContext().getCVContext().emitInlineLineTableForFunction(
*this, PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym,
FnEndSym, SecondaryFunctionIds);
FnEndSym);
this->MCStreamer::EmitCVInlineLinetableDirective(
PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym,
SecondaryFunctionIds);
PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
}
void MCObjectStreamer::EmitCVDefRangeDirective(

View File

@ -378,6 +378,9 @@ private:
bool parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc);
bool parseCVFunctionId(int64_t &FunctionId, StringRef DirectiveName);
bool parseCVFileId(int64_t &FileId, StringRef DirectiveName);
// Generic (target and platform independent) directive parsing.
enum DirectiveKind {
DK_NO_DIRECTIVE, // Placeholder
@ -397,8 +400,9 @@ private:
DK_IFNB, DK_IFC, DK_IFEQS, DK_IFNC, DK_IFNES, DK_IFDEF, DK_IFNDEF,
DK_IFNOTDEF, DK_ELSEIF, DK_ELSE, DK_ENDIF,
DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS,
DK_CV_FILE, DK_CV_LOC, DK_CV_LINETABLE, DK_CV_INLINE_LINETABLE,
DK_CV_DEF_RANGE, DK_CV_STRINGTABLE, DK_CV_FILECHECKSUMS,
DK_CV_FILE, DK_CV_FUNC_ID, DK_CV_INLINE_SITE_ID, DK_CV_LOC, DK_CV_LINETABLE,
DK_CV_INLINE_LINETABLE, DK_CV_DEF_RANGE, DK_CV_STRINGTABLE,
DK_CV_FILECHECKSUMS,
DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA,
DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER,
DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA,
@ -436,9 +440,11 @@ private:
bool parseDirectiveLoc();
bool parseDirectiveStabs();
// ".cv_file", ".cv_loc", ".cv_linetable", "cv_inline_linetable",
// ".cv_def_range"
// ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable",
// ".cv_inline_linetable", ".cv_def_range"
bool parseDirectiveCVFile();
bool parseDirectiveCVFuncId();
bool parseDirectiveCVInlineSiteId();
bool parseDirectiveCVLoc();
bool parseDirectiveCVLinetable();
bool parseDirectiveCVInlineLinetable();
@ -1790,6 +1796,10 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveStabs();
case DK_CV_FILE:
return parseDirectiveCVFile();
case DK_CV_FUNC_ID:
return parseDirectiveCVFuncId();
case DK_CV_INLINE_SITE_ID:
return parseDirectiveCVInlineSiteId();
case DK_CV_LOC:
return parseDirectiveCVLoc();
case DK_CV_LINETABLE:
@ -3240,6 +3250,107 @@ bool AsmParser::parseDirectiveCVFile() {
return false;
}
bool AsmParser::parseCVFunctionId(int64_t &FunctionId,
StringRef DirectiveName) {
SMLoc Loc;
return parseTokenLoc(Loc) ||
parseIntToken(FunctionId, "expected function id in '" + DirectiveName +
"' directive") ||
check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc,
"expected function id within range [0, UINT_MAX)");
}
bool AsmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) {
SMLoc Loc;
return parseTokenLoc(Loc) ||
parseIntToken(FileNumber, "expected integer in '" + DirectiveName +
"' directive") ||
check(FileNumber < 1, Loc, "file number less than one in '" +
DirectiveName + "' directive") ||
check(!getCVContext().isValidFileNumber(FileNumber), Loc,
"unassigned file number in '" + DirectiveName + "' directive");
}
/// parseDirectiveCVFuncId
/// ::= .cv_func_id FunctionId
///
/// Introduces a function ID that can be used with .cv_loc.
bool AsmParser::parseDirectiveCVFuncId() {
SMLoc FunctionIdLoc = getTok().getLoc();
int64_t FunctionId;
if (parseCVFunctionId(FunctionId, ".cv_func_id") ||
parseToken(AsmToken::EndOfStatement,
"unexpected token in '.cv_func_id' directive"))
return true;
if (!getStreamer().EmitCVFuncIdDirective(FunctionId))
Error(FunctionIdLoc, "function id already allocated");
return false;
}
/// parseDirectiveCVInlineSiteId
/// ::= .cv_inline_site_id FunctionId
/// "within" IAFunc
/// "inlined_at" IAFile IALine [IACol]
///
/// Introduces a function ID that can be used with .cv_loc. Includes "inlined
/// at" source location information for use in the line table of the caller,
/// whether the caller is a real function or another inlined call site.
bool AsmParser::parseDirectiveCVInlineSiteId() {
SMLoc FunctionIdLoc = getTok().getLoc();
int64_t FunctionId;
int64_t IAFunc;
int64_t IAFile;
int64_t IALine;
int64_t IACol = 0;
// FunctionId
if (parseCVFunctionId(FunctionId, ".cv_inline_site_id"))
return true;
// "within"
if (check((getLexer().isNot(AsmToken::Identifier) ||
getTok().getIdentifier() != "within"),
"expected 'within' identifier in '.cv_inline_site_id' directive"))
return true;
Lex();
// IAFunc
if (parseCVFunctionId(IAFunc, ".cv_inline_site_id"))
return true;
// "inlined_at"
if (check((getLexer().isNot(AsmToken::Identifier) ||
getTok().getIdentifier() != "inlined_at"),
"expected 'inlined_at' identifier in '.cv_inline_site_id' "
"directive") )
return true;
Lex();
// IAFile IALine
if (parseCVFileId(IAFile, ".cv_inline_site_id") ||
parseIntToken(IALine, "expected line number after 'inlined_at'"))
return true;
// [IACol]
if (getLexer().is(AsmToken::Integer)) {
IACol = getTok().getIntVal();
Lex();
}
if (parseToken(AsmToken::EndOfStatement,
"unexpected token in '.cv_inline_site_id' directive"))
return true;
if (!getStreamer().EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
IALine, IACol, FunctionIdLoc))
Error(FunctionIdLoc, "function id already allocated");
return false;
}
/// parseDirectiveCVLoc
/// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos] [prologue_end]
/// [is_stmt VALUE]
@ -3248,18 +3359,11 @@ bool AsmParser::parseDirectiveCVFile() {
/// third number is a column position (zero if not specified). The remaining
/// optional items are .loc sub-directives.
bool AsmParser::parseDirectiveCVLoc() {
SMLoc DirectiveLoc = getTok().getLoc();
SMLoc Loc;
int64_t FunctionId, FileNumber;
if (parseTokenLoc(Loc) ||
parseIntToken(FunctionId, "unexpected token in '.cv_loc' directive") ||
check(FunctionId < 0, Loc,
"function id less than zero in '.cv_loc' directive") ||
parseTokenLoc(Loc) ||
parseIntToken(FileNumber, "expected integer in '.cv_loc' directive") ||
check(FileNumber < 1, Loc,
"file number less than one in '.cv_loc' directive") ||
check(!getCVContext().isValidFileNumber(FileNumber), Loc,
"unassigned file number in '.cv_loc' directive"))
if (parseCVFunctionId(FunctionId, ".cv_loc") ||
parseCVFileId(FileNumber, ".cv_loc"))
return true;
int64_t LineNumber = 0;
@ -3307,7 +3411,8 @@ bool AsmParser::parseDirectiveCVLoc() {
Lex();
getStreamer().EmitCVLocDirective(FunctionId, FileNumber, LineNumber,
ColumnPos, PrologueEnd, IsStmt, StringRef());
ColumnPos, PrologueEnd, IsStmt, StringRef(),
DirectiveLoc);
return false;
}
@ -3317,10 +3422,7 @@ bool AsmParser::parseDirectiveCVLinetable() {
int64_t FunctionId;
StringRef FnStartName, FnEndName;
SMLoc Loc = getTok().getLoc();
if (parseIntToken(FunctionId,
"expected Integer in '.cv_linetable' directive") ||
check(FunctionId < 0, Loc,
"function id less than zero in '.cv_linetable' directive") ||
if (parseCVFunctionId(FunctionId, ".cv_linetable") ||
parseToken(AsmToken::Comma,
"unexpected token in '.cv_linetable' directive") ||
parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,
@ -3340,16 +3442,11 @@ bool AsmParser::parseDirectiveCVLinetable() {
/// parseDirectiveCVInlineLinetable
/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart FnEnd
/// ("contains" SecondaryFunctionId+)?
bool AsmParser::parseDirectiveCVInlineLinetable() {
int64_t PrimaryFunctionId, SourceFileId, SourceLineNum;
StringRef FnStartName, FnEndName;
SMLoc Loc = getTok().getLoc();
if (parseIntToken(
PrimaryFunctionId,
"expected PrimaryFunctionId in '.cv_inline_linetable' directive") ||
check(PrimaryFunctionId < 0, Loc,
"function id less than zero in '.cv_inline_linetable' directive") ||
if (parseCVFunctionId(PrimaryFunctionId, ".cv_inline_linetable") ||
parseTokenLoc(Loc) ||
parseIntToken(
SourceFileId,
@ -3368,24 +3465,6 @@ bool AsmParser::parseDirectiveCVInlineLinetable() {
"expected identifier in directive"))
return true;
SmallVector<unsigned, 8> SecondaryFunctionIds;
if (getLexer().is(AsmToken::Identifier)) {
if (getTok().getIdentifier() != "contains")
return TokError(
"unexpected identifier in '.cv_inline_linetable' directive");
Lex();
while (getLexer().isNot(AsmToken::EndOfStatement)) {
int64_t SecondaryFunctionId = getTok().getIntVal();
if (SecondaryFunctionId < 0)
return TokError(
"function id less than zero in '.cv_inline_linetable' directive");
Lex();
SecondaryFunctionIds.push_back(SecondaryFunctionId);
}
}
if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement"))
return true;
@ -3393,7 +3472,7 @@ bool AsmParser::parseDirectiveCVInlineLinetable() {
MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
getStreamer().EmitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId,
SourceLineNum, FnStartSym,
FnEndSym, SecondaryFunctionIds);
FnEndSym);
return false;
}
@ -4701,9 +4780,11 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".loc"] = DK_LOC;
DirectiveKindMap[".stabs"] = DK_STABS;
DirectiveKindMap[".cv_file"] = DK_CV_FILE;
DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;
DirectiveKindMap[".cv_loc"] = DK_CV_LOC;
DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;
DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;
DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID;
DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;
DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;

View File

@ -220,22 +220,54 @@ bool MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) {
return getContext().getCVContext().addFile(FileNo, Filename);
}
bool MCStreamer::EmitCVFuncIdDirective(unsigned FunctionId) {
return getContext().getCVContext().recordFunctionId(FunctionId);
}
bool MCStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId,
unsigned IAFunc, unsigned IAFile,
unsigned IALine, unsigned IACol,
SMLoc Loc) {
if (getContext().getCVContext().getCVFunctionInfo(IAFunc) == nullptr) {
getContext().reportError(Loc, "parent function id not introduced by "
".cv_func_id or .cv_inline_site_id");
return true;
}
return getContext().getCVContext().recordInlinedCallSiteId(
FunctionId, IAFunc, IAFile, IALine, IACol);
}
void MCStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
unsigned Line, unsigned Column,
bool PrologueEnd, bool IsStmt,
StringRef FileName) {
getContext().getCVContext().setCurrentCVLoc(FunctionId, FileNo, Line, Column,
PrologueEnd, IsStmt);
StringRef FileName, SMLoc Loc) {
CodeViewContext &CVC = getContext().getCVContext();
MCCVFunctionInfo *FI = CVC.getCVFunctionInfo(FunctionId);
if (!FI)
return getContext().reportError(
Loc, "function id not introduced by .cv_func_id or .cv_inline_site_id");
// Track the section
if (FI->Section == nullptr)
FI->Section = getCurrentSectionOnly();
else if (FI->Section != getCurrentSectionOnly())
return getContext().reportError(
Loc,
"all .cv_loc directives for a function must be in the same section");
CVC.setCurrentCVLoc(FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt);
}
void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId,
const MCSymbol *Begin,
const MCSymbol *End) {}
void MCStreamer::EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds) {}
void MCStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
unsigned SourceFileId,
unsigned SourceLineNum,
const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym) {}
void MCStreamer::EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,

View File

@ -25,13 +25,16 @@
; ASM: _main: # @main
; ASM: Lfunc_begin0:
; ASM: .cv_func_id 0
; ASM: # BB#0: # %entry
; ASM: .cv_file 1 "D:\\src\\llvm\\build\\t.cpp"
; ASM: .cv_loc 0 1 9 5 is_stmt 0 # t.cpp:9:5
; ASM: incl "?x@@3HC"
; ASM: .cv_inline_site_id 1 within 0 inlined_at 1 10 3
; ASM: .cv_loc 1 1 4 5 # t.cpp:4:5
; ASM: addl $2, "?x@@3HC"
; ASM: .cv_file 2 "D:\\src\\llvm\\build\\t.h"
; ASM: .cv_inline_site_id 2 within 1 inlined_at 1 5 3
; ASM: .cv_loc 2 2 2 5 # ./t.h:2:5
; ASM: addl $3, "?x@@3HC"
; ASM: .cv_loc 1 1 6 5 # t.cpp:6:5
@ -61,7 +64,6 @@
; OBJ: Subsection [
; OBJ: SubSectionType: Symbols (0xF1)
; OBJ: SubSectionSize: 0x62
; OBJ: ProcStart {
; OBJ: Kind: S_GPROC32_ID (0x1147)
; OBJ: FunctionType: main (0x1005)
@ -78,7 +80,8 @@
; OBJ: Inlinee: g (0x1002)
; OBJ: BinaryAnnotations [
; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1}
; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xE, LineOffset: 2}
; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
; OBJ-NEXT: ChangeCodeLength: 0x7
; OBJ-NEXT: ]
; OBJ: }

View File

@ -20,13 +20,13 @@
; OBJ: SubSectionType: Symbols (0xF1)
; OBJ: ProcStart {
; OBJ: InlineSite {
; OBJ: Inlinee: h (0x1004)
; OBJ: Inlinee: h (0x1002)
; OBJ: }
; OBJ: InlineSite {
; OBJ: Inlinee: g (0x1003)
; OBJ: }
; OBJ: InlineSite {
; OBJ: Inlinee: f (0x1002)
; OBJ: Inlinee: f (0x1004)
; OBJ: }
; OBJ: InlineSiteEnd {
; OBJ: }

View File

@ -21,11 +21,14 @@
; 16: x += 7;
; 17: }
; ASM: .cv_func_id 0
; ASM: .cv_loc 0 1 13 0 is_stmt 0 # t.cpp:13:0
; ASM: .cv_loc 0 1 14 5 # t.cpp:14:5
; ASM: addl $6, "?x@@3HC"
; ASM: .cv_inline_site_id 1 within 0 inlined_at 1 15 3
; ASM: .cv_loc 1 1 9 5 # t.cpp:9:5
; ASM: addl $4, "?x@@3HC"
; ASM: .cv_inline_site_id 2 within 1 inlined_at 1 10 3
; ASM: .cv_loc 2 1 3 7 # t.cpp:3:7
; ASM: .cv_loc 2 1 4 5 # t.cpp:4:5
; ASM: addl {{.*}}, "?x@@3HC"
@ -60,7 +63,7 @@
; ASM: .long
; ASM: .long
; ASM: .long
; ASM: .cv_inline_linetable 1 1 8 Lfunc_begin0 Lfunc_end0 contains 2
; ASM: .cv_inline_linetable 1 1 8 Lfunc_begin0 Lfunc_end0
; ASM: .short 4429
; ASM: .long
; ASM: .long
@ -184,8 +187,9 @@
; OBJ: Inlinee: bar (0x1002)
; OBJ: BinaryAnnotations [
; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x8, LineOffset: 1}
; OBJ-NEXT: ChangeLineOffset: 2
; OBJ-NEXT: ChangeCodeOffset: 0x25
; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
; OBJ-NEXT: ChangeLineOffset: 1
; OBJ-NEXT: ChangeCodeOffset: 0x1E
; OBJ-NEXT: ChangeCodeLength: 0x7
; OBJ: ]
; OBJ: }

View File

@ -22,6 +22,7 @@
; 17: }
; ASM: f: # @f
; ASM: .cv_func_id 0
; ASM: .cv_file 1 "D:\\src\\llvm\\build\\t.cpp"
; ASM: .cv_loc 0 1 7 0 is_stmt 0 # t.cpp:7:0
; ASM: .seh_proc f
@ -40,6 +41,7 @@
; ASM: .cv_loc 0 1 9 9 # t.cpp:9:9
; ASM: movl $42, 40(%rsp)
; ASM: [[inline_site1:\.Ltmp.*]]:
; ASM: .cv_inline_site_id 1 within 0 inlined_at 1 10 5
; ASM: .cv_loc 1 1 4 7 # t.cpp:4:7
; ASM: movl $3, 44(%rsp)
; ASM: leaq 44(%rsp), %rcx
@ -54,6 +56,7 @@
; ASM: .cv_loc 0 1 13 9 # t.cpp:13:9
; ASM: movl $42, 36(%rsp)
; ASM: [[inline_site2:\.Ltmp.*]]:
; ASM: .cv_inline_site_id 2 within 0 inlined_at 1 14 5
; ASM: .cv_loc 2 1 4 7 # t.cpp:4:7
; ASM: movl $3, 48(%rsp)
; ASM: leaq 48(%rsp), %rcx

View File

@ -15,6 +15,7 @@
_g: # @g
Lfunc_begin0:
.cv_file 1 "\\usr\\local\\google\\home\\majnemer\\llvm\\src\\<stdin>"
.cv_func_id 0
.cv_loc 0 1 3 0 is_stmt 0 # <stdin>:3:0
# BB#0: # %entry
pushl %ebp

View File

@ -16,6 +16,7 @@ _f: # @f
Lfunc_begin0:
# BB#0: # %entry
.cv_file 1 "cv-empty-linetable.s"
.cv_func_id 1
.cv_loc 1 1 3 15 is_stmt 0
jmp _g # TAILCALL
Lfunc_end0:

56
test/MC/COFF/cv-errors.s Normal file
View File

@ -0,0 +1,56 @@
# RUN: not llvm-mc %s -o /dev/null 2>&1 | FileCheck %s
.text
foo:
.cv_file a
# CHECK: error: expected file number in '.cv_file' directive
# CHECK-NOT: error:
.cv_file 0 "t.cpp"
# CHECK: error: file number less than one
# CHECK-NOT: error:
.cv_func_id x
# CHECK: error: expected function id in '.cv_func_id' directive
# CHECK-NOT: error:
.cv_func_id -1
# CHECK: error: expected function id in '.cv_func_id' directive
# CHECK-NOT: error:
.cv_func_id 0xFFFFFFFFFFFFFFFF
# CHECK: error: expected function id within range [0, UINT_MAX)
# CHECK-NOT: error:
.cv_inline_site_id x
# CHECK: error: expected function id in '.cv_inline_site_id' directive
# CHECK-NOT: error:
.cv_file 1 "t.cpp"
.cv_func_id 0
.cv_inline_site_id 0 0 0 0 0 0
# CHECK: error: expected 'within' identifier in '.cv_inline_site_id' directive
# CHECK-NOT: error:
.cv_inline_site_id 0 within a
# CHECK: error: expected function id in '.cv_inline_site_id' directive
# CHECK-NOT: error:
.cv_inline_site_id 0 within 0 x
# CHECK: error: expected 'inlined_at' identifier in '.cv_inline_site_id' directive
# CHECK-NOT: error:
.cv_inline_site_id 0 within 0 inlined_at 0 0 0
# CHECK: error: file number less than one in '.cv_inline_site_id' directive
# CHECK-NOT: error:
.cv_inline_site_id 0 within 0 inlined_at 10 0 0
# CHECK: error: unassigned file number in '.cv_inline_site_id' directive
# CHECK-NOT: error:
.cv_inline_site_id 0 within 0 inlined_at 1 1 1
# CHECK: error: function id already allocated
# CHECK-NOT: error:
.cv_inline_site_id 1 within 0 inlined_at 1 1 1
.cv_loc 0 1 1 1 # t.cpp:1:1
nop
.cv_loc 1 1 1 1 # t.cpp:1:1
nop

View File

@ -19,6 +19,8 @@
.p2align 4, 0x90
infloop: # @infloop
.Lfunc_begin1:
.cv_func_id 0
.cv_inline_site_id 2 within 0 inlined_at 1 1 1
.cv_loc 2 1 3 7 # t.c:3:7
jmp .Lfunc_begin1
.Lfunc_end1:
@ -31,6 +33,7 @@ infloop: # @infloop
.globl afterinfloop
.p2align 4, 0x90
afterinfloop: # @afterinfloop
.cv_func_id 3
.cv_loc 3 1 13 0 # t.c:13:0
retq

View File

@ -0,0 +1,191 @@
# RUN: llvm-mc -triple=x86_64-windows -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s
# C source to generate the assembly:
# volatile int unlikely_cond = 0;
# extern void __declspec(noreturn) abort();
# __forceinline void f() {
# if (unlikely_cond)
# abort();
# }
# void g() {
# unlikely_cond = 0;
# f();
# unlikely_cond = 0;
# }
# This test is interesting because the inlined instructions are discontiguous.
# LLVM's block layout algorithms will put the 'abort' call last, as it is
# considered highly unlikely to execute. This is similar to what it does for
# calls to __asan_report*, for which it is very important to have an accurate
# stack trace.
# CHECK: ProcStart {
# CHECK: FunctionType: g (0x1003)
# CHECK: CodeOffset: g+0x0
# CHECK: DisplayName: g
# CHECK: LinkageName: g
# CHECK: }
# CHECK: InlineSite {
# CHECK: Inlinee: f (0x1002)
# CHECK: BinaryAnnotations [
# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xE, LineOffset: 1}
# CHECK-NEXT: ChangeCodeLength: 0x9
# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xF, LineOffset: 1}
# CHECK-NEXT: ChangeCodeLength: 0x7
# CHECK-NEXT: ]
.text
.globl g
g: # @g
.Lfunc_begin0:
.cv_func_id 0
.cv_file 1 "C:\\src\\llvm\\build\\t.cpp"
.cv_loc 0 1 7 0 is_stmt 0 # t.cpp:7:0
.seh_proc g
subq $40, %rsp
.seh_stackalloc 40
.seh_endprologue
.cv_loc 0 1 8 17 # t.cpp:8:17
movl $0, unlikely_cond(%rip)
.cv_inline_site_id 1 within 0 inlined_at 1 9 3
.cv_loc 1 1 4 7 # t.cpp:4:7
cmpl $0, unlikely_cond(%rip)
jne .LBB0_1
.cv_loc 0 1 10 17 # t.cpp:10:17
movl $0, unlikely_cond(%rip)
.cv_loc 0 1 11 1 # t.cpp:11:1
addq $40, %rsp
retq
.LBB0_1: # %if.then.i
.cv_loc 1 1 5 5 # t.cpp:5:5
callq abort
ud2
.Lfunc_end0:
.seh_handlerdata
.text
.seh_endproc
.bss
.globl unlikely_cond # @unlikely_cond
.p2align 2
unlikely_cond:
.long 0 # 0x0
.section .debug$S,"dr"
.p2align 2
.long 4 # Debug section magic
.long 246 # Inlinee lines subsection
.long .Ltmp9-.Ltmp8 # Subsection size
.Ltmp8:
.long 0 # Inlinee lines signature
# Inlined function f starts at t.cpp:3
.long 4098 # Type index of inlined function
.long 0 # Offset into filechecksum table
.long 3 # Starting line number
.Ltmp9:
.p2align 2
.long 241 # Symbol subsection for g
.long .Ltmp11-.Ltmp10 # Subsection size
.Ltmp10:
.short .Ltmp13-.Ltmp12 # Record length
.Ltmp12:
.short 4423 # Record kind: S_GPROC32_ID
.long 0 # PtrParent
.long 0 # PtrEnd
.long 0 # PtrNext
.long .Lfunc_end0-g # Code size
.long 0 # Offset after prologue
.long 0 # Offset before epilogue
.long 4099 # Function type index
.secrel32 g # Function section relative address
.secidx g # Function section index
.byte 0 # Flags
.asciz "g" # Function name
.Ltmp13:
.short .Ltmp15-.Ltmp14 # Record length
.Ltmp14:
.short 4429 # Record kind: S_INLINESITE
.long 0 # PtrParent
.long 0 # PtrEnd
.long 4098 # Inlinee type index
.cv_inline_linetable 1 1 3 .Lfunc_begin0 .Lfunc_end0
.Ltmp15:
.short 2 # Record length
.short 4430 # Record kind: S_INLINESITE_END
.short 2 # Record length
.short 4431 # Record kind: S_PROC_ID_END
.Ltmp11:
.p2align 2
.cv_linetable 0, g, .Lfunc_end0
.long 241 # Symbol subsection for globals
.long .Ltmp17-.Ltmp16 # Subsection size
.Ltmp16:
.short .Ltmp19-.Ltmp18 # Record length
.Ltmp18:
.short 4365 # Record kind: S_GDATA32
.long 4100 # Type
.secrel32 unlikely_cond # DataOffset
.secidx unlikely_cond # Segment
.asciz "unlikely_cond" # Name
.Ltmp19:
.Ltmp17:
.p2align 2
.cv_filechecksums # File index to string table offset subsection
.cv_stringtable # String table
.section .debug$T,"dr"
.p2align 2
.long 4 # Debug section magic
# ArgList (0x1000) {
# TypeLeafKind: LF_ARGLIST (0x1201)
# NumArgs: 0
# Arguments [
# ]
# }
.byte 0x06, 0x00, 0x01, 0x12
.byte 0x00, 0x00, 0x00, 0x00
# Procedure (0x1001) {
# TypeLeafKind: LF_PROCEDURE (0x1008)
# ReturnType: void (0x3)
# CallingConvention: NearC (0x0)
# FunctionOptions [ (0x0)
# ]
# NumParameters: 0
# ArgListType: () (0x1000)
# }
.byte 0x0e, 0x00, 0x08, 0x10
.byte 0x03, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x10, 0x00, 0x00
# FuncId (0x1002) {
# TypeLeafKind: LF_FUNC_ID (0x1601)
# ParentScope: 0x0
# FunctionType: void () (0x1001)
# Name: f
# }
.byte 0x0e, 0x00, 0x01, 0x16
.byte 0x00, 0x00, 0x00, 0x00
.byte 0x01, 0x10, 0x00, 0x00
.byte 0x66, 0x00, 0xf2, 0xf1
# FuncId (0x1003) {
# TypeLeafKind: LF_FUNC_ID (0x1601)
# ParentScope: 0x0
# FunctionType: void () (0x1001)
# Name: g
# }
.byte 0x0e, 0x00, 0x01, 0x16
.byte 0x00, 0x00, 0x00, 0x00
.byte 0x01, 0x10, 0x00, 0x00
.byte 0x67, 0x00, 0xf2, 0xf1
# Modifier (0x1004) {
# TypeLeafKind: LF_MODIFIER (0x1001)
# ModifiedType: int (0x74)
# Modifiers [ (0x2)
# Volatile (0x2)
# ]
# }
.byte 0x0a, 0x00, 0x01, 0x10
.byte 0x74, 0x00, 0x00, 0x00
.byte 0x02, 0x00, 0xf2, 0xf1

View File

@ -15,6 +15,8 @@
_g: # @g
Lfunc_begin0:
.cv_file 1 "\\usr\\local\\google\\home\\majnemer\\llvm\\src\\<stdin>"
.cv_func_id 0
.cv_inline_site_id 1 within 0 inlined_at 1 1 1
.cv_loc 0 1 7 0 is_stmt 0 # <stdin>:7:0
# BB#0: # %entry
pushl %ebp

View File

@ -15,6 +15,9 @@
"?baz@@YAXXZ": # @"\01?baz@@YAXXZ"
Lfunc_begin0:
.cv_file 1 "D:\\src\\llvm\\build\\t.cpp"
.cv_func_id 0
.cv_inline_site_id 1 within 0 inlined_at 1 15 3
.cv_inline_site_id 2 within 1 inlined_at 1 10 3
.cv_loc 0 1 13 0 is_stmt 0 # t.cpp:13:0
# BB#0: # %entry
pushl %eax
@ -84,16 +87,18 @@ Ltmp3:
Ltmp4:
.short 4429
.asciz "\000\000\000\000\000\000\000\000\003\020\000"
.cv_inline_linetable 1 1 9 Lfunc_begin0 Lfunc_end0 contains 2
.cv_inline_linetable 1 1 9 Lfunc_begin0 Lfunc_end0
# CHECK: InlineSite {
# CHECK: PtrParent: 0x0
# CHECK: PtrEnd: 0x0
# CHECK: Inlinee: bar (0x1003)
# CHECK: BinaryAnnotations [
# CHECK: ChangeLineOffset: 2
# CHECK: ChangeCodeOffset: 0x2D
# CHECK: ChangeCodeLength: 0x7
# CHECK: ]
# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x8, LineOffset: 0}
# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
# CHECK-NEXT: ChangeLineOffset: 1
# CHECK-NEXT: ChangeCodeOffset: 0x1E
# CHECK-NEXT: ChangeCodeLength: 0x7
# CHECK-NEXT: ]
# CHECK: }
Ltmp5:
.short Ltmp7-Ltmp6
@ -106,12 +111,12 @@ Ltmp6:
# CHECK: PtrEnd: 0x0
# CHECK: Inlinee: foo (0x1004)
# CHECK: BinaryAnnotations [
# CHECK: ChangeLineOffset: 1
# CHECK: ChangeCodeOffset: 0x19
# CHECK: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1}
# CHECK: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
# CHECK: ChangeCodeLength: 0x7
# CHECK: ]
# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xF, LineOffset: 0}
# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xA, LineOffset: 1}
# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1}
# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
# CHECK-NEXT: ChangeCodeLength: 0x7
# CHECK-NEXT: ]
# CHECK: }
Ltmp7:
.short 2

View File

@ -0,0 +1,26 @@
# RUN: not llvm-mc < %s -o /dev/null 2>&1 | FileCheck %s
.text
.global baz
baz:
.Lfunc_begin0:
.cv_file 1 "t.cpp"
.cv_func_id 0
.cv_loc 0 1 1 1
pushq %rbp
movq %rsp, %rbp
.cv_loc 0 1 2 1
.data # Switching sections raises an error.
incl x(%rip)
.cv_loc 0 1 3 1
# CHECK: error: all .cv_loc directives for a function must be in the same section
popq %rbp
retq
.Lfunc_end0:
.section .debug$S,"dr"
.cv_linetable 0 .Lfunc_begin0 .Lfunc_end0
.short 2 # Record length
.short 2 # Record kind: S_INLINESITE_END

View File

@ -7,6 +7,8 @@
.cv_file 1 "a.c"
.cv_file 2 "t.inc"
.cv_func_id 0
# Implements this C:
# void f(volatile int *x) {
# ++*x;