Added optional calls to lldb_private::Process for getting memory region info

from a process and hooked it up to the new packet that was recently added
to our GDB remote executable named debugserver. Now Process has the following
new calls:

virtual Error
Process::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info);

virtual uint32_t
GetLoadAddressPermissions (lldb::addr_t load_addr);

Only the first one needs to be implemented by subclasses that can add this
support.

Cleaned up the way the new packet was implemented in debugserver to be more
useful as an API inside debugserver. Also found an error where finding a region
for an address actually will pick up the next region that follows the address
in the query so we also need ot make sure that the address we requested the
region for falls into the region that gets returned.

llvm-svn: 144976
This commit is contained in:
Greg Clayton 2011-11-18 07:03:08 +00:00
parent 7ba18027e9
commit 46fb558df1
17 changed files with 291 additions and 55 deletions

View File

@ -27,6 +27,7 @@
#include "lldb/Core/Communication.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Core/StringList.h"
#include "lldb/Core/ThreadSafeValue.h"
#include "lldb/Core/PluginInterface.h"
@ -1171,6 +1172,77 @@ inline bool operator!= (const ProcessModID &lhs, const ProcessModID &rhs)
else
return false;
}
class MemoryRegionInfo
{
public:
typedef Range<lldb::addr_t, lldb::addr_t> RangeType;
MemoryRegionInfo () :
m_range (),
m_permissions (0)
{
}
~MemoryRegionInfo ()
{
}
RangeType &
GetRange()
{
return m_range;
}
void
Clear()
{
m_range.Clear();
m_permissions = 0;
}
const RangeType &
GetRange() const
{
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
{
return m_permissions.AllSet(permissions);
}
const Flags &
GetPermissions () const
{
return m_permissions;
}
void
SetPermissions (uint32_t permissions)
{
m_permissions.Reset(permissions);
}
void
AddPermissions (uint32_t permissions)
{
m_permissions.Set (permissions);
}
void
RemovePermissions (uint32_t permissions)
{
m_permissions.Clear (permissions);
}
protected:
RangeType m_range;
Flags m_permissions; // Uses lldb::Permissions enumeration values logical OR'ed together
};
//----------------------------------------------------------------------
/// @class Process Process.h "lldb/Target/Process.h"
@ -2478,6 +2550,25 @@ public:
lldb::addr_t
AllocateMemory (size_t size, uint32_t permissions, Error &error);
virtual Error
GetMemoryRegionInfo (lldb::addr_t load_addr,
MemoryRegionInfo &range_info)
{
Error error;
error.SetErrorString ("Process::GetMemoryRegionInfo() not supported");
return error;
}
virtual uint32_t
GetLoadAddressPermissions (lldb::addr_t load_addr)
{
MemoryRegionInfo range_info;
Error error (GetMemoryRegionInfo (load_addr, range_info));
if (error.Success())
return range_info.GetPermissions().Get();
return 0;
}
//------------------------------------------------------------------
/// Determines whether executing JIT-compiled code in this process
/// is possible.

View File

@ -46,6 +46,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_vCont_S (eLazyBoolCalculate),
m_qHostInfo_is_valid (eLazyBoolCalculate),
m_supports_alloc_dealloc_memory (eLazyBoolCalculate),
m_supports_memory_region_info (eLazyBoolCalculate),
m_supports_qProcessInfoPID (true),
m_supports_qfProcessInfo (true),
m_supports_qUserName (true),
@ -123,6 +124,7 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()
m_supports_vCont_S = eLazyBoolCalculate;
m_qHostInfo_is_valid = eLazyBoolCalculate;
m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
m_supports_memory_region_info = eLazyBoolCalculate;
m_supports_qProcessInfoPID = true;
m_supports_qfProcessInfo = true;
@ -1086,6 +1088,77 @@ GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr)
return false;
}
Error
GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
lldb_private::MemoryRegionInfo &region_info)
{
Error error;
region_info.Clear();
if (m_supports_memory_region_info != eLazyBoolNo)
{
m_supports_memory_region_info = eLazyBoolYes;
char packet[64];
const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%llx", (uint64_t)addr);
assert (packet_len < sizeof(packet));
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
{
std::string name;
std::string value;
addr_t addr_value;
bool success = true;
while (success && response.GetNameColonValue(name, value))
{
if (name.compare ("start") == 0)
{
addr_value = Args::StringToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16, &success);
if (success)
region_info.GetRange().SetRangeBase(addr_value);
}
else if (name.compare ("size") == 0)
{
addr_value = Args::StringToUInt64(value.c_str(), 0, 16, &success);
if (success)
region_info.GetRange().SetByteSize (addr_value);
}
else if (name.compare ("permissions") == 0)
{
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);
}
else if (name.compare ("error") == 0)
{
StringExtractorGDBRemote name_extractor;
// Swap "value" over into "name_extractor"
name_extractor.GetStringRef().swap(value);
// Now convert the HEX bytes into a string value
name_extractor.GetHexByteString (value);
error.SetErrorString(value.c_str());
}
}
}
else
{
m_supports_memory_region_info = eLazyBoolNo;
}
}
if (m_supports_memory_region_info == eLazyBoolNo)
{
error.SetErrorString("qMemoryRegionInfo is not supported");
}
if (error.Fail())
region_info.Clear();
return error;
}
int
GDBRemoteCommunicationClient::SetSTDIN (char const *path)
{

View File

@ -17,6 +17,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ArchSpec.h"
#include "lldb/Target/Process.h"
#include "GDBRemoteCommunication.h"
@ -196,6 +197,10 @@ public:
bool
DeallocateMemory (lldb::addr_t addr);
lldb_private::Error
GetMemoryRegionInfo (lldb::addr_t addr,
lldb_private::MemoryRegionInfo &range_info);
const lldb_private::ArchSpec &
GetHostArchitecture ();
@ -332,6 +337,7 @@ protected:
lldb_private::LazyBool m_supports_vCont_S;
lldb_private::LazyBool m_qHostInfo_is_valid;
lldb_private::LazyBool m_supports_alloc_dealloc_memory;
lldb_private::LazyBool m_supports_memory_region_info;
bool
m_supports_qProcessInfoPID:1,

View File

@ -1703,6 +1703,15 @@ ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &er
return allocated_addr;
}
Error
ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr,
MemoryRegionInfo &region_info)
{
Error error (m_gdb_comm.GetMemoryRegionInfo (load_addr, region_info));
return error;
}
Error
ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr)
{

View File

@ -166,6 +166,10 @@ public:
virtual lldb::addr_t
DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error);
virtual lldb_private::Error
GetMemoryRegionInfo (lldb::addr_t load_addr,
lldb_private::MemoryRegionInfo &region_info);
virtual lldb_private::Error
DoDeallocateMemory (lldb::addr_t ptr);

