summaryrefslogtreecommitdiffstats
path: root/lldb
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>2011-12-13 05:39:38 +0000
committerJason Molenda <jmolenda@apple.com>2011-12-13 05:39:38 +0000
commitcb349ee19c8eccc65829e6739096aceb0ae09135 (patch)
treeefd0b80136c2966805c616c7199d288f9dc01ee9 /lldb
parentf43e681ed7170770abf9ea21a7ca3afefcd73b7b (diff)
downloadbcm5719-llvm-cb349ee19c8eccc65829e6739096aceb0ae09135.tar.gz
bcm5719-llvm-cb349ee19c8eccc65829e6739096aceb0ae09135.zip
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
Diffstat (limited to 'lldb')
-rw-r--r--lldb/docs/lldb-gdb-remote.txt12
-rw-r--r--lldb/include/lldb/Target/Process.h109
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp25
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp42
4 files changed, 144 insertions, 44 deletions
diff --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index 381d720164e..bfede67df70 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -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
//
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index a921c771824..843300d0692 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -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);
+ m_read = val;
}
-
+
void
- AddPermissions (uint32_t permissions)
+ SetWritable (OptionalBool val)
{
- m_permissions.Set (permissions);
+ m_write = val;
}
void
- RemovePermissions (uint32_t permissions)
+ SetExecutable (OptionalBool val)
{
- m_permissions.Clear (permissions);
+ 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.
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index 8eefb5e2ca8..fe1426913ab 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -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.
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 60234ac07bd..eaa03984f50 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -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
{
OpenPOWER on IntegriCloud