diff options
Diffstat (limited to 'llvm/lib/MC')
-rw-r--r-- | llvm/lib/MC/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/MC/MCAsmStreamer.cpp | 72 | ||||
-rw-r--r-- | llvm/lib/MC/MCCodeView.cpp | 222 | ||||
-rw-r--r-- | llvm/lib/MC/MCContext.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/MC/MCObjectStreamer.cpp | 31 | ||||
-rw-r--r-- | llvm/lib/MC/MCParser/AsmParser.cpp | 174 | ||||
-rw-r--r-- | llvm/lib/MC/MCStreamer.cpp | 16 | ||||
-rw-r--r-- | llvm/lib/MC/StringTableBuilder.cpp | 55 |
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'; |