View File

@ -1139,13 +1139,12 @@ DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr)
//
//----------------------------------------------------------------------
int
DNBMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, char *outbuf, nub_size_t outbufsize)
DNBMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info)
{
MachProcessSP procSP;
if (GetProcessSP (pid, procSP))
{
return procSP->MemoryRegionInfo(addr, outbuf, outbufsize);
}
return procSP->Task().GetMemoryRegionInfo (addr, region_info);
return -1;
}

View File

@ -66,7 +66,7 @@ nub_size_t DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub
nub_size_t DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) DNB_EXPORT;
nub_addr_t DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions) DNB_EXPORT;
nub_bool_t DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) DNB_EXPORT;
int DNBMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, char *outbuf, nub_size_t outbufsize);
int DNBMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info) DNB_EXPORT;
//----------------------------------------------------------------------
// Process status

View File

@ -333,6 +333,13 @@ struct DNBExecutableImageInfo
DNBSegment *segments; // Array of contiguous memory segments in executable
};
struct DNBRegionInfo
{
nub_addr_t addr;
nub_addr_t size;
uint32_t permissions;
};
typedef nub_bool_t (*DNBCallbackBreakpointHit)(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton);
typedef nub_addr_t (*DNBCallbackNameToAddress)(nub_process_t pid, const char *name, const char *shlib_regex, void *baton);
typedef nub_size_t (*DNBCallbackCopyExecutableImageInfos)(nub_process_t pid, struct DNBExecutableImageInfo **image_infos, nub_bool_t only_changed, void *baton);

View File

@ -603,12 +603,6 @@ MachProcess::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf)
return bytes_written;
}
int
MachProcess::MemoryRegionInfo(nub_addr_t address, char *outbuf, nub_size_t outbufsize)
{
return m_task.MemoryRegionInfo (address, outbuf, outbufsize);
}
void
MachProcess::ReplyToAllExceptions ()
{

View File

@ -99,7 +99,6 @@ public:
bool Detach ();
nub_size_t ReadMemory (nub_addr_t addr, nub_size_t size, void *buf);
nub_size_t WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf);
int MemoryRegionInfo(nub_addr_t address, char *outbuf, nub_size_t outbufsize);
//----------------------------------------------------------------------
// Path and arg accessors

View File

