Index: lldb/include/lldb/Symbol/LineTable.h =================================================================== --- lldb/include/lldb/Symbol/LineTable.h +++ lldb/include/lldb/Symbol/LineTable.h @@ -329,6 +329,8 @@ private: DISALLOW_COPY_AND_ASSIGN(LineTable); + + bool m_clear_address_zeroth_bit = false; }; } // namespace lldb_private Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h @@ -22,7 +22,7 @@ typedef RangeToDIE::Entry Range; typedef std::vector RangeColl; - DWARFDebugAranges(); + DWARFDebugAranges(dw_addr_t addr_mask); void Clear() { m_aranges.Clear(); } @@ -50,6 +50,7 @@ protected: RangeToDIE m_aranges; + dw_addr_t m_addr_mask; }; #endif // SymbolFileDWARF_DWARFDebugAranges_h_ Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -16,7 +16,8 @@ using namespace lldb_private; // Constructor -DWARFDebugAranges::DWARFDebugAranges() : m_aranges() {} +DWARFDebugAranges::DWARFDebugAranges(dw_addr_t addr_mask) + : m_aranges(), m_addr_mask(addr_mask) {} // CountArangeDescriptors class CountArangeDescriptors { @@ -74,7 +75,8 @@ void DWARFDebugAranges::AppendRange(dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc) { if (high_pc > low_pc) - m_aranges.Append(RangeToDIE::Entry(low_pc, high_pc - low_pc, offset)); + m_aranges.Append( + RangeToDIE::Entry(low_pc & m_addr_mask, high_pc - low_pc, offset)); } void DWARFDebugAranges::Sort(bool minimize) { Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -38,7 +38,8 @@ if (m_cu_aranges_up) return *m_cu_aranges_up; - m_cu_aranges_up = std::make_unique(); + m_cu_aranges_up = + std::make_unique(m_dwarf.GetAddressMask()); const DWARFDataExtractor &debug_aranges_data = m_context.getOrLoadArangesData(); if (llvm::Error error = m_cu_aranges_up->extract(debug_aranges_data)) Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -41,6 +41,8 @@ bool operator==(const DWARFDebugInfoEntry &rhs) const; bool operator!=(const DWARFDebugInfoEntry &rhs) const; + void SetAddrMask(dw_addr_t addr_mask) { m_addr_mask = addr_mask; } + void BuildAddressRangeTable(const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; @@ -185,6 +187,7 @@ /// A copy of the DW_TAG value so we don't have to go through the compile /// unit abbrev table dw_tag_t m_tag = llvm::dwarf::DW_TAG_null; + dw_addr_t m_addr_mask = ~0ull; }; #endif // SymbolFileDWARF_DWARFDebugInfoEntry_h_ Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -255,7 +255,7 @@ if (form_value.ExtractValue(data, &offset)) { switch (attr) { case DW_AT_low_pc: - lo_pc = form_value.Address(); + lo_pc = form_value.Address() & m_addr_mask; if (do_offset) hi_pc += lo_pc; @@ -270,7 +270,7 @@ if (form_value.Form() == DW_FORM_addr || form_value.Form() == DW_FORM_addrx || form_value.Form() == DW_FORM_GNU_addr_index) { - hi_pc = form_value.Address(); + hi_pc = form_value.Address() & m_addr_mask; } else { hi_pc = form_value.Unsigned(); if (lo_pc == LLDB_INVALID_ADDRESS) @@ -735,7 +735,7 @@ dw_form_t form = form_value.Form(); if (form == DW_FORM_addr || form == DW_FORM_addrx || form == DW_FORM_GNU_addr_index) - return form_value.Address(); + return form_value.Address() & m_addr_mask; // DWARF4 can specify the hi_pc as an return lo_pc + form_value.Unsigned(); @@ -755,6 +755,7 @@ lo_pc = GetAttributeValueAsAddress(cu, DW_AT_low_pc, fail_value, check_specification_or_abstract_origin); if (lo_pc != fail_value) { + lo_pc &= m_addr_mask; hi_pc = GetAttributeHighPC(cu, lo_pc, fail_value, check_specification_or_abstract_origin); if (hi_pc != fail_value) @@ -1125,8 +1126,10 @@ dw_addr_t lo_pc = GetAttributeValueAsAddress(cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS); if (lo_pc != LLDB_INVALID_ADDRESS) { + lo_pc &= m_addr_mask; dw_addr_t hi_pc = GetAttributeHighPC(cu, lo_pc, LLDB_INVALID_ADDRESS); if (hi_pc != LLDB_INVALID_ADDRESS) { + hi_pc &= m_addr_mask; // printf("\n0x%8.8x: %30s: address = 0x%8.8x [0x%8.8x - 0x%8.8x) ", // m_offset, DW_TAG_value_to_name(tag), address, lo_pc, hi_pc); if ((lo_pc <= address) && (address < hi_pc)) { Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -59,6 +59,7 @@ // We are in our compile unit, parse starting at the offset we were told to // parse + m_first_die.SetAddrMask(m_dwarf.GetAddressMask()); const DWARFDataExtractor &data = GetData(); if (offset < GetNextUnitOffset() && m_first_die.Extract(data, this, &offset)) { @@ -155,6 +156,7 @@ lldb::offset_t next_cu_offset = GetNextUnitOffset(); DWARFDebugInfoEntry die; + die.SetAddrMask(m_dwarf.GetAddressMask()); uint32_t depth = 0; // We are in our compile unit, parse starting at the offset we were told to @@ -721,7 +723,7 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { if (m_func_aranges_up == nullptr) { - m_func_aranges_up.reset(new DWARFDebugAranges()); + m_func_aranges_up.reset(new DWARFDebugAranges(m_dwarf.GetAddressMask())); const DWARFDebugInfoEntry *die = DIEPtr(); if (die) die->BuildFunctionAddressRangeTable(this, m_func_aranges_up.get()); Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -318,6 +318,8 @@ lldb_private::FileSpec GetFile(DWARFUnit &unit, size_t file_idx); + dw_addr_t GetAddressMask() const; + protected: typedef llvm::DenseMap DIEToTypePtr; Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -4003,3 +4003,12 @@ }); return m_dwp_symfile.get(); } + +dw_addr_t SymbolFileDWARF::GetAddressMask() const { + if (ArchSpec arch = m_objfile_sp->GetArchitecture()) { + if (arch.GetTriple().getArch() == llvm::Triple::arm || + arch.GetTriple().getArch() == llvm::Triple::thumb) + return ~1ull; + } + return ~0ull; +} Index: lldb/source/Symbol/LineTable.cpp =================================================================== --- lldb/source/Symbol/LineTable.cpp +++ lldb/source/Symbol/LineTable.cpp @@ -19,7 +19,13 @@ // LineTable constructor LineTable::LineTable(CompileUnit *comp_unit) - : m_comp_unit(comp_unit), m_entries() {} + : m_comp_unit(comp_unit), m_entries() { + if (ArchSpec arch = m_comp_unit->GetModule()->GetArchitecture()) { + if (arch.GetTriple().getArch() == llvm::Triple::arm || + arch.GetTriple().getArch() == llvm::Triple::thumb) + m_clear_address_zeroth_bit = true; + } +} // Destructor LineTable::~LineTable() {} @@ -30,6 +36,8 @@ bool is_start_of_basic_block, bool is_prologue_end, bool is_epilogue_begin, bool is_terminal_entry) { + if (m_clear_address_zeroth_bit) + file_addr &= ~1ull; Entry entry(file_addr, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry); @@ -63,6 +71,8 @@ bool is_terminal_entry) { assert(sequence != nullptr); LineSequenceImpl *seq = reinterpret_cast(sequence); + if (m_clear_address_zeroth_bit) + file_addr &= ~1ull; Entry entry(file_addr, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry); Index: lldb/test/Shell/SymbolFile/DWARF/thumb-windows.s =================================================================== --- /dev/null +++ lldb/test/Shell/SymbolFile/DWARF/thumb-windows.s @@ -0,0 +1,183 @@ +# Test that a linked windows executable, with a thumb bit in many address +# fields, gets the thumb bit stripped out from addresses. + +# If the thumb bit isn't stripped out from subprogram ranges, 0x401006 is +# associated with the function "entry", while it actually is the start of +# the function "other". +# If the thumb bit isn't stripped out from line tables, the LineEntry +# points to the wrong line. + +# REQUIRES: lld, arm + +# RUN: llvm-mc -triple armv7-windows-gnu %s -filetype=obj > %t.o +# RUN: lld-link %t.o -out:%t.exe -debug:dwarf -entry:entry -subsystem:console -lldmingw +# RUN: %lldb %t.exe -o "image lookup -v -a 0x401006" -b | FileCheck %s + +# CHECK-LABEL: image lookup -v -a 0x401006 +# CHECK: Function: {{.*}}, name = "other", range = [0x00401006-0x0040100c) +# CHECK: LineEntry: [0x00401006-0x0040100a): /path/to/src/dwarf-thumb.c:7:12 + + .text + .syntax unified + .file "dwarf-thumb.c" + .file 1 "" "dwarf-thumb.c" + .def entry; + .scl 2; + .type 32; + .endef + .globl entry @ -- Begin function entry + .p2align 1 + .code 16 @ @entry + .thumb_func +entry: +.Lfunc_begin0: + .loc 1 2 0 @ dwarf-thumb.c:2:0 + .cfi_sections .debug_frame + .cfi_startproc + .loc 1 4 9 prologue_end @ dwarf-thumb.c:4:9 + mov r1, r0 +.Ltmp0: + b other +.Ltmp1: +.Lfunc_end0: + .cfi_endproc + @ -- End function + .def other; + .scl 2; + .type 32; + .endef + .globl other @ -- Begin function other + .p2align 1 + .code 16 @ @other + .thumb_func +other: +.Lfunc_begin1: + .loc 1 6 0 @ dwarf-thumb.c:6:0 + .cfi_startproc + .loc 1 7 12 prologue_end @ dwarf-thumb.c:7:12 + add.w r0, r1, r1, lsl #1 + .loc 1 7 2 is_stmt 0 @ dwarf-thumb.c:7:2 + bx lr +.Ltmp2: +.Lfunc_end1: + .cfi_endproc + @ -- End function + .section .debug_str,"dr" +.Linfo_string: +.Linfo_string1: + .asciz "dwarf-thumb.c" +.Linfo_string2: + .asciz "/path/to/src" +.Linfo_string3: + .asciz "other" +.Linfo_string6: + .asciz "entry" + .section .debug_loc,"dr" +.Lsection_debug_loc: +.Ldebug_loc0: + .long .Lfunc_begin0-.Lfunc_begin0 + .long .Ltmp0-.Lfunc_begin0 + .short 1 @ Loc expr size + .byte 80 @ DW_OP_reg0 + .long .Ltmp0-.Lfunc_begin0 + .long .Lfunc_end0-.Lfunc_begin0 + .short 1 @ Loc expr size + .byte 81 @ DW_OP_reg1 + .long 0 + .long 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 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 18 @ DW_AT_high_pc + .byte 6 @ DW_FORM_data4 + .byte 0 @ EOM(1) + .byte 0 @ EOM(2) + + .byte 6 @ 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 + .ascii "\227B" @ DW_AT_GNU_all_call_sites + .byte 25 @ DW_FORM_flag_present + .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 39 @ DW_AT_prototyped + .byte 25 @ DW_FORM_flag_present + .byte 73 @ DW_AT_type + .byte 19 @ DW_FORM_ref4 + .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:0xbf DW_TAG_compile_unit + .byte 0 @ DW_AT_producer + .short 12 @ DW_AT_language + .secrel32 .Linfo_string1 @ DW_AT_name + .secrel32 .Lline_table_start0 @ DW_AT_stmt_list + .secrel32 .Linfo_string2 @ DW_AT_comp_dir + .long .Lfunc_begin0 @ DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin0 @ DW_AT_high_pc + + .byte 6 @ Abbrev [6] 0x4f:0x39 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 91 + @ DW_AT_GNU_all_call_sites + .secrel32 .Linfo_string6 @ DW_AT_name + .byte 1 @ DW_AT_decl_file + .byte 2 @ DW_AT_decl_line + @ DW_AT_prototyped + .long 60 @ DW_AT_type + @ DW_AT_external + .byte 0 @ End Of Children Mark + .byte 6 @ Abbrev [6] 0x88:0x2e DW_TAG_subprogram + .long .Lfunc_begin1 @ DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 @ DW_AT_high_pc + .byte 1 @ DW_AT_frame_base + .byte 91 + @ DW_AT_GNU_all_call_sites + .secrel32 .Linfo_string3 @ DW_AT_name + .byte 1 @ DW_AT_decl_file + .byte 6 @ DW_AT_decl_line + @ DW_AT_prototyped + .long 60 @ DW_AT_type + @ DW_AT_external + .byte 0 @ End Of Children Mark +.Ldebug_info_end0: + .addrsig + .section .debug_line,"dr" +.Lsection_line: +.Lline_table_start0: