From 35729bb1f8250df77c8b2d4025fa87d4db777b3b Mon Sep 17 00:00:00 2001 From: Ashok Thirumurthi Date: Tue, 24 Sep 2013 15:34:13 +0000 Subject: [PATCH] Adds an option to resolve a symbol from an address that can be used to build out the symbol table as addresses are used, and implements the mechanism for ELF to add stripped symbols from eh_frame. Uses this mechanism to allow disassembly for addresses corresponding to stripped symbols for ELF, and provide hooks to implement this for PE COFF. Also removes eSymbolContextTailCall in favor of an option for ResolveSymbolContextForAddress for consistency with the documentation for eSymbolContextEverything. Essentially, this is just an option for interpreting the so_addr. llvm-svn: 191307 --- lldb/include/lldb/Core/Module.h | 11 +++- lldb/include/lldb/Symbol/ObjectFile.h | 28 ++++++++++ lldb/include/lldb/lldb-enumerations.h | 1 - .../Commands/CommandObjectDisassemble.cpp | 4 +- lldb/source/Core/Module.cpp | 18 +++++-- .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 52 +++++++++++++++++++ .../Plugins/ObjectFile/ELF/ObjectFileELF.h | 3 ++ .../Process/Utility/RegisterContextLLDB.cpp | 8 ++- .../inferior-assert/TestInferiorAssert.py | 4 +- 9 files changed, 117 insertions(+), 12 deletions(-) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index bb43db49b4b5..1473fb90cf85 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 8934c31bb988..b85f9888c6a2 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 d84827999e0e..9ef342e3e989 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 f14398a68b7b..95c6f37bfa44 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 f899693cb3f6..d774a5fe5d70 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 f09151c7acfc..0e31cbb45c8b 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 2365101f4275..d66b6a1f2524 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 99bc548d28a5..b3d9aa3031c0 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 437453a90c2a..6787e1710c2d 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() -- GitLab