forked from OSchip/llvm-project
When unwinding from the first frame, try to ask the remote debugserver
if this is a mapped/executable region of memory. If it isn't, we've jumped through a bad pointer and we know how to unwind the stack correctly based on the ABI. Previously I had 0x0 special cased but if you jumped to 0x2 on x86_64 one frame would be skipped because the unwinder would try using the x86_64 ArchDefaultUnwindPlan which relied on the rbp. Fixes <rdar://problem/10508291> llvm-svn: 146477
This commit is contained in:
parent
f43e681ed7
commit
cb349ee19c
|
@ -592,6 +592,18 @@ tuples tp return are:
|
|||
// a hex encoded string value that
|
||||
// contains an error string
|
||||
|
||||
If the address requested is not in a mapped region (e.g. we've jumped through
|
||||
a NULL pointer and are at 0x0) currently lldb expects to get back the size
|
||||
of the unmapped region -- that is, the distance to the next valid region.
|
||||
For instance, with a Mac OS X process which has nothing mapped in the first
|
||||
4GB of its address space, if we're asking about address 0x2,
|
||||
|
||||
qMemoryRegionInfo:2
|
||||
start:2;size:fffffffe;
|
||||
|
||||
The lack of 'permissions:' indicates that none of read/write/execute are valid
|
||||
for this region.
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Stop reply packet extensions
|
||||
//
|
||||
|
|
|
@ -1177,10 +1177,18 @@ class MemoryRegionInfo
|
|||
{
|
||||
public:
|
||||
typedef Range<lldb::addr_t, lldb::addr_t> RangeType;
|
||||
|
||||
|
||||
enum OptionalBool {
|
||||
eDontKnow = -1,
|
||||
eNo = 0,
|
||||
eYes = 1
|
||||
};
|
||||
|
||||
MemoryRegionInfo () :
|
||||
m_range (),
|
||||
m_permissions (0)
|
||||
m_read (eDontKnow),
|
||||
m_write (eDontKnow),
|
||||
m_execute (eDontKnow)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1198,7 +1206,7 @@ public:
|
|||
Clear()
|
||||
{
|
||||
m_range.Clear();
|
||||
m_permissions = 0;
|
||||
m_read = m_write = m_execute = eDontKnow;
|
||||
}
|
||||
|
||||
const RangeType &
|
||||
|
@ -1206,42 +1214,48 @@ public:
|
|||
{
|
||||
return m_range;
|
||||
}
|
||||
|
||||
// Pass in a uint32_t permissions with one or more lldb::Permissions
|
||||
// enumeration values logical OR'ed together.
|
||||
bool
|
||||
TestPermissions (uint32_t permissions) const
|
||||
|
||||
OptionalBool
|
||||
GetReadable () const
|
||||
{
|
||||
return m_permissions.AllSet(permissions);
|
||||
return m_read;
|
||||
}
|
||||
|
||||
const Flags &
|
||||
GetPermissions () const
|
||||
|
||||
OptionalBool
|
||||
GetWritable () const
|
||||
{
|
||||
return m_permissions;
|
||||
return m_write;
|
||||
}
|
||||
|
||||
OptionalBool
|
||||
GetExecutable () const
|
||||
{
|
||||
return m_execute;
|
||||
}
|
||||
|
||||
void
|
||||
SetPermissions (uint32_t permissions)
|
||||
SetReadable (OptionalBool val)
|
||||
{
|
||||
m_permissions.Reset(permissions);
|
||||
}
|
||||
|
||||
void
|
||||
AddPermissions (uint32_t permissions)
|
||||
{
|
||||
m_permissions.Set (permissions);
|
||||
m_read = val;
|
||||
}
|
||||
|
||||
void
|
||||
RemovePermissions (uint32_t permissions)
|
||||
SetWritable (OptionalBool val)
|
||||
{
|
||||
m_permissions.Clear (permissions);
|
||||
m_write = val;
|
||||
}
|
||||
|
||||
void
|
||||
SetExecutable (OptionalBool val)
|
||||
{
|
||||
m_execute = val;
|
||||
}
|
||||
|
||||
protected:
|
||||
RangeType m_range;
|
||||
Flags m_permissions; // Uses lldb::Permissions enumeration values logical OR'ed together
|
||||
OptionalBool m_read;
|
||||
OptionalBool m_write;
|
||||
OptionalBool m_execute;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -2558,17 +2572,56 @@ public:
|
|||
error.SetErrorString ("Process::GetMemoryRegionInfo() not supported");
|
||||
return error;
|
||||
}
|
||||
|
||||
virtual uint32_t
|
||||
GetLoadAddressPermissions (lldb::addr_t load_addr)
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Attempt to get the attributes for a region of memory in the process.
|
||||
///
|
||||
/// It may be possible for the remote debug server to inspect attributes
|
||||
/// for a region of memory in the process, such as whether there is a
|
||||
/// valid page of memory at a given address or whether that page is
|
||||
/// readable/writable/executable by the process.
|
||||
///
|
||||
/// @param[in] load_addr
|
||||
/// The address of interest in the process.
|
||||
///
|
||||
/// @param[out] permissions
|
||||
/// If this call returns successfully, this bitmask will have
|
||||
/// its Permissions bits set to indicate whether the region is
|
||||
/// readable/writable/executable. If this call fails, the
|
||||
/// bitmask values are undefined.
|
||||
///
|
||||
/// @return
|
||||
/// Returns true if it was able to determine the attributes of the
|
||||
/// memory region. False if not.
|
||||
//------------------------------------------------------------------
|
||||
|
||||
virtual bool
|
||||
GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions)
|
||||
{
|
||||
MemoryRegionInfo range_info;
|
||||
permissions = 0;
|
||||
Error error (GetMemoryRegionInfo (load_addr, range_info));
|
||||
if (error.Success())
|
||||
return range_info.GetPermissions().Get();
|
||||
return 0;
|
||||
if (!error.Success())
|
||||
return false;
|
||||
if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow
|
||||
|| range_info.GetWritable() == MemoryRegionInfo::eDontKnow
|
||||
|| range_info.GetExecutable() == MemoryRegionInfo::eDontKnow)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (range_info.GetReadable() == MemoryRegionInfo::eYes)
|
||||
permissions |= lldb::ePermissionsReadable;
|
||||
|
||||
if (range_info.GetWritable() == MemoryRegionInfo::eYes)
|
||||
permissions |= lldb::ePermissionsWritable;
|
||||
|
||||
if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
|
||||
permissions |= lldb::ePermissionsExecutable;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Determines whether executing JIT-compiled code in this process
|
||||
/// is possible.
|
||||
|
|
|
@ -562,8 +562,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
|
|||
UnwindPlanSP unwind_plan_sp;
|
||||
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
|
||||
UnwindPlanSP arch_default_unwind_plan_sp;
|
||||
|
||||
|
||||
|
||||
ABI *abi = m_thread.GetProcess().GetABI().get();
|
||||
if (abi)
|
||||
{
|
||||
|
@ -584,14 +583,22 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
|
|||
|
||||
// If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
|
||||
// in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
|
||||
if (behaves_like_zeroth_frame
|
||||
&& m_current_pc.IsValid()
|
||||
&& m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()) == 0)
|
||||
// Also, if this Process can report on memory region attributes, any non-executable region means
|
||||
// we jumped through a bad function pointer - handle the same way as 0x0.
|
||||
|
||||
if (behaves_like_zeroth_frame && m_current_pc.IsValid())
|
||||
{
|
||||
unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
|
||||
abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
|
||||
m_frame_type = eNormalFrame;
|
||||
return unwind_plan_sp;
|
||||
uint32_t permissions;
|
||||
addr_t current_pc_addr = m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget());
|
||||
if (current_pc_addr == 0
|
||||
|| (m_thread.GetProcess().GetLoadAddressPermissions(current_pc_addr, permissions)
|
||||
&& (permissions & ePermissionsExecutable) == 0))
|
||||
{
|
||||
unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
|
||||
abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
|
||||
m_frame_type = eNormalFrame;
|
||||
return unwind_plan_sp;
|
||||
}
|
||||
}
|
||||
|
||||
// No Module fm_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()or the current pc, try using the architecture default unwind.
|
||||
|
|
|
@ -1108,6 +1108,7 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
|
|||
std::string value;
|
||||
addr_t addr_value;
|
||||
bool success = true;
|
||||
bool saw_permissions = false;
|
||||
while (success && response.GetNameColonValue(name, value))
|
||||
{
|
||||
if (name.compare ("start") == 0)
|
||||
|
@ -1122,14 +1123,33 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
|
|||
if (success)
|
||||
region_info.GetRange().SetByteSize (addr_value);
|
||||
}
|
||||
else if (name.compare ("permissions") == 0)
|
||||
else if (name.compare ("permissions") == 0 && region_info.GetRange().IsValid())
|
||||
{
|
||||
if (value.find('r') != std::string::npos)
|
||||
region_info.AddPermissions (ePermissionsReadable);
|
||||
if (value.find('w') != std::string::npos)
|
||||
region_info.AddPermissions (ePermissionsWritable);
|
||||
if (value.find('x') != std::string::npos)
|
||||
region_info.AddPermissions (ePermissionsExecutable);
|
||||
saw_permissions = true;
|
||||
if (region_info.GetRange().Contains (addr))
|
||||
{
|
||||
if (value.find('r') != std::string::npos)
|
||||
region_info.SetReadable (MemoryRegionInfo::eYes);
|
||||
else
|
||||
region_info.SetReadable (MemoryRegionInfo::eNo);
|
||||
|
||||
if (value.find('w') != std::string::npos)
|
||||
region_info.SetWritable (MemoryRegionInfo::eYes);
|
||||
else
|
||||
region_info.SetWritable (MemoryRegionInfo::eNo);
|
||||
|
||||
if (value.find('x') != std::string::npos)
|
||||
region_info.SetExecutable (MemoryRegionInfo::eYes);
|
||||
else
|
||||
region_info.SetExecutable (MemoryRegionInfo::eNo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The reported region does not contain this address -- we're looking at an unmapped page
|
||||
region_info.SetReadable (MemoryRegionInfo::eNo);
|
||||
region_info.SetWritable (MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable (MemoryRegionInfo::eNo);
|
||||
}
|
||||
}
|
||||
else if (name.compare ("error") == 0)
|
||||
{
|
||||
|
@ -1141,6 +1161,14 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
|
|||
error.SetErrorString(value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// We got a valid address range back but no permissions -- which means this is an unmapped page
|
||||
if (region_info.GetRange().IsValid() && saw_permissions == false)
|
||||
{
|
||||
region_info.SetReadable (MemoryRegionInfo::eNo);
|
||||
region_info.SetWritable (MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable (MemoryRegionInfo::eNo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue