From: Martin Storsjo Date: Fri, 18 Oct 2019 10:43:15 +0000 (+0000) Subject: [LLD] [COFF] Try to report source locations for duplicate symbols X-Git-Tag: llvmorg-11-init~6197 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b38f577c015c210605c2e463e9ac6a03249225a2;p=platform%2Fupstream%2Fllvm.git [LLD] [COFF] Try to report source locations for duplicate symbols This fixes the second part of PR42407. For files with dwarf debug info, it manually loads and iterates .debug_info to find the declared location of variables, to allow reporting them. (This matches the corresponding code in the ELF linker.) For functions, it uses the existing getFileLineDwarf which uses LLVMSymbolizer for translating addresses to file lines. In object files with codeview debug info, only the source location of duplicate functions is printed. (And even there, only for the first input file. The getFileLineCodeView function requires the object file to be fully loaded and initialized to properly resolve source locations, but duplicate symbols are reported at a stage when the second object file isn't fully loaded yet.) Differential Revision: https://reviews.llvm.org/D68975 llvm-svn: 375218 --- diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index d1ef201..8770a87 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -382,7 +382,8 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) { StringRef name; coffObj->getSymbolName(sym, name); if (sc) - return symtab->addRegular(this, name, sym.getGeneric(), sc); + return symtab->addRegular(this, name, sym.getGeneric(), sc, + sym.getValue()); // For MinGW symbols named .weak.* that point to a discarded section, // don't create an Undefined symbol. If nothing ever refers to the symbol, // everything should be fine. If something actually refers to the symbol @@ -536,7 +537,7 @@ void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection, // if the two comdat sections have e.g. different alignment. // Match that. if (leaderChunk->getContents() != newChunk.getContents()) - symtab->reportDuplicate(leader, this); + symtab->reportDuplicate(leader, this, &newChunk, sym.getValue()); break; } @@ -788,6 +789,89 @@ void ObjFile::initializeDependencies() { debugTypesObj = makeTpiSource(this); } +// Used only for DWARF debug info, which is not common (except in MinGW +// environments). This returns an optional pair of file name and line +// number for where the variable was defined. +Optional> +ObjFile::getVariableLocation(StringRef var) { + if (!dwarf) { + dwarf = DWARFContext::create(*getCOFFObj()); + if (!dwarf) + return None; + initializeDwarf(); + } + if (config->machine == I386) + var.consume_front("_"); + auto it = variableLoc.find(var); + if (it == variableLoc.end()) + return None; + + // Take file name string from line table. + std::string fileName; + if (!it->second.lt->getFileNameByIndex( + it->second.file, {}, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName)) + return None; + + return std::make_pair(saver.save(fileName), it->second.line); +} + +// Used only for DWARF debug info, which is not common (except in MinGW +// environments). This initializes the dwarf, lineTables and variableLoc +// members. +void ObjFile::initializeDwarf() { + for (std::unique_ptr &cu : dwarf->compile_units()) { + auto report = [](Error err) { + handleAllErrors(std::move(err), + [](ErrorInfoBase &info) { warn(info.message()); }); + }; + Expected expectedLT = + dwarf->getLineTableForUnit(cu.get(), report); + const DWARFDebugLine::LineTable *lt = nullptr; + if (expectedLT) + lt = *expectedLT; + else + report(expectedLT.takeError()); + if (!lt) + continue; + lineTables.push_back(lt); + + // Loop over variable records and insert them to variableLoc. + for (const auto &entry : cu->dies()) { + DWARFDie die(cu.get(), &entry); + // Skip all tags that are not variables. + if (die.getTag() != dwarf::DW_TAG_variable) + continue; + + // Skip if a local variable because we don't need them for generating + // error messages. In general, only non-local symbols can fail to be + // linked. + if (!dwarf::toUnsigned(die.find(dwarf::DW_AT_external), 0)) + continue; + + // Get the source filename index for the variable. + unsigned file = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_file), 0); + if (!lt->hasFileAtIndex(file)) + continue; + + // Get the line number on which the variable is declared. + unsigned line = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_line), 0); + + // Here we want to take the variable name to add it into variableLoc. + // Variable can have regular and linkage name associated. At first, we try + // to get linkage name as it can be different, for example when we have + // two variables in different namespaces of the same object. Use common + // name otherwise, but handle the case when it also absent in case if the + // input object file lacks some debug info. + StringRef name = + dwarf::toString(die.find(dwarf::DW_AT_linkage_name), + dwarf::toString(die.find(dwarf::DW_AT_name), "")); + if (!name.empty()) + variableLoc.insert({name, {lt, file, line}}); + } + } +} + StringRef ltrim1(StringRef s, const char *chars) { if (!s.empty() && strchr(chars, s[0])) return s.substr(1); diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h index 108a4ca..d3f4cd7 100644 --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -16,6 +16,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" @@ -202,6 +203,9 @@ public: // The .debug$T stream if there's one. llvm::Optional debugTypes; + llvm::Optional> + getVariableLocation(StringRef var); + private: const coff_section* getSection(uint32_t i); const coff_section *getSection(COFFSymbolRef sym) { @@ -212,6 +216,7 @@ private: void initializeSymbols(); void initializeFlags(); void initializeDependencies(); + void initializeDwarf(); SectionChunk * readSection(uint32_t sectionNumber, @@ -285,6 +290,15 @@ private: // index. Nonexistent indices (which are occupied by auxiliary // symbols in the real symbol table) are filled with null pointers. std::vector symbols; + + std::unique_ptr dwarf; + std::vector lineTables; + struct VarLoc { + const llvm::DWARFDebugLine::LineTable *lt; + unsigned file; + unsigned line; + }; + llvm::DenseMap variableLoc; }; // This type represents import library members that contain DLL names diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 2d971a0..183761f 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -520,15 +520,69 @@ void SymbolTable::addLazyObject(LazyObjFile *f, StringRef n) { f->fetch(); } -void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) { - std::string msg = "duplicate symbol: " + toString(*existing) + " in " + - toString(existing->getFile()) + " and in " + - toString(newFile); +static std::string getSourceLocationBitcode(BitcodeFile *file) { + std::string res("\n>>> defined at "); + StringRef source = file->obj->getSourceFileName(); + if (!source.empty()) + res += source.str() + "\n>>> "; + res += toString(file); + return res; +} + +static std::string getSourceLocationObj(ObjFile *file, SectionChunk *sc, + uint32_t offset, StringRef name) { + Optional> fileLine; + if (sc) + fileLine = getFileLine(sc, offset); + if (!fileLine) + fileLine = file->getVariableLocation(name); + + std::string res; + llvm::raw_string_ostream os(res); + os << "\n>>> defined at "; + if (fileLine) + os << fileLine->first << ":" << fileLine->second << "\n>>> "; + os << toString(file); + return os.str(); +} + +static std::string getSourceLocation(InputFile *file, SectionChunk *sc, + uint32_t offset, StringRef name) { + if (auto *o = dyn_cast(file)) + return getSourceLocationObj(o, sc, offset, name); + if (auto *b = dyn_cast(file)) + return getSourceLocationBitcode(b); + return "\n>>> defined at " + toString(file); +} + +// Construct and print an error message in the form of: +// +// lld-link: error: duplicate symbol: foo +// >>> defined at bar.c:30 +// >>> bar.o +// >>> defined at baz.c:563 +// >>> baz.o +void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile, + SectionChunk *newSc, + uint32_t newSectionOffset) { + std::string msg; + llvm::raw_string_ostream os(msg); + os << "duplicate symbol: " << toString(*existing); + + DefinedRegular *d = cast(existing); + if (d && isa(d->getFile())) { + os << getSourceLocation(d->getFile(), d->getChunk(), d->getValue(), + existing->getName()); + } else { + os << getSourceLocation(existing->getFile(), nullptr, 0, ""); + } + os << getSourceLocation(newFile, newSc, newSectionOffset, + existing->getName()); if (config->forceMultiple) - warn(msg); + warn(os.str()); else - error(msg); + error(os.str()); } Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) { @@ -568,8 +622,8 @@ Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) { } Symbol *SymbolTable::addRegular(InputFile *f, StringRef n, - const coff_symbol_generic *sym, - SectionChunk *c) { + const coff_symbol_generic *sym, SectionChunk *c, + uint32_t sectionOffset) { Symbol *s; bool wasInserted; std::tie(s, wasInserted) = insert(n, f); @@ -577,7 +631,7 @@ Symbol *SymbolTable::addRegular(InputFile *f, StringRef n, replaceSymbol(s, f, n, /*IsCOMDAT*/ false, /*IsExternal*/ true, sym, c); else - reportDuplicate(s, f); + reportDuplicate(s, f, c, sectionOffset); return s; } diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h index 4ae818e..cd8a53d 100644 --- a/lld/COFF/SymbolTable.h +++ b/lld/COFF/SymbolTable.h @@ -91,7 +91,7 @@ public: Symbol *addAbsolute(StringRef n, COFFSymbolRef s); Symbol *addRegular(InputFile *f, StringRef n, const llvm::object::coff_symbol_generic *s = nullptr, - SectionChunk *c = nullptr); + SectionChunk *c = nullptr, uint32_t sectionOffset = 0); std::pair addComdat(InputFile *f, StringRef n, const llvm::object::coff_symbol_generic *s = nullptr); @@ -103,7 +103,9 @@ public: uint16_t machine); void addLibcall(StringRef name); - void reportDuplicate(Symbol *existing, InputFile *newFile); + void reportDuplicate(Symbol *existing, InputFile *newFile, + SectionChunk *newSc = nullptr, + uint32_t newSectionOffset = 0); // A list of chunks which to be added to .rdata. std::vector localImportChunks; diff --git a/lld/test/COFF/conflict-mangled.test b/lld/test/COFF/conflict-mangled.test index eaaede5..381c035 100644 --- a/lld/test/COFF/conflict-mangled.test +++ b/lld/test/COFF/conflict-mangled.test @@ -5,9 +5,13 @@ # RUN: not lld-link /out:%t.exe /demangle %t1.obj %t2.obj 2>&1 | FileCheck %s # RUN: not lld-link /out:%t.exe /demangle:no %t1.obj %t2.obj 2>&1 | FileCheck --check-prefix=NODEMANGLE %s -# NODEMANGLE: duplicate symbol: ?mangled@@YAHXZ in {{.+}}1.obj and in {{.+}}2.obj +# NODEMANGLE: duplicate symbol: ?mangled@@YAHXZ +# NODEMANGLE: defined at {{.+}}1.obj +# NODEMANGLE: defined at {{.+}}2.obj -# CHECK: duplicate symbol: int __cdecl mangled(void) in {{.+}}1.obj and in {{.+}}2.obj +# CHECK: duplicate symbol: int __cdecl mangled(void) +# CHECK: defined at {{.+}}1.obj +# CHECK: defined at {{.+}}2.obj --- !COFF header: diff --git a/lld/test/COFF/conflict.test b/lld/test/COFF/conflict.test index ae8e6c8..b468956 100644 --- a/lld/test/COFF/conflict.test +++ b/lld/test/COFF/conflict.test @@ -1,15 +1,21 @@ # REQUIRES: x86 # RUN: yaml2obj < %s > %t1.obj # RUN: yaml2obj < %s > %t2.obj -# RUN: not lld-link /out:%t.exe %t1.obj %t2.obj >& %t.log -# RUN: FileCheck %s < %t.log +# RUN: not lld-link /out:%t.exe %t1.obj %t2.obj 2>&1 | FileCheck --check-prefix=OBJ %s # RUN: llvm-as -o %t.lto1.obj %S/Inputs/conflict.ll # RUN: llvm-as -o %t.lto2.obj %S/Inputs/conflict.ll -# RUN: not lld-link /out:%t.exe %t.lto1.obj %t.lto2.obj >& %t.log -# RUN: FileCheck %s < %t.log +# RUN: not lld-link /out:%t.exe %t.lto1.obj %t.lto2.obj 2>&1 | FileCheck --check-prefix=BC %s -# CHECK: duplicate symbol: foo in {{.+}}1.obj and in {{.+}}2.obj +# OBJ: duplicate symbol: foo +# OBJ: defined at {{.+}}1.obj +# OBJ: defined at {{.+}}2.obj + +# BC: duplicate symbol: foo +# BC: defined at {{.+}}conflict.ll +# BC: {{.+}}1.obj +# BC: defined at {{.+}}conflict.ll +# BC: {{.+}}2.obj --- !COFF header: diff --git a/lld/test/COFF/duplicate-cv.s b/lld/test/COFF/duplicate-cv.s new file mode 100644 index 0000000..2075cc3 --- /dev/null +++ b/lld/test/COFF/duplicate-cv.s @@ -0,0 +1,30 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s +# RUN: cp %t.obj %t.dupl.obj +# RUN: not lld-link /out:%t.exe %t.obj %t.dupl.obj 2>&1 | FileCheck %s + +# CHECK: error: duplicate symbol: main +# CHECK-NEXT: >>> defined at file1.cpp:2 +# CHECK-NEXT: >>> {{.*}}.obj +# CHECK-NEXT: >>> defined at {{.*}}.obj + + .cv_file 1 "file1.cpp" "EDA15C78BB573E49E685D8549286F33C" 1 + .cv_file 2 "file2.cpp" "EDA15C78BB573E49E685D8549286F33D" 1 + + .section .text,"xr",one_only,main +.globl main +main: + .cv_func_id 0 + .cv_loc 0 1 1 0 is_stmt 0 + .cv_loc 0 1 2 0 + retq +.Lfunc_end0: + + .section .debug$S,"dr",associative,main + .long 4 + .cv_linetable 0, main, .Lfunc_end0 + + .section .debug$S,"dr" + .long 4 + .cv_filechecksums + .cv_stringtable diff --git a/lld/test/COFF/duplicate-dwarf.s b/lld/test/COFF/duplicate-dwarf.s new file mode 100644 index 0000000..b81c13c --- /dev/null +++ b/lld/test/COFF/duplicate-dwarf.s @@ -0,0 +1,213 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple=i686-windows-gnu -filetype=obj -o %t.o %s +# RUN: cp %t.o %t.dupl.o +# RUN: not lld-link -lldmingw -out:%t.exe %t.o %t.dupl.o -entry:_Z4funcv 2>&1 | FileCheck %s + +# CHECK: error: duplicate symbol: func() +# CHECK-NEXT: >>> defined at /path/to/src{{[/\\]}}dupl.cpp:6 +# CHECK-NEXT: >>> {{.*}}.o +# CHECK-NEXT: >>> defined at /path/to/src{{[/\\]}}dupl.cpp:6 +# CHECK-NEXT: >>> {{.*}}.o +# CHECK-EMPTY: +# CHECK-NEXT: error: duplicate symbol: _var +# CHECK-NEXT: >>> defined at /path/to/src{{[/\\]}}dupl.cpp:1 +# CHECK-NEXT: >>> {{.*}}.o +# CHECK-NEXT: >>> defined at /path/to/src{{[/\\]}}dupl.cpp:1 +# CHECK-NEXT: >>> {{.*}}.o +# CHECK-EMPTY: +# CHECK-NEXT: error: duplicate symbol: A::namespaceVar +# CHECK-NEXT: >>> defined at /path/to/src{{[/\\]}}dupl.cpp:3 +# CHECK-NEXT: >>> {{.*}}.o +# CHECK-NEXT: >>> defined at /path/to/src{{[/\\]}}dupl.cpp:3 +# CHECK-NEXT: >>> {{.*}}.o + + .text + .file "dupl.cpp" + .file 1 "/path/to/src" "dupl.cpp" + .def __Z4funcv; + .globl __Z4funcv # -- Begin function _Z4funcv +__Z4funcv: # @_Z4funcv +Lfunc_begin0: + .loc 1 5 0 # dupl.cpp:5:0 +# %bb.0: # %entry + .loc 1 6 1 prologue_end # dupl.cpp:6:1 + retl +Lfunc_end0: + # -- End function + .bss + .globl _var # @var +_var: + .long 0 # 0x0 + + .globl __ZN1A12namespaceVarE # @_ZN1A12namespaceVarE +__ZN1A12namespaceVarE: + .long 0 # 0x0 + + .section .debug_str,"dr" +Linfo_string: +Linfo_string0: + .asciz "var" +Linfo_string1: + .asciz "int" +Linfo_string2: + .asciz "A" +Linfo_string3: + .asciz "namespaceVar" +Linfo_string4: + .asciz "_ZN1A12namespaceVarE" +Linfo_string5: + .asciz "_Z4funcv" +Linfo_string6: + .asciz "func" + .section .debug_abbrev,"dr" +Lsection_abbrev: + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 57 # DW_TAG_namespace + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 14 # DW_FORM_strp + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"dr" +Lsection_info: +Lcu_begin0: + .long Ldebug_info_end0-Ldebug_info_start0 # Length of Unit +Ldebug_info_start0: + .short 4 # DWARF version number + .secrel32 Lsection_abbrev # Offset Into Abbrev. Section + .byte 4 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x64 DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 0 # DW_AT_name + .secrel32 Lline_table_start0 # DW_AT_stmt_list + .long Lfunc_begin0 # DW_AT_low_pc + .long Lfunc_end0-Lfunc_begin0 # DW_AT_high_pc + .byte 2 # Abbrev [2] 0x26:0x11 DW_TAG_variable + .secrel32 Linfo_string0 # DW_AT_name + .secrel32 Linfo_type_int # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .byte 5 # DW_AT_location + .byte 3 + .long _var +Linfo_type_int: + .byte 3 # Abbrev [3] 0x37:0x7 DW_TAG_base_type + .secrel32 Linfo_string1 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 4 # Abbrev [4] 0x3e:0x1b DW_TAG_namespace + .secrel32 Linfo_string2 # DW_AT_name + .byte 5 # Abbrev [5] 0x43:0x15 DW_TAG_variable + .secrel32 Linfo_string3 # DW_AT_name + .secrel32 Linfo_type_int # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .byte 5 # DW_AT_location + .byte 3 + .long __ZN1A12namespaceVarE + .secrel32 Linfo_string4 # DW_AT_linkage_name + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0x59:0x15 DW_TAG_subprogram + .long Lfunc_begin0 # DW_AT_low_pc + .long Lfunc_end0-Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 84 + .secrel32 Linfo_string5 # DW_AT_linkage_name + .secrel32 Linfo_string6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 5 # DW_AT_decl_line + # DW_AT_external + .byte 0 # End Of Children Mark +Ldebug_info_end0: + + .section .debug_line,"dr" +Lline_table_start0: diff --git a/lld/test/COFF/duplicate.test b/lld/test/COFF/duplicate.test index 0c0f351..76c88b0 100644 --- a/lld/test/COFF/duplicate.test +++ b/lld/test/COFF/duplicate.test @@ -4,10 +4,14 @@ RUN: llc -mtriple x86_64-windows-msvc -filetype obj -o beta.obj %S/Inputs/beta.l RUN: lld-link /out:alpha.dll /dll alpha.obj /implib:alpha.lib RUN: not lld-link /out:beta.dll /dll alpha.obj beta.obj alpha.lib 2>&1 | FileCheck %s -check-prefix CHECK-ALPHA -CHECK-ALPHA: error: duplicate symbol: f in {{.*}}alpha.obj and in alpha.dll +CHECK-ALPHA: error: duplicate symbol: f +CHECK-ALPHA: defined at {{.*}}alpha.obj +CHECK-APLHA: defined at alpha.dll RUN: llc -mtriple x86_64-windows-msvc -filetype obj -o gamma.obj %S/Inputs/gamma.ll RUN: not lld-link /out:gamma.exe /subsystem:console /entry:mainCRTStartup gamma.obj alpha.lib 2>&1 | FileCheck %s -check-prefix CHECK-GAMMA -CHECK-GAMMA: error: duplicate symbol: __declspec(dllimport) f in {{.*}}gamma.obj and in alpha.dll +CHECK-GAMMA: error: duplicate symbol: __declspec(dllimport) f +CHECK-GAMMA: defined at {{.*}}gamma.obj +CHECK-GAMMA: defined at alpha.dll