Skip to content

Commit cb349ee

Browse files
committed
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
1 parent f43e681 commit cb349ee

File tree

4 files changed

+144
-44
lines changed

4 files changed

+144
-44
lines changed

lldb/docs/lldb-gdb-remote.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,18 @@ tuples tp return are:
592592
// a hex encoded string value that
593593
// contains an error string
594594

595+
If the address requested is not in a mapped region (e.g. we've jumped through
596+
a NULL pointer and are at 0x0) currently lldb expects to get back the size
597+
of the unmapped region -- that is, the distance to the next valid region.
598+
For instance, with a Mac OS X process which has nothing mapped in the first
599+
4GB of its address space, if we're asking about address 0x2,
600+
601+
qMemoryRegionInfo:2
602+
start:2;size:fffffffe;
603+
604+
The lack of 'permissions:' indicates that none of read/write/execute are valid
605+
for this region.
606+
595607
//----------------------------------------------------------------------
596608
// Stop reply packet extensions
597609
//

lldb/include/lldb/Target/Process.h

Lines changed: 81 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,10 +1177,18 @@ class MemoryRegionInfo
11771177
{
11781178
public:
11791179
typedef Range<lldb::addr_t, lldb::addr_t> RangeType;
1180-
1180+
1181+
enum OptionalBool {
1182+
eDontKnow = -1,
1183+
eNo = 0,
1184+
eYes = 1
1185+
};
1186+
11811187
MemoryRegionInfo () :
11821188
m_range (),
1183-
m_permissions (0)
1189+
m_read (eDontKnow),
1190+
m_write (eDontKnow),
1191+
m_execute (eDontKnow)
11841192
{
11851193
}
11861194

@@ -1198,50 +1206,56 @@ class MemoryRegionInfo
11981206
Clear()
11991207
{
12001208
m_range.Clear();
1201-
m_permissions = 0;
1209+
m_read = m_write = m_execute = eDontKnow;
12021210
}
12031211

12041212
const RangeType &
12051213
GetRange() const
12061214
{
12071215
return m_range;
12081216
}
1209-
1210-
// Pass in a uint32_t permissions with one or more lldb::Permissions
1211-
// enumeration values logical OR'ed together.
1212-
bool
1213-
TestPermissions (uint32_t permissions) const
1217+
1218+
OptionalBool
1219+
GetReadable () const
12141220
{
1215-
return m_permissions.AllSet(permissions);
1221+
return m_read;
12161222
}
1217-
1218-
const Flags &
1219-
GetPermissions () const
1223+
1224+
OptionalBool
1225+
GetWritable () const
12201226
{
1221-
return m_permissions;
1227+
return m_write;
1228+
}
1229+
1230+
OptionalBool
1231+
GetExecutable () const
1232+
{
1233+
return m_execute;
12221234
}
12231235

12241236
void
1225-
SetPermissions (uint32_t permissions)
1237+
SetReadable (OptionalBool val)
12261238
{
1227-
m_permissions.Reset(permissions);
1239+
m_read = val;
12281240
}
1229-
1241+
12301242
void
1231-
AddPermissions (uint32_t permissions)
1243+
SetWritable (OptionalBool val)
12321244
{
1233-
m_permissions.Set (permissions);
1245+
m_write = val;
12341246
}
12351247

12361248
void
1237-
RemovePermissions (uint32_t permissions)
1249+
SetExecutable (OptionalBool val)
12381250
{
1239-
m_permissions.Clear (permissions);
1251+
m_execute = val;
12401252
}
12411253

12421254
protected:
12431255
RangeType m_range;
1244-
Flags m_permissions; // Uses lldb::Permissions enumeration values logical OR'ed together
1256+
OptionalBool m_read;
1257+
OptionalBool m_write;
1258+
OptionalBool m_execute;
12451259
};
12461260

12471261
//----------------------------------------------------------------------
@@ -2558,17 +2572,56 @@ friend class StopInfo;
25582572
error.SetErrorString ("Process::GetMemoryRegionInfo() not supported");
25592573
return error;
25602574
}
2561-
2562-
virtual uint32_t
2563-
GetLoadAddressPermissions (lldb::addr_t load_addr)
2575+
2576+
//------------------------------------------------------------------
2577+
/// Attempt to get the attributes for a region of memory in the process.
2578+
///
2579+
/// It may be possible for the remote debug server to inspect attributes
2580+
/// for a region of memory in the process, such as whether there is a
2581+
/// valid page of memory at a given address or whether that page is
2582+
/// readable/writable/executable by the process.
2583+
///
2584+
/// @param[in] load_addr
2585+
/// The address of interest in the process.
2586+
///
2587+
/// @param[out] permissions
2588+
/// If this call returns successfully, this bitmask will have
2589+
/// its Permissions bits set to indicate whether the region is
2590+
/// readable/writable/executable. If this call fails, the
2591+
/// bitmask values are undefined.
2592+
///
2593+
/// @return
2594+
/// Returns true if it was able to determine the attributes of the
2595+
/// memory region. False if not.
2596+
//------------------------------------------------------------------
2597+
2598+
virtual bool
2599+
GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions)
25642600
{
25652601
MemoryRegionInfo range_info;
2602+
permissions = 0;
25662603
Error error (GetMemoryRegionInfo (load_addr, range_info));
2567-
if (error.Success())
2568-
return range_info.GetPermissions().Get();
2569-
return 0;
2604+
if (!error.Success())
2605+
return false;
2606+
if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow
2607+
|| range_info.GetWritable() == MemoryRegionInfo::eDontKnow
2608+
|| range_info.GetExecutable() == MemoryRegionInfo::eDontKnow)
2609+
{
2610+
return false;
2611+
}
2612+
2613+
if (range_info.GetReadable() == MemoryRegionInfo::eYes)
2614+
permissions |= lldb::ePermissionsReadable;
2615+
2616+
if (range_info.GetWritable() == MemoryRegionInfo::eYes)
2617+
permissions |= lldb::ePermissionsWritable;
2618+
2619+
if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
2620+
permissions |= lldb::ePermissionsExecutable;
2621+
2622+
return true;
25702623
}
2571-
2624+
25722625
//------------------------------------------------------------------
25732626
/// Determines whether executing JIT-compiled code in this process
25742627
/// is possible.

lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
562562
UnwindPlanSP unwind_plan_sp;
563563
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
564564
UnwindPlanSP arch_default_unwind_plan_sp;
565-
566-
565+
567566
ABI *abi = m_thread.GetProcess().GetABI().get();
568567
if (abi)
569568
{
@@ -584,14 +583,22 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
584583

585584
// If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
586585
// in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
587-
if (behaves_like_zeroth_frame
588-
&& m_current_pc.IsValid()
589-
&& m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()) == 0)
586+
// Also, if this Process can report on memory region attributes, any non-executable region means
587+
// we jumped through a bad function pointer - handle the same way as 0x0.
588+
589+
if (behaves_like_zeroth_frame && m_current_pc.IsValid())
590590
{
591-
unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
592-
abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
593-
m_frame_type = eNormalFrame;
594-
return unwind_plan_sp;
591+
uint32_t permissions;
592+
addr_t current_pc_addr = m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget());
593+
if (current_pc_addr == 0
594+
|| (m_thread.GetProcess().GetLoadAddressPermissions(current_pc_addr, permissions)
595+
&& (permissions & ePermissionsExecutable) == 0))
596+
{
597+
unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
598+
abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
599+
m_frame_type = eNormalFrame;
600+
return unwind_plan_sp;
601+
}
595602
}
596603

597604
// No Module fm_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()or the current pc, try using the architecture default unwind.

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,7 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
11081108
std::string value;
11091109
addr_t addr_value;
11101110
bool success = true;
1111+
bool saw_permissions = false;
11111112
while (success && response.GetNameColonValue(name, value))
11121113
{
11131114
if (name.compare ("start") == 0)
@@ -1122,14 +1123,33 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
11221123
if (success)
11231124
region_info.GetRange().SetByteSize (addr_value);
11241125
}
1125-
else if (name.compare ("permissions") == 0)
1126+
else if (name.compare ("permissions") == 0 && region_info.GetRange().IsValid())
11261127
{
1127-
if (value.find('r') != std::string::npos)
1128-
region_info.AddPermissions (ePermissionsReadable);
1129-
if (value.find('w') != std::string::npos)
1130-
region_info.AddPermissions (ePermissionsWritable);
1131-
if (value.find('x') != std::string::npos)
1132-
region_info.AddPermissions (ePermissionsExecutable);
1128+
saw_permissions = true;
1129+
if (region_info.GetRange().Contains (addr))
1130+
{
1131+
if (value.find('r') != std::string::npos)
1132+
region_info.SetReadable (MemoryRegionInfo::eYes);
1133+
else
1134+
region_info.SetReadable (MemoryRegionInfo::eNo);
1135+
1136+
if (value.find('w') != std::string::npos)
1137+
region_info.SetWritable (MemoryRegionInfo::eYes);
1138+
else
1139+
region_info.SetWritable (MemoryRegionInfo::eNo);
1140+
1141+
if (value.find('x') != std::string::npos)
1142+
region_info.SetExecutable (MemoryRegionInfo::eYes);
1143+
else
1144+
region_info.SetExecutable (MemoryRegionInfo::eNo);
1145+
}
1146+
else
1147+
{
1148+
// The reported region does not contain this address -- we're looking at an unmapped page
1149+
region_info.SetReadable (MemoryRegionInfo::eNo);
1150+
region_info.SetWritable (MemoryRegionInfo::eNo);
1151+
region_info.SetExecutable (MemoryRegionInfo::eNo);
1152+
}
11331153
}
11341154
else if (name.compare ("error") == 0)
11351155
{
@@ -1141,6 +1161,14 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
11411161
error.SetErrorString(value.c_str());
11421162
}
11431163
}
1164+
1165+
// We got a valid address range back but no permissions -- which means this is an unmapped page
1166+
if (region_info.GetRange().IsValid() && saw_permissions == false)
1167+
{
1168+
region_info.SetReadable (MemoryRegionInfo::eNo);
1169+
region_info.SetWritable (MemoryRegionInfo::eNo);
1170+
region_info.SetExecutable (MemoryRegionInfo::eNo);
1171+
}
11441172
}
11451173
else
11461174
{

0 commit comments

Comments
 (0)