From f3284d8600790cb2069512507cb0e70f3bfca181 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Fri, 1 Mar 2019 20:58:04 +0000 Subject: [PATCH] [DWARF] Make -g with empty assembler source work better. This was sometimes causing clang or llvm-mc to crash, and in other cases could emit a bogus DWARF line-table header. I did an interim patch in r352541; this patch should be a cleaner and more complete fix, and retains the test. Addresses PR40538. Differential Revision: https://reviews.llvm.org/D58750 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@355226 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCContext.h | 4 ++++ include/llvm/MC/MCDwarf.h | 2 ++ lib/MC/MCContext.cpp | 24 ++++++++++++++++++++++++ lib/MC/MCDwarf.cpp | 24 +++++++++++++++++------- lib/MC/MCParser/AsmParser.cpp | 11 ++++++----- test/MC/ELF/debug-prefix-map.s | 2 +- tools/llvm-mc/llvm-mc.cpp | 14 ++------------ 7 files changed, 56 insertions(+), 25 deletions(-) diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index b964965cf47..c87df5a82ce 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -594,6 +594,10 @@ namespace llvm { GenDwarfFileNumber = FileNumber; } + /// Specifies information about the "root file" for assembler clients + /// (e.g., llvm-mc). Assumes compilation dir etc. have been set up. + void setGenDwarfRootFile(StringRef FileName, StringRef Buffer); + const SetVector &getGenDwarfSectionSyms() { return SectionsForRanges; } diff --git a/include/llvm/MC/MCDwarf.h b/include/llvm/MC/MCDwarf.h index 8eaa1523fe8..991ad525f89 100644 --- a/include/llvm/MC/MCDwarf.h +++ b/include/llvm/MC/MCDwarf.h @@ -320,6 +320,8 @@ public: bool hasRootFile() const { return !Header.RootFile.Name.empty(); } + const MCDwarfFile &getRootFile() const { return Header.RootFile; } + // Report whether MD5 usage has been consistent (all-or-none). bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); } diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index d7f95df726f..7cf4e1da5ac 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -37,6 +37,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" @@ -565,6 +566,29 @@ void MCContext::RemapDebugPaths() { // Dwarf Management //===----------------------------------------------------------------------===// +void MCContext::setGenDwarfRootFile(StringRef InputFileName, StringRef Buffer) { + // MCDwarf needs the root file as well as the compilation directory. + // If we find a '.file 0' directive that will supersede these values. + MD5::MD5Result *Cksum = nullptr; + if (getDwarfVersion() >= 5) { + MD5 Hash; + Cksum = (MD5::MD5Result *)allocate(sizeof(MD5::MD5Result), 1); + Hash.update(Buffer); + Hash.final(*Cksum); + } + // Canonicalize the root filename. It cannot be empty, and should not + // repeat the compilation dir. + StringRef FileName = + !getMainFileName().empty() ? StringRef(getMainFileName()) : InputFileName; + if (FileName.empty() || FileName == "-") + FileName = ""; + if (FileName.consume_front(getCompilationDir())) + FileName.consume_front(llvm::sys::path::get_separator()); + assert(!FileName.empty()); + setMCLineTableRootFile( + /*CUID=*/0, getCompilationDir(), FileName, Cksum, None); +} + /// getDwarfFile - takes a file name and number to place in the dwarf file and /// directory tables. If the file number has already been allocated it is an /// error and zero is returned and the client reports the error, else the diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 2cab55f15bc..2b5bb610536 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -430,10 +430,14 @@ void MCDwarfLineTableHeader::emitV5FileDirTables( : 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()); + // files as provide by .file directives. + // MCDwarfFiles has an unused element [0] so use size() not size()+1. + // But sometimes MCDwarfFiles is empty, in which case we still emit one file. + MCOS->EmitULEB128IntValue(MCDwarfFiles.empty() ? 1 : MCDwarfFiles.size()); + // 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. + assert((!RootFile.Name.empty() || MCDwarfFiles.size() >= 1) && + "No root file and no .file directives"); emitOneV5FileEntry(MCOS, RootFile.Name.empty() ? MCDwarfFiles[1] : RootFile, HasAllMD5, HasSource, LineStr); for (unsigned i = 1; i < MCDwarfFiles.size(); ++i) @@ -1006,9 +1010,15 @@ static void EmitGenDwarfInfo(MCStreamer *MCOS, MCOS->EmitBytes(MCDwarfDirs[0]); MCOS->EmitBytes(sys::path::get_separator()); } - const SmallVectorImpl &MCDwarfFiles = - MCOS->getContext().getMCDwarfFiles(); - MCOS->EmitBytes(MCDwarfFiles[1].Name); + const SmallVectorImpl &MCDwarfFiles = context.getMCDwarfFiles(); + // MCDwarfFiles might be empty if we have an empty source file. + // If it's not empty, [0] is unused and [1] is the first actual file. + assert(MCDwarfFiles.empty() || MCDwarfFiles.size() >= 2); + const MCDwarfFile &RootFile = + MCDwarfFiles.empty() + ? context.getMCDwarfLineTable(/*CUID=*/0).getRootFile() + : MCDwarfFiles[1]; + MCOS->EmitBytes(RootFile.Name); MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string. // AT_comp_dir, the working directory the assembly was done in. diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index a66a4eb29af..4b487825935 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -845,9 +845,13 @@ bool AsmParser::enabledGenDwarfForAssembly() { // If we haven't encountered any .file directives (which would imply that // the assembler source was produced with debug info already) then emit one // describing the assembler source file itself. - if (getContext().getGenDwarfFileNumber() == 0) + if (getContext().getGenDwarfFileNumber() == 0) { + const MCDwarfFile &RootFile = + getContext().getMCDwarfLineTable(/*CUID=*/0).getRootFile(); getContext().setGenDwarfFileNumber(getStreamer().EmitDwarfFileDirective( - 0, StringRef(), getContext().getMainFileName())); + /*CUID=*/0, getContext().getCompilationDir(), RootFile.Name, + RootFile.Checksum, RootFile.Source)); + } return true; } @@ -900,9 +904,6 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { eatToEndOfStatement(); } - // Make sure we get proper DWARF even for empty files. - (void)enabledGenDwarfForAssembly(); - getTargetParser().onEndOfFile(); printPendingErrors(); diff --git a/test/MC/ELF/debug-prefix-map.s b/test/MC/ELF/debug-prefix-map.s index 4d56b8816c6..9fe4c9bf176 100644 --- a/test/MC/ELF/debug-prefix-map.s +++ b/test/MC/ELF/debug-prefix-map.s @@ -20,6 +20,6 @@ f: // MAP: DW_AT_comp_dir [DW_FORM_string] ("src_root") // MAP: DW_AT_decl_file [DW_FORM_data4] ("src_root{{(/|\\)+}}src.s") -// MAP_ABS: DW_AT_name [DW_FORM_string] ("{{(/|\\)+}}src_root{{(/|\\)+}}src.s") +// MAP_ABS: DW_AT_name [DW_FORM_string] ("src.s") // MAP_ABS: DW_AT_comp_dir [DW_FORM_string] ("{{(/|\\)+}}src_root") // MAP_ABS: DW_AT_decl_file [DW_FORM_data4] ("{{(/|\\)+}}src_root{{(/|\\)+}}src.s") diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index af19a64d37d..ec189c29786 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -401,18 +401,8 @@ int main(int argc, char **argv) { } if (!MainFileName.empty()) Ctx.setMainFileName(MainFileName); - if (GenDwarfForAssembly && DwarfVersion >= 5) { - // DWARF v5 needs the root file as well as the compilation directory. - // If we find a '.file 0' directive that will supersede these values. - MD5 Hash; - MD5::MD5Result *Cksum = - (MD5::MD5Result *)Ctx.allocate(sizeof(MD5::MD5Result), 1); - Hash.update(Buffer->getBuffer()); - Hash.final(*Cksum); - Ctx.setMCLineTableRootFile( - /*CUID=*/0, Ctx.getCompilationDir(), - !MainFileName.empty() ? MainFileName : InputFilename, Cksum, None); - } + if (GenDwarfForAssembly) + Ctx.setGenDwarfRootFile(InputFilename, Buffer->getBuffer()); // Package up features to be passed to target/subtarget std::string FeaturesStr;