@ -208,14 +208,19 @@ MachTask::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf)
// MachTask::MemoryRegionInfo
//----------------------------------------------------------------------
int
MachTask::MemoryRegionInfo (nub_addr_t addr, char *outbuf, nub_size_t outbufsize)
MachTask::GetMemoryRegionInfo (nub_addr_t addr, DNBRegionInfo *region_info)
{
task_t task = TaskPort();
if (task == TASK_NULL)
return -1;
int ret = m_vm_memory.MemoryRegionInfo(task, addr, outbuf, outbufsize);
DNBLogThreadedIf(LOG_MEMORY, "MachTask::MemoryRegionInfo ( addr = 0x%8.8llx ) => %d", (uint64_t)addr, ret);
int ret = m_vm_memory.GetMemoryRegionInfo(task, addr, region_info);
DNBLogThreadedIf(LOG_MEMORY, "MachTask::MemoryRegionInfo ( addr = 0x%8.8llx ) => %i (start = 0x%8.8llx, size = 0x%8.8llx, permissions = %u)",
(uint64_t)addr,
ret,
(uint64_t)region_info->addr,
(uint64_t)region_info->size,
region_info->permissions);
return ret;
}

View File

@ -64,7 +64,7 @@ public:
nub_size_t ReadMemory (nub_addr_t addr, nub_size_t size, void *buf);
nub_size_t WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf);
int MemoryRegionInfo (nub_addr_t addr, char *outbuf, nub_size_t outbufsize);
int GetMemoryRegionInfo (nub_addr_t addr, DNBRegionInfo *region_info);
nub_addr_t AllocateMemory (nub_size_t size, uint32_t permissions);
nub_bool_t DeallocateMemory (nub_addr_t addr);

View File

@ -53,15 +53,21 @@ MachVMMemory::MaxBytesLeftInPage(nub_addr_t addr, nub_size_t count)
}
int
MachVMMemory::MemoryRegionInfo(task_t task, nub_addr_t address, char *outbuf, nub_size_t outbufsize)
MachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info)
{
MachVMRegion vmRegion(task);
outbuf[0] = '\0';
if (vmRegion.GetRegionForAddress(address) && vmRegion.GetRegionDescription(outbuf, outbufsize))
if (vmRegion.GetRegionForAddress(address))
{
region_info->addr = vmRegion.StartAddress();
region_info->size = vmRegion.GetByteSize();
region_info->permissions = vmRegion.GetDNBPermissions();
return 1;
else
return 0;
}
region_info->addr = 0;
region_info->size = 0;
region_info->permissions = 0;
return 0;
}
nub_size_t

View File

@ -27,7 +27,7 @@ public:
nub_size_t Read(task_t task, nub_addr_t address, void *data, nub_size_t data_count);
nub_size_t Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count);
nub_size_t PageSize();
int MemoryRegionInfo(task_t task, nub_addr_t address, char *outbuf, nub_size_t outbufsize);
int GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info);
protected:
nub_size_t MaxBytesLeftInPage(nub_addr_t addr, nub_size_t count);

View File

