Index: COFF/CMakeLists.txt =================================================================== --- COFF/CMakeLists.txt +++ COFF/CMakeLists.txt @@ -36,6 +36,7 @@ Object Option Support + Symbolize WindowsManifest LINK_LIBS Index: COFF/SymbolTable.cpp =================================================================== --- COFF/SymbolTable.cpp +++ COFF/SymbolTable.cpp @@ -15,6 +15,7 @@ #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "lld/Common/Timer.h" +#include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Object/WindowsMachineFlag.h" #include "llvm/Support/Debug.h" @@ -89,6 +90,19 @@ return {res}; } +static std::pair symbolizeFileLine(const SectionChunk *c, + uint32_t addr) { + symbolize::LLVMSymbolizer symbolizer; + Expected expectedLineInfo = symbolizer.symbolizeCode( + *c->file->getCOFFObj(), {addr, c->getSectionNumber() - 1}); + if (!expectedLineInfo) + return {"", 0}; + const DILineInfo &lineInfo = *expectedLineInfo; + if (lineInfo.FileName == DILineInfo::BadString) + return {"", 0}; + return {saver.save(lineInfo.FileName), lineInfo.Line}; +} + // Given a file and the index of a symbol in that file, returns a description // of all references to that symbol from that file. If no debug information is // available, returns just the name of the file, else one string per actual @@ -109,6 +123,8 @@ continue; std::pair fileLine = getFileLine(sc, r.VirtualAddress); + if (fileLine.first.empty() && config->mingw) + fileLine = symbolizeFileLine(sc, r.VirtualAddress); Symbol *sym = getSymbol(sc, r.VirtualAddress); if (!fileLine.first.empty() || sym) locations.push_back({sym, fileLine}); Index: test/COFF/undefined-symbol-dwarf.s =================================================================== --- /dev/null +++ test/COFF/undefined-symbol-dwarf.s @@ -0,0 +1,389 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple=x86_64-windows-gnu -filetype=obj -o %t.o %s +# RUN: not lld-link /lldmingw /out:%t.exe %t.o /entry:entry 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: bar() +# CHECK-NEXT: >>> referenced by /path/to/src/undef.cpp:17 +# CHECK-NEXT: >>> {{.*}}.o:(entry) +# CHECK-EMPTY: +# CHECK-NEXT: error: undefined symbol: foo() +# CHECK-NEXT: >>> referenced by /path/to/src/undef.cpp:7 +# CHECK-NEXT: >>> {{.*}}.o:(A::afunc()) +# CHECK-EMPTY: +# CHECK-NEXT: error: undefined symbol: baz +# CHECK-NEXT: >>> referenced by {{.*}}.o:(myptr) + + .text + .def @feat.00; + .scl 3; + .type 0; + .endef + .globl @feat.00 +.set @feat.00, 0 + .file "undef.cpp" + .file 1 "/path/to/src" "undef.cpp" + .def entry; + .scl 2; + .type 32; + .endef + .globl entry # -- Begin function entry + .p2align 4, 0x90 +entry: # @entry +.Lfunc_begin0: + .loc 1 14 0 # undef.cpp:14:0 +.seh_proc entry +# %bb.0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue +.Ltmp0: + .loc 1 16 4 prologue_end # undef.cpp:16:4 + leaq 32(%rsp), %rcx +.Ltmp1: + #DEBUG_VALUE: entry:a <- [$rcx+0] + callq _ZN1A5afuncEv +.Ltmp2: + .loc 1 17 2 # undef.cpp:17:2 + callq _Z3barv + .loc 1 18 1 # undef.cpp:18:1 + nop + addq $40, %rsp + retq +.Ltmp3: +.Lfunc_end0: + .seh_handlerdata + .text + .seh_endproc + # -- End function + .def _ZN1A5afuncEv; + .scl 2; + .type 32; + .endef + .section .text$_ZN1A5afuncEv,"xr",discard,_ZN1A5afuncEv + .globl _ZN1A5afuncEv # -- Begin function _ZN1A5afuncEv + .p2align 4, 0x90 +_ZN1A5afuncEv: # @_ZN1A5afuncEv +.Lfunc_begin1: + .loc 1 6 0 # undef.cpp:6:0 +.seh_proc _ZN1A5afuncEv +# %bb.0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + movq %rcx, 32(%rsp) +.Ltmp4: + .loc 1 7 3 prologue_end # undef.cpp:7:3 + callq _Z3foov + .loc 1 8 2 # undef.cpp:8:2 + nop + addq $40, %rsp + retq +.Ltmp5: +.Lfunc_end1: + .seh_handlerdata + .section .text$_ZN1A5afuncEv,"xr",discard,_ZN1A5afuncEv + .seh_endproc + # -- End function + .data + .globl myptr # @myptr + .p2align 3 +myptr: + .quad baz + + .section .debug_str,"dr" +.Linfo_string: +.Linfo_string0: + .asciz "clang version 10.0.0 (trunk 370609) (llvm/trunk 370615)" # string offset=0 +.Linfo_string1: + .asciz "undef.cpp" # string offset=56 +.Linfo_string2: + .asciz "/path/to/src" # string offset=66 +.Linfo_string3: + .asciz "myptr" # string offset=79 +.Linfo_string4: + .asciz "int" # string offset=85 +.Linfo_string5: + .asciz "_ZN1A5afuncEv" # string offset=89 +.Linfo_string6: + .asciz "afunc" # string offset=103 +.Linfo_string7: + .asciz "A" # string offset=109 +.Linfo_string8: + .asciz "entry" # string offset=111 +.Linfo_string9: + .asciz "a" # string offset=117 +.Linfo_string10: + .asciz "this" # string offset=119 + .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 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .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 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # 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 5 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .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 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 6 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .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 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 1 # DW_CHILDREN_yes + .byte 54 # DW_AT_calling_convention + .byte 11 # DW_FORM_data1 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .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 8 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .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 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 50 # DW_AT_accessibility + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 52 # DW_AT_artificial + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .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 100 # DW_AT_object_pointer + .byte 19 # DW_FORM_ref4 + .byte 71 # DW_AT_specification + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 52 # DW_AT_artificial + .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 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0xaf DW_TAG_compile_unit + .secrel32 .Linfo_string0 # DW_AT_producer + .short 4 # DW_AT_language + .secrel32 .Linfo_string1 # DW_AT_name + .secrel32 .Lline_table_start0 # DW_AT_stmt_list + .secrel32 .Linfo_string2 # DW_AT_comp_dir + .quad 0 # DW_AT_low_pc + .secrel32 .Ldebug_ranges0 # DW_AT_ranges + .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_variable + .secrel32 .Linfo_string3 # DW_AT_name + .long 63 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_decl_file + .byte 12 # DW_AT_decl_line + .byte 9 # DW_AT_location + .byte 3 + .quad myptr + .byte 3 # Abbrev [3] 0x3f:0x5 DW_TAG_pointer_type + .long 68 # DW_AT_type + .byte 4 # Abbrev [4] 0x44:0x7 DW_TAG_base_type + .secrel32 .Linfo_string4 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 5 # Abbrev [5] 0x4b:0x24 DW_TAG_subprogram + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 87 + .secrel32 .Linfo_string8 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + # DW_AT_external + .byte 6 # Abbrev [6] 0x60:0xe DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 32 + .secrel32 .Linfo_string9 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 15 # DW_AT_decl_line + .long 111 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 7 # Abbrev [7] 0x6f:0x1c DW_TAG_class_type + .byte 5 # DW_AT_calling_convention + .secrel32 .Linfo_string7 # DW_AT_name + .byte 1 # DW_AT_byte_size + .byte 1 # DW_AT_decl_file + .byte 4 # DW_AT_decl_line + .byte 8 # Abbrev [8] 0x78:0x12 DW_TAG_subprogram + .secrel32 .Linfo_string5 # DW_AT_linkage_name + .secrel32 .Linfo_string6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 6 # DW_AT_decl_line + # DW_AT_declaration + # DW_AT_external + .byte 1 # DW_AT_accessibility + # DW_ACCESS_public + .byte 9 # Abbrev [9] 0x84:0x5 DW_TAG_formal_parameter + .long 139 # DW_AT_type + # DW_AT_artificial + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 3 # Abbrev [3] 0x8b:0x5 DW_TAG_pointer_type + .long 111 # DW_AT_type + .byte 10 # Abbrev [10] 0x90:0x24 DW_TAG_subprogram + .quad .Lfunc_begin1 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 87 + .long 167 # DW_AT_object_pointer + .long 120 # DW_AT_specification + .byte 11 # Abbrev [11] 0xa7:0xc DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 32 + .secrel32 .Linfo_string10 # DW_AT_name + .long 180 # DW_AT_type + # DW_AT_artificial + .byte 0 # End Of Children Mark + .byte 3 # Abbrev [3] 0xb4:0x5 DW_TAG_pointer_type + .long 111 # DW_AT_type + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_ranges,"dr" +.Ldebug_range: +.Ldebug_ranges0: + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad .Lfunc_begin1 + .quad .Lfunc_end1 + .quad 0 + .quad 0 + .section .debug_macinfo,"dr" +.Ldebug_macinfo: + .byte 0 # End Of Macro List Mark + + .addrsig + .addrsig_sym _ZN1A5afuncEv + .addrsig_sym _Z3barv + .addrsig_sym _Z3foov + .addrsig_sym baz + .section .debug_line,"dr" +.Lsection_line: +.Lline_table_start0: