summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp349
1 files changed, 203 insertions, 146 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 94dac0c2d4e..b866766dec6 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -376,7 +376,8 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
m_async_broadcaster (NULL, "lldb.process.gdb-remote.async-broadcaster"),
m_async_thread_state_mutex(Mutex::eMutexTypeRecursive),
m_thread_ids (),
- m_threads_info_sp (),
+ m_jstopinfo_sp (),
+ m_jthreadsinfo_sp (),
m_continue_c_tids (),
m_continue_C_tids (),
m_continue_s_tids (),
@@ -792,7 +793,7 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
}
const StateType state = SetThreadStopInfo (response);
- if (state == eStateStopped)
+ if (state != eStateInvalid)
{
SetPrivateState (state);
}
@@ -1397,7 +1398,8 @@ ProcessGDBRemote::WillResume ()
m_continue_C_tids.clear();
m_continue_s_tids.clear();
m_continue_S_tids.clear();
- m_threads_info_sp.reset();
+ m_jstopinfo_sp.reset();
+ m_jthreadsinfo_sp.reset();
return Error();
}
@@ -1717,10 +1719,10 @@ ProcessGDBRemote::UpdateThreadIDList ()
{
Mutex::Locker locker(m_thread_list_real.GetMutex());
- if (m_threads_info_sp)
+ if (m_jthreadsinfo_sp)
{
// If we have the JSON threads info, we can get the thread list from that
- StructuredData::Array *thread_infos = m_threads_info_sp->GetAsArray();
+ StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray();
if (thread_infos && thread_infos->GetSize() > 0)
{
m_thread_ids.clear();
@@ -1841,13 +1843,14 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new
return true;
}
+
bool
-ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread)
+ProcessGDBRemote::GetThreadStopInfoFromJSON (ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp)
{
// See if we got thread stop infos for all threads via the "jThreadsInfo" packet
- if (m_threads_info_sp)
+ if (thread_infos_sp)
{
- StructuredData::Array *thread_infos = m_threads_info_sp->GetAsArray();
+ StructuredData::Array *thread_infos = thread_infos_sp->GetAsArray();
if (thread_infos)
{
lldb::tid_t tid;
@@ -1860,12 +1863,36 @@ ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread)
if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid, LLDB_INVALID_THREAD_ID))
{
if (tid == thread->GetID())
- return SetThreadStopInfo(thread_dict);
+ return (bool)SetThreadStopInfo(thread_dict);
}
}
}
}
}
+ return false;
+}
+
+bool
+ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread)
+{
+ // See if we got thread stop infos for all threads via the "jThreadsInfo" packet
+ if (GetThreadStopInfoFromJSON (thread, m_jthreadsinfo_sp))
+ return true;
+
+ // See if we got thread stop info for any threads valid stop info reasons threads
+ // via the "jstopinfo" packet stop reply packet key/value pair?
+ if (m_jstopinfo_sp)
+ {
+ // If we have "jstopinfo" then we have stop descriptions for all threads
+ // that have stop reasons, and if there is no entry for a thread, then
+ // it has no stop reason.
+ thread->GetRegisterContext()->InvalidateIfNeeded(true);
+ if (!GetThreadStopInfoFromJSON (thread, m_jstopinfo_sp))
+ {
+ thread->SetStopInfo (StopInfoSP());
+ }
+ return true;
+ }
// Fall back to using the qThreadStopInfo packet
StringExtractorGDBRemote stop_packet;
@@ -1921,8 +1948,6 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
gdb_thread->PrivateSetRegisterValue (pair.first, reg_value_extractor);
}
- // Clear the stop info just in case we don't set it to anything
- thread_sp->SetStopInfo (StopInfoSP());
thread_sp->SetName (thread_name.empty() ? NULL : thread_name.c_str());
gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr);
@@ -1932,144 +1957,149 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
else
gdb_thread->ClearQueueInfo();
-
- if (exc_type != 0)
- {
- const size_t exc_data_size = exc_data.size();
-
- thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp,
- exc_type,
- exc_data_size,
- exc_data_size >= 1 ? exc_data[0] : 0,
- exc_data_size >= 2 ? exc_data[1] : 0,
- exc_data_size >= 3 ? exc_data[2] : 0));
- }
- else
+ // Make sure we update our thread stop reason just once
+ if (!thread_sp->StopInfoIsUpToDate())
{
- bool handled = false;
- bool did_exec = false;
- if (!reason.empty())
+ thread_sp->SetStopInfo (StopInfoSP());
+
+ if (exc_type != 0)
{
- if (reason.compare("trace") == 0)
- {
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
- handled = true;
- }
- else if (reason.compare("breakpoint") == 0)
+ const size_t exc_data_size = exc_data.size();
+
+ thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp,
+ exc_type,
+ exc_data_size,
+ exc_data_size >= 1 ? exc_data[0] : 0,
+ exc_data_size >= 2 ? exc_data[1] : 0,
+ exc_data_size >= 3 ? exc_data[2] : 0));
+ }
+ else
+ {
+ bool handled = false;
+ bool did_exec = false;
+ if (!reason.empty())
{
- addr_t pc = thread_sp->GetRegisterContext()->GetPC();
- lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
- if (bp_site_sp)
+ if (reason.compare("trace") == 0)
{
- // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
- // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
- // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
handled = true;
- if (bp_site_sp->ValidForThisThread (thread_sp.get()))
- {
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
- }
- else
+ }
+ else if (reason.compare("breakpoint") == 0)
+ {
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp)
{
- StopInfoSP invalid_stop_info_sp;
- thread_sp->SetStopInfo (invalid_stop_info_sp);
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ handled = true;
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
}
}
- }
- else if (reason.compare("trap") == 0)
- {
- // Let the trap just use the standard signal stop reason below...
- }
- else if (reason.compare("watchpoint") == 0)
- {
- StringExtractor desc_extractor(description.c_str());
- addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
- uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32);
- watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
- if (wp_addr != LLDB_INVALID_ADDRESS)
+ else if (reason.compare("trap") == 0)
+ {
+ // Let the trap just use the standard signal stop reason below...
+ }
+ else if (reason.compare("watchpoint") == 0)
{
- WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
- if (wp_sp)
+ StringExtractor desc_extractor(description.c_str());
+ addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
+ uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32);
+ watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
+ if (wp_addr != LLDB_INVALID_ADDRESS)
+ {
+ WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
+ if (wp_sp)
+ {
+ wp_sp->SetHardwareIndex(wp_index);
+ watch_id = wp_sp->GetID();
+ }
+ }
+ if (watch_id == LLDB_INVALID_WATCH_ID)
{
- wp_sp->SetHardwareIndex(wp_index);
- watch_id = wp_sp->GetID();
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS));
+ if (log) log->Printf ("failed to find watchpoint");
}
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id));
+ handled = true;
}
- if (watch_id == LLDB_INVALID_WATCH_ID)
+ else if (reason.compare("exception") == 0)
{
- Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS));
- if (log) log->Printf ("failed to find watchpoint");
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str()));
+ handled = true;
+ }
+ else if (reason.compare("exec") == 0)
+ {
+ did_exec = true;
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp));
+ handled = true;
}
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id));
- handled = true;
- }
- else if (reason.compare("exception") == 0)
- {
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str()));
- handled = true;
- }
- else if (reason.compare("exec") == 0)
- {
- did_exec = true;
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp));
- handled = true;
}
- }
- if (!handled && signo && did_exec == false)
- {
- if (signo == SIGTRAP)
+ if (!handled && signo && did_exec == false)
{
- // Currently we are going to assume SIGTRAP means we are either
- // hitting a breakpoint or hardware single stepping.
- handled = true;
- addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset;
- lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
-
- if (bp_site_sp)
+ if (signo == SIGTRAP)
{
- // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
- // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
- // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
- if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ // Currently we are going to assume SIGTRAP means we are either
+ // hitting a breakpoint or hardware single stepping.
+ handled = true;
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset;
+ lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+
+ if (bp_site_sp)
{
- if(m_breakpoint_pc_offset != 0)
- thread_sp->GetRegisterContext()->SetPC(pc);
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ if(m_breakpoint_pc_offset != 0)
+ thread_sp->GetRegisterContext()->SetPC(pc);
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
}
else
{
- StopInfoSP invalid_stop_info_sp;
- thread_sp->SetStopInfo (invalid_stop_info_sp);
+ // If we were stepping then assume the stop was the result of the trace. If we were
+ // not stepping then report the SIGTRAP.
+ // FIXME: We are still missing the case where we single step over a trap instruction.
+ if (thread_sp->GetTemporaryResumeState() == eStateStepping)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
+ else
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo, description.c_str()));
}
}
- else
- {
- // If we were stepping then assume the stop was the result of the trace. If we were
- // not stepping then report the SIGTRAP.
- // FIXME: We are still missing the case where we single step over a trap instruction.
- if (thread_sp->GetTemporaryResumeState() == eStateStepping)
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
- else
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo, description.c_str()));
- }
+ if (!handled)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo, description.c_str()));
}
- if (!handled)
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo, description.c_str()));
- }
- if (!description.empty())
- {
- lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
- if (stop_info_sp)
- {
- const char *stop_info_desc = stop_info_sp->GetDescription();
- if (!stop_info_desc || !stop_info_desc[0])
- stop_info_sp->SetDescription (description.c_str());
- }
- else
+ if (!description.empty())
{
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str()));
+ lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
+ if (stop_info_sp)
+ {
+ const char *stop_info_desc = stop_info_sp->GetDescription();
+ if (!stop_info_desc || !stop_info_desc[0])
+ stop_info_sp->SetDescription (description.c_str());
+ }
+ else
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str()));
+ }
}
}
}
@@ -2078,7 +2108,7 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
return thread_sp;
}
-StateType
+lldb::ThreadSP
ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
{
static ConstString g_key_tid("tid");
@@ -2245,21 +2275,19 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
return true; // Keep iterating through all dictionary key/value pairs
});
- SetThreadStopInfo (tid,
- expedited_register_map,
- signo,
- thread_name,
- reason,
- description,
- exc_type,
- exc_data,
- thread_dispatch_qaddr,
- queue_vars_valid,
- queue_name,
- queue_kind,
- queue_serial);
-
- return eStateExited;
+ return SetThreadStopInfo (tid,
+ expedited_register_map,
+ signo,
+ thread_name,
+ reason,
+ description,
+ exc_type,
+ exc_data,
+ thread_dispatch_qaddr,
+ queue_vars_valid,
+ queue_name,
+ queue_kind,
+ queue_serial);
}
StateType
@@ -2345,7 +2373,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
if (tid != LLDB_INVALID_THREAD_ID)
m_thread_ids.push_back (tid);
}
- else if (key.compare("jthreads") == 0)
+ else if (key.compare("jstopinfo") == 0)
{
StringExtractor json_extractor;
// Swap "value" over into "name_extractor"
@@ -2355,7 +2383,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
// This JSON contains thread IDs and thread stop info for all threads.
// It doesn't contain expedited registers, memory or queue info.
- m_threads_info_sp = StructuredData::ParseJSON (value);
+ m_jstopinfo_sp = StructuredData::ParseJSON (value);
}
else if (key.compare("hexname") == 0)
{
@@ -2540,11 +2568,6 @@ ProcessGDBRemote::RefreshStateAfterStop ()
m_initial_tid = LLDB_INVALID_THREAD_ID;
}
- // Fetch the threads via an efficient packet that gets stop infos for all threads
- // only if we have more than one thread
- if (m_thread_ids.size() > 1)
- m_threads_info_sp = m_gdb_comm.GetThreadsInfo();
-
// Let all threads recover from stopping and do any clean up based
// on the previous thread state (if any).
m_thread_list_real.RefreshStateAfterStop();
@@ -2819,6 +2842,12 @@ ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response)
{
// Lock the thread stack while we access it
Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex);
+
+ // We are are not using non-stop mode, there can only be one last stop
+ // reply packet, so clear the list.
+ if (GetTarget().GetNonStopModeEnabled() == false)
+ m_stop_packet_stack.clear();
+
// Add this stop packet to the stop packet stack
// This stack will get popped and examined when we switch to the
// Stopped state
@@ -2826,7 +2855,6 @@ ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response)
}
}
-
//------------------------------------------------------------------
// Process Queries
//------------------------------------------------------------------
@@ -2854,6 +2882,35 @@ ProcessGDBRemote::GetImageInfoAddress()
return addr;
}
+void
+ProcessGDBRemote::WillPublicStop ()
+{
+ // See if the GDB remote client supports the JSON threads info.
+ // If so, we gather stop info for all threads, expedited registers,
+ // expedited memory, runtime queue information (iOS and MacOSX only),
+ // and more. Expediting memory will help stack backtracing be much
+ // faster. Expediting registers will make sure we don't have to read
+ // the thread registers for GPRs.
+ m_jthreadsinfo_sp = m_gdb_comm.GetThreadsInfo();
+
+ if (m_jthreadsinfo_sp)
+ {
+ // Now set the stop info for each thread and also expedite any registers
+ // and memory that was in the jThreadsInfo response.
+ StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray();
+ if (thread_infos)
+ {
+ const size_t n = thread_infos->GetSize();
+ for (size_t i=0; i<n; ++i)
+ {
+ StructuredData::Dictionary *thread_dict = thread_infos->GetItemAtIndex(i)->GetAsDictionary();
+ if (thread_dict)
+ SetThreadStopInfo(thread_dict);
+ }
+ }
+ }
+}
+
//------------------------------------------------------------------
// Process Memory
//------------------------------------------------------------------
OpenPOWER on IntegriCloud