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.cpp184
1 files changed, 142 insertions, 42 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index b503f1dc31e..f1716361a1d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -13,7 +13,6 @@
#include "CodeViewDebug.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCSymbol.h"
@@ -75,18 +74,6 @@ StringRef CodeViewDebug::getFullFilepath(const DIFile *File) {
return Filepath;
}
-unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
- unsigned NextId = FileIdMap.size() + 1;
- auto Insertion = FileIdMap.insert(std::make_pair(F, NextId));
- if (Insertion.second) {
- // We have to compute the full filepath and emit a .cv_file directive.
- StringRef FullPath = getFullFilepath(F);
- NextId = Asm->OutStreamer->EmitCVFileDirective(NextId, FullPath);
- assert(NextId == FileIdMap.size() && ".cv_file directive failed");
- }
- 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.
@@ -98,26 +85,15 @@ void CodeViewDebug::maybeRecordLocation(DebugLoc DL,
return;
// Skip this line if it is longer than the maximum we can record.
- LineInfo LI(DL.getLine(), DL.getLine(), /*IsStatement=*/true);
- if (LI.getStartLine() != DL.getLine() || LI.isAlwaysStepInto() ||
- LI.isNeverStepInto())
+ if (DL.getLine() > COFF::CVL_MaxLineNumber)
return;
- ColumnInfo CI(DL.getCol(), /*EndColumn=*/0);
- if (CI.getStartColumn() != DL.getCol())
- return;
-
- if (!CurFn->HaveLineInfo)
- CurFn->HaveLineInfo = true;
- unsigned FileId = 0;
- if (CurFn->LastLoc.get() && CurFn->LastLoc->getFile() == DL->getFile())
- FileId = CurFn->LastFileId;
- else
- FileId = CurFn->LastFileId = maybeRecordFile(DL->getFile());
CurFn->LastLoc = DL;
- Asm->OutStreamer->EmitCVLocDirective(CurFn->FuncId, FileId, DL.getLine(),
- DL.getCol(), /*PrologueEnd=*/false,
- /*IsStmt=*/false, DL->getFilename());
+
+ MCSymbol *MCL = Asm->MMI->getContext().createTempSymbol();
+ Asm->OutStreamer->EmitLabel(MCL);
+ CurFn->Instrs.push_back(MCL);
+ LabelsAndLocs[MCL] = DL;
}
CodeViewDebug::CodeViewDebug(AsmPrinter *AP)
@@ -152,17 +128,39 @@ void CodeViewDebug::endModule() {
// of the payload followed by the payload itself. The subsections are 4-byte
// aligned.
- // Emit per-function debug information.
- for (auto &P : FnDebugInfo)
- emitDebugInfoForFunction(P.first, P.second);
+ // Emit per-function debug information. This code is extracted into a
+ // separate function for readability.
+ for (size_t I = 0, E = VisitedFunctions.size(); I != E; ++I)
+ emitDebugInfoForFunction(VisitedFunctions[I]);
// This subsection holds a file index to offset in string table table.
Asm->OutStreamer->AddComment("File index to string table offset subsection");
- Asm->OutStreamer->EmitCVFileChecksumsDirective();
+ Asm->EmitInt32(unsigned(ModuleSubstreamKind::FileChecksums));
+ size_t NumFilenames = FileNameRegistry.Infos.size();
+ Asm->EmitInt32(8 * NumFilenames);
+ for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
+ StringRef Filename = FileNameRegistry.Filenames[I];
+ // For each unique filename, just write its offset in the string table.
+ Asm->EmitInt32(FileNameRegistry.Infos[Filename].StartOffset);
+ // The function name offset is not followed by any additional data.
+ Asm->EmitInt32(0);
+ }
// This subsection holds the string table.
Asm->OutStreamer->AddComment("String table");
- Asm->OutStreamer->EmitCVStringTableDirective();
+ Asm->EmitInt32(unsigned(ModuleSubstreamKind::StringTable));
+ Asm->EmitInt32(FileNameRegistry.LastOffset);
+ // The payload starts with a null character.
+ Asm->EmitInt8(0);
+
+ for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
+ // Just emit unique filenames one by one, separated by a null character.
+ Asm->OutStreamer->EmitBytes(FileNameRegistry.Filenames[I]);
+ Asm->EmitInt8(0);
+ }
+
+ // No more subsections. Fill with zeros to align the end of the section by 4.
+ Asm->OutStreamer->EmitFill((-FileNameRegistry.LastOffset) % 4, 0);
clear();
}
@@ -179,13 +177,21 @@ static void EmitLabelDiff(MCStreamer &Streamer,
Streamer.EmitValue(AddrDelta, Size);
}
-void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
- FunctionInfo &FI) {
+static const DIFile *getFileFromLoc(DebugLoc DL) {
+ return DL.get()->getScope()->getFile();
+}
+
+void CodeViewDebug::emitDebugInfoForFunction(const Function *GV) {
// For each function there is a separate subsection
// which holds the PC to file:line table.
const MCSymbol *Fn = Asm->getSymbol(GV);
assert(Fn);
+ const FunctionInfo &FI = FnDebugInfo[GV];
+ if (FI.Instrs.empty())
+ return;
+ assert(FI.End && "Don't know where the function ends?");
+
StringRef FuncName;
if (auto *SP = getDISubprogram(GV))
FuncName = SP->getDisplayName();
@@ -232,8 +238,102 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
// Every subsection must be aligned to a 4-byte boundary.
Asm->OutStreamer->EmitFill((-FuncName.size()) % 4, 0);
- // We have an assembler directive that takes care of the whole line table.
- Asm->OutStreamer->EmitCVLinetableDirective(FI.FuncId, Fn, FI.End);
+ // PCs/Instructions are grouped into segments sharing the same filename.
+ // Pre-calculate the lengths (in instructions) of these segments and store
+ // them in a map for convenience. Each index in the map is the sequential
+ // number of the respective instruction that starts a new segment.
+ DenseMap<size_t, size_t> FilenameSegmentLengths;
+ size_t LastSegmentEnd = 0;
+ const DIFile *PrevFile = getFileFromLoc(LabelsAndLocs[FI.Instrs[0]]);
+ for (size_t J = 1, F = FI.Instrs.size(); J != F; ++J) {
+ const DIFile *CurFile = getFileFromLoc(LabelsAndLocs[FI.Instrs[J]]);
+ if (PrevFile == CurFile)
+ continue;
+ FilenameSegmentLengths[LastSegmentEnd] = J - LastSegmentEnd;
+ LastSegmentEnd = J;
+ PrevFile = CurFile;
+ }
+ FilenameSegmentLengths[LastSegmentEnd] = FI.Instrs.size() - LastSegmentEnd;
+
+ // Emit a line table subsection, required to do PC-to-file:line lookup.
+ Asm->OutStreamer->AddComment("Line table subsection for " + Twine(FuncName));
+ Asm->EmitInt32(unsigned(ModuleSubstreamKind::Lines));
+ MCSymbol *LineTableBegin = Asm->MMI->getContext().createTempSymbol(),
+ *LineTableEnd = Asm->MMI->getContext().createTempSymbol();
+ EmitLabelDiff(*Asm->OutStreamer, LineTableBegin, LineTableEnd);
+ Asm->OutStreamer->EmitLabel(LineTableBegin);
+
+ // Identify the function this subsection is for.
+ Asm->OutStreamer->EmitCOFFSecRel32(Fn);
+ Asm->OutStreamer->EmitCOFFSectionIndex(Fn);
+ // Insert flags after a 16-bit section index.
+ Asm->EmitInt16(COFF::DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS);
+
+ // Length of the function's code, in bytes.
+ EmitLabelDiff(*Asm->OutStreamer, Fn, FI.End);
+
+ // PC-to-linenumber lookup table:
+ MCSymbol *FileSegmentEnd = nullptr;
+
+ // The start of the last segment:
+ size_t LastSegmentStart = 0;
+
+ auto FinishPreviousChunk = [&] {
+ if (!FileSegmentEnd)
+ return;
+ for (size_t ColSegI = LastSegmentStart,
+ ColSegEnd = ColSegI + FilenameSegmentLengths[LastSegmentStart];
+ ColSegI != ColSegEnd; ++ColSegI) {
+ unsigned ColumnNumber = LabelsAndLocs[FI.Instrs[ColSegI]].getCol();
+ // Truncate the column number if it is longer than the maximum we can
+ // record.
+ if (ColumnNumber > COFF::CVL_MaxColumnNumber)
+ ColumnNumber = 0;
+ Asm->EmitInt16(ColumnNumber); // Start column
+ Asm->EmitInt16(0); // End column
+ }
+ Asm->OutStreamer->EmitLabel(FileSegmentEnd);
+ };
+
+ for (size_t J = 0, F = FI.Instrs.size(); J != F; ++J) {
+ MCSymbol *Instr = FI.Instrs[J];
+ assert(LabelsAndLocs.count(Instr));
+
+ if (FilenameSegmentLengths.count(J)) {
+ // We came to a beginning of a new filename segment.
+ FinishPreviousChunk();
+ const DIFile *File = getFileFromLoc(LabelsAndLocs[FI.Instrs[J]]);
+ StringRef CurFilename = getFullFilepath(File);
+ size_t IndexInFileTable = FileNameRegistry.add(CurFilename);
+ // Each segment starts with the offset of the filename
+ // in the string table.
+ Asm->OutStreamer->AddComment(
+ "Segment for file '" + Twine(CurFilename) + "' begins");
+ MCSymbol *FileSegmentBegin = Asm->MMI->getContext().createTempSymbol();
+ Asm->OutStreamer->EmitLabel(FileSegmentBegin);
+ Asm->EmitInt32(8 * IndexInFileTable);
+
+ // Number of PC records in the lookup table.
+ size_t SegmentLength = FilenameSegmentLengths[J];
+ Asm->EmitInt32(SegmentLength);
+
+ // Full size of the segment for this filename, including the prev two
+ // records.
+ FileSegmentEnd = Asm->MMI->getContext().createTempSymbol();
+ EmitLabelDiff(*Asm->OutStreamer, FileSegmentBegin, FileSegmentEnd);
+ LastSegmentStart = J;
+ }
+
+ // The first PC with the given linenumber and the linenumber itself.
+ EmitLabelDiff(*Asm->OutStreamer, Fn, Instr);
+ uint32_t LineNumber = LabelsAndLocs[Instr].getLine();
+ assert(LineNumber <= COFF::CVL_MaxLineNumber);
+ uint32_t LineData = LineNumber | COFF::CVL_IsStatement;
+ Asm->EmitInt32(LineData);
+ }
+
+ FinishPreviousChunk();
+ Asm->OutStreamer->EmitLabel(LineTableEnd);
}
void CodeViewDebug::beginFunction(const MachineFunction *MF) {
@@ -244,8 +344,8 @@ void CodeViewDebug::beginFunction(const MachineFunction *MF) {
const Function *GV = MF->getFunction();
assert(FnDebugInfo.count(GV) == false);
+ VisitedFunctions.push_back(GV);
CurFn = &FnDebugInfo[GV];
- CurFn->FuncId = NextFuncId++;
// Find the end of the function prolog.
// FIXME: is there a simpler a way to do this? Can we just search
@@ -284,9 +384,9 @@ void CodeViewDebug::endFunction(const MachineFunction *MF) {
assert(FnDebugInfo.count(GV));
assert(CurFn == &FnDebugInfo[GV]);
- // Don't emit anything if we don't have any line tables.
- if (!CurFn->HaveLineInfo) {
+ if (CurFn->Instrs.empty()) {
FnDebugInfo.erase(GV);
+ VisitedFunctions.pop_back();
} else {
CurFn->End = Asm->getFunctionEnd();
}
OpenPOWER on IntegriCloud