diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index bb43db49b4b5b727395a9103beca5c89058fd40e..1473fb90cf8591b8e9c82dde8e986c211394682e 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -776,13 +776,22 @@ public: /// eSymbolContextModule, and eSymbolContextFunction requires /// eSymbolContextSymbol. /// + /// @param[out] sc + /// The SymbolContext that is modified based on symbol resolution. + /// + /// @param[in] resolve_tail_call_address + /// Determines if so_addr should resolve to a symbol in the case + /// of a function whose last instruction is a call. In this case, + /// the PC can be one past the address range of the function. + /// /// @return /// The scope that has been resolved (see SymbolContext::Scope). /// /// @see SymbolContext::Scope //------------------------------------------------------------------ uint32_t - ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc); + ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, + SymbolContext& sc, bool resolve_tail_call_address = false); //------------------------------------------------------------------ /// Resolve items in the symbol context for a given file and line. diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 8934c31bb988894d8a7c782e79a168525384e92a..b85f9888c6a2582cf6d675583b62720aa04a7fc0 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -367,6 +367,34 @@ public: virtual Symtab * GetSymtab () = 0; + //------------------------------------------------------------------ + /// Appends a Symbol for the specified so_addr to the symbol table. + /// + /// If verify_unique is false, the symbol table is not searched + /// to determine if a Symbol found at this address has already been + /// added to the symbol table. When verify_unique is true, this + /// method resolves the Symbol as the first match in the SymbolTable + /// and appends a Symbol only if required/found. + /// + /// @return + /// The resolved symbol or nullptr. Returns nullptr if a + /// a Symbol could not be found for the specified so_addr. + //------------------------------------------------------------------ + virtual Symbol * + ResolveSymbolForAddress(const Address &so_addr, bool verify_unique) + { + // Typically overridden to lazily add stripped symbols recoverable from + // the exception handling unwind information (i.e. without parsing + // the entire eh_frame section. + // + // The availability of LC_FUNCTION_STARTS allows ObjectFileMachO + // to efficiently add stripped symbols when the symbol table is + // first constructed. Poorer cousins are PECoff and ELF. + return nullptr; + } + + //------------------------------------------------------------------ + /// Detect if this object file has been stripped of local symbols. //------------------------------------------------------------------ /// Detect if this object file has been stripped of local symbols. /// diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index d84827999e0e60175b3884a4b1183b4577e8ca85..9ef342e3e98900991e20b2c77e22c8c1213e3082 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -263,7 +263,6 @@ namespace lldb { eSymbolContextBlock = (1u << 4), ///< Set when the deepest \a block is requested from a query, or was located in query results eSymbolContextLineEntry = (1u << 5), ///< Set when \a line_entry is requested from a query, or was located in query results eSymbolContextSymbol = (1u << 6), ///< Set when \a symbol is requested from a query, or was located in query results - eSymbolContextTailCall = (1u << 7), ///< Set when a function symbol with a tail call is requested from a query, or was located in query results eSymbolContextEverything = ((eSymbolContextSymbol << 1) - 1u) ///< Indicates to try and lookup everything up during a query. } SymbolContextItem; diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp index f14398a68b7ba0eeae2bc22111ddb02337e42e16..95c6f37bfa440c48d5e4bb31032a21ac44bafd87 100644 --- a/lldb/source/Commands/CommandObjectDisassemble.cpp +++ b/lldb/source/Commands/CommandObjectDisassemble.cpp @@ -453,7 +453,9 @@ CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result) { ModuleSP module_sp (symbol_containing_address.GetModule()); SymbolContext sc; - module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc); + bool resolve_tail_call_address = true; // PC can be one past the address range of the function. + module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc, + resolve_tail_call_address); if (sc.function || sc.symbol) { sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range); diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index f899693cb3f6369ecbdf4150223c6241de0e46d0..d774a5fe5d7099cde3b162221bcea8447e5d2515 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -449,7 +449,8 @@ Module::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr) } uint32_t -Module::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) +Module::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc, + bool resolve_tail_call_address) { Mutex::Locker locker (m_mutex); uint32_t resolved_flags = 0; @@ -489,6 +490,14 @@ Module::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve if (symtab && so_addr.IsSectionOffset()) { sc.symbol = symtab->FindSymbolContainingFileAddress(so_addr.GetFileAddress()); + if (!sc.symbol && + resolve_scope & eSymbolContextFunction && !(resolved_flags & eSymbolContextFunction)) + { + bool verify_unique = false; // No need to check again since ResolveSymbolContext failed to find a symbol at this address. + if (ObjectFile *obj_file = sc.module_sp->GetObjectFile()) + sc.symbol = obj_file->ResolveSymbolForAddress(so_addr, verify_unique); + } + if (sc.symbol) resolved_flags |= eSymbolContextSymbol; } @@ -498,13 +507,14 @@ Module::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve // with FDE row indices in eh_frame sections, but requires extra logic here to permit // symbol lookup for disassembly and unwind. if (resolve_scope & eSymbolContextSymbol && !(resolved_flags & eSymbolContextSymbol) && - resolve_scope & eSymbolContextTailCall && - so_addr.IsSectionOffset()) + resolve_tail_call_address && so_addr.IsSectionOffset()) { Address previous_addr = so_addr; previous_addr.Slide(-1); - const uint32_t flags = ResolveSymbolContextForAddress(previous_addr, resolve_scope & ~eSymbolContextTailCall, sc); + bool do_resolve_tail_call_address = false; // prevent recursion + const uint32_t flags = ResolveSymbolContextForAddress(previous_addr, resolve_scope, sc, + do_resolve_tail_call_address); if (flags & eSymbolContextSymbol) { AddressRange addr_range; diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index f09151c7acfc538a5c93ea19b45ec8facfe53e5f..0e31cbb45c8bb6b10b171eb04a9dea2ee810cd44 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Core/Stream.h" +#include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Host/Host.h" @@ -1513,6 +1514,57 @@ ObjectFileELF::GetSymtab() return m_symtab_ap.get(); } +Symbol * +ObjectFileELF::ResolveSymbolForAddress(const Address& so_addr, bool verify_unique) +{ + if (!m_symtab_ap.get()) + return nullptr; // GetSymtab() should be called first. + + const SectionList *section_list = GetSectionList(); + if (!section_list) + return nullptr; + + if (DWARFCallFrameInfo *eh_frame = GetUnwindTable().GetEHFrameInfo()) + { + AddressRange range; + if (eh_frame->GetAddressRange (so_addr, range)) + { + const addr_t file_addr = range.GetBaseAddress().GetFileAddress(); + Symbol * symbol = verify_unique ? m_symtab_ap->FindSymbolContainingFileAddress(file_addr) : nullptr; + if (symbol) + return symbol; + + // Note that a (stripped) symbol won't be found by GetSymtab()... + lldb::SectionSP eh_sym_section_sp = section_list->FindSectionContainingFileAddress(file_addr); + if (eh_sym_section_sp.get()) + { + addr_t section_base = eh_sym_section_sp->GetFileAddress(); + addr_t offset = file_addr - section_base; + uint64_t symbol_id = m_symtab_ap->GetNumSymbols(); + + Symbol eh_symbol( + symbol_id, // Symbol table index. + "???", // Symbol name. + false, // Is the symbol name mangled? + eSymbolTypeCode, // Type of this symbol. + true, // Is this globally visible? + false, // Is this symbol debug info? + false, // Is this symbol a trampoline? + true, // Is this symbol artificial? + eh_sym_section_sp, // Section in which this symbol is defined or null. + offset, // Offset in section or symbol value. + range.GetByteSize(), // Size in bytes of this symbol. + true, // Size is valid. + 0); // Symbol flags. + if (symbol_id == m_symtab_ap->AddSymbol(eh_symbol)) + return m_symtab_ap->SymbolAtIndex(symbol_id); + } + } + } + return nullptr; +} + + bool ObjectFileELF::IsStripped () { diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 2365101f42750917fc09768b7cc4741f81010f79..d66b6a1f25248e9115a84fd2ef5cffac6356a563 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -102,6 +102,9 @@ public: virtual lldb_private::Symtab * GetSymtab(); + virtual lldb_private::Symbol * + ResolveSymbolForAddress(const lldb_private::Address& so_addr, bool verify_unique); + virtual bool IsStripped (); diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 99bc548d28a5672cc64bc322b27e475c743d3b15..b3d9aa3031c025e0c0e6e41127e852f7de071924 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -369,9 +369,13 @@ RegisterContextLLDB::InitializeNonZerothFrame() return; } + bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function... + uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, + eSymbolContextFunction | eSymbolContextSymbol, + m_sym_ctx, resolve_tail_call_address); + // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us. - uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol | eSymbolContextTailCall; - if ((pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, resolve_scope, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + if ((resolved_scope & eSymbolContextSymbol) == eSymbolContextSymbol) { m_sym_ctx_valid = true; } diff --git a/lldb/test/functionalities/inferior-assert/TestInferiorAssert.py b/lldb/test/functionalities/inferior-assert/TestInferiorAssert.py index 437453a90c2a5c71253481572697d1eb4eec3946..6787e1710c2dde48c064514b5fdc8bdeb3b689dd 100644 --- a/lldb/test/functionalities/inferior-assert/TestInferiorAssert.py +++ b/lldb/test/functionalities/inferior-assert/TestInferiorAssert.py @@ -32,9 +32,7 @@ class AssertingInferiorTestCase(TestBase): self.buildDwarf() self.inferior_asserting_registers() - @skipIfGcc # Avoid xpasses as the verion of libc used on the gcc buildbot has the required function symbols. - @expectedFailureFreeBSD # ResolveSymbolContextForAddress can fail using ELF with stripped function symbols. - @expectedFailureLinux # ResolveSymbolContextForAddress can fail using ELF with stripped function symbols. + @expectedFailureLinux # Disassembly does not specify '->' for the PC for a non-terminal frame for a function with a tail call. def test_inferior_asserting_disassemble(self): """Test that lldb reliably disassembles frames after asserting (command).""" self.buildDefault()