summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp139
1 files changed, 138 insertions, 1 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index b503f1dc31e..e3c48296f34 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -15,6 +15,8 @@
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/COFF.h"
@@ -87,6 +89,17 @@ unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
return Insertion.first->second;
}
+CodeViewDebug::InlineSite &CodeViewDebug::getInlineSite(const DILocation *Loc) {
+ const DILocation *InlinedAt = Loc->getInlinedAt();
+ auto Insertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()});
+ if (Insertion.second) {
+ InlineSite &Site = Insertion.first->second;
+ Site.SiteFuncId = NextFuncId++;
+ Site.Inlinee = Loc->getScope()->getSubprogram();
+ }
+ return Insertion.first->second;
+}
+
void CodeViewDebug::maybeRecordLocation(DebugLoc DL,
const MachineFunction *MF) {
// Skip this instruction if it has the same location as the previous one.
@@ -115,7 +128,28 @@ void CodeViewDebug::maybeRecordLocation(DebugLoc DL,
else
FileId = CurFn->LastFileId = maybeRecordFile(DL->getFile());
CurFn->LastLoc = DL;
- Asm->OutStreamer->EmitCVLocDirective(CurFn->FuncId, FileId, DL.getLine(),
+
+ unsigned FuncId = CurFn->FuncId;
+ if (const DILocation *Loc = DL->getInlinedAt()) {
+ // If this location was actually inlined from somewhere else, give it the ID
+ // of the inline call site.
+ FuncId = getInlineSite(DL.get()).SiteFuncId;
+ // Ensure we have links in the tree of inline call sites.
+ const DILocation *ChildLoc = nullptr;
+ while (Loc->getInlinedAt()) {
+ InlineSite &Site = getInlineSite(Loc);
+ if (ChildLoc) {
+ // Record the child inline site if not already present.
+ auto B = Site.ChildSites.begin(), E = Site.ChildSites.end();
+ if (std::find(B, E, Loc) != E)
+ break;
+ Site.ChildSites.push_back(Loc);
+ }
+ ChildLoc = Loc;
+ }
+ }
+
+ Asm->OutStreamer->EmitCVLocDirective(FuncId, FileId, DL.getLine(),
DL.getCol(), /*PrologueEnd=*/false,
/*IsStmt=*/false, DL->getFilename());
}
@@ -139,6 +173,8 @@ void CodeViewDebug::endModule() {
if (FnDebugInfo.empty())
return;
+ emitTypeInformation();
+
// FIXME: For functions that are comdat, we should emit separate .debug$S
// sections that are comdat associative with the main function instead of
// having one big .debug$S section.
@@ -167,6 +203,60 @@ void CodeViewDebug::endModule() {
clear();
}
+template <typename T> static void emitRecord(MCStreamer &OS, const T &Rec) {
+ OS.EmitBytes(StringRef(reinterpret_cast<const char *>(&Rec), sizeof(Rec)));
+}
+
+void CodeViewDebug::emitTypeInformation() {
+ // Start the .debug$T section with 0x4.
+ Asm->OutStreamer->SwitchSection(
+ Asm->getObjFileLowering().getCOFFDebugTypesSection());
+ Asm->EmitInt32(COFF::DEBUG_SECTION_MAGIC);
+
+ NamedMDNode *CU_Nodes =
+ Asm->MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
+ if (!CU_Nodes)
+ return;
+
+ // This type info currently only holds function ids for use with inline call
+ // frame info. All functions are assigned a simple 'void ()' type. Emit that
+ // type here.
+ TypeIndex ArgListIdx = getNextTypeIndex();
+ Asm->EmitInt16(2 + sizeof(ArgList));
+ Asm->EmitInt16(LF_ARGLIST);
+ Asm->EmitInt32(0);
+
+ TypeIndex VoidProcIdx = getNextTypeIndex();
+ Asm->EmitInt16(2 + sizeof(ProcedureType));
+ Asm->EmitInt16(LF_PROCEDURE);
+ ProcedureType Proc{}; // Zero initialize.
+ Proc.ReturnType = TypeIndex::Void();
+ Proc.CallConv = CallingConvention::NearC;
+ Proc.Options = FunctionOptions::None;
+ Proc.NumParameters = 0;
+ Proc.ArgListType = ArgListIdx;
+ emitRecord(*Asm->OutStreamer, Proc);
+
+ for (MDNode *N : CU_Nodes->operands()) {
+ auto *CUNode = cast<DICompileUnit>(N);
+ for (auto *SP : CUNode->getSubprograms()) {
+ StringRef DisplayName = SP->getDisplayName();
+ Asm->EmitInt16(2 + sizeof(FuncId) + DisplayName.size() + 1);
+ Asm->EmitInt16(LF_FUNC_ID);
+
+ FuncId Func{}; // Zero initialize.
+ Func.ParentScope = TypeIndex();
+ Func.FunctionType = VoidProcIdx;
+ emitRecord(*Asm->OutStreamer, Func);
+ Asm->OutStreamer->EmitBytes(DisplayName);
+ Asm->EmitInt8(0);
+
+ TypeIndex FuncIdIdx = getNextTypeIndex();
+ SubprogramToFuncId.insert(std::make_pair(SP, FuncIdIdx));
+ }
+ }
+}
+
static void EmitLabelDiff(MCStreamer &Streamer,
const MCSymbol *From, const MCSymbol *To,
unsigned int Size = 4) {
@@ -179,6 +269,44 @@ static void EmitLabelDiff(MCStreamer &Streamer,
Streamer.EmitValue(AddrDelta, Size);
}
+void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
+ const DILocation *InlinedAt,
+ const InlineSite &Site) {
+ MCStreamer &OS = *Asm->OutStreamer;
+
+ MCSymbol *InlineBegin = Asm->MMI->getContext().createTempSymbol(),
+ *InlineEnd = Asm->MMI->getContext().createTempSymbol();
+
+ assert(SubprogramToFuncId.count(Site.Inlinee));
+ TypeIndex InlineeIdx = SubprogramToFuncId[Site.Inlinee];
+
+ // SymbolRecord
+ EmitLabelDiff(OS, InlineBegin, InlineEnd, 2); // RecordLength
+ OS.EmitLabel(InlineBegin);
+ Asm->EmitInt16(SymbolRecordKind::S_INLINESITE); // RecordKind
+
+ InlineSiteSym SiteBytes{};
+ SiteBytes.Inlinee = InlineeIdx;
+ Asm->OutStreamer->EmitBytes(
+ StringRef(reinterpret_cast<const char *>(&SiteBytes), sizeof(SiteBytes)));
+
+ // FIXME: annotations
+
+ OS.EmitLabel(InlineEnd);
+
+ // Recurse on child inlined call sites before closing the scope.
+ for (const DILocation *ChildSite : Site.ChildSites) {
+ auto I = FI.InlineSites.find(ChildSite);
+ assert(I != FI.InlineSites.end() &&
+ "child site not in function inline site map");
+ emitInlinedCallSite(FI, ChildSite, I->second);
+ }
+
+ // Close the scope.
+ Asm->EmitInt16(2); // RecordLength
+ Asm->EmitInt16(SymbolRecordKind::S_INLINESITE_END); // RecordKind
+}
+
void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
FunctionInfo &FI) {
// For each function there is a separate subsection
@@ -224,6 +352,15 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
Asm->EmitInt8(0);
Asm->OutStreamer->EmitLabel(ProcSegmentEnd);
+ // Emit inlined call site information. Only emit functions inlined directly
+ // into the parent function. We'll emit the other sites recursively as part
+ // of their parent inline site.
+ for (auto &KV : FI.InlineSites) {
+ const DILocation *InlinedAt = KV.first;
+ if (!InlinedAt->getInlinedAt())
+ emitInlinedCallSite(FI, InlinedAt, KV.second);
+ }
+
// We're done with this function.
Asm->EmitInt16(0x0002);
Asm->EmitInt16(unsigned(SymbolRecordKind::S_PROC_ID_END));
OpenPOWER on IntegriCloud