Skip to content

Commit

Permalink
[codeview] Add new directives to record inlined call site line info
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rnk committed Sep 7, 2016
1 parent 9aa7d66 commit a9f4cc9
Show file tree
Hide file tree
Showing 23 changed files with 741 additions and 176 deletions.
83 changes: 79 additions & 4 deletions llvm/include/llvm/MC/MCCodeView.h
Expand Up @@ -105,6 +105,55 @@ class MCCVLineEntry : public MCCVLoc {
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:
Expand All @@ -115,6 +164,27 @@ class CodeViewContext {
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
Expand Down Expand Up @@ -179,10 +249,12 @@ class CodeViewContext {
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,
Expand Down Expand Up @@ -230,6 +302,9 @@ class CodeViewContext {

/// 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
Expand Down
5 changes: 1 addition & 4 deletions llvm/include/llvm/MC/MCFragment.h
Expand Up @@ -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
Expand All @@ -502,12 +501,10 @@ class MCCVInlineLineTableFragment : public MCFragment {
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
/// @{
Expand Down
11 changes: 6 additions & 5 deletions llvm/include/llvm/MC/MCObjectStreamer.h
Expand Up @@ -124,13 +124,14 @@ class MCObjectStreamer : public MCStreamer {
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;
Expand Down
20 changes: 15 additions & 5 deletions llvm/include/llvm/MC/MCStreamer.h
Expand Up @@ -713,11 +713,20 @@ class MCStreamer {
/// 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,
Expand All @@ -726,10 +735,11 @@ class MCStreamer {

/// \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.
Expand Down
30 changes: 14 additions & 16 deletions llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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) {
Expand All @@ -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);

Expand Down Expand Up @@ -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
Expand Down
56 changes: 36 additions & 20 deletions llvm/lib/MC/MCAsmStreamer.cpp
Expand Up @@ -222,15 +222,20 @@ class MCAsmStreamer final : public MCStreamer {
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;
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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(
Expand Down

0 comments on commit a9f4cc9

Please sign in to comment.