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,138 @@ +# 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 + .file "undef.cpp" + .file 1 "/path/to/src" "undef.cpp" + .globl entry # -- Begin function entry +entry: # @entry +.Lfunc_begin0: + .loc 1 14 0 # undef.cpp:14:0 + subq $40, %rsp +.Ltmp0: + leaq 32(%rsp), %rcx +.Ltmp1: + .loc 1 16 4 prologue_end # undef.cpp:16:4 + callq _ZN1A5afuncEv + .loc 1 17 2 # undef.cpp:17:2 + callq _Z3barv + .loc 1 18 1 # undef.cpp:18:1 + addq $40, %rsp + retq +.Ltmp2: +.Lfunc_end0: + + .def _ZN1A5afuncEv; + .scl 2; + .type 32; + .endef + .section .text$_ZN1A5afuncEv,"xr",discard,_ZN1A5afuncEv + .globl _ZN1A5afuncEv # -- Begin function _ZN1A5afuncEv + .p2align 1, 0x90 +_ZN1A5afuncEv: # @_ZN1A5afuncEv +.Lfunc_begin1: + .loc 1 6 0 # undef.cpp:6:0 + .loc 1 7 3 prologue_end # undef.cpp:7:3 + jmp _Z3foov # TAILCALL +.Ltmp3: +.Lfunc_end1: + + .data + .globl myptr # @myptr + .p2align 3 +myptr: + .quad baz + + .section .debug_str,"dr" +.Linfo_string0: + .asciz "myptr" # string offset=0 + .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 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .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 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:0xb0 DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 4 # DW_AT_language + .byte 0 # DW_AT_name + .secrel32 .Lline_table_start0 # DW_AT_stmt_list + .byte 0 # 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_string0 # 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 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_line,"dr" +.Lline_table_start0: