From 6223db27780ec34421fa9b22f44119aae68e1024 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Thu, 13 Feb 2014 07:11:08 +0000 Subject: [PATCH] The Platform base class now maintains a list of trap handlers aka asynchronous signal handlers, which subclasses should fill in as appropriate. For most Unix user process environments, the one entry in this list is _sigtramp. For bare-board and kernel environments, there will be different sets of trap handlers. The unwinder needs to know when a frame is a trap handler because the rules it enforces for the frame "above" the trap handler is different from most middle-of-the-stack frames. llvm-svn: 201300 --- lldb/include/lldb/Target/Platform.h | 29 ++++++++++ .../Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp | 4 +- .../Plugins/Platform/Linux/PlatformLinux.cpp | 1 + .../Plugins/Platform/MacOSX/PlatformDarwin.cpp | 1 + .../Platform/MacOSX/PlatformDarwinKernel.cpp | 2 + .../Plugins/Platform/POSIX/PlatformPOSIX.cpp | 1 + .../gdb-server/PlatformRemoteGDBServer.cpp | 1 + .../Process/Utility/RegisterContextLLDB.cpp | 66 +++++++++++++--------- .../Plugins/Process/Utility/RegisterContextLLDB.h | 4 +- lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp | 2 +- lldb/source/Target/Platform.cpp | 3 +- 11 files changed, 81 insertions(+), 33 deletions(-) diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index be54df9..65b774e 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -835,6 +835,32 @@ namespace lldb_private { return LLDB_INVALID_QUEUE_ID; } + //------------------------------------------------------------------ + /// Provide a list of trap handler function names for this platform + /// + /// The unwinder needs to treat trap handlers specially -- the stack + /// frame may not be aligned correctly for a trap handler (the kernel + /// often won't perturb the stack pointer, or won't re-align it properly, + /// in the process of calling the handler) and the frame above the handler + /// needs to be treated by the unwinder's "frame 0" rules instead of its + /// "middle of the stack frame" rules. + /// + /// In a user process debugging scenario, the list of trap handlers is + /// typically just "_sigtramp". + /// + /// The Platform base class provides the m_trap_handlers ivar but it does + /// not populate it. Subclasses should add the names of the asynchronous + /// signal handler routines as needed. For most Unix platforms, add _sigtramp. + /// + /// @return + /// A list of symbol names. The list may be empty. + //------------------------------------------------------------------ + virtual const std::vector & + GetTrapHandlerSymbolNames () + { + return m_trap_handlers; + } + protected: bool m_is_host; // Set to true when we are able to actually set the OS version while @@ -867,6 +893,7 @@ namespace lldb_private { std::string m_ssh_opts; bool m_ignores_remote_hostname; std::string m_local_cache_directory; + std::vector m_trap_handlers; const char * GetCachedUserName (uint32_t uid) @@ -1115,7 +1142,9 @@ namespace lldb_private { bool m_ssh; std::string m_ssh_opts; + private: + DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformSSH); }; diff --git a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index a10c04f..1ebb143 100644 --- a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -142,8 +142,10 @@ PlatformFreeBSD::Terminate () /// Default Constructor //------------------------------------------------------------------ PlatformFreeBSD::PlatformFreeBSD (bool is_host) : -Platform(is_host) +Platform(is_host), +m_remote_platform_sp() { + m_trap_handlers.push_back (ConstString ("_sigtramp")); } //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp index c30211c..3e42b6a 100644 --- a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -307,6 +307,7 @@ PlatformLinux::PlatformLinux (bool is_host) : Platform(is_host), // This is the local host platform m_remote_platform_sp () { + m_trap_handlers.push_back (ConstString ("_sigtramp")); } //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 0f38338..ff4e235 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -40,6 +40,7 @@ PlatformDarwin::PlatformDarwin (bool is_host) : PlatformPOSIX(is_host), // This is the local host platform m_developer_directory () { + m_trap_handlers.push_back (ConstString ("_sigtramp")); } //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp index 5e5a8aa..6378f1a 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -257,6 +257,8 @@ PlatformDarwinKernel::PlatformDarwinKernel (lldb_private::LazyBool is_ios_debug_ { SearchForKexts (); } + m_trap_handlers.push_back(ConstString ("trap_from_kernel")); + m_trap_handlers.push_back(ConstString ("hndl_double_fault")); } //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index b5f92dc..b9bf255 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -32,6 +32,7 @@ PlatformPOSIX::PlatformPOSIX (bool is_host) : Platform(is_host), // This is the local host platform m_remote_platform_sp () { + m_trap_handlers.push_back (ConstString ("_sigtramp")); } //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 80421ad..3b28362 100644 --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -135,6 +135,7 @@ PlatformRemoteGDBServer::PlatformRemoteGDBServer () : Platform(false), // This is a remote platform m_gdb_client(true) { + m_trap_handlers.push_back (ConstString ("_sigtramp")); } //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 954bf7b..3f4c660 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -21,16 +21,17 @@ #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" -#include "lldb/Target/DynamicLoader.h" #include "RegisterContextLLDB.h" @@ -76,7 +77,7 @@ RegisterContextLLDB::RegisterContextLLDB // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet if (IsFrameZero() - || next_frame->m_frame_type == eSigtrampFrame + || next_frame->m_frame_type == eTrapHandlerFrame || next_frame->m_frame_type == eDebuggerFrame) { m_all_registers_available = true; @@ -171,17 +172,21 @@ RegisterContextLLDB::InitializeZerothFrame() AddressRange addr_range; m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range); - static ConstString g_sigtramp_name ("_sigtramp"); - if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) || - (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name)) + m_frame_type = eNormalFrame; + PlatformSP platform_sp (process->GetTarget().GetPlatform()); + if (platform_sp) { - m_frame_type = eSigtrampFrame; - } - else - { - // FIXME: Detect eDebuggerFrame here. - m_frame_type = eNormalFrame; + const std::vector trap_handler_names (platform_sp->GetTrapHandlerSymbolNames()); + for (ConstString name : trap_handler_names) + { + if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || + (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) + { + m_frame_type = eTrapHandlerFrame; + } + } } + // FIXME: Detect eDebuggerFrame here. // If we were able to find a symbol/function, set addr_range to the bounds of that symbol/function. // else treat the current pc value as the start_pc and record no offset. @@ -442,7 +447,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() // 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... if (m_sym_ctx_valid - && GetNextFrame()->m_frame_type != eSigtrampFrame + && GetNextFrame()->m_frame_type != eTrapHandlerFrame && GetNextFrame()->m_frame_type != eDebuggerFrame && addr_range.GetBaseAddress().IsValid() && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() @@ -492,20 +497,25 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_current_offset_backed_up_one = -1; } - static ConstString sigtramp_name ("_sigtramp"); - if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name) - || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name)) + if (m_frame_type != eSkipFrame) // don't override eSkipFrame { - m_frame_type = eSigtrampFrame; + m_frame_type = eNormalFrame; } - else + PlatformSP platform_sp (process->GetTarget().GetPlatform()); + if (platform_sp) { - // FIXME: Detect eDebuggerFrame here. - if (m_frame_type != eSkipFrame) // don't override eSkipFrame + const std::vector trap_handler_names (platform_sp->GetTrapHandlerSymbolNames()); + for (ConstString name : trap_handler_names) { - m_frame_type = eNormalFrame; + if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || + (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) + { + m_frame_type = eTrapHandlerFrame; + } } } + // FIXME: Detect eDebuggerFrame here. + // We've set m_frame_type and m_sym_ctx before this call. m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame (); @@ -617,7 +627,7 @@ RegisterContextLLDB::IsFrameZero () const // // On entry to this method, // -// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct, // 2. m_sym_ctx should already be filled in, and // 3. m_current_pc should have the current pc value for this frame // 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -639,7 +649,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame () return unwind_plan_sp; // If we're in _sigtramp(), unwinding past this frame requires special knowledge. - if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame) + if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame) return unwind_plan_sp; unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread); @@ -668,7 +678,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame () // On entry to this method, // -// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct, // 2. m_sym_ctx should already be filled in, and // 3. m_current_pc should have the current pc value for this frame // 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -693,7 +703,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () bool behaves_like_zeroth_frame = false; if (IsFrameZero () - || GetNextFrame()->m_frame_type == eSigtrampFrame + || GetNextFrame()->m_frame_type == eTrapHandlerFrame || GetNextFrame()->m_frame_type == eDebuggerFrame) { behaves_like_zeroth_frame = true; @@ -763,7 +773,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // is properly encoded in the eh_frame section, so prefer that if available. // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of // how to unwind out of sigtramp. - if (m_frame_type == eSigtrampFrame) + if (m_frame_type == eTrapHandlerFrame) { m_fast_unwind_plan_sp.reset(); unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); @@ -983,9 +993,9 @@ RegisterContextLLDB::IsValid () const } bool -RegisterContextLLDB::IsSigtrampFrame () const +RegisterContextLLDB::IsTrapHandlerFrame () const { - return m_frame_type == eSigtrampFrame; + return m_frame_type == eTrapHandlerFrame; } // A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h index 1479787..5054572 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -73,7 +73,7 @@ public: IsValid () const; bool - IsSigtrampFrame () const; + IsTrapHandlerFrame () const; bool GetCFA (lldb::addr_t& cfa); @@ -89,7 +89,7 @@ private: enum FrameType { eNormalFrame, - eSigtrampFrame, + eTrapHandlerFrame, eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger eSkipFrame, // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack diff --git a/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp b/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp index ddded5a..36223db 100644 --- a/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -174,7 +174,7 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not have // its (constructed) CFA aligned correctly -- don't do the abi alignment check for // these. - if (reg_ctx_sp->IsSigtrampFrame() == false) + if (reg_ctx_sp->IsTrapHandlerFrame() == false) { if (log) { diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index c49499d..a27c91a 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -255,7 +255,8 @@ Platform::Platform (bool is_host) : m_rsync_prefix (), m_supports_ssh (false), m_ssh_opts (), - m_ignores_remote_hostname (false) + m_ignores_remote_hostname (false), + m_trap_handlers() { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) -- 2.7.4