diff options
author | Jason Molenda <jmolenda@apple.com> | 2011-12-13 05:39:38 +0000 |
---|---|---|
committer | Jason Molenda <jmolenda@apple.com> | 2011-12-13 05:39:38 +0000 |
commit | cb349ee19c8eccc65829e6739096aceb0ae09135 (patch) | |
tree | efd0b80136c2966805c616c7199d288f9dc01ee9 /lldb | |
parent | f43e681ed7170770abf9ea21a7ca3afefcd73b7b (diff) | |
download | bcm5719-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.txt | 12 | ||||
-rw-r--r-- | lldb/include/lldb/Target/Process.h | 109 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp | 25 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 42 |
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 { |