Index: lldb/include/lldb/Expression/DWARFExpression.h =================================================================== --- lldb/include/lldb/Expression/DWARFExpression.h +++ lldb/include/lldb/Expression/DWARFExpression.h @@ -139,6 +139,8 @@ void SetLocationListAddresses(lldb::addr_t cu_file_addr, lldb::addr_t func_file_addr); + std::pair GetLocationListAddresses() const; + /// Return the call-frame-info style register kind int GetRegisterKind(); Index: lldb/include/lldb/Symbol/LineTable.h =================================================================== --- lldb/include/lldb/Symbol/LineTable.h +++ lldb/include/lldb/Symbol/LineTable.h @@ -85,6 +85,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 @@ -504,6 +504,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/include/lldb/Utility/RangeMap.h =================================================================== --- lldb/include/lldb/Utility/RangeMap.h +++ lldb/include/lldb/Utility/RangeMap.h @@ -244,6 +244,10 @@ return ((i < m_entries.size()) ? &m_entries[i] : nullptr); } + Entry *GetMutableEntryAtIndex(size_t i) { + return ((i < m_entries.size()) ? &m_entries[i] : nullptr); + } + // Clients must ensure that "i" is a valid index prior to calling this // function const Entry &GetEntryRef(size_t i) const { return m_entries[i]; } Index: lldb/source/Expression/DWARFExpression.cpp =================================================================== --- lldb/source/Expression/DWARFExpression.cpp +++ lldb/source/Expression/DWARFExpression.cpp @@ -99,6 +99,11 @@ m_loclist_addresses = LoclistAddresses{cu_file_addr, func_file_addr}; } +std::pair DWARFExpression::GetLocationListAddresses() const { + return std::make_pair(m_loclist_addresses->cu_file_addr, + m_loclist_addresses->func_file_addr); +} + int DWARFExpression::GetRegisterKind() { return m_reg_kind; } void DWARFExpression::SetRegisterKind(RegisterKind reg_kind) { Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -392,6 +392,18 @@ } } } + + ArchSpec arch = dwarf.GetArchSpec(); + for (size_t i = 0; i < ranges.GetSize(); i++) { + DWARFRangeList::Entry *entry = ranges.GetMutableEntryAtIndex(i); + entry->base = arch.GetOpcodeLoadAddress(entry->base); + } + if (frame_base && frame_base->IsLocationList()) { + std::pair loclist = frame_base->GetLocationListAddresses(); + loclist.second = arch.GetOpcodeLoadAddress(loclist.second); + frame_base->SetLocationListAddresses(loclist.first, loclist.second); + } + return !ranges.IsEmpty(); } @@ -738,8 +750,13 @@ if (lo_pc != fail_value) { hi_pc = GetAttributeHighPC(cu, lo_pc, fail_value, check_specification_or_abstract_origin); - if (hi_pc != fail_value) + if (hi_pc != fail_value) { + SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); + ArchSpec arch = dwarf.GetArchSpec(); + lo_pc = arch.GetOpcodeLoadAddress(lo_pc); + hi_pc = arch.GetOpcodeLoadAddress(hi_pc); return true; + } } lo_pc = fail_value; hi_pc = fail_value; @@ -754,6 +771,12 @@ DWARFFormValue form_value; if (GetAttributeValue(cu, DW_AT_ranges, form_value)) { ranges = GetRangesOrReportError(*cu, *this, form_value); + SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); + ArchSpec arch = dwarf.GetArchSpec(); + for (size_t i = 0; i < ranges.GetSize(); i++) { + DWARFRangeList::Entry *entry = ranges.GetMutableEntryAtIndex(i); + entry->base = arch.GetOpcodeLoadAddress(entry->base); + } } else if (check_hi_lo_pc) { dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -24,6 +24,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" @@ -305,6 +306,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 @@ -1011,6 +1011,7 @@ std::unique_ptr line_table_up = std::make_unique(&comp_unit, std::move(sequences)); + 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 @@ -3143,9 +3144,10 @@ if (sc.function) { DWARFDIE function_die = GetDIE(sc.function->GetID()); - const dw_addr_t func_lo_pc = function_die.GetAttributeValueAsAddress( + dw_addr_t func_lo_pc = function_die.GetAttributeValueAsAddress( DW_AT_low_pc, LLDB_INVALID_ADDRESS); if (func_lo_pc != LLDB_INVALID_ADDRESS) { + func_lo_pc = GetArchSpec().GetOpcodeLoadAddress(func_lo_pc); const size_t num_variables = ParseVariables( sc, function_die.GetFirstChild(), func_lo_pc, true, true); @@ -3969,3 +3971,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 @@ -174,6 +174,12 @@ return (*this)(seq_a->m_entries.front(), seq_b->m_entries.front()); } +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 @@ -1463,3 +1463,26 @@ if (!environ_str.empty()) s << "-" << environ_str; } + +addr_t ArchSpec::GetOpcodeLoadAddress(addr_t opcode_addr, + AddressClass addr_class) const { + if (opcode_addr == LLDB_INVALID_ADDRESS) + return opcode_addr; + 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: