diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 3f01eaf6c93c..bb43db49b4b5 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -749,6 +749,38 @@ public: bool ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr); + //------------------------------------------------------------------ + /// Resolve the symbol context for the given address. + /// + /// Tries to resolve the matching symbol context based on a lookup + /// from the current symbol vendor. If the lazy lookup fails, + /// an attempt is made to parse the eh_frame section to handle + /// stripped symbols. If this fails, an attempt is made to resolve + /// the symbol to the previous address to handle the case of a + /// function with a tail call. + /// + /// Use properties of the modified SymbolContext to inspect any + /// resolved target, module, compilation unit, symbol, function, + /// function block or line entry. Use the return value to determine + /// which of these properties have been modified. + /// + /// @param[in] so_addr + /// A load address to resolve. + /// + /// @param[in] resolve_scope + /// The scope that should be resolved (see SymbolContext::Scope). + /// A combination of flags from the enumeration SymbolContextItem + /// requesting a resolution depth. Note that the flags that are + /// actually resolved may be a superset of the requested flags. + /// For instance, eSymbolContextSymbol requires resolution of + /// eSymbolContextModule, and eSymbolContextFunction requires + /// eSymbolContextSymbol. + /// + /// @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); diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 859ec866ac03..f010f39f8d49 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -468,6 +468,10 @@ Module::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve sc.module_sp = shared_from_this(); resolved_flags |= eSymbolContextModule; + SymbolVendor* sym_vendor = GetSymbolVendor(); + if (!sym_vendor) + return resolved_flags; + // Resolve the compile unit, function, block, line table or line // entry if requested. if (resolve_scope & eSymbolContextCompUnit || @@ -475,25 +479,51 @@ Module::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve resolve_scope & eSymbolContextBlock || resolve_scope & eSymbolContextLineEntry ) { - SymbolVendor *symbols = GetSymbolVendor (); - if (symbols) - resolved_flags |= symbols->ResolveSymbolContext (so_addr, resolve_scope, sc); + resolved_flags |= sym_vendor->ResolveSymbolContext (so_addr, resolve_scope, sc); } // Resolve the symbol if requested, but don't re-look it up if we've already found it. if (resolve_scope & eSymbolContextSymbol && !(resolved_flags & eSymbolContextSymbol)) { - SymbolVendor* sym_vendor = GetSymbolVendor(); - if (sym_vendor) + Symtab *symtab = sym_vendor->GetSymtab(); + if (symtab && so_addr.IsSectionOffset()) { - Symtab *symtab = sym_vendor->GetSymtab(); - if (symtab) + sc.symbol = symtab->FindSymbolContainingFileAddress(so_addr.GetFileAddress()); + if (sc.symbol) + resolved_flags |= eSymbolContextSymbol; + } + } + + // For function symbols, so_addr may be off by one. This is a convention consistent + // 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 & eSymbolContextFunction && !(resolved_flags & eSymbolContextFunction) && + so_addr.GetOffset() > 0) + { + Address previous_addr = so_addr; + previous_addr.SetOffset(so_addr.GetOffset() - 1); + + const uint32_t flags = sym_vendor->ResolveSymbolContext (previous_addr, resolve_scope, sc); + if (flags & eSymbolContextSymbol) + { + AddressRange addr_range; + if (sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) { - if (so_addr.IsSectionOffset()) + if (addr_range.GetBaseAddress().GetSection() == so_addr.GetSection()) { - sc.symbol = symtab->FindSymbolContainingFileAddress(so_addr.GetFileAddress()); - if (sc.symbol) - resolved_flags |= eSymbolContextSymbol; + // If the requested address is one past the address range of a function (i.e. a tail call), + // or the decremented address is the start of a function (i.e. some forms of trampoline), + // indicate that the symbol has been resolved. + if (so_addr.GetOffset() == addr_range.GetBaseAddress().GetOffset() || + so_addr.GetOffset() == addr_range.GetBaseAddress().GetOffset() + addr_range.GetByteSize()) + { + resolved_flags |= flags; + } + } + else + { + sc.symbol = nullptr; // Don't trust the symbol if the sections didn't match. } } } diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 0e4bca0f063f..694a143df4ea 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -387,35 +387,18 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (m_sym_ctx_valid == false) decr_pc_and_recompute_addr_range = true; - // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), - // and our "current" pc is the start of a function... + // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), and + // our "current" pc is the start of a function or our "current" pc is one past the end of a function... if (m_sym_ctx_valid && GetNextFrame()->m_frame_type != eSigtrampFrame && GetNextFrame()->m_frame_type != eDebuggerFrame && addr_range.GetBaseAddress().IsValid() - && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() - && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()) + && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()) { - decr_pc_and_recompute_addr_range = true; - } - - // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc" - // value is pointing to the next function, e.g. if a function ends with a CALL instruction. - // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function - // to the ABI plugin and consult that. - if (decr_pc_and_recompute_addr_range) - { - Address temporary_pc(m_current_pc); - temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); - m_sym_ctx.Clear(false); - m_sym_ctx_valid = false; - if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + if (addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset() || + addr_range.GetBaseAddress().GetOffset() + addr_range.GetByteSize() == m_current_pc.GetOffset()) { - m_sym_ctx_valid = true; - } - if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) - { - m_sym_ctx_valid = false; + decr_pc_and_recompute_addr_range = true; } }