@ -134,7 +134,21 @@ MachVMRegion::GetRegionForAddress(nub_addr_t addr)
mach_msg_type_number_t info_size = kRegionInfoSize;
assert(sizeof(info_size) == 4);
m_err = ::mach_vm_region_recurse (m_task, &m_start, &m_size, &m_depth, (vm_region_recurse_info_t)&m_data, &info_size);
if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail())
const bool log_protections = DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS);
if (m_err.Success())
{
if ((addr < m_start) || (addr >= (m_start + m_size)))
{
m_err.SetErrorString("no region for address");
m_err.SetError(-1, DNBError::Generic);
if (log_protections)
m_err.LogThreaded("::mach_vm_region_recurse ( task = 0x%4.4x, address => 0x%8.8llx, size => %llu, nesting_depth => %d, info => %p, infoCnt => %d) addr = 0x%8.8llx not in range [0x%8.8llx - 0x%8.8llx)",
m_task, (uint64_t)m_start, (uint64_t)m_size, m_depth, &m_data, info_size, (uint64_t)addr, (uint64_t)m_start, (uint64_t)m_start + m_size);
return false;
}
}
if (log_protections || m_err.Fail())
m_err.LogThreaded("::mach_vm_region_recurse ( task = 0x%4.4x, address => 0x%8.8llx, size => %llu, nesting_depth => %d, info => %p, infoCnt => %d) addr = 0x%8.8llx ", m_task, (uint64_t)m_start, (uint64_t)m_size, m_depth, &m_data, info_size, (uint64_t)addr);
if (m_err.Fail())
{
@ -142,7 +156,7 @@ MachVMRegion::GetRegionForAddress(nub_addr_t addr)
}
else
{
if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS))
if (log_protections)
{
DNBLogThreaded("info = { prot = %u, "
"max_prot = %u, "
@ -178,26 +192,18 @@ MachVMRegion::GetRegionForAddress(nub_addr_t addr)
return true;
}
bool
MachVMRegion::GetRegionDescription (char *outbuf, nub_size_t outbufsize)
uint32_t
MachVMRegion::GetDNBPermissions () const
{
if (m_addr == INVALID_NUB_ADDRESS || m_start == INVALID_NUB_ADDRESS || m_size == 0)
return false;
snprintf (outbuf, outbufsize, "start:%llx,size:%llx", m_start, m_size);
outbuf[outbufsize - 1] = '\0';
char tmpbuf[128];
strcpy (tmpbuf, ",permissions:");
if ((m_data.protection & VM_PROT_READ) == VM_PROT_READ)
strcat (tmpbuf, "r");
if ((m_data.protection & VM_PROT_WRITE) == VM_PROT_WRITE)
strcat (tmpbuf, "w");
if ((m_data.protection & VM_PROT_EXECUTE) == VM_PROT_EXECUTE)
strcat (tmpbuf, "x");
strlcat (outbuf, tmpbuf, outbufsize);
// It would be nice if we could figure out whether the memory region is stack memory or jitted code memory as well
outbuf[outbufsize - 1] = '\0';
return true;
if (m_addr == INVALID_NUB_ADDRESS || m_start == INVALID_NUB_ADDRESS || m_size == 0)
return 0;
uint32_t dnb_permissions = 0;
if ((m_data.protection & VM_PROT_READ) == VM_PROT_READ)
dnb_permissions |= eMemoryPermissionsReadable;
if ((m_data.protection & VM_PROT_WRITE) == VM_PROT_WRITE)
dnb_permissions |= eMemoryPermissionsWritable;
if ((m_data.protection & VM_PROT_EXECUTE) == VM_PROT_EXECUTE)
dnb_permissions |= eMemoryPermissionsExecutable;
return dnb_permissions;
}

View File

@ -27,6 +27,7 @@ public:
void Clear();
mach_vm_address_t StartAddress() const { return m_start; }
mach_vm_address_t EndAddress() const { return m_start + m_size; }
mach_vm_size_t GetByteSize () const { return m_size; }
mach_vm_address_t BytesRemaining(mach_vm_address_t addr) const
{
if (ContainsAddress(addr))
@ -43,7 +44,8 @@ public:
bool RestoreProtections();
bool GetRegionForAddress(nub_addr_t addr);
bool GetRegionDescription (char *outbuf, nub_size_t outbufsize);
uint32_t
GetDNBPermissions () const;
protected:
#if defined (VM_REGION_SUBMAP_SHORT_INFO_COUNT_64)

View File

@ -3282,16 +3282,51 @@ RNBRemote::HandlePacket_MemoryRegionInfo (const char *p)
return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid address in qMemoryRegionInfo packet");
}
char retbuf[1024];
DNBRegionInfo region_info = { 0, 0, 0 };
int ret = DNBMemoryRegionInfo (m_ctx.ProcessID(), address, &region_info);
std::ostringstream ostrm;
int ret = DNBMemoryRegionInfo (m_ctx.ProcessID(), address, retbuf, sizeof (retbuf));
retbuf[sizeof (retbuf) - 1] = '\0';
if (ret == 1)
return SendPacket (retbuf);
if (ret == 0)
return SendPacket ("error:address in unmapped region");
if (ret == -1)
return SendPacket ("error:region lookup cannot be performed");
if (ret == 1 && region_info.size > 0)
{
// start:3a50000,size:100000,permissions:rwx
ostrm << "start:" << std::hex << region_info.addr << ';'
<< "size:" << std::hex << region_info.size << ';';
if (region_info.permissions)
{
ostrm << "permissions:";
if (region_info.permissions & eMemoryPermissionsReadable)
ostrm << 'r';
if (region_info.permissions & eMemoryPermissionsWritable)
ostrm << 'w';
if (region_info.permissions & eMemoryPermissionsExecutable)
ostrm << 'x';
ostrm << ';';
}
return SendPacket (ostrm.str());
}
else
{
ostrm << std::hex << "error:";
const char *error_message = NULL;
if (ret == -1)
{
error_message = "region lookup cannot be performed";
}
else
{
error_message = "address in unmapped region";
}
// hex encode the error message so we can send any characters we want in
// the future since this is text
const int error_message_len = strlen (error_message);
const uint8_t *u_error_message = (const uint8_t *)error_message;
for (int i = 0; i < error_message_len; i++)
ostrm << RAWHEX8(u_error_message[i]);
ostrm << ';';
return SendPacket (ostrm.str());
}
return SendPacket ("E68");
}