Skip to content

Commit

Permalink
[DWARFv5] Tolerate files not all having an MD5 checksum.
Browse files Browse the repository at this point in the history
In some cases, for example when compiling a preprocessed file, the
front-end is not able to provide an MD5 checksum for all files. When
that happens, omit the MD5 checksums from the final DWARF, because
DWARF doesn't have a way to indicate that some but not all files have
a checksum.

When assembling a .s file, and some but not all .file directives
provide an MD5 checksum, issue a warning and don't emit MD5 into the
DWARF.

Fixes PR37623.

Differential Revision: https://reviews.llvm.org/D48135

llvm-svn: 334710
  • Loading branch information
pogo59 committed Jun 14, 2018
1 parent 767e152 commit cc7344a
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 30 deletions.
5 changes: 5 additions & 0 deletions llvm/include/llvm/MC/MCContext.h
Expand Up @@ -550,6 +550,11 @@ namespace llvm {
Source);
}

/// Reports whether MD5 checksum usage is consistent (all-or-none).
bool isDwarfMD5UsageConsistent(unsigned CUID) const {
return getMCDwarfLineTable(CUID).isMD5UsageConsistent();
}

/// Saves the information from the currently parsed dwarf .loc directive
/// and sets DwarfLocSeen. When the next instruction is assembled an entry
/// in the line number table with this information and the address of the
Expand Down
29 changes: 26 additions & 3 deletions llvm/include/llvm/MC/MCDwarf.h
Expand Up @@ -215,9 +215,12 @@ struct MCDwarfLineTableHeader {
StringMap<unsigned> SourceIdMap;
StringRef CompilationDir;
MCDwarfFile RootFile;
bool HasMD5 = false;
bool HasSource = false;
private:
bool HasAllMD5 = true;
bool HasAnyMD5 = false;

public:
MCDwarfLineTableHeader() = default;

Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
Expand All @@ -231,6 +234,17 @@ struct MCDwarfLineTableHeader {
Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
ArrayRef<char> SpecialOpcodeLengths,
Optional<MCDwarfLineStr> &LineStr) const;
void resetMD5Usage() {
HasAllMD5 = true;
HasAnyMD5 = false;
}
void trackMD5Usage(bool MD5Used) {
HasAllMD5 &= MD5Used;
HasAnyMD5 |= MD5Used;
}
bool isMD5UsageConsistent() const {
return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5);
}

private:
void emitV2FileDirTables(MCStreamer *MCOS) const;
Expand All @@ -251,7 +265,7 @@ class MCDwarfDwoLineTable {
Header.RootFile.DirIndex = 0;
Header.RootFile.Checksum = Checksum;
Header.RootFile.Source = Source;
Header.HasMD5 = (Checksum != nullptr);
Header.trackMD5Usage(Checksum);
Header.HasSource = Source.hasValue();
}

Expand Down Expand Up @@ -294,10 +308,19 @@ class MCDwarfLineTable {
Header.RootFile.DirIndex = 0;
Header.RootFile.Checksum = Checksum;
Header.RootFile.Source = Source;
Header.HasMD5 = (Checksum != nullptr);
Header.trackMD5Usage(Checksum);
Header.HasSource = Source.hasValue();
}

void resetRootFile() {
assert(Header.MCDwarfFiles.empty());
Header.resetMD5Usage();
Header.HasSource = false;
}

// Report whether MD5 usage has been consistent (all-or-none).
bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); }

MCSymbol *getLabel() const {
return Header.Label;
}
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/MC/MCAsmStreamer.cpp
Expand Up @@ -1171,6 +1171,9 @@ void MCAsmStreamer::emitDwarfFile0Directive(StringRef Directory,
// .file 0 is new for DWARF v5.
if (getContext().getDwarfVersion() < 5)
return;
// Inform MCDwarf about the root file.
getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum,
Source);

SmallString<128> Str;
raw_svector_ostream OS1(Str);
Expand Down
24 changes: 10 additions & 14 deletions llvm/lib/MC/MCDwarf.cpp
Expand Up @@ -350,7 +350,7 @@ void MCDwarfLineTableHeader::emitV2FileDirTables(MCStreamer *MCOS) const {
}

