[Lldb-commits] [lldb] r242593 - More packet performance improvements.

Greg Clayton gclayton at apple.com
Fri Jul 17 16:42:29 PDT 2015


Author: gclayton
Date: Fri Jul 17 18:42:28 2015
New Revision: 242593

URL: http://llvm.org/viewvc/llvm-project?rev=242593&view=rev
Log:
More packet performance improvements. 

Changed the "jthreads" key/value in the stop reply packets to be "jstopinfo". This JSON only contains threads with valid stop reasons and allows us not to have to ask about other threads via qThreadStopInfo when we are stepping. The "jstopinfo" only gets sent if there are more than one thread since the stop reply packet contains all the info needed for a single thread.

Added a Process::WillPublicStop() in case process subclasses want to do any extra gathering for public stops. For ProcessGDBRemote, we end up sending a jThreadsInfo packet to gather all expedited registers, expedited memory and MacOSX queue information. We only do this for public stops to minimize the packets we send when we have multiple private stops. Multiple private stops happen when a source level single step, step into or step out run the process multiple times while implementing the stepping, and none of these private stops make it out to the UI via notifications because they are private stops. 


Modified:
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/include/lldb/Target/Thread.h
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/source/Target/Thread.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/MachException.cpp
    lldb/trunk/tools/debugserver/source/RNBRemote.cpp
    lldb/trunk/tools/debugserver/source/RNBRemote.h

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=242593&r1=242592&r2=242593&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Fri Jul 17 18:42:28 2015
@@ -1263,6 +1263,26 @@ public:
     UnloadImage (uint32_t image_token);
 
     //------------------------------------------------------------------
+    /// Called when the process is about to broadcast a public stop.
+    ///
+    /// There are public and private stops. Private stops are when the
+    /// process is doing things like stepping and the client doesn't
+    /// need to know about starts and stop that implement a thread plan.
+    /// Single stepping over a source line in code might end up being
+    /// implemented by one or more process starts and stops. Public stops
+    /// are when clients will be notified that the process is stopped.
+    /// These events typically trigger UI updates (thread stack frames to
+    /// be displayed, variables to be displayed, and more). This function
+    /// can be overriden and allows process subclasses to do something
+    /// before the eBroadcastBitStateChanged event is sent to public
+    /// clients.
+    //------------------------------------------------------------------
+    virtual void
+    WillPublicStop ()
+    {
+    }
+
+    //------------------------------------------------------------------
     /// Register for process and thread notifications.
     ///
     /// Clients can register notification callbacks by filling out a

Modified: lldb/trunk/include/lldb/Target/Thread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=242593&r1=242592&r2=242593&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Thread.h (original)
+++ lldb/trunk/include/lldb/Target/Thread.h Fri Jul 17 18:42:28 2015
@@ -303,6 +303,9 @@ public:
     lldb::StopReason
     GetStopReason();
 
