summaryrefslogtreecommitdiff
path: root/lib/MC/MCDwarf.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
commiteb11fae6d08f479c0799db45860a98af528fa6e7 (patch)
tree44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/MC/MCDwarf.cpp
parentb8a2042aa938069e862750553db0e4d82d25822c (diff)
Notes
Diffstat (limited to 'lib/MC/MCDwarf.cpp')
-rw-r--r--lib/MC/MCDwarf.cpp265
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);
}
}