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
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index 8eefb5e..fe14269 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -562,8 +562,7 @@
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 @@
// 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.
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 60234ac..eaa0398 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1108,6 +1108,7 @@
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 @@
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 @@
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
{