Index: Common/ErrorHandler.cpp =================================================================== --- Common/ErrorHandler.cpp +++ Common/ErrorHandler.cpp @@ -83,6 +83,13 @@ outs().flush(); } +void ErrorHandler::remark(const Twine &Msg) { + std::lock_guard Lock(Mu); + newline(ErrorOS, Msg); + print("remark: ", raw_ostream::BLUE); + *ErrorOS << Msg << "\n"; +} + void ErrorHandler::warn(const Twine &Msg) { if (FatalWarnings) { error(Msg); Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -121,11 +121,21 @@ DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE, Config->Wordsize); - // The second parameter is offset in .debug_line section - // for compilation unit (CU) of interest. We have only one - // CU (object file), so offset is always 0. - const DWARFDebugLine::LineTable *LT = - DwarfLine->getOrParseLineTable(LineData, 0, Dwarf, nullptr); + const DWARFDebugLine::LineTable *LT = nullptr; + // The second parameter in getOrParseLineTable is the offset in the + // .debug_line section for the compilation unit (CU) of interest. We assume we + // have only one CU (object file), so the offset is always 0. + // FIXME: Under some circustances, we can have more than one CU, e.g. objects + // built via -r links or LTO. See PR36793. + if (LineData.isValidOffset(0)) { + Expected ErrOrLineTable = + DwarfLine->getOrParseLineTable(LineData, 0, Dwarf, nullptr, remark); + if (ErrOrLineTable) + LT = *ErrOrLineTable; + else + handleAllErrors(ErrOrLineTable.takeError(), + [](ErrorInfoBase &Err) { remark(Err.message()); }); + } if (!LT) return; Index: include/lld/Common/ErrorHandler.h =================================================================== --- include/lld/Common/ErrorHandler.h +++ include/lld/Common/ErrorHandler.h @@ -52,6 +52,7 @@ LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); void log(const Twine &Msg); void message(const Twine &Msg); + void remark(const Twine &Msg); void warn(const Twine &Msg); std::unique_ptr OutputBuffer; @@ -69,6 +70,7 @@ } inline void log(const Twine &Msg) { errorHandler().log(Msg); } inline void message(const Twine &Msg) { errorHandler().message(Msg); } +inline void remark(const Twine &Msg) { errorHandler().remark(Msg); } inline void warn(const Twine &Msg) { errorHandler().warn(Msg); } inline uint64_t errorCount() { return errorHandler().ErrorCount; } Index: test/ELF/Inputs/undef-bad-debug.s =================================================================== --- test/ELF/Inputs/undef-bad-debug.s +++ test/ELF/Inputs/undef-bad-debug.s @@ -1,7 +1,37 @@ .section .text,"ax" sym: .quad zed6 - + +.section .debug_line,"",@progbits + .long .Lunit_end - .Lunit_start # unit length +.Lunit_start: + .short 4 # version + .long .Lprologue_end - .Lprologue_start # prologue length +.Lprologue_start: + .byte 1 # minimum instruction length + .byte 1 # maximum operatiosn per instruction + .byte 1 # default is_stmt + .byte -5 # line base + .byte 14 # line range + .byte 13 # opcode base + .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # standard opcode lengths + .asciz "dir" # include directories + .byte 0 + .asciz "undef-bad-debug.s" # file names + .byte 1, 0, 0 + .byte 0 + .byte 0 # extraneous byte +.Lprologue_end: + .byte 0, 9, 2 # DW_LNE_set_address + .quad sym + .byte 3 # DW_LNS_advance_line + .byte 10 + .byte 1 # DW_LNS_copy + .byte 2 # DW_LNS_advance_pc + .byte 8 + .byte 0, 1, 1 # DW_LNE_end_sequence +.Lunit_end: + .section .debug_info,"",@progbits .long .Lcu_end - .Lcu_start # Length of Unit .Lcu_start: Index: test/ELF/Inputs/undef-bad-debug2.s =================================================================== --- test/ELF/Inputs/undef-bad-debug2.s +++ test/ELF/Inputs/undef-bad-debug2.s @@ -0,0 +1,81 @@ +.section .text,"ax" +sym: + .quad zed7 + +.section .debug_line,"",@progbits + .long .Lunit_end - .Lunit_start # unit length +.Lunit_start: + .short 4 # version + .long .Lprologue_end - .Lprologue_start # prologue length +.Lprologue_start: + .byte 1 # minimum instruction length + .byte 1 # maximum operatiosn per instruction + .byte 1 # default is_stmt + .byte -5 # line base + .byte 14 # line range + .byte 13 # opcode base + .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # standard opcode lengths + .asciz "dir" # include directories + .byte 0 + .asciz "undef-bad-debug2.s" # file names + .byte 1, 0, 0 + .byte 0 +.Lprologue_end: + .byte 0, 9, 2 # DW_LNE_set_address + .quad sym + .byte 3 # DW_LNS_advance_line + .byte 10 + .byte 1 # DW_LNS_copy + .byte 2 # DW_LNS_advance_pc + .byte 8 + .byte 0, 1, 1 # DW_LNE_end_sequence + .byte 0, 9, 2 # DW_LNE_set_address + .quad 0x0badbeef + .byte 3 # DW_LNS_advance_line + .byte 99 + .byte 1 # DW_LNS_copy + .byte 99 # DW_LNS_advance_pc + .byte 119 + # Missing end of sequence. +.Lunit_end: + +.section .debug_info,"",@progbits + .long .Lcu_end - .Lcu_start # Length of Unit +.Lcu_start: + .short 4 # DWARF version number + .long .Lsection_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x79 DW_TAG_compile_unit + .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_variable + .long .Linfo_string # DW_AT_name + # DW_AT_external + .byte 1 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .byte 0 # End Of Children Mark +.Lcu_end: + +.section .debug_abbrev,"",@progbits +.Lsection_abbrev: + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .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 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 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + +.section .debug_str,"MS",@progbits,1 +.Linfo_string: + .asciz "sym" Index: test/ELF/no-line-parser-errors-if-empty-section.s =================================================================== --- test/ELF/no-line-parser-errors-if-empty-section.s +++ test/ELF/no-line-parser-errors-if-empty-section.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 + +# LLD uses the debug data to get information for error messages, if possible. +# However, if the debug line section is empty, we should not attempt to parse +# it, as that would result in errors from the parser. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o %t.elf 2>&1 | FileCheck %s + +# CHECK-NOT: warning: +# CHECK-NOT: error: +# CHECK: error: undefined symbol: undefined +# CHECK-NEXT: {{.*}}.o:(.text+0x1) +# CHECK-NOT: warning: +# CHECK-NOT: error: + +.globl _start +_start: + callq undefined + +.section .debug_line,"",@progbits Index: test/ELF/no-line-parser-errors-if-no-section.s =================================================================== --- test/ELF/no-line-parser-errors-if-no-section.s +++ test/ELF/no-line-parser-errors-if-no-section.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 + +# LLD uses the debug data to get information for error messages, if possible. +# However, if there is no debug line section, we should not attempt to parse +# it, as that would result in errors from the parser. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o %t.elf 2>&1 | FileCheck %s + +# CHECK-NOT: warning: +# CHECK-NOT: error: +# CHECK: error: undefined symbol: undefined +# CHECK-NEXT: {{.*}}.o:(.text+0x1) +# CHECK-NOT: warning: +# CHECK-NOT: error: + +.globl _start +_start: + callq undefined Index: test/ELF/undef.s =================================================================== --- test/ELF/undef.s +++ test/ELF/undef.s @@ -3,9 +3,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef.s -o %t2.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-debug.s -o %t3.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-bad-debug.s -o %t4.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-bad-debug2.s -o %t5.o # RUN: llvm-ar rc %t2.a %t2.o -# RUN: not ld.lld %t.o %t2.a %t3.o %t4.o -o %t.exe 2>&1 | FileCheck %s -# RUN: not ld.lld -pie %t.o %t2.a %t3.o %t4.o -o %t.exe 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o %t2.a %t3.o %t4.o %t5.o -o %t.exe 2>&1 | FileCheck %s +# RUN: not ld.lld -pie %t.o %t2.a %t3.o %t4.o %t5.o -o %t.exe 2>&1 | FileCheck %s # CHECK: error: undefined symbol: foo # CHECK: >>> referenced by undef.s @@ -34,9 +35,15 @@ # CHECK: >>> referenced by undef-debug.s:11 (dir{{/|\\}}undef-debug.s:11) # CHECK: >>> {{.*}}.o:(.text.2+0x0) +# CHECK: remark: parsing line table prologue at 0x00000000 should have ended at 0x00000038 but it ended at 0x00000037 # CHECK: error: undefined symbol: zed6 # CHECK: >>> referenced by {{.*}}tmp4.o:(.text+0x0) +# CHECK: remark: last sequence in debug line table is not terminated! +# CHECK: error: undefined symbol: zed7 +# CHECK: >>> referenced by undef-bad-debug2.s:11 (dir{{/|\\}}undef-bad-debug2.s:11) +# CHECK: >>> {{.*}}tmp5.o:(.text+0x0) + # RUN: not ld.lld %t.o %t2.a -o %t.exe -no-demangle 2>&1 | \ # RUN: FileCheck -check-prefix=NO-DEMANGLE %s # NO-DEMANGLE: error: undefined symbol: _Z3fooi