diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/MC/MCDwarf.cpp | |
parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) |
Notes
Diffstat (limited to 'lib/MC/MCDwarf.cpp')
-rw-r--r-- | lib/MC/MCDwarf.cpp | 265 |
1 files changed, 205 insertions, 60 deletions
diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 9e5d9ff73c76..6131fcd658b2 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -11,7 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -28,6 +28,7 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/StringTableBuilder.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" @@ -45,6 +46,29 @@ using namespace llvm; +/// Manage the .debug_line_str section contents, if we use it. +class llvm::MCDwarfLineStr { + MCSymbol *LineStrLabel = nullptr; + StringTableBuilder LineStrings{StringTableBuilder::DWARF}; + bool UseRelocs = false; + +public: + /// Construct an instance that can emit .debug_line_str (for use in a normal + /// v5 line table). + explicit MCDwarfLineStr(MCContext &Ctx) { + UseRelocs = Ctx.getAsmInfo()->doesDwarfUseRelocationsAcrossSections(); + if (UseRelocs) + LineStrLabel = + Ctx.getObjectFileInfo()->getDwarfLineStrSection()->getBeginSymbol(); + } + + /// Emit a reference to the string. + void emitRef(MCStreamer *MCOS, StringRef Path); + + /// Emit the .debug_line_str section if appropriate. + void emitSection(MCStreamer *MCOS); +}; + static inline uint64_t ScaleAddrDelta(MCContext &Context, uint64_t AddrDelta) { unsigned MinInsnLength = Context.getAsmInfo()->getMinInstAlignment(); if (MinInsnLength == 1) @@ -108,6 +132,18 @@ static inline const MCExpr *MakeStartMinusEndExpr(const MCStreamer &MCOS, } // +// This helper routine returns an expression of Start + IntVal . +// +static inline const MCExpr * +makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *LHS = MCSymbolRefExpr::create(&Start, Variant, Ctx); + const MCExpr *RHS = MCConstantExpr::create(IntVal, Ctx); + const MCExpr *Res = MCBinaryExpr::create(MCBinaryExpr::Add, LHS, RHS, Ctx); + return Res; +} + +// // This emits the Dwarf line table for the specified section from the entries // in the LineSection. // @@ -205,22 +241,35 @@ void MCDwarfLineTable::Emit(MCObjectStreamer *MCOS, if (LineTables.empty()) return; + // In a v5 non-split line table, put the strings in a separate section. + Optional<MCDwarfLineStr> LineStr; + if (context.getDwarfVersion() >= 5) + LineStr = MCDwarfLineStr(context); + // Switch to the section where the table will be emitted into. MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfLineSection()); // Handle the rest of the Compile Units. - for (const auto &CUIDTablePair : LineTables) - CUIDTablePair.second.EmitCU(MCOS, Params); + for (const auto &CUIDTablePair : LineTables) { + CUIDTablePair.second.EmitCU(MCOS, Params, LineStr); + } + + if (LineStr) + LineStr->emitSection(MCOS); } -void MCDwarfDwoLineTable::Emit(MCStreamer &MCOS, - MCDwarfLineTableParams Params) const { - MCOS.EmitLabel(Header.Emit(&MCOS, Params, None).second); +void MCDwarfDwoLineTable::Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params, + MCSection *Section) const { + if (Header.MCDwarfFiles.empty()) + return; + Optional<MCDwarfLineStr> NoLineStr(None); + MCOS.SwitchSection(Section); + MCOS.EmitLabel(Header.Emit(&MCOS, Params, None, NoLineStr).second); } std::pair<MCSymbol *, MCSymbol *> -MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, - MCDwarfLineTableParams Params) const { +MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, + Optional<MCDwarfLineStr> &LineStr) const { static const char StandardOpcodeLengths[] = { 0, // length of DW_LNS_copy 1, // length of DW_LNS_advance_pc @@ -237,8 +286,10 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, }; assert(array_lengthof(StandardOpcodeLengths) >= (Params.DWARF2LineOpcodeBase - 1U)); - return Emit(MCOS, Params, makeArrayRef(StandardOpcodeLengths, - Params.DWARF2LineOpcodeBase - 1)); + return Emit( + MCOS, Params, + makeArrayRef(StandardOpcodeLengths, Params.DWARF2LineOpcodeBase - 1), + LineStr); } static const MCExpr *forceExpAbs(MCStreamer &OS, const MCExpr* Expr) { @@ -257,12 +308,31 @@ static void emitAbsValue(MCStreamer &OS, const MCExpr *Value, unsigned Size) { OS.EmitValue(ABS, Size); } -static void -emitV2FileDirTables(MCStreamer *MCOS, - const SmallVectorImpl<std::string> &MCDwarfDirs, - const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles) { +void MCDwarfLineStr::emitSection(MCStreamer *MCOS) { + // Switch to the .debug_line_str section. + MCOS->SwitchSection( + MCOS->getContext().getObjectFileInfo()->getDwarfLineStrSection()); + // Emit the strings without perturbing the offsets we used. + LineStrings.finalizeInOrder(); + SmallString<0> Data; + Data.resize(LineStrings.getSize()); + LineStrings.write((uint8_t *)Data.data()); + MCOS->EmitBinaryData(Data.str()); +} + +void MCDwarfLineStr::emitRef(MCStreamer *MCOS, StringRef Path) { + int RefSize = 4; // FIXME: Support DWARF-64 + size_t Offset = LineStrings.add(Path); + if (UseRelocs) { + MCContext &Ctx = MCOS->getContext(); + MCOS->EmitValue(makeStartPlusIntExpr(Ctx, *LineStrLabel, Offset), RefSize); + } else + MCOS->EmitIntValue(Offset, RefSize); +} + +void MCDwarfLineTableHeader::emitV2FileDirTables(MCStreamer *MCOS) const { // First the directory table. - for (auto Dir : MCDwarfDirs) { + for (auto &Dir : MCDwarfDirs) { MCOS->EmitBytes(Dir); // The DirectoryName, and... MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. } @@ -280,46 +350,101 @@ emitV2FileDirTables(MCStreamer *MCOS, MCOS->EmitIntValue(0, 1); // Terminate the file list. } -static void -emitV5FileDirTables(MCStreamer *MCOS, - const SmallVectorImpl<std::string> &MCDwarfDirs, - const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles, - StringRef CompilationDir) { - // The directory format, which is just inline null-terminated strings. +static void emitOneV5FileEntry(MCStreamer *MCOS, const MCDwarfFile &DwarfFile, + bool EmitMD5, bool HasSource, + Optional<MCDwarfLineStr> &LineStr) { + assert(!DwarfFile.Name.empty()); + if (LineStr) + LineStr->emitRef(MCOS, DwarfFile.Name); + else { + MCOS->EmitBytes(DwarfFile.Name); // FileName and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + } + MCOS->EmitULEB128IntValue(DwarfFile.DirIndex); // Directory number. + if (EmitMD5) { + MD5::MD5Result *Cksum = DwarfFile.Checksum; + MCOS->EmitBinaryData( + StringRef(reinterpret_cast<const char *>(Cksum->Bytes.data()), + Cksum->Bytes.size())); + } + if (HasSource) { + if (LineStr) + LineStr->emitRef(MCOS, DwarfFile.Source.getValueOr(StringRef())); + else { + MCOS->EmitBytes( + DwarfFile.Source.getValueOr(StringRef())); // Source and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + } + } +} + +void MCDwarfLineTableHeader::emitV5FileDirTables( + MCStreamer *MCOS, Optional<MCDwarfLineStr> &LineStr, + StringRef CtxCompilationDir) const { + // The directory format, which is just a list of the directory paths. In a + // non-split object, these are references to .debug_line_str; in a split + // object, they are inline strings. MCOS->EmitIntValue(1, 1); MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path); - MCOS->EmitULEB128IntValue(dwarf::DW_FORM_string); - // Then the list of directory paths. CompilationDir comes first. + MCOS->EmitULEB128IntValue(LineStr ? dwarf::DW_FORM_line_strp + : dwarf::DW_FORM_string); MCOS->EmitULEB128IntValue(MCDwarfDirs.size() + 1); - MCOS->EmitBytes(CompilationDir); - MCOS->EmitBytes(StringRef("\0", 1)); - for (auto Dir : MCDwarfDirs) { - MCOS->EmitBytes(Dir); // The DirectoryName, and... - MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + // Try not to emit an empty compilation directory. + const StringRef CompDir = + CompilationDir.empty() ? CtxCompilationDir : StringRef(CompilationDir); + if (LineStr) { + // Record path strings, emit references here. + LineStr->emitRef(MCOS, CompDir); + for (const auto &Dir : MCDwarfDirs) + LineStr->emitRef(MCOS, Dir); + } else { + // The list of directory paths. Compilation directory comes first. + MCOS->EmitBytes(CompDir); + MCOS->EmitBytes(StringRef("\0", 1)); + for (const auto &Dir : MCDwarfDirs) { + MCOS->EmitBytes(Dir); // The DirectoryName, and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + } } // The file format, which is the inline null-terminated filename and a // directory index. We don't track file size/timestamp so don't emit them - // in the v5 table. - // FIXME: Arrange to emit MD5 signatures for the source files. - MCOS->EmitIntValue(2, 1); + // in the v5 table. Emit MD5 checksums and source if we have them. + uint64_t Entries = 2; + if (HasAllMD5) + Entries += 1; + if (HasSource) + Entries += 1; + MCOS->EmitIntValue(Entries, 1); MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path); - MCOS->EmitULEB128IntValue(dwarf::DW_FORM_string); + MCOS->EmitULEB128IntValue(LineStr ? dwarf::DW_FORM_line_strp + : dwarf::DW_FORM_string); MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_directory_index); MCOS->EmitULEB128IntValue(dwarf::DW_FORM_udata); - // Then the list of file names. These start at 1 for some reason. - MCOS->EmitULEB128IntValue(MCDwarfFiles.size() - 1); - for (unsigned i = 1; i < MCDwarfFiles.size(); ++i) { - assert(!MCDwarfFiles[i].Name.empty()); - MCOS->EmitBytes(MCDwarfFiles[i].Name); // FileName and... - MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. - MCOS->EmitULEB128IntValue(MCDwarfFiles[i].DirIndex); // Directory number. + if (HasAllMD5) { + MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_MD5); + MCOS->EmitULEB128IntValue(dwarf::DW_FORM_data16); + } + if (HasSource) { + MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_LLVM_source); + MCOS->EmitULEB128IntValue(LineStr ? dwarf::DW_FORM_line_strp + : dwarf::DW_FORM_string); } + // Then the counted list of files. The root file is file #0, then emit the + // files as provide by .file directives. To accommodate assembler source + // written for DWARF v4 but trying to emit v5, if we didn't see a root file + // explicitly, replicate file #1. + MCOS->EmitULEB128IntValue(MCDwarfFiles.size()); + emitOneV5FileEntry(MCOS, RootFile.Name.empty() ? MCDwarfFiles[1] : RootFile, + HasAllMD5, HasSource, LineStr); + for (unsigned i = 1; i < MCDwarfFiles.size(); ++i) + emitOneV5FileEntry(MCOS, MCDwarfFiles[i], HasAllMD5, HasSource, LineStr); } std::pair<MCSymbol *, MCSymbol *> MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, - ArrayRef<char> StandardOpcodeLengths) const { + ArrayRef<char> StandardOpcodeLengths, + Optional<MCDwarfLineStr> &LineStr) const { MCContext &context = MCOS->getContext(); // Create a symbol at the beginning of the line table. @@ -384,9 +509,9 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, // Put out the directory and file tables. The formats vary depending on // the version. if (LineTableVersion >= 5) - emitV5FileDirTables(MCOS, MCDwarfDirs, MCDwarfFiles, CompilationDir); + emitV5FileDirTables(MCOS, LineStr, context.getCompilationDir()); else - emitV2FileDirTables(MCOS, MCDwarfDirs, MCDwarfFiles); + emitV2FileDirTables(MCOS); // This is the end of the prologue, so set the value of the symbol at the // end of the prologue (that was used in a previous expression). @@ -396,8 +521,9 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, } void MCDwarfLineTable::EmitCU(MCObjectStreamer *MCOS, - MCDwarfLineTableParams Params) const { - MCSymbol *LineEndSym = Header.Emit(MCOS, Params).second; + MCDwarfLineTableParams Params, + Optional<MCDwarfLineStr> &LineStr) const { + MCSymbol *LineEndSym = Header.Emit(MCOS, Params, LineStr).second; // Put out the line tables. for (const auto &LineSec : MCLineSections.getMCLineEntries()) @@ -408,14 +534,20 @@ void MCDwarfLineTable::EmitCU(MCObjectStreamer *MCOS, MCOS->EmitLabel(LineEndSym); } -unsigned MCDwarfLineTable::getFile(StringRef &Directory, StringRef &FileName, - unsigned FileNumber) { - return Header.getFile(Directory, FileName, FileNumber); +Expected<unsigned> MCDwarfLineTable::tryGetFile(StringRef &Directory, + StringRef &FileName, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned FileNumber) { + return Header.tryGetFile(Directory, FileName, Checksum, Source, FileNumber); } -unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory, - StringRef &FileName, - unsigned FileNumber) { +Expected<unsigned> +MCDwarfLineTableHeader::tryGetFile(StringRef &Directory, + StringRef &FileName, + MD5::MD5Result *Checksum, + Optional<StringRef> &Source, + unsigned FileNumber) { if (Directory == CompilationDir) Directory = ""; if (FileName.empty()) { @@ -423,6 +555,12 @@ unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory, Directory = ""; } assert(!FileName.empty()); + // Keep track of whether any or all files have an MD5 checksum. + // If any files have embedded source, they all must. + if (MCDwarfFiles.empty()) { + trackMD5Usage(Checksum); + HasSource = (Source != None); + } if (FileNumber == 0) { // File numbers start with 1 and/or after any file numbers // allocated by inline-assembler .file directives. @@ -441,9 +579,15 @@ unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory, // Get the new MCDwarfFile slot for this FileNumber. MCDwarfFile &File = MCDwarfFiles[FileNumber]; - // It is an error to use see the same number more than once. + // It is an error to see the same number more than once. if (!File.Name.empty()) - return 0; + return make_error<StringError>("file number already allocated", + inconvertibleErrorCode()); + + // If any files have embedded source, they all must. + if (HasSource != (Source != None)) + return make_error<StringError>("inconsistent use of embedded source", + inconvertibleErrorCode()); if (Directory.empty()) { // Separate the directory part from the basename of the FileName. @@ -478,6 +622,11 @@ unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory, File.Name = FileName; File.DirIndex = DirIndex; + File.Checksum = Checksum; + trackMD5Usage(Checksum); + File.Source = Source; + if (Source) + HasSource = true; // return the allocated FileNumber. return FileNumber; @@ -1653,6 +1802,8 @@ void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context, // Scale the address delta by the minimum instruction length. AddrDelta = ScaleAddrDelta(Context, AddrDelta); + support::endianness E = + Context.getAsmInfo()->isLittleEndian() ? support::little : support::big; if (AddrDelta == 0) { } else if (isUIntN(6, AddrDelta)) { uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta; @@ -1662,16 +1813,10 @@ void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context, OS << uint8_t(AddrDelta); } else if (isUInt<16>(AddrDelta)) { OS << uint8_t(dwarf::DW_CFA_advance_loc2); - if (Context.getAsmInfo()->isLittleEndian()) - support::endian::Writer<support::little>(OS).write<uint16_t>(AddrDelta); - else - support::endian::Writer<support::big>(OS).write<uint16_t>(AddrDelta); + support::endian::write<uint16_t>(OS, AddrDelta, E); } else { assert(isUInt<32>(AddrDelta)); OS << uint8_t(dwarf::DW_CFA_advance_loc4); - if (Context.getAsmInfo()->isLittleEndian()) - support::endian::Writer<support::little>(OS).write<uint32_t>(AddrDelta); - else - support::endian::Writer<support::big>(OS).write<uint32_t>(AddrDelta); + support::endian::write<uint32_t>(OS, AddrDelta, E); } } |