Index: lldb/include/lldb/Symbol/LineTable.h =================================================================== --- lldb/include/lldb/Symbol/LineTable.h +++ lldb/include/lldb/Symbol/LineTable.h @@ -78,6 +78,8 @@ // Insert a sequence of entries into this line table. void InsertSequence(LineSequence *sequence); + void Finalize(); + /// Dump all line entries in this line table to the stream \a s. /// /// \param[in] s Index: lldb/include/lldb/Utility/ArchSpec.h =================================================================== --- lldb/include/lldb/Utility/ArchSpec.h +++ lldb/include/lldb/Utility/ArchSpec.h @@ -502,6 +502,21 @@ void SetFlags(std::string elf_abi); + /// Get \a load_addr as an opcode for this target. + /// + /// Take \a load_addr and potentially strip any address bits that are + /// needed to make the address point to an opcode. For ARM this can + /// clear bit zero (if it already isn't) if \a load_addr is a + /// thumb function and load_addr is in code. + /// If \a addr_class is set to AddressClass::eInvalid, then the address + /// adjustment will always happen. If it is set to an address class + /// that doesn't have code in it, LLDB_INVALID_ADDRESS will be + /// returned. + + lldb::addr_t + GetOpcodeLoadAddress(lldb::addr_t addr, + AddressClass addr_class = AddressClass::eInvalid) const; + protected: bool IsEqualTo(const ArchSpec &rhs, bool exact_match) const; void UpdateCore(); Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h @@ -10,6 +10,7 @@ #define SymbolFileDWARF_DWARFDebugAranges_h_ #include "lldb/Core/dwarf.h" +#include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/RangeMap.h" #include "llvm/Support/Error.h" @@ -34,6 +35,8 @@ void Sort(bool minimize); + void Finalize(const lldb_private::ArchSpec &arch); + void Dump(lldb_private::Log *log) const; dw_offset_t FindAddress(dw_addr_t address) const; Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -86,6 +86,13 @@ m_aranges.CombineConsecutiveEntriesWithEqualData(); } +void DWARFDebugAranges::Finalize(const ArchSpec &arch) { + for (size_t i = 0; i < m_aranges.GetSize(); i++) { + RangeToDIE::Entry *entry = m_aranges.GetMutableEntryAtIndex(i); + entry->base = arch.GetOpcodeLoadAddress(entry->base); + } +} + // FindAddress dw_offset_t DWARFDebugAranges::FindAddress(dw_addr_t address) const { const RangeToDIE::Entry *entry = m_aranges.FindEntryThatContains(address); Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -65,6 +65,7 @@ const bool minimize = true; m_cu_aranges_up->Sort(minimize); + m_cu_aranges_up->Finalize(m_dwarf.GetArchSpec()); return *m_cu_aranges_up; } Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -236,6 +236,7 @@ SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); lldb::ModuleSP module = dwarf.GetObjectFile()->GetModule(); + ArchSpec arch = dwarf.GetArchSpec(); if (abbrevDecl) { const DWARFDataExtractor &data = cu->GetData(); @@ -256,6 +257,7 @@ switch (attr) { case DW_AT_low_pc: lo_pc = form_value.Address(); + lo_pc = arch.GetOpcodeLoadAddress(lo_pc); if (do_offset) hi_pc += lo_pc; @@ -271,6 +273,7 @@ form_value.Form() == DW_FORM_addrx || form_value.Form() == DW_FORM_GNU_addr_index) { hi_pc = form_value.Address(); + hi_pc = arch.GetOpcodeLoadAddress(hi_pc); } else { hi_pc = form_value.Unsigned(); if (lo_pc == LLDB_INVALID_ADDRESS) @@ -729,13 +732,15 @@ dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC( const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value, bool check_specification_or_abstract_origin) const { + SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); + ArchSpec arch = dwarf.GetArchSpec(); DWARFFormValue form_value; if (GetAttributeValue(cu, DW_AT_high_pc, form_value, nullptr, check_specification_or_abstract_origin)) { 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 arch.GetOpcodeLoadAddress(form_value.Address()); // DWARF4 can specify the hi_pc as an return lo_pc + form_value.Unsigned(); @@ -752,9 +757,12 @@ bool DWARFDebugInfoEntry::GetAttributeAddressRange( const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc, uint64_t fail_value, bool check_specification_or_abstract_origin) const { + SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); + ArchSpec arch = dwarf.GetArchSpec(); lo_pc = GetAttributeValueAsAddress(cu, DW_AT_low_pc, fail_value, check_specification_or_abstract_origin); if (lo_pc != fail_value) { + lo_pc = arch.GetOpcodeLoadAddress(lo_pc); hi_pc = GetAttributeHighPC(cu, lo_pc, fail_value, check_specification_or_abstract_origin); if (hi_pc != fail_value) @@ -1015,6 +1023,8 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die) { + SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); + ArchSpec arch = dwarf.GetArchSpec(); bool found_address = false; if (m_tag) { bool check_children = false; @@ -1124,8 +1134,10 @@ dw_addr_t lo_pc = GetAttributeValueAsAddress(cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS); if (lo_pc != LLDB_INVALID_ADDRESS) { + lo_pc = arch.GetOpcodeLoadAddress(lo_pc); dw_addr_t hi_pc = GetAttributeHighPC(cu, lo_pc, LLDB_INVALID_ADDRESS); if (hi_pc != LLDB_INVALID_ADDRESS) { + hi_pc = arch.GetOpcodeLoadAddress(hi_pc); // 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 @@ -783,6 +783,7 @@ const bool minimize = false; m_func_aranges_up->Sort(minimize); + m_func_aranges_up->Finalize(m_dwarf.GetArchSpec()); } return *m_func_aranges_up; } Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -25,6 +25,7 @@ #include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Flags.h" #include "lldb/Utility/RangeMap.h" @@ -316,6 +317,8 @@ lldb_private::FileSpec GetFile(DWARFUnit &unit, size_t file_idx); + lldb_private::ArchSpec GetArchSpec() 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 @@ -1027,6 +1027,8 @@ } } + line_table_up->Finalize(); + if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile()) { // We have an object file that has a line table with addresses that are not // linked. We need to link the line table and convert the addresses that @@ -3995,3 +3997,7 @@ }); return m_dwp_symfile.get(); } + +ArchSpec SymbolFileDWARF::GetArchSpec() const { + return m_objfile_sp->GetArchitecture(); +} Index: lldb/source/Symbol/DWARFCallFrameInfo.cpp =================================================================== --- lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -423,12 +423,7 @@ Timer scoped_timer(func_cat, "%s - %s", LLVM_PRETTY_FUNCTION, m_objfile.GetFileSpec().GetFilename().AsCString("")); - bool clear_address_zeroth_bit = false; - if (ArchSpec arch = m_objfile.GetArchitecture()) { - if (arch.GetTriple().getArch() == llvm::Triple::arm || - arch.GetTriple().getArch() == llvm::Triple::thumb) - clear_address_zeroth_bit = true; - } + ArchSpec arch = m_objfile.GetArchitecture(); lldb::offset_t offset = 0; if (!m_cfi_data_initialized) @@ -503,8 +498,7 @@ lldb::addr_t addr = GetGNUEHPointer(m_cfi_data, &offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr); - if (clear_address_zeroth_bit) - addr &= ~1ull; + addr = arch.GetOpcodeLoadAddress(addr); lldb::addr_t length = GetGNUEHPointer( m_cfi_data, &offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, Index: lldb/source/Symbol/LineTable.cpp =================================================================== --- lldb/source/Symbol/LineTable.cpp +++ lldb/source/Symbol/LineTable.cpp @@ -154,6 +154,12 @@ #undef LT_COMPARE } +void LineTable::Finalize() { + ArchSpec arch = m_comp_unit->GetModule()->GetArchitecture(); + for (Entry &entry : m_entries) + entry.file_addr = arch.GetOpcodeLoadAddress(entry.file_addr); +} + uint32_t LineTable::GetSize() const { return m_entries.size(); } bool LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry &line_entry) { Index: lldb/source/Utility/ArchSpec.cpp =================================================================== --- lldb/source/Utility/ArchSpec.cpp +++ lldb/source/Utility/ArchSpec.cpp @@ -1464,3 +1464,24 @@ if (!environ_str.empty()) s << "-" << environ_str; } + +addr_t ArchSpec::GetOpcodeLoadAddress(addr_t opcode_addr, + AddressClass addr_class) const { + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + default: + break; + } + + if (!IsValid()) + return opcode_addr; + if (m_triple.getArch() == llvm::Triple::arm || + m_triple.getArch() == llvm::Triple::thumb || + m_triple.isMIPS()) { + return opcode_addr & ~(1ull); + } else { + return opcode_addr; + } +} 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: