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.

<rdar://problem/15835846> 

llvm-svn: 201300
This commit is contained in:
Jason Molenda 2014-02-13 07:11:08 +00:00
parent 69e245c01d
commit 6223db2778
11 changed files with 81 additions and 33 deletions

View File

@ -835,6 +835,32 @@ namespace lldb_private {
return LLDB_INVALID_QUEUE_ID; 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<ConstString> &
GetTrapHandlerSymbolNames ()
{
return m_trap_handlers;
}
protected: protected:
bool m_is_host; bool m_is_host;
// Set to true when we are able to actually set the OS version while // 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; std::string m_ssh_opts;
bool m_ignores_remote_hostname; bool m_ignores_remote_hostname;
std::string m_local_cache_directory; std::string m_local_cache_directory;
std::vector<ConstString> m_trap_handlers;
const char * const char *
GetCachedUserName (uint32_t uid) GetCachedUserName (uint32_t uid)
@ -1115,7 +1142,9 @@ namespace lldb_private {
bool m_ssh; bool m_ssh;
std::string m_ssh_opts; std::string m_ssh_opts;
private: private:
DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformSSH); DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformSSH);
}; };

View File

@ -142,8 +142,10 @@ PlatformFreeBSD::Terminate ()
/// Default Constructor /// Default Constructor
//------------------------------------------------------------------ //------------------------------------------------------------------
PlatformFreeBSD::PlatformFreeBSD (bool is_host) : PlatformFreeBSD::PlatformFreeBSD (bool is_host) :
Platform(is_host) Platform(is_host),
m_remote_platform_sp()
{ {
m_trap_handlers.push_back (ConstString ("_sigtramp"));
} }
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -307,6 +307,7 @@ PlatformLinux::PlatformLinux (bool is_host) :
Platform(is_host), // This is the local host platform Platform(is_host), // This is the local host platform
m_remote_platform_sp () m_remote_platform_sp ()
{ {
m_trap_handlers.push_back (ConstString ("_sigtramp"));
} }
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -40,6 +40,7 @@ PlatformDarwin::PlatformDarwin (bool is_host) :
PlatformPOSIX(is_host), // This is the local host platform PlatformPOSIX(is_host), // This is the local host platform
m_developer_directory () m_developer_directory ()
{ {
m_trap_handlers.push_back (ConstString ("_sigtramp"));
} }
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -257,6 +257,8 @@ PlatformDarwinKernel::PlatformDarwinKernel (lldb_private::LazyBool is_ios_debug_
{ {
SearchForKexts (); SearchForKexts ();
} }
m_trap_handlers.push_back(ConstString ("trap_from_kernel"));
m_trap_handlers.push_back(ConstString ("hndl_double_fault"));
} }
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -32,6 +32,7 @@ PlatformPOSIX::PlatformPOSIX (bool is_host) :
Platform(is_host), // This is the local host platform Platform(is_host), // This is the local host platform
m_remote_platform_sp () m_remote_platform_sp ()
{ {
m_trap_handlers.push_back (ConstString ("_sigtramp"));
} }
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -135,6 +135,7 @@ PlatformRemoteGDBServer::PlatformRemoteGDBServer () :
Platform(false), // This is a remote platform Platform(false), // This is a remote platform
m_gdb_client(true) m_gdb_client(true)
{ {
m_trap_handlers.push_back (ConstString ("_sigtramp"));
} }
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -21,16 +21,17 @@
#include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/FuncUnwinders.h"
#include "lldb/Symbol/Function.h" #include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/ABI.h" #include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h" #include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h" #include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h" #include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h" #include "lldb/Target/Thread.h"
#include "lldb/Target/DynamicLoader.h"
#include "RegisterContextLLDB.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 // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet
if (IsFrameZero() if (IsFrameZero()
|| next_frame->m_frame_type == eSigtrampFrame || next_frame->m_frame_type == eTrapHandlerFrame
|| next_frame->m_frame_type == eDebuggerFrame) || next_frame->m_frame_type == eDebuggerFrame)
{ {
m_all_registers_available = true; m_all_registers_available = true;
@ -171,17 +172,21 @@ RegisterContextLLDB::InitializeZerothFrame()
AddressRange addr_range; AddressRange addr_range;
m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range); m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range);
static ConstString g_sigtramp_name ("_sigtramp"); m_frame_type = eNormalFrame;
if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) || PlatformSP platform_sp (process->GetTarget().GetPlatform());
(m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name)) if (platform_sp)
{ {
m_frame_type = eSigtrampFrame; const std::vector<ConstString> trap_handler_names (platform_sp->GetTrapHandlerSymbolNames());
} for (ConstString name : trap_handler_names)
else {
{ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) ||
// FIXME: Detect eDebuggerFrame here. (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name))
m_frame_type = eNormalFrame; {
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. // 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. // 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), // 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... // and our "current" pc is the start of a function...
if (m_sym_ctx_valid if (m_sym_ctx_valid
&& GetNextFrame()->m_frame_type != eSigtrampFrame && GetNextFrame()->m_frame_type != eTrapHandlerFrame
&& GetNextFrame()->m_frame_type != eDebuggerFrame && GetNextFrame()->m_frame_type != eDebuggerFrame
&& addr_range.GetBaseAddress().IsValid() && addr_range.GetBaseAddress().IsValid()
&& addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
@ -492,20 +497,25 @@ RegisterContextLLDB::InitializeNonZerothFrame()
m_current_offset_backed_up_one = -1; m_current_offset_backed_up_one = -1;
} }
static ConstString sigtramp_name ("_sigtramp"); if (m_frame_type != eSkipFrame) // don't override eSkipFrame
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))
{ {
m_frame_type = eSigtrampFrame; m_frame_type = eNormalFrame;
} }
else PlatformSP platform_sp (process->GetTarget().GetPlatform());
if (platform_sp)
{ {
// FIXME: Detect eDebuggerFrame here. const std::vector<ConstString> trap_handler_names (platform_sp->GetTrapHandlerSymbolNames());
if (m_frame_type != eSkipFrame) // don't override eSkipFrame 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. // We've set m_frame_type and m_sym_ctx before this call.
m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame (); m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
@ -617,7 +627,7 @@ RegisterContextLLDB::IsFrameZero () const
// //
// On entry to this method, // 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 // 2. m_sym_ctx should already be filled in, and
// 3. m_current_pc should have the current pc value for this frame // 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 // 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; return unwind_plan_sp;
// If we're in _sigtramp(), unwinding past this frame requires special knowledge. // 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; return unwind_plan_sp;
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread); unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
@ -668,7 +678,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame ()
// On entry to this method, // 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 // 2. m_sym_ctx should already be filled in, and
// 3. m_current_pc should have the current pc value for this frame // 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 // 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; bool behaves_like_zeroth_frame = false;
if (IsFrameZero () if (IsFrameZero ()
|| GetNextFrame()->m_frame_type == eSigtrampFrame || GetNextFrame()->m_frame_type == eTrapHandlerFrame
|| GetNextFrame()->m_frame_type == eDebuggerFrame) || GetNextFrame()->m_frame_type == eDebuggerFrame)
{ {
behaves_like_zeroth_frame = true; behaves_like_zeroth_frame = true;
@ -763,7 +773,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// is properly encoded in the eh_frame section, so prefer that if available. // 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 // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of
// how to unwind out of sigtramp. // how to unwind out of sigtramp.
if (m_frame_type == eSigtrampFrame) if (m_frame_type == eTrapHandlerFrame)
{ {
m_fast_unwind_plan_sp.reset(); m_fast_unwind_plan_sp.reset();
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
@ -983,9 +993,9 @@ RegisterContextLLDB::IsValid () const
} }
bool 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 // A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther

View File

@ -73,7 +73,7 @@ public:
IsValid () const; IsValid () const;
bool bool
IsSigtrampFrame () const; IsTrapHandlerFrame () const;
bool bool
GetCFA (lldb::addr_t& cfa); GetCFA (lldb::addr_t& cfa);
@ -89,7 +89,7 @@ private:
enum FrameType enum FrameType
{ {
eNormalFrame, eNormalFrame,
eSigtrampFrame, eTrapHandlerFrame,
eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger 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 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 eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack

View File

@ -174,7 +174,7 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)
// On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not have // 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 // its (constructed) CFA aligned correctly -- don't do the abi alignment check for
// these. // these.
if (reg_ctx_sp->IsSigtrampFrame() == false) if (reg_ctx_sp->IsTrapHandlerFrame() == false)
{ {
if (log) if (log)
{ {

View File

@ -255,7 +255,8 @@ Platform::Platform (bool is_host) :
m_rsync_prefix (), m_rsync_prefix (),
m_supports_ssh (false), m_supports_ssh (false),
m_ssh_opts (), m_ssh_opts (),
m_ignores_remote_hostname (false) m_ignores_remote_hostname (false),
m_trap_handlers()
{ {
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log) if (log)