summaryrefslogtreecommitdiffstats
path: root/llvm/lib/MC
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC')
-rw-r--r--llvm/lib/MC/CMakeLists.txt1
-rw-r--r--llvm/lib/MC/MCAsmStreamer.cpp72
-rw-r--r--llvm/lib/MC/MCCodeView.cpp222
-rw-r--r--llvm/lib/MC/MCContext.cpp17
-rw-r--r--llvm/lib/MC/MCObjectStreamer.cpp31
-rw-r--r--llvm/lib/MC/MCParser/AsmParser.cpp174
-rw-r--r--llvm/lib/MC/MCStreamer.cpp16
-rw-r--r--llvm/lib/MC/StringTableBuilder.cpp55
8 files changed, 580 insertions, 8 deletions
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index d1aac8104a3..a04f16c6ea7 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -10,6 +10,7 @@ add_llvm_library(LLVMMC
MCAssembler.cpp
MCCodeEmitter.cpp
MCCodeGenInfo.cpp
+ MCCodeView.cpp
MCContext.cpp
MCDwarf.cpp
MCELFObjectTargetWriter.cpp
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 2de36f8561c..d9382c5df9f 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -199,6 +199,15 @@ public:
StringRef FileName) override;
MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;
+ unsigned EmitCVFileDirective(unsigned FileNo, StringRef Filename) override;
+ void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
+ unsigned Column, bool PrologueEnd, bool IsStmt,
+ StringRef FileName) override;
+ void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,
+ const MCSymbol *FnEnd) override;
+ void EmitCVStringTableDirective() override;
+ void EmitCVFileChecksumsDirective() override;
+
void EmitIdent(StringRef IdentString) override;
void EmitCFISections(bool EH, bool Debug) override;
void EmitCFIDefCfa(int64_t Register, int64_t Offset) override;
@@ -954,6 +963,69 @@ MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) {
return MCStreamer::getDwarfLineTableSymbol(0);
}
+unsigned MCAsmStreamer::EmitCVFileDirective(unsigned FileNo,
+ StringRef Filename) {
+ if (!getContext().getCVFile(Filename, FileNo))
+ return 0;
+
+ OS << "\t.cv_file\t" << FileNo << ' ';
+
+ PrintQuotedString(Filename, OS);
+ EmitEOL();
+
+ return FileNo;
+}
+
+void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
+ unsigned Line, unsigned Column,
+ bool PrologueEnd, bool IsStmt,
+ StringRef FileName) {
+ OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " "
+ << Column;
+ if (PrologueEnd)
+ OS << " prologue_end";
+
+ unsigned OldIsStmt = getContext().getCurrentCVLoc().isStmt();
+ if (IsStmt != OldIsStmt) {
+ OS << " is_stmt ";
+
+ if (IsStmt)
+ OS << "1";
+ else
+ OS << "0";
+ }
+
+ if (IsVerboseAsm) {
+ OS.PadToColumn(MAI->getCommentColumn());
+ OS << MAI->getCommentString() << ' ' << FileName << ':'
+ << Line << ':' << Column;
+ }
+ EmitEOL();
+ this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column,
+ PrologueEnd, IsStmt, FileName);
+}
+
+void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId,
+ const MCSymbol *FnStart,
+ const MCSymbol *FnEnd) {
+ OS << "\t.cv_linetable\t" << FunctionId << ", ";
+ FnStart->print(OS, MAI);
+ OS << ", ";
+ FnEnd->print(OS, MAI);
+ EmitEOL();
+ this->MCStreamer::EmitCVLinetableDirective(FunctionId, FnStart, FnEnd);
+}
+
+void MCAsmStreamer::EmitCVStringTableDirective() {
+ OS << "\t.cv_stringtable";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCVFileChecksumsDirective() {
+ OS << "\t.cv_filechecksums";
+ EmitEOL();
+}
+
void MCAsmStreamer::EmitIdent(StringRef IdentString) {
assert(MAI->hasIdentDirective() && ".ident directive not supported");
OS << "\t.ident\t";
diff --git a/llvm/lib/MC/MCCodeView.cpp b/llvm/lib/MC/MCCodeView.cpp
new file mode 100644
index 00000000000..992edd0a8bc
--- /dev/null
+++ b/llvm/lib/MC/MCCodeView.cpp
@@ -0,0 +1,222 @@
+//===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Holds state from .cv_file and .cv_loc directives for later emission.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCCodeView.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/Support/COFF.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+CodeViewContext::CodeViewContext() {}
+
+CodeViewContext::~CodeViewContext() {
+ // If someone inserted strings into the string table but never actually
+ // emitted them somewhere, clean up the fragment.
+ if (!InsertedStrTabFragment)
+ delete StrTabFragment;
+}
+
+/// This is a valid number for use with .cv_loc if we've already seen a .cv_file
+/// for it.
+bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const {
+ unsigned Idx = FileNumber - 1;
+ if (Idx < Filenames.size())
+ return !Filenames[Idx].empty();
+ return false;
+}
+
+bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) {
+ assert(FileNumber > 0);
+ Filename = addToStringTable(Filename);
+ unsigned Idx = FileNumber - 1;
+ if (Idx >= Filenames.size())
+ Filenames.resize(Idx + 1);
+
+ if (Filename.empty())
+ Filename = "<stdin>";
+
+ if (!Filenames[Idx].empty())
+ return false;
+
+ // FIXME: We should store the string table offset of the filename, rather than
+ // the filename itself for efficiency.
+ Filename = addToStringTable(Filename);
+
+ Filenames[Idx] = Filename;
+ return true;
+}
+
+MCDataFragment *CodeViewContext::getStringTableFragment() {
+ if (!StrTabFragment) {
+ StrTabFragment = new MCDataFragment();
+ // Start a new string table out with a null byte.
+ StrTabFragment->getContents().push_back('\0');
+ }
+ return StrTabFragment;
+}
+
+StringRef CodeViewContext::addToStringTable(StringRef S) {
+ SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents();
+ auto Insertion =
+ StringTable.insert(std::make_pair(S, unsigned(Contents.size())));
+ // Return the string from the table, since it is stable.
+ S = Insertion.first->first();
+ if (Insertion.second) {
+ // The string map key is always null terminated.
+ Contents.append(S.begin(), S.end() + 1);
+ }
+ return S;
+}
+
+unsigned CodeViewContext::getStringTableOffset(StringRef S) {
+ // A string table offset of zero is always the empty string.
+ if (S.empty())
+ return 0;
+ auto I = StringTable.find(S);
+ assert(I != StringTable.end());
+ return I->second;
+}
+
+void CodeViewContext::emitStringTable(MCObjectStreamer &OS) {
+ MCContext &Ctx = OS.getContext();
+ MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin"),
+ *StringEnd = Ctx.createTempSymbol("strtab_end");
+
+ OS.EmitIntValue(unsigned(ModuleSubstreamKind::StringTable), 4);
+ OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4);
+ OS.EmitLabel(StringBegin);
+
+ // Put the string table data fragment here, if we haven't already put it
+ // somewhere else. If somebody wants two string tables in their .s file, one
+ // will just be empty.
+ if (!InsertedStrTabFragment) {
+ OS.insert(getStringTableFragment());
+ InsertedStrTabFragment = true;
+ }
+
+ OS.EmitValueToAlignment(4, 0);
+
+ OS.EmitLabel(StringEnd);
+}
+
+void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) {
+ MCContext &Ctx = OS.getContext();
+ MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin"),
+ *FileEnd = Ctx.createTempSymbol("filechecksums_end");
+
+ OS.EmitIntValue(unsigned(ModuleSubstreamKind::FileChecksums), 4);
+ OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4);
+ OS.EmitLabel(FileBegin);
+
+ // Emit an array of FileChecksum entries. We index into this table using the
+ // user-provided file number. Each entry is currently 8 bytes, as we don't
+ // emit checksums.
+ for (StringRef Filename : Filenames) {
+ OS.EmitIntValue(getStringTableOffset(Filename), 4);
+ // Zero the next two fields and align back to 4 bytes. This indicates that
+ // no checksum is present.
+ OS.EmitIntValue(0, 4);
+ }
+
+ OS.EmitLabel(FileEnd);
+}
+
+void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
+ unsigned FuncId,
+ const MCSymbol *FuncBegin,
+ const MCSymbol *FuncEnd) {
+ MCContext &Ctx = OS.getContext();
+ MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin"),
+ *LineEnd = Ctx.createTempSymbol("linetable_end");
+
+ OS.EmitIntValue(unsigned(ModuleSubstreamKind::Lines), 4);
+ OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4);
+ OS.EmitLabel(LineBegin);
+ OS.EmitCOFFSecRel32(FuncBegin);
+ OS.EmitCOFFSectionIndex(FuncBegin);
+
+ // Actual line info.
+ ArrayRef<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId);
+ bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) {
+ return LineEntry.getColumn() != 0;
+ });
+ OS.EmitIntValue(HaveColumns ? int(codeview::LineFlags::HaveColumns) : 0, 2);
+ OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4);
+
+ for (auto I = Locs.begin(), E = Locs.end(); I != E;) {
+ // Emit a file segment for the run of locations that share a file id.
+ unsigned CurFileNum = I->getFileNum();
+ auto FileSegEnd =
+ std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) {
+ return Loc.getFileNum() != CurFileNum;
+ });
+ unsigned EntryCount = FileSegEnd - I;
+ OS.AddComment("Segment for file '" + Twine(Filenames[CurFileNum - 1]) +
+ "' begins");
+ OS.EmitIntValue(8 * (CurFileNum - 1), 4);
+ OS.EmitIntValue(EntryCount, 4);
+ uint32_t SegmentSize = 12;
+ SegmentSize += 8 * EntryCount;
+ if (HaveColumns)
+ SegmentSize += 4 * EntryCount;
+ OS.EmitIntValue(SegmentSize, 4);
+
+ for (auto J = I; J != FileSegEnd; ++J) {
+ OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4);
+ unsigned LineData = J->getLine();
+ if (J->isStmt())
+ LineData |= codeview::LineInfo::StatementFlag;
+ OS.EmitIntValue(LineData, 4);
+ }
+ if (HaveColumns) {
+ for (auto J = I; J != FileSegEnd; ++J) {
+ OS.EmitIntValue(J->getColumn(), 2);
+ OS.EmitIntValue(0, 2);
+ }
+ }
+ I = FileSegEnd;
+ }
+ OS.EmitLabel(LineEnd);
+}
+
+//
+// This is called when an instruction is assembled into the specified section
+// and if there is information from the last .cv_loc directive that has yet to have
+// a line entry made for it is made.
+//
+void MCCVLineEntry::Make(MCObjectStreamer *MCOS) {
+ if (!MCOS->getContext().getCVLocSeen())
+ return;
+
+ // Create a symbol at in the current section for use in the line entry.
+ MCSymbol *LineSym = MCOS->getContext().createTempSymbol();
+ // Set the value of the symbol to use for the MCCVLineEntry.
+ MCOS->EmitLabel(LineSym);
+
+ // Get the current .loc info saved in the context.
+ const MCCVLoc &CVLoc = MCOS->getContext().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();
+
+ // Add the line entry to this section's entries.
+ MCOS->getContext().getCVContext().addLineEntry(LineEntry);
+}
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index b5ad518d033..c5243ef62c9 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -12,6 +12,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeView.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCLabel.h"
#include "llvm/MC/MCObjectFileInfo.h"
@@ -90,6 +91,8 @@ void MCContext::reset() {
DwarfCompileUnitID = 0;
CurrentDwarfLoc = MCDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0);
+ CVContext.reset();
+
MachOUniquingMap.clear();
ELFUniquingMap.clear();
COFFUniquingMap.clear();
@@ -474,6 +477,20 @@ void MCContext::finalizeDwarfSections(MCStreamer &MCOS) {
[&](MCSection *Sec) { return !MCOS.mayHaveInstructions(*Sec); });
}
+CodeViewContext &MCContext::getCVContext() {
+ if (!CVContext.get())
+ CVContext.reset(new CodeViewContext);
+ return *CVContext.get();
+}
+
+unsigned MCContext::getCVFile(StringRef FileName, unsigned FileNumber) {
+ return getCVContext().addFile(FileNumber, FileName) ? FileNumber : 0;
+}
+
+bool MCContext::isValidCVFileNumber(unsigned FileNumber) {
+ return getCVContext().isValidFileNumber(FileNumber);
+}
+
//===----------------------------------------------------------------------===//
// Error Reporting
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index 39755e5b0a8..71d578aca9d 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -125,6 +125,7 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
MCDataFragment *DF = getOrCreateDataFragment();
flushPendingLabels(DF, DF->getContents().size());
+ MCCVLineEntry::Make(this);
MCDwarfLineEntry::Make(this, getCurrentSection().first);
// Avoid fixups when possible.
@@ -232,6 +233,7 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst,
// Now that a machine instruction has been assembled into this section, make
// a line entry for any .loc directive that has been seen.
+ MCCVLineEntry::Make(this);
MCDwarfLineEntry::Make(this, getCurrentSection().first);
// If this instruction doesn't need relaxation, just emit it as data.
@@ -362,7 +364,36 @@ void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
insert(new MCDwarfCallFrameFragment(*AddrDelta));
}
+void MCObjectStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
+ unsigned Line, unsigned Column,
+ bool PrologueEnd, bool IsStmt,
+ StringRef FileName) {
+ // 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);
+}
+
+void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId,
+ const MCSymbol *Begin,
+ const MCSymbol *End) {
+ getContext().getCVContext().emitLineTableForFunction(*this, FunctionId, Begin,
+ End);
+ this->MCStreamer::EmitCVLinetableDirective(FunctionId, Begin, End);
+}
+
+void MCObjectStreamer::EmitCVStringTableDirective() {
+ getContext().getCVContext().emitStringTable(*this);
+}
+void MCObjectStreamer::EmitCVFileChecksumsDirective() {
+ getContext().getCVContext().emitFileChecksums(*this);
+}
+
+
void MCObjectStreamer::EmitBytes(StringRef Data) {
+ MCCVLineEntry::Make(this);
MCDwarfLineEntry::Make(this, getCurrentSection().first);
MCDataFragment *DF = getOrCreateDataFragment();
flushPendingLabels(DF, DF->getContents().size());
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index b1814f8c8ff..360de5db883 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -357,6 +357,8 @@ 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_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,
@@ -394,6 +396,13 @@ private:
bool parseDirectiveLoc();
bool parseDirectiveStabs();
+ // ".cv_file", ".cv_loc", ".cv_linetable"
+ bool parseDirectiveCVFile();
+ bool parseDirectiveCVLoc();
+ bool parseDirectiveCVLinetable();
+ bool parseDirectiveCVStringTable();
+ bool parseDirectiveCVFileChecksums();
+
// .cfi directives
bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);
bool parseDirectiveCFIWindowSave();
@@ -1638,6 +1647,16 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveLoc();
case DK_STABS:
return parseDirectiveStabs();
+ case DK_CV_FILE:
+ return parseDirectiveCVFile();
+ case DK_CV_LOC:
+ return parseDirectiveCVLoc();
+ case DK_CV_LINETABLE:
+ return parseDirectiveCVLinetable();
+ case DK_CV_STRINGTABLE:
+ return parseDirectiveCVStringTable();
+ case DK_CV_FILECHECKSUMS:
+ return parseDirectiveCVFileChecksums();
case DK_CFI_SECTIONS:
return parseDirectiveCFISections();
case DK_CFI_STARTPROC:
@@ -3070,6 +3089,156 @@ bool AsmParser::parseDirectiveStabs() {
return TokError("unsupported directive '.stabs'");
}
+/// parseDirectiveCVFile
+/// ::= .cv_file number filename
+bool AsmParser::parseDirectiveCVFile() {
+ SMLoc FileNumberLoc = getLexer().getLoc();
+ if (getLexer().isNot(AsmToken::Integer))
+ return TokError("expected file number in '.cv_file' directive");
+
+ int64_t FileNumber = getTok().getIntVal();
+ Lex();
+
+ if (FileNumber < 1)
+ return TokError("file number less than one");
+
+ if (getLexer().isNot(AsmToken::String))
+ return TokError("unexpected token in '.cv_file' directive");
+
+ // Usually the directory and filename together, otherwise just the directory.
+ // Allow the strings to have escaped octal character sequence.
+ std::string Filename;
+ if (parseEscapedString(Filename))
+ return true;
+ Lex();
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.cv_file' directive");
+
+ if (getStreamer().EmitCVFileDirective(FileNumber, Filename) == 0)
+ Error(FileNumberLoc, "file number already allocated");
+
+ return false;
+}
+
+/// parseDirectiveCVLoc
+/// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos] [prologue_end]
+/// [is_stmt VALUE]
+/// The first number is a file number, must have been previously assigned with
+/// a .file directive, the second number is the line number and optionally the
+/// third number is a column position (zero if not specified). The remaining
+/// optional items are .loc sub-directives.
+bool AsmParser::parseDirectiveCVLoc() {
+ if (getLexer().isNot(AsmToken::Integer))
+ return TokError("unexpected token in '.cv_loc' directive");
+
+ int64_t FunctionId = getTok().getIntVal();
+ if (FunctionId < 0)
+ return TokError("function id less than zero in '.cv_loc' directive");
+ Lex();
+
+ int64_t FileNumber = getTok().getIntVal();
+ if (FileNumber < 1)
+ return TokError("file number less than one in '.cv_loc' directive");
+ if (!getContext().isValidCVFileNumber(FileNumber))
+ return TokError("unassigned file number in '.cv_loc' directive");
+ Lex();
+
+ int64_t LineNumber = 0;
+ if (getLexer().is(AsmToken::Integer)) {
+ LineNumber = getTok().getIntVal();
+ if (LineNumber < 0)
+ return TokError("line number less than zero in '.cv_loc' directive");
+ Lex();
+ }
+
+ int64_t ColumnPos = 0;
+ if (getLexer().is(AsmToken::Integer)) {
+ ColumnPos = getTok().getIntVal();
+ if (ColumnPos < 0)
+ return TokError("column position less than zero in '.cv_loc' directive");
+ Lex();
+ }
+
+ bool PrologueEnd = false;
+ uint64_t IsStmt = 0;
+ while (getLexer().isNot(AsmToken::EndOfStatement)) {
+ StringRef Name;
+ SMLoc Loc = getTok().getLoc();
+ if (parseIdentifier(Name))
+ return TokError("unexpected token in '.cv_loc' directive");
+
+ if (Name == "prologue_end")
+ PrologueEnd = true;
+ else if (Name == "is_stmt") {
+ Loc = getTok().getLoc();
+ const MCExpr *Value;
+ if (parseExpression(Value))
+ return true;
+ // The expression must be the constant 0 or 1.
+ IsStmt = ~0ULL;
+ if (const auto *MCE = dyn_cast<MCConstantExpr>(Value))
+ IsStmt = MCE->getValue();
+
+ if (IsStmt > 1)
+ return Error(Loc, "is_stmt value not 0 or 1");
+ } else {
+ return Error(Loc, "unknown sub-directive in '.cv_loc' directive");
+ }
+ }
+
+ getStreamer().EmitCVLocDirective(FunctionId, FileNumber, LineNumber,
+ ColumnPos, PrologueEnd, IsStmt, StringRef());
+ return false;
+}
+
+/// parseDirectiveCVLinetable
+/// ::= .cv_linetable FunctionId, FnStart, FnEnd
+bool AsmParser::parseDirectiveCVLinetable() {
+ int64_t FunctionId = getTok().getIntVal();
+ if (FunctionId < 0)
+ return TokError("function id less than zero in '.cv_linetable' directive");
+ Lex();
+
+ if (Lexer.isNot(AsmToken::Comma))
+ return TokError("unexpected token in '.cv_linetable' directive");
+ Lex();
+
+ SMLoc Loc = getLexer().getLoc();
+ StringRef FnStartName;
+ if (parseIdentifier(FnStartName))
+ return Error(Loc, "expected identifier in directive");
+
+ if (Lexer.isNot(AsmToken::Comma))
+ return TokError("unexpected token in '.cv_linetable' directive");
+ Lex();
+
+ Loc = getLexer().getLoc();
+ StringRef FnEndName;
+ if (parseIdentifier(FnEndName))
+ return Error(Loc, "expected identifier in directive");
+
+ MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName);
+ MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
+
+ getStreamer().EmitCVLinetableDirective(FunctionId, FnStartSym, FnEndSym);
+ return false;
+}
+
+/// parseDirectiveCVStringTable
+/// ::= .cv_stringtable
+bool AsmParser::parseDirectiveCVStringTable() {
+ getStreamer().EmitCVStringTableDirective();
+ return false;
+}
+
+/// parseDirectiveCVFileChecksums
+/// ::= .cv_filechecksums
+bool AsmParser::parseDirectiveCVFileChecksums() {
+ getStreamer().EmitCVFileChecksumsDirective();
+ return false;
+}
+
/// parseDirectiveCFISections
/// ::= .cfi_sections section [, section]
bool AsmParser::parseDirectiveCFISections() {
@@ -4381,6 +4550,11 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".line"] = DK_LINE;
DirectiveKindMap[".loc"] = DK_LOC;
DirectiveKindMap[".stabs"] = DK_STABS;
+ DirectiveKindMap[".cv_file"] = DK_CV_FILE;
+ DirectiveKindMap[".cv_loc"] = DK_CV_LOC;
+ DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;
+ DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
+ DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
DirectiveKindMap[".sleb128"] = DK_SLEB128;
DirectiveKindMap[".uleb128"] = DK_ULEB128;
DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 836b4054464..adae5d73ce5 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -180,6 +180,22 @@ void MCStreamer::EnsureValidDwarfFrame() {
report_fatal_error("No open frame");
}
+unsigned MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) {
+ return getContext().getCVFile(Filename, FileNo);
+}
+
+void MCStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
+ unsigned Line, unsigned Column,
+ bool PrologueEnd, bool IsStmt,
+ StringRef FileName) {
+ getContext().setCurrentCVLoc(FunctionId, FileNo, Line, Column, PrologueEnd,
+ IsStmt);
+}
+
+void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId,
+ const MCSymbol *Begin,
+ const MCSymbol *End) {}
+
void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol,
MCSymbol *EHSymbol) {
}
diff --git a/llvm/lib/MC/StringTableBuilder.cpp b/llvm/lib/MC/StringTableBuilder.cpp
index 80e552287b3..f50e098e6e4 100644
--- a/llvm/lib/MC/StringTableBuilder.cpp
+++ b/llvm/lib/MC/StringTableBuilder.cpp
@@ -16,7 +16,22 @@
using namespace llvm;
-StringTableBuilder::StringTableBuilder(Kind K) : K(K) {}
+StringTableBuilder::StringTableBuilder(Kind K) : K(K) {
+ // Account for leading bytes in table so that offsets returned from add are
+ // correct.
+ switch (K) {
+ case RAW:
+ Size = 0;
+ break;
+ case MachO:
+ case ELF:
+ Size = 1;
+ break;
+ case WinCOFF:
+ Size = 4;
+ break;
+ }
+}
typedef std::pair<StringRef, size_t> StringPair;
@@ -62,13 +77,32 @@ tailcall:
}
void StringTableBuilder::finalize() {
- std::vector<std::pair<StringRef, size_t> *> Strings;
+ finalizeStringTable(/*Optimize=*/true);
+}
+
+void StringTableBuilder::finalizeInOrder() {
+ finalizeStringTable(/*Optimize=*/false);
+}
+
+void StringTableBuilder::finalizeStringTable(bool Optimize) {
+ typedef std::pair<StringRef, size_t> StringOffsetPair;
+ std::vector<StringOffsetPair *> Strings;
Strings.reserve(StringIndexMap.size());
- for (std::pair<StringRef, size_t> &P : StringIndexMap)
+ for (StringOffsetPair &P : StringIndexMap)
Strings.push_back(&P);
- if (!Strings.empty())
- multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0);
+ if (!Strings.empty()) {
+ // If we're optimizing, sort by name. If not, sort by previously assigned
+ // offset.
+ if (Optimize) {
+ multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0);
+ } else {
+ std::sort(Strings.begin(), Strings.end(),
+ [](const StringOffsetPair *LHS, const StringOffsetPair *RHS) {
+ return LHS->second < RHS->second;
+ });
+ }
+ }
switch (K) {
case RAW:
@@ -85,17 +119,22 @@ void StringTableBuilder::finalize() {
}
StringRef Previous;
- for (std::pair<StringRef, size_t> *P : Strings) {
+ for (StringOffsetPair *P : Strings) {
StringRef S = P->first;
if (K == WinCOFF)
assert(S.size() > COFF::NameSize && "Short string in COFF string table!");
- if (Previous.endswith(S)) {
+ if (Optimize && Previous.endswith(S)) {
P->second = StringTable.size() - S.size() - (K != RAW);
continue;
}
- P->second = StringTable.size();
+ if (Optimize)
+ P->second = StringTable.size();
+ else
+ assert(P->second == StringTable.size() &&
+ "different strtab offset after finalization");
+
StringTable += S;
if (K != RAW)
StringTable += '\x00';
OpenPOWER on IntegriCloud