+    bool
+    StopInfoIsUpToDate() const;
+
     // This sets the stop reason to a "blank" stop reason, so you can call functions on the thread
     // without having the called function run with whatever stop reason you stopped with.
     void

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=242593&r1=242592&r2=242593&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Fri Jul 17 18:42:28 2015
@@ -376,7 +376,8 @@ ProcessGDBRemote::ProcessGDBRemote(Targe
     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 (Strea
             }
 
             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 (Thre
     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::CalculateThreadStopInf
                     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 (lld
                 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 (lld
             else
                 gdb_thread->ClearQueueInfo();
 
-
-            if (exc_type != 0)
+            // Make sure we update our thread stop reason just once
+            if (!thread_sp->StopInfoIsUpToDate())
             {
-                const size_t exc_data_size = exc_data.size();
+                thread_sp->SetStopInfo (StopInfoSP());
 
-                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())
+                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)
                         {
-                            WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
-                            if (wp_sp)
+                            // 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)
+                            {
+                                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)
+                    if (!description.empty())
                     {
-                        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()));
+                        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 (lld
     return thread_sp;
 }
 
-StateType
+lldb::ThreadSP
 ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
 {
     static ConstString g_key_tid("tid");
@@ -2245,21 +2275,19 @@ ProcessGDBRemote::SetThreadStopInfo (Str
         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 (Str
                     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 (Str
 
                     // 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 (con
     {
         // 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 (con
     }
 }
 
-
 //------------------------------------------------------------------
 // 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
 //------------------------------------------------------------------

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=242593&r1=242592&r2=242593&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Fri Jul 17 18:42:28 2015
@@ -161,6 +161,9 @@ public:
     lldb::addr_t
     GetImageInfoAddress() override;
 
+    void
+    WillPublicStop () override;
+
     //------------------------------------------------------------------
     // Process Memory
     //------------------------------------------------------------------
@@ -359,7 +362,8 @@ protected:
     typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
     typedef std::map<uint32_t, std::string> ExpeditedRegisterMap;
     tid_collection m_thread_ids; // Thread IDs for all threads. This list gets updated after stopping
-    StructuredData::ObjectSP m_threads_info_sp; // Stop info for all threads if "jThreadsInfo" packet is supported
+    StructuredData::ObjectSP m_jstopinfo_sp; // Stop info only for any threads that have valid stop infos
+    StructuredData::ObjectSP m_jthreadsinfo_sp; // Full stop info, expedited registers and memory for all threads if "jThreadsInfo" packet is supported
     tid_collection m_continue_c_tids;                  // 'c' for continue
     tid_sig_collection m_continue_C_tids; // 'C' for continue with signal
     tid_collection m_continue_s_tids;                  // 's' for step
@@ -396,7 +400,10 @@ protected:
     lldb::StateType
     SetThreadStopInfo (StringExtractor& stop_packet);
 
-    lldb::StateType
+    bool
+    GetThreadStopInfoFromJSON (ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp);
+
+    lldb::ThreadSP
     SetThreadStopInfo (StructuredData::Dictionary *thread_dict);
 
     lldb::ThreadSP

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=242593&r1=242592&r2=242593&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Fri Jul 17 18:42:28 2015
@@ -4734,7 +4734,12 @@ Process::ProcessEventData::DoOnRemoval (
     
     // If we're stopped and haven't restarted, then do the StopInfo actions here:
     if (m_state == eStateStopped && ! m_restarted)
-    {        
+    {
+        // Let process subclasses know we are about to do a public stop and
+        // do anything they might need to in order to speed up register and
+        // memory accesses.
+        process_sp->WillPublicStop();
+
         ThreadList &curr_thread_list = process_sp->GetThreadList();
         uint32_t num_threads = curr_thread_list.GetSize();
         uint32_t idx;

Modified: lldb/trunk/source/Target/Thread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=242593&r1=242592&r2=242593&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Fri Jul 17 18:42:28 2015
@@ -501,6 +501,15 @@ Thread::GetStopReason()
 }
 
 
+bool
+Thread::StopInfoIsUpToDate() const
+{
+    ProcessSP process_sp (GetProcess());
+    if (process_sp)
+        return m_stop_info_stop_id == process_sp->GetStopID();
+    else
+        return true; // Process is no longer around so stop info is always up to date...
+}
 
 void
 Thread::SetStopInfo (const lldb::StopInfoSP &stop_info_sp)

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachException.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachException.cpp?rev=242593&r1=242592&r2=242593&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachException.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachException.cpp Fri Jul 17 18:42:28 2015
@@ -206,6 +206,13 @@ MachException::Data::GetStopInfo(struct
 {
     // Zero out the structure.
     memset(stop_info, 0, sizeof(struct DNBThreadStopInfo));
+
+    if (exc_type == 0)
+    {
+        stop_info->reason = eStopTypeInvalid;
+        return true;
+    }
+
     // We always stop with a mach exceptions
     stop_info->reason = eStopTypeException;
     // Save the EXC_XXXX exception type

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=242593&r1=242592&r2=242593&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Fri Jul 17 18:42:28 2015
@@ -2736,21 +2736,24 @@ RNBRemote::SendStopReplyPacketForThread
                 ostrm << ';';
             }
 
-            // Include JSON info that describes the stop reason for all threads
-            // so when stepping we don't have to query each thread for its stop
-            // info. We use the new "jthreads" key whose values is hex ascii JSON
-            // that contains the thread IDs and only the stop info.
-            const bool queue_info = false;
-            const bool registers = false;
-            const bool memory = false;
-            JSONGenerator::ObjectSP threads_info_sp = GetJSONThreadsInfo(queue_info, registers, memory);
-            if (threads_info_sp)
-            {
-                ostrm << std::hex << "jthreads:";
-                std::ostringstream json_strm;
-                threads_info_sp->Dump (json_strm);
-                append_hexified_string (ostrm, json_strm.str());
-                ostrm << ';';
+            // Include JSON info that describes the stop reason for any threads
+            // that actually have stop reasons. We use the new "jstopinfo" key
+            // whose values is hex ascii JSON that contains the thread IDs
+            // thread stop info only for threads that have stop reasons. Only send
+            // this if we have more than one thread otherwise this packet has all
+            // the info it needs.
+            if (numthreads > 1)
+            {
+                const bool threads_with_valid_stop_info_only = true;
+                JSONGenerator::ObjectSP threads_info_sp = GetJSONThreadsInfo(threads_with_valid_stop_info_only);
+                if (threads_info_sp)
+                {
+                    ostrm << std::hex << "jstopinfo:";
+                    std::ostringstream json_strm;
+                    threads_info_sp->Dump (json_strm);
+                    append_hexified_string (ostrm, json_strm.str());
+                    ostrm << ';';
+                }
             }
         }
 
@@ -4981,7 +4984,7 @@ get_integer_value_for_key_name_from_json
 }
 
 JSONGenerator::ObjectSP
-RNBRemote::GetJSONThreadsInfo(bool queue_info, bool registers, bool memory)
+RNBRemote::GetJSONThreadsInfo(bool threads_with_valid_stop_info_only)
 {
     JSONGenerator::ArraySP threads_array_sp;
     if (m_ctx.HasValidProcessID())
@@ -4997,54 +5000,64 @@ RNBRemote::GetJSONThreadsInfo(bool queue
 
             struct DNBThreadStopInfo tid_stop_info;
 
-            JSONGenerator::DictionarySP thread_dict_sp(new JSONGenerator::Dictionary());
+            const bool stop_info_valid = DNBThreadGetStopReason (pid, tid, &tid_stop_info);
 
+            // If we are doing stop info only, then we only show threads that have a
+            // valid stop reason
+            if (threads_with_valid_stop_info_only)
+            {
+                if (!stop_info_valid || tid_stop_info.reason == eStopTypeInvalid)
+                    continue;
+            }
+
+            JSONGenerator::DictionarySP thread_dict_sp(new JSONGenerator::Dictionary());
             thread_dict_sp->AddIntegerItem("tid", tid);
 
             std::string reason_value("none");
-            if (DNBThreadGetStopReason (pid, tid, &tid_stop_info))
+
+            if (stop_info_valid)
             {
                 switch (tid_stop_info.reason)
                 {
                     case eStopTypeInvalid:
                         break;
+
                     case eStopTypeSignal:
                         if (tid_stop_info.details.signal.signo != 0)
+                        {
+                            thread_dict_sp->AddIntegerItem("signal", tid_stop_info.details.signal.signo);
                             reason_value = "signal";
+                        }
                         break;
+
                     case eStopTypeException:
                         if (tid_stop_info.details.exception.type != 0)
+                        {
                             reason_value = "exception";
+                            thread_dict_sp->AddIntegerItem("metype", tid_stop_info.details.exception.type);
+                            JSONGenerator::ArraySP medata_array_sp(new JSONGenerator::Array());
+                            for (nub_size_t i=0; i<tid_stop_info.details.exception.data_count; ++i)
+                            {
+                                medata_array_sp->AddItem(JSONGenerator::IntegerSP(new JSONGenerator::Integer(tid_stop_info.details.exception.data[i])));
+                            }
+                            thread_dict_sp->AddItem("medata", medata_array_sp);
+                        }
                         break;
+
                     case eStopTypeExec:
                         reason_value = "exec";
                         break;
                 }
-                if (tid_stop_info.reason == eStopTypeSignal)
-                {
-                    thread_dict_sp->AddIntegerItem("signal", tid_stop_info.details.signal.signo);
-                }
-                else if (tid_stop_info.reason == eStopTypeException && tid_stop_info.details.exception.type != 0)
-                {
-                    thread_dict_sp->AddIntegerItem("metype", tid_stop_info.details.exception.type);
-                    JSONGenerator::ArraySP medata_array_sp(new JSONGenerator::Array());
-                    for (nub_size_t i=0; i<tid_stop_info.details.exception.data_count; ++i)
-                    {
-                        medata_array_sp->AddItem(JSONGenerator::IntegerSP(new JSONGenerator::Integer(tid_stop_info.details.exception.data[i])));
-                    }
-                    thread_dict_sp->AddItem("medata", medata_array_sp);
-                }
             }
 
             thread_dict_sp->AddStringItem("reason", reason_value);
 
-            const char *thread_name = DNBThreadGetName (pid, tid);
-            if (thread_name && thread_name[0])
-                thread_dict_sp->AddStringItem("name", thread_name);
-
-
-            if (queue_info)
+            if (threads_with_valid_stop_info_only == false)
             {
+                const char *thread_name = DNBThreadGetName (pid, tid);
+                if (thread_name && thread_name[0])
+                    thread_dict_sp->AddStringItem("name", thread_name);
+
                 thread_identifier_info_data_t thread_ident_info;
                 if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info))
                 {
@@ -5070,10 +5083,7 @@ RNBRemote::GetJSONThreadsInfo(bool queue
                         }
                     }
                 }
-            }
 
-            if (registers)
-            {
                 DNBRegisterValue reg_value;
 
                 if (g_reg_entries != NULL)
@@ -5098,10 +5108,7 @@ RNBRemote::GetJSONThreadsInfo(bool queue
                     }
                     thread_dict_sp->AddItem("registers", registers_dict_sp);
                 }
-            }
 
-            if (memory)
-            {
                 // Add expedited stack memory so stack backtracing doesn't need to read anything from the
                 // frame pointer chain.
                 StackMemoryMap stack_mmap;
@@ -5136,10 +5143,8 @@ RNBRemote::HandlePacket_jThreadsInfo (co
     // If we haven't run the process yet, return an error.
     if (m_ctx.HasValidProcessID())
     {
-        const bool queue_info = true;
-        const bool registers = true;
-        const bool memory = true;
-        JSONGenerator::ObjectSP threads_info_sp = GetJSONThreadsInfo(queue_info, registers, memory);
+        const bool threads_with_valid_stop_info_only = false;
+        JSONGenerator::ObjectSP threads_info_sp = GetJSONThreadsInfo(threads_with_valid_stop_info_only);
 
         if (threads_info_sp)
         {

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.h?rev=242593&r1=242592&r2=242593&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.h (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.h Fri Jul 17 18:42:28 2015
@@ -398,7 +398,7 @@ protected:
     GetDispatchQueueOffsets();
 
     JSONGenerator::ObjectSP
-    GetJSONThreadsInfo (bool queue_info, bool registers, bool memory);
+    GetJSONThreadsInfo (bool threads_with_valid_stop_info_only);
 
     RNBContext      m_ctx;              // process context
     RNBSocket       m_comm;             // communication port





More information about the lldb-commits mailing list