forked from OSchip/llvm-project
Add a call to "sync" a thread state before checkpointing registers in preparation for
calling functions. This is necessary on Mac OS X, since bad things can happen if you set the registers of a thread that's sitting in a kernel trap. <rdar://problem/11145013> llvm-svn: 160756
This commit is contained in:
parent
e8c6b15137
commit
279ceecf65
|
@ -59,6 +59,13 @@ public:
|
|||
virtual bool
|
||||
WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) = 0;
|
||||
|
||||
// These two functions are used to implement "push" and "pop" of register states. They are used primarily
|
||||
// for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then
|
||||
// restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues.
|
||||
// ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which
|
||||
// may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation,
|
||||
// so these API's should only be used when this behavior is needed.
|
||||
|
||||
virtual bool
|
||||
ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0;
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
|
|||
m_supports_watchpoint_support_info (eLazyBoolCalculate),
|
||||
m_watchpoints_trigger_after_instruction(eLazyBoolCalculate),
|
||||
m_attach_or_wait_reply(eLazyBoolCalculate),
|
||||
m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
|
||||
m_supports_qProcessInfoPID (true),
|
||||
m_supports_qfProcessInfo (true),
|
||||
m_supports_qUserName (true),
|
||||
|
@ -154,6 +155,26 @@ GDBRemoteCommunicationClient::GetVAttachOrWaitSupported ()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::GetSyncThreadStateSupported ()
|
||||
{
|
||||
if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate)
|
||||
{
|
||||
m_prepare_for_reg_writing_reply = eLazyBoolNo;
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
m_prepare_for_reg_writing_reply = eLazyBoolYes;
|
||||
}
|
||||
}
|
||||
if (m_prepare_for_reg_writing_reply == eLazyBoolYes)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GDBRemoteCommunicationClient::ResetDiscoverableSettings()
|
||||
|
@ -168,6 +189,8 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()
|
|||
m_qHostInfo_is_valid = eLazyBoolCalculate;
|
||||
m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
|
||||
m_supports_memory_region_info = eLazyBoolCalculate;
|
||||
m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
|
||||
m_attach_or_wait_reply = eLazyBoolCalculate;
|
||||
|
||||
m_supports_qProcessInfoPID = true;
|
||||
m_supports_qfProcessInfo = true;
|
||||
|
|
|
@ -224,6 +224,9 @@ public:
|
|||
bool
|
||||
GetVAttachOrWaitSupported ();
|
||||
|
||||
bool
|
||||
GetSyncThreadStateSupported();
|
||||
|
||||
void
|
||||
ResetDiscoverableSettings();
|
||||
|
||||
|
@ -369,6 +372,7 @@ protected:
|
|||
lldb_private::LazyBool m_supports_watchpoint_support_info;
|
||||
lldb_private::LazyBool m_watchpoints_trigger_after_instruction;
|
||||
lldb_private::LazyBool m_attach_or_wait_reply;
|
||||
lldb_private::LazyBool m_prepare_for_reg_writing_reply;
|
||||
|
||||
bool
|
||||
m_supports_qProcessInfoPID:1,
|
||||
|
|
|
@ -286,7 +286,6 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info,
|
||||
const RegisterValue &value)
|
||||
|
@ -326,6 +325,29 @@ GDBRemoteRegisterContext::SetPrimordialRegister(const lldb_private::RegisterInfo
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GDBRemoteRegisterContext::SyncThreadState(Process *process)
|
||||
{
|
||||
// NB. We assume our caller has locked the sequence mutex.
|
||||
|
||||
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *) process)->GetGDBRemote());
|
||||
if (!gdb_comm.GetSyncThreadStateSupported())
|
||||
return;
|
||||
|
||||
StreamString packet;
|
||||
StringExtractorGDBRemote response;
|
||||
packet.Printf ("QSyncThreadState:%4.4llx;", m_thread.GetID());
|
||||
if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
|
||||
packet.GetString().size(),
|
||||
response,
|
||||
false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
InvalidateAllRegisters();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset)
|
||||
{
|
||||
|
@ -479,6 +501,8 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
|
|||
Mutex::Locker locker;
|
||||
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers."))
|
||||
{
|
||||
SyncThreadState(process);
|
||||
|
||||
char packet[32];
|
||||
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
|
||||
ProcessSP process_sp (m_thread.GetProcess());
|
||||
|
|
|
@ -243,6 +243,9 @@ protected:
|
|||
void
|
||||
SetAllRegisterValid (bool b);
|
||||
|
||||
void
|
||||
SyncThreadState(lldb_private::Process *process); // Assumes the sequence mutex has already been acquired.
|
||||
|
||||
GDBRemoteDynamicRegisterInfo &m_reg_info;
|
||||
std::vector<bool> m_reg_valid;
|
||||
lldb_private::DataExtractor m_reg_data;
|
||||
|
|
|
@ -1797,6 +1797,19 @@ DNBProcessGetThreadAtIndex (nub_process_t pid, size_t thread_idx)
|
|||
return INVALID_NUB_THREAD;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Do whatever is needed to sync the thread's register state with it's kernel values.
|
||||
//----------------------------------------------------------------------
|
||||
nub_bool_t
|
||||
DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid)
|
||||
{
|
||||
MachProcessSP procSP;
|
||||
if (GetProcessSP (pid, procSP))
|
||||
return procSP->SyncThreadState (tid);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
nub_addr_t
|
||||
DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid)
|
||||
{
|
||||
|
|
|
@ -79,6 +79,7 @@ nub_size_t DNBProcessGetNumThreads (nub_process_t pid) DNB_
|
|||
nub_thread_t DNBProcessGetCurrentThread (nub_process_t pid) DNB_EXPORT;
|
||||
nub_thread_t DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
|
||||
nub_thread_t DNBProcessGetThreadAtIndex (nub_process_t pid, nub_size_t thread_idx) DNB_EXPORT;
|
||||
nub_bool_t DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
|
||||
nub_addr_t DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid) DNB_EXPORT;
|
||||
nub_bool_t DNBProcessSharedLibrariesUpdated (nub_process_t pid) DNB_EXPORT;
|
||||
nub_size_t DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos) DNB_EXPORT;
|
||||
|
|
|
@ -151,6 +151,22 @@ MachProcess::GetThreadAtIndex (nub_size_t thread_idx) const
|
|||
return m_thread_list.ThreadIDAtIndex(thread_idx);
|
||||
}
|
||||
|
||||
nub_bool_t
|
||||
MachProcess::SyncThreadState (nub_thread_t tid)
|
||||
{
|
||||
MachThreadSP thread_sp(m_thread_list.GetThreadByID(tid));
|
||||
if (!thread_sp)
|
||||
return false;
|
||||
kern_return_t kret = ::thread_abort_safely(thread_sp->ThreadID());
|
||||
DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (GetGPRState() for stop_count = %u)", thread_sp->ThreadID(), kret, thread_sp->Process()->StopCount());
|
||||
|
||||
if (kret == KERN_SUCCESS)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
nub_thread_t
|
||||
MachProcess::GetCurrentThread ()
|
||||
{
|
||||
|
|
|
@ -159,6 +159,7 @@ public:
|
|||
GetRegisterSetInfo (nub_thread_t tid, nub_size_t *num_reg_sets) const;
|
||||
bool GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value) const;
|
||||
bool SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value) const;
|
||||
nub_bool_t SyncThreadState (nub_thread_t tid);
|
||||
const char * ThreadGetName (nub_thread_t tid);
|
||||
nub_state_t ThreadGetState (nub_thread_t tid);
|
||||
nub_size_t GetNumThreads () const;
|
||||
|
|
|
@ -155,9 +155,6 @@ DNBArchImplX86_64::GetGPRState(bool force)
|
|||
{
|
||||
if (force || m_state.GetError(e_regSetGPR, Read))
|
||||
{
|
||||
kern_return_t kret = ::thread_abort_safely(m_thread->ThreadID());
|
||||
DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (GetGPRState() for stop_count = %u)", m_thread->ThreadID(), kret, m_thread->Process()->StopCount());
|
||||
|
||||
#if DEBUG_GPR_VALUES
|
||||
m_state.context.gpr.__rax = ('a' << 8) + 'x';
|
||||
m_state.context.gpr.__rbx = ('b' << 8) + 'x';
|
||||
|
|
|
@ -171,6 +171,7 @@ RNBRemote::CreatePacketTable ()
|
|||
t.push_back (Packet (query_shlib_notify_info_addr, &RNBRemote::HandlePacket_qShlibInfoAddr,NULL, "qShlibInfoAddr", "Returns the address that contains info needed for getting shared library notifications"));
|
||||
t.push_back (Packet (query_step_packet_supported, &RNBRemote::HandlePacket_qStepPacketSupported,NULL, "qStepPacketSupported", "Replys with OK if the 's' packet is supported."));
|
||||
t.push_back (Packet (query_vattachorwait_supported, &RNBRemote::HandlePacket_qVAttachOrWaitSupported,NULL, "qVAttachOrWaitSupported", "Replys with OK if the 'vAttachOrWait' packet is supported."));
|
||||
t.push_back (Packet (query_sync_thread_state_supported, &RNBRemote::HandlePacket_qSyncThreadStateSupported,NULL, "qSyncThreadStateSupported", "Replys with OK if the 'QSyncThreadState:' packet is supported."));
|
||||
t.push_back (Packet (query_host_info, &RNBRemote::HandlePacket_qHostInfo, NULL, "qHostInfo", "Replies with multiple 'key:value;' tuples appended to each other."));
|
||||
// t.push_back (Packet (query_symbol_lookup, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qSymbol", "Notify that host debugger is ready to do symbol lookups"));
|
||||
t.push_back (Packet (start_noack_mode, &RNBRemote::HandlePacket_QStartNoAckMode , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets"));
|
||||
|
@ -187,6 +188,7 @@ RNBRemote::CreatePacketTable ()
|
|||
t.push_back (Packet (set_stderr, &RNBRemote::HandlePacket_QSetSTDIO , NULL, "QSetSTDERR:", "Set the standard error for a process to be launched with the 'A' packet"));
|
||||
t.push_back (Packet (set_working_dir, &RNBRemote::HandlePacket_QSetWorkingDir , NULL, "QSetWorkingDir:", "Set the working directory for a process to be launched with the 'A' packet"));
|
||||
t.push_back (Packet (set_list_threads_in_stop_reply,&RNBRemote::HandlePacket_QListThreadsInStopReply , NULL, "QListThreadsInStopReply", "Set if the 'threads' key should be added to the stop reply packets with a list of all thread IDs."));
|
||||
t.push_back (Packet (sync_thread_state, &RNBRemote::HandlePacket_QSyncThreadState , NULL, "QSyncThreadState:", "Do whatever is necessary to make sure 'thread' is in a safe state to call functions on."));
|
||||
// t.push_back (Packet (pass_signals_to_inferior, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "QPassSignals:", "Specify which signals are passed to the inferior"));
|
||||
t.push_back (Packet (allocate_memory, &RNBRemote::HandlePacket_AllocateMemory, NULL, "_M", "Allocate memory in the inferior process."));
|
||||
t.push_back (Packet (deallocate_memory, &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m", "Deallocate memory in the inferior process."));
|
||||
|
@ -1303,6 +1305,13 @@ RNBRemote::HandlePacket_qStepPacketSupported (const char *p)
|
|||
return SendPacket("OK");
|
||||
}
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_qSyncThreadStateSupported (const char *p)
|
||||
{
|
||||
// We support attachOrWait meaning attach if the process exists, otherwise wait to attach.
|
||||
return SendPacket("OK");
|
||||
}
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_qVAttachOrWaitSupported (const char *p)
|
||||
{
|
||||
|
@ -1880,6 +1889,30 @@ RNBRemote::HandlePacket_QSetWorkingDir (const char *p)
|
|||
return SendPacket ("E60"); // Already had a process, too late to set working dir
|
||||
}
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_QSyncThreadState (const char *p)
|
||||
{
|
||||
if (!m_ctx.HasValidProcessID())
|
||||
{
|
||||
// We allow gdb to connect to a server that hasn't started running
|
||||
// the target yet. gdb still wants to ask questions about it and
|
||||
// freaks out if it gets an error. So just return OK here.
|
||||
return SendPacket ("OK");
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
p += strlen("QSyncThreadState:");
|
||||
nub_thread_t tid = strtoul (p, NULL, 16);
|
||||
if (errno != 0 && tid == 0)
|
||||
{
|
||||
return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid thread number in QSyncThreadState packet");
|
||||
}
|
||||
if (DNBProcessSyncThreadState(m_ctx.ProcessID(), tid))
|
||||
return SendPacket("OK");
|
||||
else
|
||||
return SendPacket ("E61");
|
||||
}
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_QListThreadsInStopReply (const char *p)
|
||||
{
|
||||
|
|
|
@ -93,6 +93,7 @@ public:
|
|||
query_shlib_notify_info_addr, // 'qShlibInfoAddr'
|
||||
query_step_packet_supported, // 'qStepPacketSupported'
|
||||
query_vattachorwait_supported, // 'qVAttachOrWaitSupported'
|
||||
query_sync_thread_state_supported,// 'QSyncThreadState'
|
||||
query_host_info, // 'qHostInfo'
|
||||
pass_signals_to_inferior, // 'QPassSignals'
|
||||
start_noack_mode, // 'QStartNoAckMode'
|
||||
|
@ -109,6 +110,7 @@ public:
|
|||
set_stderr, // 'QSetSTDERR:'
|
||||
set_working_dir, // 'QSetWorkingDir:'
|
||||
set_list_threads_in_stop_reply, // 'QListThreadsInStopReply:'
|
||||
sync_thread_state, // 'QSyncThreadState:'
|
||||
memory_region_info, // 'qMemoryRegionInfo:'
|
||||
watchpoint_support_info, // 'qWatchpointSupportInfo:'
|
||||
allocate_memory, // '_M'
|
||||
|
@ -167,6 +169,7 @@ public:
|
|||
rnb_err_t HandlePacket_qShlibInfoAddr (const char *p);
|
||||
rnb_err_t HandlePacket_qStepPacketSupported (const char *p);
|
||||
rnb_err_t HandlePacket_qVAttachOrWaitSupported (const char *p);
|
||||
rnb_err_t HandlePacket_qSyncThreadStateSupported (const char *p);
|
||||
rnb_err_t HandlePacket_qThreadInfo (const char *p);
|
||||
rnb_err_t HandlePacket_qThreadExtraInfo (const char *p);
|
||||
rnb_err_t HandlePacket_qThreadStopInfo (const char *p);
|
||||
|
@ -183,6 +186,7 @@ public:
|
|||
rnb_err_t HandlePacket_QEnvironmentHexEncoded (const char *p);
|
||||
rnb_err_t HandlePacket_QLaunchArch (const char *p);
|
||||
rnb_err_t HandlePacket_QListThreadsInStopReply (const char *p);
|
||||
rnb_err_t HandlePacket_QSyncThreadState (const char *p);
|
||||
rnb_err_t HandlePacket_QPrefixRegisterPacketsWithThreadID (const char *p);
|
||||
rnb_err_t HandlePacket_last_signal (const char *p);
|
||||
rnb_err_t HandlePacket_m (const char *p);
|
||||
|
|
Loading…
Reference in New Issue