static void emitOneV5FileEntry(MCStreamer *MCOS, const MCDwarfFile &DwarfFile,
bool HasMD5, bool HasSource,
bool EmitMD5, bool HasSource,
Optional<MCDwarfLineStr> &LineStr) {
assert(!DwarfFile.Name.empty());
if (LineStr)
Expand All @@ -360,7 +360,7 @@ static void emitOneV5FileEntry(MCStreamer *MCOS, const MCDwarfFile &DwarfFile,
MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator.
}
MCOS->EmitULEB128IntValue(DwarfFile.DirIndex); // Directory number.
if (HasMD5) {
if (EmitMD5) {
MD5::MD5Result *Cksum = DwarfFile.Checksum;
MCOS->EmitBinaryData(
StringRef(reinterpret_cast<const char *>(Cksum->Bytes.data()),
Expand Down Expand Up @@ -410,7 +410,7 @@ void MCDwarfLineTableHeader::emitV5FileDirTables(
// directory index. We don't track file size/timestamp so don't emit them
// in the v5 table. Emit MD5 checksums and source if we have them.
uint64_t Entries = 2;
if (HasMD5)
if (HasAllMD5)
Entries += 1;
if (HasSource)
Entries += 1;
Expand All @@ -420,7 +420,7 @@ void MCDwarfLineTableHeader::emitV5FileDirTables(
: dwarf::DW_FORM_string);
MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_directory_index);
MCOS->EmitULEB128IntValue(dwarf::DW_FORM_udata);
if (HasMD5) {
if (HasAllMD5) {
MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_MD5);
MCOS->EmitULEB128IntValue(dwarf::DW_FORM_data16);
}
Expand All @@ -435,9 +435,9 @@ void MCDwarfLineTableHeader::emitV5FileDirTables(
// explicitly, replicate file #1.
MCOS->EmitULEB128IntValue(MCDwarfFiles.size());
emitOneV5FileEntry(MCOS, RootFile.Name.empty() ? MCDwarfFiles[1] : RootFile,
HasMD5, HasSource, LineStr);
HasAllMD5, HasSource, LineStr);
for (unsigned i = 1; i < MCDwarfFiles.size(); ++i)
emitOneV5FileEntry(MCOS, MCDwarfFiles[i], HasMD5, HasSource, LineStr);
emitOneV5FileEntry(MCOS, MCDwarfFiles[i], HasAllMD5, HasSource, LineStr);
}

std::pair<MCSymbol *, MCSymbol *>
Expand Down Expand Up @@ -554,9 +554,10 @@ MCDwarfLineTableHeader::tryGetFile(StringRef &Directory,
Directory = "";
}
assert(!FileName.empty());
// If any files have an MD5 checksum or embedded source, they all must.
// Keep track of whether any or all files have an MD5 checksum.
// If any files have embedded source, they all must.
if (MCDwarfFiles.empty()) {
HasMD5 = (Checksum != nullptr);
trackMD5Usage(Checksum);
HasSource = (Source != None);
}
if (FileNumber == 0) {
Expand All @@ -582,10 +583,6 @@ MCDwarfLineTableHeader::tryGetFile(StringRef &Directory,
return make_error<StringError>("file number already allocated",
inconvertibleErrorCode());

// If any files have an MD5 checksum, they all must.
if (HasMD5 != (Checksum != nullptr))
return make_error<StringError>("inconsistent use of MD5 checksums",
inconvertibleErrorCode());
// If any files have embedded source, they all must.
if (HasSource != (Source != None))
return make_error<StringError>("inconsistent use of embedded source",
Expand Down Expand Up @@ -625,8 +622,7 @@ MCDwarfLineTableHeader::tryGetFile(StringRef &Directory,
File.Name = FileName;
File.DirIndex = DirIndex;
File.Checksum = Checksum;
if (Checksum)
HasMD5 = true;
trackMD5Usage(Checksum);
File.Source = Source;
if (Source)
HasSource = true;
Expand Down
15 changes: 14 additions & 1 deletion llvm/lib/MC/MCParser/AsmParser.cpp
Expand Up @@ -177,6 +177,9 @@ class AsmParser : public MCAsmParser {
/// Are we parsing ms-style inline assembly?
bool ParsingInlineAsm = false;

/// Did we already inform the user about inconsistent MD5 usage?
bool ReportedInconsistentMD5 = false;

public:
AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
const MCAsmInfo &MAI, unsigned CB);
Expand Down Expand Up @@ -3337,7 +3340,11 @@ bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) {

// In case there is a -g option as well as debug info from directive .file,
// we turn off the -g option, directly use the existing debug info instead.
getContext().setGenDwarfForAssembly(false);
// Also reset any implicit ".file 0" for the assembler source.
if (Ctx.getGenDwarfForAssembly()) {
Ctx.getMCDwarfLineTable(0).resetRootFile();
Ctx.setGenDwarfForAssembly(false);
}

if (FileNumber == -1)
getStreamer().EmitFileDirective(Filename);
Expand All @@ -3364,6 +3371,12 @@ bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) {
return Error(DirectiveLoc, toString(FileNumOrErr.takeError()));
FileNumber = FileNumOrErr.get();
}
// Alert the user if there are some .file directives with MD5 and some not.
// But only do that once.
if (!ReportedInconsistentMD5 && !Ctx.isDwarfMD5UsageConsistent(0)) {
ReportedInconsistentMD5 = true;
return Warning(DirectiveLoc, "inconsistent use of MD5 checksums");
}
}

return false;
Expand Down
14 changes: 7 additions & 7 deletions llvm/test/CodeGen/Generic/dwarf-md5.ll
Expand Up @@ -5,21 +5,21 @@
; XFAIL: darwin

; REQUIRES: object-emission
; RUN: %llc_dwarf -dwarf-version 4 -filetype=asm -o - %s | FileCheck %s --check-prefixes=ASM,ASM-4
; RUN: %llc_dwarf -dwarf-version 5 -filetype=asm -o - %s | FileCheck %s --check-prefixes=ASM,ASM-5
; RUN: %llc_dwarf -dwarf-version 4 -filetype=asm -o - %s | FileCheck %s --check-prefix=ASM-4
; RUN: %llc_dwarf -dwarf-version 5 -filetype=asm -o - %s | FileCheck %s --check-prefix=ASM-5
; RUN: %llc_dwarf -dwarf-version 4 -filetype=obj -o %t4.o %s
; RUN: llvm-dwarfdump -debug-line %t4.o | FileCheck %s --check-prefix=OBJ
; RUN: %llc_dwarf -dwarf-version 5 -filetype=obj -o %t5.o %s
; RUN: llvm-dwarfdump -debug-line %t5.o | FileCheck %s --check-prefixes=OBJ,OBJ-5

; ASM-4-NOT: .file 0
; ASM-5: .file 0 "/scratch{{.*[/\\]}}t.c" md5 0x00000000000000000000000000000000
; ASM: .file 1 "/scratch{{.*[/\\]}}t1.h"
; ASM-4: .file 1 "/scratch{{.*[/\\]}}t1.h"
; ASM-4-NOT: md5
; ASM-5-SAME: md5 0x11111111111111111111111111111111
; ASM: .file 2 "/scratch{{.*[/\\]}}t2.h"
; ASM-4: .file 2 "/scratch{{.*[/\\]}}t2.h"
; ASM-4-NOT: md5
; ASM-5-SAME: md5 0x22222222222222222222222222222222
; ASM-5: .file 0 "/scratch{{.*[/\\]}}t.c" md5 0x00000000000000000000000000000000
; ASM-5: .file 1 "t1.h" md5 0x11111111111111111111111111111111
; ASM-5: .file 2 "t2.h" md5 0x22222222222222222222222222222222

; OBJ-5: file_names[ 0]:
; OBJ-5-NEXT: name: "t.c"
Expand Down
10 changes: 6 additions & 4 deletions llvm/test/CodeGen/Generic/dwarf-source.ll
Expand Up @@ -5,16 +5,18 @@
; XFAIL: darwin

; REQUIRES: object-emission
; RUN: %llc_dwarf -dwarf-version 4 -filetype=asm -o - %s | FileCheck %s --check-prefix=ASM
; RUN: %llc_dwarf -dwarf-version 5 -filetype=asm -o - %s | FileCheck %s --check-prefixes=ASM,ASM-5
; RUN: %llc_dwarf -dwarf-version 4 -filetype=asm -o - %s | FileCheck %s --check-prefix=ASM-4
; RUN: %llc_dwarf -dwarf-version 5 -filetype=asm -o - %s | FileCheck %s --check-prefix=ASM-5
; RUN: %llc_dwarf -dwarf-version 4 -filetype=obj -o %t4.o %s
; RUN: llvm-dwarfdump -debug-line %t4.o | FileCheck %s --check-prefixes=OBJ,OBJ-4
; RUN: %llc_dwarf -dwarf-version 5 -filetype=obj -o %t5.o %s
; RUN: llvm-dwarfdump -debug-line %t5.o | FileCheck %s --check-prefixes=OBJ,OBJ-5

; ASM-4: .file 1 "/test{{.*[/\\]}}t1.h" source "11111111111111111111111111111111"
; ASM-4: .file 2 "/test{{.*[/\\]}}t2.h" source "22222222222222222222222222222222"
; ASM-5: .file 0 "/test{{.*[/\\]}}t.c" source "00000000000000000000000000000000"
; ASM: .file 1 "/test{{.*[/\\]}}t1.h" source "11111111111111111111111111111111"
; ASM: .file 2 "/test{{.*[/\\]}}t2.h" source "22222222222222222222222222222222"
; ASM-5: .file 1 "t1.h" source "11111111111111111111111111111111"
; ASM-5: .file 2 "t2.h" source "22222222222222222222222222222222"

; OBJ-5: file_names[ 0]:
; OBJ-5-NEXT: name: "t.c"
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/MC/ELF/debug-md5-err.s
Expand Up @@ -22,5 +22,5 @@
.file "baz" md5 0xffeeddccbbaa99887766554433221100

# Inconsistent use of MD5 option. Note: .file 1 did not supply one.
# CHECK: [[@LINE+1]]:{{[0-9]+}}: error: inconsistent use of MD5 checksums
# CHECK: [[@LINE+1]]:{{[0-9]+}}: warning: inconsistent use of MD5 checksums
.file 5 "bax" md5 0xffeeddccbbaa99887766554433221100
44 changes: 44 additions & 0 deletions llvm/test/MC/ELF/debug-mixed-md5.ll
@@ -0,0 +1,44 @@
; RUN: %llc_dwarf -filetype=asm -dwarf-version=5 %s -o - | FileCheck %s -check-prefix=ASM
; RUN: %llc_dwarf -filetype=obj -dwarf-version=5 %s -o - | llvm-dwarfdump -debug-line - | FileCheck %s -check-prefix=OBJ
; ASM: .file 0 "{{.+}}" md5
; ASM: .file 1 "{{.+}}" md5
; ASM: .file 2 "t1.cpp"
; ASM-NOT: md5
; OBJ: file_names[ 0]:
; OBJ-NOT: md5
;
; Generated from this source (see PR37623):
;
; #define a(...) template __VA_ARGS__;
; template <class> class b {};
; a(class b<int>)
; # 1 ""
; int c;

; ModuleID = 't1.cpp'
source_filename = "t1.cpp"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@c = global i32 0, align 4, !dbg !0

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!12, !13, !14}
!llvm.ident = !{!15}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 1, type: !10, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !11)
!3 = !DIFile(filename: "<stdin>", directory: "/home/probinson/projects/scratch", checksumkind: CSK_MD5, checksum: "9252ff18ee25a08c2b4216b21b5d66d4")
!4 = !{}
!5 = !{!6}
!6 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "b<int>", file: !7, line: 3, size: 8, flags: DIFlagTypePassByValue, elements: !4, templateParams: !8, identifier: "_ZTS1bIiE")
!7 = !DIFile(filename: "t1.cpp", directory: "/home/probinson/projects/scratch")
!8 = !{!9}
!9 = !DITemplateTypeParameter(type: !10)
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !{!0}
!12 = !{i32 2, !"Dwarf Version", i32 5}
!13 = !{i32 2, !"Debug Info Version", i32 3}
!14 = !{i32 1, !"wchar_size", i32 4}
!15 = !{!"clang version 7.0.0 "}

0 comments on commit cc7344a

Please sign in to comment.