[Lldb-commits] [lldb] r240354 - Reduced packet counts to the remote GDB server where possible.
Chaoren Lin
chaorenl at google.com
Mon Jun 22 19:10:16 PDT 2015
Hi Greg,
This commit caused a severe breakage on the Linux buildbot
<http://lab.llvm.org:8011/builders/lldb-x86_64-ubuntu-14.04-cmake/builds/3436>.
Would you mind if I reverted it until you can find a fix?
On Mon, Jun 22, 2015 at 4:12 PM, Greg Clayton <gclayton at apple.com> wrote:
> Author: gclayton
> Date: Mon Jun 22 18:12:45 2015
> New Revision: 240354
>
> URL: http://llvm.org/viewvc/llvm-project?rev=240354&view=rev
> Log:
> Reduced packet counts to the remote GDB server where possible.
>
> We have been working on reducing the packet count that is sent between
> LLDB and the debugserver on MacOSX and iOS. Our approach to this was to
> reduce the packets required when debugging multiple threads. We currently
> make one qThreadStopInfoXXXX call (where XXXX is the thread ID in hex) per
> thread except the thread that stopped with a stop reply packet. In order to
> implement multiple thread infos in a single reply, we need to use
> structured data, which means JSON. The new jThreadsInfo packet will attempt
> to retrieve all thread infos in a single packet. The data is very similar
> to the stop reply packets, but packaged in JSON and uses JSON arrays where
> applicable. The JSON output looks like:
>
>
> [
> { "tid":1580681,
> "metype":6,
> "medata":[2,0],
> "reason":"exception",
> "qaddr":140735118423168,
> "registers": {
> "0":"8000000000000000",
> "1":"0000000000000000",
> "2":"20fabf5fff7f0000",
> "3":"e8f8bf5fff7f0000",
> "4":"0100000000000000",
> "5":"d8f8bf5fff7f0000",
> "6":"b0f8bf5fff7f0000",
> "7":"20f4bf5fff7f0000",
> "8":"8000000000000000",
> "9":"61a8db78a61500db",
> "10":"3200000000000000",
> "11":"4602000000000000",
> "12":"0000000000000000",
> "13":"0000000000000000",
> "14":"0000000000000000",
> "15":"0000000000000000",
> "16":"960b000001000000",
> "17":"0202000000000000",
> "18":"2b00000000000000",
> "19":"0000000000000000",
> "20":"0000000000000000"},
> "memory":[
>
> {"address":140734799804592,"bytes":"c8f8bf5fff7f0000c9a59e8cff7f0000"},
>
> {"address":140734799804616,"bytes":"00000000000000000100000000000000"}
> ]
> }
> ]
>
> It contains an array of dicitionaries with all of the key value pairs that
> are normally in the stop reply packet. Including the expedited registers.
> Notice that is also contains expedited memory in the "memory" key. Any
> values in this memory will get included in a new L1 cache in
> lldb_private::Process where if a memory read request is made and that
> memory request fits into one of the L1 memory cache blocks, it will use
> that memory data. If a memory request fails in the L1 cache, it will fall
> back to the L2 cache which is the same block sized caching we were using
> before these changes. This allows a process to expedite memory that you are
> likely to use and it reduces packet count. On MacOSX with debugserver, we
> expedite the frame pointer backchain for a thread (up to 256 entries) by
> reading 2 pointers worth of bytes at the frame pointer (for the previous FP
> and PC), and follow the backchain. Most backtraces on MacOSX and iOS now
> don't require us to read any memory!
>
> We will try these packets out and if successful, we should port these to
> lldb-server in the near future.
>
> <rdar://problem/21494354>
>
>
> Added:
> lldb/trunk/tools/debugserver/source/JSONGenerator.h
> Modified:
> lldb/trunk/include/lldb/Core/RangeMap.h
> lldb/trunk/include/lldb/Core/StructuredData.h
> lldb/trunk/include/lldb/Target/Memory.h
> lldb/trunk/source/API/SBThread.cpp
> lldb/trunk/source/Core/StructuredData.cpp
>
> lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
>
> lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
> lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
> lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
> lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
> lldb/trunk/source/Target/Memory.cpp
> lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj
> lldb/trunk/tools/debugserver/source/RNBRemote.cpp
> lldb/trunk/tools/debugserver/source/RNBRemote.h
>
> Modified: lldb/trunk/include/lldb/Core/RangeMap.h
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/RangeMap.h?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/include/lldb/Core/RangeMap.h (original)
> +++ lldb/trunk/include/lldb/Core/RangeMap.h Mon Jun 22 18:12:45 2015
> @@ -128,9 +128,10 @@ namespace lldb_private {
> {
> return Contains(range.GetRangeBase()) &&
> ContainsEndInclusive(range.GetRangeEnd());
> }
> -
> +
> + // Returns true if the two ranges adjoing or intersect
> bool
> - Overlap (const Range &rhs) const
> + DoesAdjoinOrIntersect (const Range &rhs) const
> {
> const BaseType lhs_base = this->GetRangeBase();
> const BaseType rhs_base = rhs.GetRangeBase();
> @@ -139,7 +140,19 @@ namespace lldb_private {
> bool result = (lhs_base <= rhs_end) && (lhs_end >= rhs_base);
> return result;
> }
> -
> +
> + // Returns true if the two ranges intersect
> + bool
> + DoesIntersect (const Range &rhs) const
> + {
> + const BaseType lhs_base = this->GetRangeBase();
> + const BaseType rhs_base = rhs.GetRangeBase();
> + const BaseType lhs_end = this->GetRangeEnd();
> + const BaseType rhs_end = rhs.GetRangeEnd();
> + bool result = (lhs_base < rhs_end) && (lhs_end > rhs_base);
> + return result;
> + }
> +
> bool
> operator < (const Range &rhs) const
> {
> @@ -241,7 +254,7 @@ namespace lldb_private {
> // don't end up allocating and making a new collection
> for no reason
> for (pos = m_entries.begin(), end = m_entries.end(), prev
> = end; pos != end; prev = pos++)
> {
> - if (prev != end && prev->Overlap(*pos))
> + if (prev != end && prev->DoesAdjoinOrIntersect(*pos))
> {
> can_combine = true;
> break;
> @@ -255,7 +268,7 @@ namespace lldb_private {
> Collection minimal_ranges;
> for (pos = m_entries.begin(), end = m_entries.end(),
> prev = end; pos != end; prev = pos++)
> {
> - if (prev != end && prev->Overlap(*pos))
> + if (prev != end &&
> prev->DoesAdjoinOrIntersect(*pos))
> minimal_ranges.back().SetRangeEnd
> (std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd()));
> else
> minimal_ranges.push_back (*pos);
> @@ -521,7 +534,7 @@ namespace lldb_private {
> // don't end up allocating and making a new collection
> for no reason
> for (pos = m_entries.begin(), end = m_entries.end(), prev
> = end; pos != end; prev = pos++)
> {
> - if (prev != end && prev->Overlap(*pos))
> + if (prev != end && prev->DoesAdjoinOrIntersect(*pos))
> {
> can_combine = true;
> break;
> @@ -535,7 +548,7 @@ namespace lldb_private {
> Collection minimal_ranges;
> for (pos = m_entries.begin(), end = m_entries.end(),
> prev = end; pos != end; prev = pos++)
> {
> - if (prev != end && prev->Overlap(*pos))
> + if (prev != end &&
> prev->DoesAdjoinOrIntersect(*pos))
> minimal_ranges.back().SetRangeEnd
> (std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd()));
> else
> minimal_ranges.push_back (*pos);
>
> Modified: lldb/trunk/include/lldb/Core/StructuredData.h
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/StructuredData.h?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/include/lldb/Core/StructuredData.h (original)
> +++ lldb/trunk/include/lldb/Core/StructuredData.h Mon Jun 22 18:12:45 2015
> @@ -13,10 +13,11 @@
> // C Includes
> // C++ Includes
>
> +#include <functional>
> #include <map>
> +#include <string>
> #include <utility>
> #include <vector>
> -#include <string>
>
> #include "llvm/ADT/StringRef.h"
>
> @@ -140,6 +141,15 @@ public:
> return NULL;
> }
>
> + uint64_t
> + GetIntegerValue (uint64_t fail_value = 0)
> + {
> + Integer *integer = GetAsInteger ();
> + if (integer)
> + return integer->GetValue();
> + return fail_value;
> + }
> +
> Float *
> GetAsFloat ()
> {
> @@ -148,6 +158,15 @@ public:
> return NULL;
> }
>
> + double
> + GetFloatValue (double fail_value = 0.0)
> + {
> + Float *f = GetAsFloat ();
> + if (f)
> + return f->GetValue();
> + return fail_value;
> + }
> +
> Boolean *
> GetAsBoolean ()
> {
> @@ -156,6 +175,15 @@ public:
> return NULL;
> }
>
> + bool
> + GetBooleanValue (bool fail_value = false)
> + {
> + Boolean *b = GetAsBoolean ();
> + if (b)
> + return b->GetValue();
> + return fail_value;
> + }
> +
> String *
> GetAsString ()
> {
> @@ -164,6 +192,19 @@ public:
> return NULL;
> }
>
> + std::string
> + GetStringValue(const char *fail_value = NULL)
> + {
> + String *s = GetAsString ();
> + if (s)
> + return s->GetValue();
> +
> + if (fail_value && fail_value[0])
> + return std::string(fail_value);
> +
> + return std::string();
> + }
> +
> Generic *
> GetAsGeneric()
> {
> @@ -197,6 +238,17 @@ public:
> {
> }
>
> + void
> + ForEach (std::function <bool(Object* object)> const
> &foreach_callback) const
> + {
> + for (const auto &object_sp : m_items)
> + {
> + if (foreach_callback(object_sp.get()) == false)
> + break;
> + }
> + }
> +
> +
> size_t
> GetSize() const
> {
> @@ -447,7 +499,7 @@ public:
> m_value = string;
> }
>
> - std::string
> + const std::string &
> GetValue ()
> {
> return m_value;
> @@ -462,6 +514,7 @@ public:
> class Dictionary : public Object
> {
> public:
> +
> Dictionary () :
> Object (Type::eTypeDictionary),
> m_dict ()
> @@ -478,6 +531,16 @@ public:
> return m_dict.size();
> }
>
> + void
> + ForEach (std::function <bool(ConstString key, Object* object)>
> const &callback) const
> + {
> + for (const auto &pair : m_dict)
> + {
> + if (callback (pair.first, pair.second.get()) == false)
> + break;
> + }
> + }
> +
> ObjectSP
> GetKeys() const
> {
> @@ -628,33 +691,25 @@ public:
> void
> AddIntegerItem (llvm::StringRef key, uint64_t value)
> {
> - ObjectSP val_obj (new Integer());
> - val_obj->GetAsInteger()->SetValue (value);
> - AddItem (key, val_obj);
> + AddItem (key, ObjectSP (new Integer(value)));
> }
>
> void
> AddFloatItem (llvm::StringRef key, double value)
> {
> - ObjectSP val_obj (new Float());
> - val_obj->GetAsFloat()->SetValue (value);
> - AddItem (key, val_obj);
> + AddItem (key, ObjectSP (new Float(value)));
> }
>
> void
> AddStringItem (llvm::StringRef key, std::string value)
> {
> - ObjectSP val_obj (new String());
> - val_obj->GetAsString()->SetValue (value);
> - AddItem (key, val_obj);
> + AddItem (key, ObjectSP (new String(std::move(value))));
> }
>
> void
> AddBooleanItem (llvm::StringRef key, bool value)
> {
> - ObjectSP val_obj (new Boolean());
> - val_obj->GetAsBoolean()->SetValue (value);
> - AddItem (key, val_obj);
> + AddItem (key, ObjectSP (new Boolean(value)));
> }
>
> void Dump(Stream &s) const override;
> @@ -690,9 +745,9 @@ public:
> class Generic : public Object
> {
> public:
> - explicit Generic(void *object = nullptr)
> - : Object(Type::eTypeGeneric)
> - , m_object(object)
> + explicit Generic(void *object = nullptr) :
> + Object (Type::eTypeGeneric),
> + m_object (object)
> {
> }
>
>
> Modified: lldb/trunk/include/lldb/Target/Memory.h
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Memory.h?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/include/lldb/Target/Memory.h (original)
> +++ lldb/trunk/include/lldb/Target/Memory.h Mon Jun 22 18:12:45 2015
> @@ -52,7 +52,7 @@ namespace lldb_private {
> uint32_t
> GetMemoryCacheLineSize() const
> {
> - return m_cache_line_byte_size ;
> + return m_L2_cache_line_byte_size ;
> }
>
> void
> @@ -61,17 +61,26 @@ namespace lldb_private {
> bool
> RemoveInvalidRange (lldb::addr_t base_addr, lldb::addr_t
> byte_size);
>
> + // Allow external sources to populate data into the L1 memory
> cache
> + void
> + AddL1CacheData(lldb::addr_t addr, const void *src, size_t
> src_len);
> +
> + void
> + AddL1CacheData(lldb::addr_t addr, const lldb::DataBufferSP
> &data_buffer_sp);
> +
> protected:
> typedef std::map<lldb::addr_t, lldb::DataBufferSP> BlockMap;
> typedef RangeArray<lldb::addr_t, lldb::addr_t, 4> InvalidRanges;
> + typedef Range<lldb::addr_t, lldb::addr_t> AddrRange;
>
> //------------------------------------------------------------------
> // Classes that inherit from MemoryCache can see and modify these
>
> //------------------------------------------------------------------
> - Process &m_process;
> - uint32_t m_cache_line_byte_size;
> Mutex m_mutex;
> - BlockMap m_cache;
> + BlockMap m_L1_cache; // A first level memory cache whose chunk
> sizes vary that will be used only if the memory read fits entirely in a
> chunk
> + BlockMap m_L2_cache; // A memory cache of fixed size chinks
> (m_L2_cache_line_byte_size bytes in size each)
> InvalidRanges m_invalid_ranges;
> + Process &m_process;
> + uint32_t m_L2_cache_line_byte_size;
> private:
> DISALLOW_COPY_AND_ASSIGN (MemoryCache);
> };
>
> Modified: lldb/trunk/source/API/SBThread.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBThread.cpp?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/source/API/SBThread.cpp (original)
> +++ lldb/trunk/source/API/SBThread.cpp Mon Jun 22 18:12:45 2015
> @@ -114,13 +114,13 @@ SBThread::GetQueue () const
> else
> {
> if (log)
> - log->Printf ("SBThread(%p)::GetQueueKind() => error:
> process is running",
> + log->Printf ("SBThread(%p)::GetQueue() => error: process
> is running",
> static_cast<void*>(exe_ctx.GetThreadPtr()));
> }
> }
>
> if (log)
> - log->Printf ("SBThread(%p)::GetQueueKind () => SBQueue(%p)",
> + log->Printf ("SBThread(%p)::GetQueue () => SBQueue(%p)",
> static_cast<void*>(exe_ctx.GetThreadPtr()),
> static_cast<void*>(queue_sp.get()));
>
> return sb_queue;
>
> Modified: lldb/trunk/source/Core/StructuredData.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/StructuredData.cpp?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/source/Core/StructuredData.cpp (original)
> +++ lldb/trunk/source/Core/StructuredData.cpp Mon Jun 22 18:12:45 2015
> @@ -298,6 +298,10 @@ StructuredData::ParseJSON (std::string j
> {
> object_sp = read_json_object (&c);
> }
> + else if (*c == '[')
> + {
> + object_sp = read_json_array (&c);
> + }
> else
> {
> // We have bad characters here, this is likely an illegal
> JSON string.
>
> Modified:
> lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> ---
> lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
> (original)
> +++
> lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
> Mon Jun 22 18:12:45 2015
> @@ -98,6 +98,7 @@ GDBRemoteCommunicationClient::GDBRemoteC
> m_supports_z4 (true),
> m_supports_QEnvironment (true),
> m_supports_QEnvironmentHexEncoded (true),
> + m_supports_jThreadsInfo (true),
> m_curr_pid (LLDB_INVALID_PROCESS_ID),
> m_curr_tid (LLDB_INVALID_THREAD_ID),
> m_curr_tid_run (LLDB_INVALID_THREAD_ID),
> @@ -601,6 +602,32 @@ GDBRemoteCommunicationClient::GetpPacket
> return m_supports_p;
> }
>
> +StructuredData::ObjectSP
> +GDBRemoteCommunicationClient::GetThreadsInfo()
> +{
> + // Get information on all threads at one using the "jThreadsInfo"
> packet
> + StructuredData::ObjectSP object_sp;
> +
> + if (m_supports_jThreadsInfo)
> + {
> + StringExtractorGDBRemote response;
> + m_supports_jThreadExtendedInfo = eLazyBoolNo;
> + if (SendPacketAndWaitForResponse("jThreadsInfo", response, false)
> == PacketResult::Success)
> + {
> + if (response.IsUnsupportedResponse())
> + {
> + m_supports_jThreadsInfo = false;
> + }
> + else if (!response.Empty())
> + {
> + object_sp = StructuredData::ParseJSON
> (response.GetStringRef());
> + }
> + }
> + }
> + return object_sp;
> +}
> +
> +
> bool
> GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported ()
> {
>
> Modified:
> lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> ---
> lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
> (original)
> +++
> lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
> Mon Jun 22 18:12:45 2015
> @@ -17,6 +17,7 @@
> // Other libraries and framework includes
> // Project includes
> #include "lldb/Core/ArchSpec.h"
> +#include "lldb/Core/StructuredData.h"
> #include "lldb/Target/Process.h"
>
> #include "GDBRemoteCommunication.h"
> @@ -537,6 +538,9 @@ public:
> bool
> AvoidGPackets(ProcessGDBRemote *process);
>
> + StructuredData::ObjectSP
> + GetThreadsInfo();
> +
> bool
> GetThreadExtendedInfoSupported();
>
> @@ -615,7 +619,8 @@ protected:
> m_supports_z3:1,
> m_supports_z4:1,
> m_supports_QEnvironment:1,
> - m_supports_QEnvironmentHexEncoded:1;
> + m_supports_QEnvironmentHexEncoded:1,
> + m_supports_jThreadsInfo:1;
>
> lldb::pid_t m_curr_pid;
> lldb::tid_t m_curr_tid; // Current gdb remote protocol thread
> index for all other operations
>
> 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=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
> (original)
> +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Mon
> Jun 22 18:12:45 2015
> @@ -378,6 +378,7 @@ 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_continue_c_tids (),
> m_continue_C_tids (),
> m_continue_s_tids (),
> @@ -1784,6 +1785,356 @@ ProcessGDBRemote::UpdateThreadList (Thre
> return true;
> }
>
> +bool
> +ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread)
> +{
> + // See if we got thread stop infos for all threads via the
> "jThreadsInfo" packet
> + if (m_threads_info_sp)
> + {
> + StructuredData::Array *thread_infos =
> m_threads_info_sp->GetAsArray();
> + if (thread_infos)
> + {
> + lldb::tid_t tid;
> + 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)
> + {
> + if
> (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid,
> LLDB_INVALID_THREAD_ID))
> + {
> + if (tid == thread->GetID())
> + return SetThreadStopInfo(thread_dict);
> + }
> + }
> + }
> + }
> + }
> +
> + // Fall back to using the qThreadStopInfo packet
> + StringExtractorGDBRemote stop_packet;
> + if (GetGDBRemote().GetThreadStopInfo(thread->GetProtocolID(),
> stop_packet))
> + return SetThreadStopInfo (stop_packet) == eStateStopped;
> + return false;
> +}
> +
> +
> +ThreadSP
> +ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
> + uint8_t signo,
> + const std::string &thread_name,
> + const std::string &reason,
> + const std::string &description,
> + uint32_t exc_type,
> + const std::vector<addr_t> &exc_data,
> + addr_t thread_dispatch_qaddr)
> +{
> + ThreadSP thread_sp;
> + if (tid != LLDB_INVALID_THREAD_ID)
> + {
> + // Scope for "locker" below
> + {
> + // m_thread_list_real does have its own mutex, but we need to
> + // hold onto the mutex between the call to
> m_thread_list_real.FindThreadByID(...)
> + // and the m_thread_list_real.AddThread(...) so it doesn't
> change on us
> + Mutex::Locker locker (m_thread_list_real.GetMutex ());
> + thread_sp = m_thread_list_real.FindThreadByProtocolID(tid,
> false);
> +
> + if (!thread_sp)
> + {
> + // Create the thread if we need to
> + thread_sp.reset (new ThreadGDBRemote (*this, tid));
> + m_thread_list_real.AddThread(thread_sp);
> + }
> + }
> +
> + if (thread_sp)
> + {
> + ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>
> (thread_sp.get());
> +
> + // 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);
> + 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
> + {
> + bool handled = false;
> + bool did_exec = false;
> + if (!reason.empty())
> + {
> + if (reason.compare("trace") == 0)
> + {
> + thread_sp->SetStopInfo
> (StopInfo::CreateStopReasonToTrace (*thread_sp));
> + handled = true;
> + }
> + 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)
> + {
> + // 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)
> + {
> + 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)
> + {
> + 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;
> + }
> + 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)
> + {
> + // 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 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
> + {
> + // 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 (!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
> + {
> + thread_sp->SetStopInfo
> (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str()));
> + }
> + }
> + }
> + }
> + }
> + return thread_sp;
> +}
> +
> +StateType
> +ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary
> *thread_dict)
> +{
> + static ConstString g_key_tid("tid");
> + static ConstString g_key_name("name");
> + static ConstString g_key_reason("reason");
> + static ConstString g_key_metype("metype");
> + static ConstString g_key_medata("medata");
> + static ConstString g_key_qaddr("qaddr");
> + static ConstString g_key_registers("registers");
> + static ConstString g_key_memory("memory");
> + static ConstString g_key_address("address");
> + static ConstString g_key_bytes("bytes");
> + static ConstString g_key_description("description");
> +
> + // Stop with signal and thread info
> + lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
> + uint8_t signo = 0;
> + std::string value;
> + std::string thread_name;
> + std::string reason;
> + std::string description;
> + uint32_t exc_type = 0;
> + std::vector<addr_t> exc_data;
> + addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
> + StructuredData::Dictionary *registers_dict = nullptr;
> +
> + // Iterate through all of the thread dictionary key/value pairs from
> the structured data dictionary
> +
> + thread_dict->ForEach([this, &tid, ®isters_dict, &thread_name,
> &signo, &reason, &description, &exc_type, &exc_data,
> &thread_dispatch_qaddr](ConstString key, StructuredData::Object* object) ->
> bool
> + {
> + if (key == g_key_tid)
> + {
> + // thread in big endian hex
> + tid = object->GetIntegerValue(LLDB_INVALID_THREAD_ID);
> + }
> + else if (key == g_key_metype)
> + {
> + // exception type in big endian hex
> + exc_type = object->GetIntegerValue(0);
> + }
> + else if (key == g_key_medata)
> + {
> + // exception data in big endian hex
> + StructuredData::Array *array = object->GetAsArray();
> + if (array)
> + {
> + array->ForEach([&exc_data](StructuredData::Object*
> object) -> bool {
> + exc_data.push_back(object->GetIntegerValue());
> + return true; // Keep iterating through all array items
> + });
> + }
> + }
> + else if (key == g_key_name)
> + {
> + thread_name = std::move(object->GetStringValue());
> + }
> + else if (key == g_key_qaddr)
> + {
> + thread_dispatch_qaddr =
> object->GetIntegerValue(LLDB_INVALID_ADDRESS);
> + }
> + else if (key == g_key_reason)
> + {
> + reason = std::move(object->GetStringValue());
> + }
> + else if (key == g_key_description)
> + {
> + description = std::move(object->GetStringValue());
> + }
> + else if (key == g_key_registers)
> + {
> + registers_dict = object->GetAsDictionary();
> + }
> + else if (key == g_key_memory)
> + {
> + StructuredData::Array *array = object->GetAsArray();
> + if (array)
> + {
> + array->ForEach([this](StructuredData::Object* object) ->
> bool {
> + StructuredData::Dictionary *mem_cache_dict =
> object->GetAsDictionary();
> + if (mem_cache_dict)
> + {
> + lldb::addr_t mem_cache_addr =
> LLDB_INVALID_ADDRESS;
> + if
> (mem_cache_dict->GetValueForKeyAsInteger<lldb::addr_t>("address",
> mem_cache_addr))
> + {
> + if (mem_cache_addr != LLDB_INVALID_ADDRESS)
> + {
> + StringExtractor bytes;
> + if
> (mem_cache_dict->GetValueForKeyAsString("bytes", bytes.GetStringRef()))
> + {
> + bytes.SetFilePos(0);
> +
> + const size_t byte_size =
> bytes.GetStringRef().size()/2;
> + DataBufferSP data_buffer_sp(new
> DataBufferHeap(byte_size, 0));
> + const size_t bytes_copied =
> bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0);
> + if (bytes_copied == byte_size)
> +
> m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp);
> + }
> + }
> + }
> + }
> + return true; // Keep iterating through all array items
> + });
> + }
> +
> + }
> + return true; // Keep iterating through all dictionary key/value
> pairs
> + });
> +
> +
> + ThreadSP thread_sp = SetThreadStopInfo (tid, signo, thread_name,
> reason, description, exc_type, exc_data, thread_dispatch_qaddr);
> + if (thread_sp)
> + {
> + // Process any expedited register values so we don't have to read
> them with p/P or g/G packets
> + if (registers_dict)
> + {
> + ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>
> (thread_sp.get());
> +
> + registers_dict->ForEach([gdb_thread](ConstString key,
> StructuredData::Object* object) -> bool {
> + const uint32_t reg = StringConvert::ToUInt32
> (key.GetCString(), UINT32_MAX, 10);
> + if (reg != UINT32_MAX)
> + {
> + StringExtractor reg_value_extractor;
> + reg_value_extractor.GetStringRef() =
> std::move(object->GetStringValue());
> + gdb_thread->PrivateSetRegisterValue (reg,
> reg_value_extractor);
> + }
> + return true; // Keep iterating through all array items
> + });
> + }
> + return eStateStopped;
> + }
> + return eStateExited;
> +}
>
> StateType
> ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
> @@ -1814,8 +2165,9 @@ ProcessGDBRemote::SetThreadStopInfo (Str
> BuildDynamicRegisterInfo (true);
> }
> // Stop with signal and thread info
> + lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
> const uint8_t signo = stop_packet.GetHexU8();
> - std::string name;
> + std::string key;
> std::string value;
> std::string thread_name;
> std::string reason;
> @@ -1823,48 +2175,26 @@ ProcessGDBRemote::SetThreadStopInfo (Str
> uint32_t exc_type = 0;
> std::vector<addr_t> exc_data;
> addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
> - ThreadSP thread_sp;
> - ThreadGDBRemote *gdb_thread = NULL;
> -
> - while (stop_packet.GetNameColonValue(name, value))
> + typedef std::map<uint32_t, std::string> ExpeditedRegisterMap;
> + ExpeditedRegisterMap expedited_register_map;
> + while (stop_packet.GetNameColonValue(key, value))
> {
> - if (name.compare("metype") == 0)
> + if (key.compare("metype") == 0)
> {
> // exception type in big endian hex
> exc_type = StringConvert::ToUInt32 (value.c_str(), 0,
> 16);
> }
> - else if (name.compare("medata") == 0)
> + else if (key.compare("medata") == 0)
> {
> // exception data in big endian hex
> exc_data.push_back(StringConvert::ToUInt64
> (value.c_str(), 0, 16));
> }
> - else if (name.compare("thread") == 0)
> + else if (key.compare("thread") == 0)
> {
> // thread in big endian hex
> - lldb::tid_t tid = StringConvert::ToUInt64
> (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
> - // m_thread_list_real does have its own mutex, but we
> need to
> - // hold onto the mutex between the call to
> m_thread_list_real.FindThreadByID(...)
> - // and the m_thread_list_real.AddThread(...) so it
> doesn't change on us
> - Mutex::Locker locker (m_thread_list_real.GetMutex ());
> - thread_sp =
> m_thread_list_real.FindThreadByProtocolID(tid, false);
> -
> - if (!thread_sp)
> - {
> - // Create the thread if we need to
> - thread_sp.reset (new ThreadGDBRemote (*this,
> tid));
> - Log *log
> (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD));
> - if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
> - log->Printf ("ProcessGDBRemote::%s Adding new
> thread: %p for thread ID: 0x%" PRIx64 ".\n",
> - __FUNCTION__,
> -
> static_cast<void*>(thread_sp.get()),
> - thread_sp->GetID());
> -
> - m_thread_list_real.AddThread(thread_sp);
> - }
> - gdb_thread = static_cast<ThreadGDBRemote *>
> (thread_sp.get());
> -
> + tid = StringConvert::ToUInt64 (value.c_str(),
> LLDB_INVALID_THREAD_ID, 16);
> }
> - else if (name.compare("threads") == 0)
> + else if (key.compare("threads") == 0)
> {
> Mutex::Locker locker(m_thread_list_real.GetMutex());
> m_thread_ids.clear();
> @@ -1886,7 +2216,7 @@ ProcessGDBRemote::SetThreadStopInfo (Str
> if (tid != LLDB_INVALID_THREAD_ID)
> m_thread_ids.push_back (tid);
> }
> - else if (name.compare("hexname") == 0)
> + else if (key.compare("hexname") == 0)
> {
> StringExtractor name_extractor;
> // Swap "value" over into "name_extractor"
> @@ -1895,19 +2225,19 @@ ProcessGDBRemote::SetThreadStopInfo (Str
> name_extractor.GetHexByteString (value);
> thread_name.swap (value);
> }
> - else if (name.compare("name") == 0)
> + else if (key.compare("name") == 0)
> {
> thread_name.swap (value);
> }
> - else if (name.compare("qaddr") == 0)
> + else if (key.compare("qaddr") == 0)
> {
> thread_dispatch_qaddr = StringConvert::ToUInt64
> (value.c_str(), 0, 16);
> }
> - else if (name.compare("reason") == 0)
> + else if (key.compare("reason") == 0)
> {
> reason.swap(value);
> }
> - else if (name.compare("description") == 0)
> + else if (key.compare("description") == 0)
> {
> StringExtractor desc_extractor;
> // Swap "value" over into "name_extractor"
> @@ -1916,34 +2246,49 @@ ProcessGDBRemote::SetThreadStopInfo (Str
> desc_extractor.GetHexByteString (value);
> description.swap(value);
> }
> - else if (name.size() == 2 && ::isxdigit(name[0]) &&
> ::isxdigit(name[1]))
> + else if (key.compare("memory") == 0)
> {
> - // We have a register number that contains an
> expedited
> - // register value. Lets supply this register to our
> thread
> - // so it won't have to go and read it.
> - if (gdb_thread)
> - {
> - uint32_t reg = StringConvert::ToUInt32
> (name.c_str(), UINT32_MAX, 16);
> -
> - if (reg != UINT32_MAX)
> + // Expedited memory. GDB servers can choose to send
> back expedited memory
> + // that can populate the L1 memory cache in the
> process so that things like
> + // the frame pointer backchain can be expedited. This
> will help stack
> + // backtracing be more efficient by not having to
> send as many memory read
> + // requests down the remote GDB server.
> +
> + // Key/value pair format: memory:<addr>=<bytes>;
> + // <addr> is a number whose base will be interpreted
> by the prefix:
> + // "0x[0-9a-fA-F]+" for hex
> + // "0[0-7]+" for octal
> + // "[1-9]+" for decimal
> + // <bytes> is native endian ASCII hex bytes just like
> the register values
> + llvm::StringRef value_ref(value);
> + std::pair<llvm::StringRef, llvm::StringRef> pair;
> + pair = value_ref.split('=');
> + if (!pair.first.empty() && !pair.second.empty())
> + {
> + std::string addr_str(pair.first.str());
> + const lldb::addr_t mem_cache_addr =
> StringConvert::ToUInt64(addr_str.c_str(), LLDB_INVALID_ADDRESS, 0);
> + if (mem_cache_addr != LLDB_INVALID_ADDRESS)
> {
> - StringExtractor reg_value_extractor;
> - // Swap "value" over into
> "reg_value_extractor"
> -
> reg_value_extractor.GetStringRef().swap(value);
> - if (!gdb_thread->PrivateSetRegisterValue
> (reg, reg_value_extractor))
> - {
> -
> Host::SetCrashDescriptionWithFormat("Setting thread register '%s' (decoded
> to %u (0x%x)) with value '%s' for stop packet: '%s'",
> -
> name.c_str(),
> - reg,
> - reg,
> -
> reg_value_extractor.GetStringRef().c_str(),
> -
> stop_packet.GetStringRef().c_str());
> - }
> + StringExtractor bytes;
> + bytes.GetStringRef() =
> std::move(pair.second.str());
> + const size_t byte_size =
> bytes.GetStringRef().size()/2;
> + DataBufferSP data_buffer_sp(new
> DataBufferHeap(byte_size, 0));
> + const size_t bytes_copied = bytes.GetHexBytes
> (data_buffer_sp->GetBytes(), byte_size, 0);
> + if (bytes_copied == byte_size)
> +
> m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp);
> }
> }
> }
> + else if (key.size() == 2 && ::isxdigit(key[0]) &&
> ::isxdigit(key[1]))
> + {
> + uint32_t reg = StringConvert::ToUInt32 (key.c_str(),
> UINT32_MAX, 16);
> + if (reg != UINT32_MAX)
> + expedited_register_map[reg] = std::move(value);
> + }
> }
>
> + ThreadSP thread_sp = SetThreadStopInfo (tid, signo,
> thread_name, reason, description, exc_type, exc_data,
> thread_dispatch_qaddr);
> +
> // If the response is old style 'S' packet which does not
> provide us with thread information
> // then update the thread list and choose the first one.
> if (!thread_sp)
> @@ -1954,156 +2299,23 @@ ProcessGDBRemote::SetThreadStopInfo (Str
> {
> Mutex::Locker locker (m_thread_list_real.GetMutex ());
> thread_sp = m_thread_list_real.FindThreadByProtocolID
> (m_thread_ids.front (), false);
> - if (thread_sp)
> - gdb_thread = static_cast<ThreadGDBRemote *>
> (thread_sp.get ());
> }
> }
>
> - if (thread_sp)
> + if (thread_sp && !expedited_register_map.empty())
> {
> - // Clear the stop info just in case we don't set it to
> anything
> - thread_sp->SetStopInfo (StopInfoSP());
> -
> - gdb_thread->SetThreadDispatchQAddr
> (thread_dispatch_qaddr);
> - gdb_thread->SetName (thread_name.empty() ? NULL :
> thread_name.c_str());
> - 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
> - {
> - bool handled = false;
> - bool did_exec = false;
> - if (!reason.empty())
> - {
> - if (reason.compare("trace") == 0)
> - {
> - thread_sp->SetStopInfo
> (StopInfo::CreateStopReasonToTrace (*thread_sp));
> - handled = true;
> - }
> - 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)
> - {
> - // 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)
> - {
> - 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)
> - {
> - 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;
> - }
> - 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)
> - {
> - // 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 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
> - {
> - // 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 (!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
> - {
> - thread_sp->SetStopInfo
> (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str()));
> - }
> + // Process any expedited register values so we don't have
> to read them with p/P or g/G packets
> + ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote
> *> (thread_sp.get());
> + for (const auto &pair : expedited_register_map)
> + {
> + StringExtractor reg_value_extractor;
> + reg_value_extractor.GetStringRef() = pair.second;
> + if (!gdb_thread->PrivateSetRegisterValue (pair.first,
> reg_value_extractor))
> + {
> + Host::SetCrashDescriptionWithFormat("Setting
> thread register '0x%2.2x' with value '%s' for stop packet: '%s'",
> + pair.first,
> +
> reg_value_extractor.GetStringRef().c_str(),
> +
> stop_packet.GetStringRef().c_str());
> }
> }
> }
> @@ -2163,6 +2375,11 @@ 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();
>
> 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=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
> (original)
> +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Mon
> Jun 22 18:12:45 2015
> @@ -323,6 +323,9 @@ protected:
> void
> GetMaxMemorySize();
>
> + bool
> + CalculateThreadStopInfo (ThreadGDBRemote *thread);
> +
> //------------------------------------------------------------------
> /// Broadcaster event bits definitions.
> //------------------------------------------------------------------
> @@ -346,6 +349,7 @@ protected:
> typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection;
> typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
> 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
> 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
> @@ -379,6 +383,19 @@ protected:
> lldb::StateType
> SetThreadStopInfo (StringExtractor& stop_packet);
>
> + lldb::StateType
> + SetThreadStopInfo (StructuredData::Dictionary *thread_dict);
> +
> + lldb::ThreadSP
> + SetThreadStopInfo (lldb::tid_t tid,
> + uint8_t signo,
> + const std::string &thread_name,
> + const std::string &reason,
> + const std::string &description,
> + uint32_t exc_type,
> + const std::vector<lldb::addr_t> &exc_data,
> + lldb::addr_t thread_dispatch_qaddr);
> +
> void
> HandleStopReplySequence ();
>
>
> Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
> (original)
> +++ lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp Mon
> Jun 22 18:12:45 2015
> @@ -284,12 +284,7 @@ ThreadGDBRemote::CalculateStopInfo ()
> {
> ProcessSP process_sp (GetProcess());
> if (process_sp)
> - {
> - StringExtractorGDBRemote stop_packet;
> - ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote
> *>(process_sp.get());
> - if
> (gdb_process->GetGDBRemote().GetThreadStopInfo(GetProtocolID(),
> stop_packet))
> - return gdb_process->SetThreadStopInfo (stop_packet) ==
> eStateStopped;
> - }
> + return static_cast<ProcessGDBRemote
> *>(process_sp.get())->CalculateThreadStopInfo(this);
> return false;
> }
>
>
> Modified: lldb/trunk/source/Target/Memory.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Memory.cpp?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/source/Target/Memory.cpp (original)
> +++ lldb/trunk/source/Target/Memory.cpp Mon Jun 22 18:12:45 2015
> @@ -14,8 +14,9 @@
> // Other libraries and framework includes
> // Project includes
> #include "lldb/Core/DataBufferHeap.h"
> -#include "lldb/Core/State.h"
> #include "lldb/Core/Log.h"
> +#include "lldb/Core/RangeMap.h"
> +#include "lldb/Core/State.h"
> #include "lldb/Target/Process.h"
>
> using namespace lldb;
> @@ -25,11 +26,12 @@ using namespace lldb_private;
> // MemoryCache constructor
> //----------------------------------------------------------------------
> MemoryCache::MemoryCache(Process &process) :
> - m_process (process),
> - m_cache_line_byte_size (process.GetMemoryCacheLineSize()),
> m_mutex (Mutex::eMutexTypeRecursive),
> - m_cache (),
> - m_invalid_ranges ()
> + m_L1_cache (),
> + m_L2_cache (),
> + m_invalid_ranges (),
> + m_process (process),
> + m_L2_cache_line_byte_size (process.GetMemoryCacheLineSize())
> {
> }
>
> @@ -44,10 +46,24 @@ void
> MemoryCache::Clear(bool clear_invalid_ranges)
> {
> Mutex::Locker locker (m_mutex);
> - m_cache.clear();
> + m_L1_cache.clear();
> + m_L2_cache.clear();
> if (clear_invalid_ranges)
> m_invalid_ranges.Clear();
> - m_cache_line_byte_size = m_process.GetMemoryCacheLineSize();
> + m_L2_cache_line_byte_size = m_process.GetMemoryCacheLineSize();
> +}
> +
> +void
> +MemoryCache::AddL1CacheData(lldb::addr_t addr, const void *src, size_t
> src_len)
> +{
> + AddL1CacheData(addr,DataBufferSP (new
> DataBufferHeap(DataBufferHeap(src, src_len))));
> +}
> +
> +void
> +MemoryCache::AddL1CacheData(lldb::addr_t addr, const DataBufferSP
> &data_buffer_sp)
> +{
> + Mutex::Locker locker (m_mutex);
> + m_L1_cache[addr] = data_buffer_sp;
> }
>
> void
> @@ -57,29 +73,44 @@ MemoryCache::Flush (addr_t addr, size_t
> return;
>
> Mutex::Locker locker (m_mutex);
> - if (m_cache.empty())
> - return;
>
> - const uint32_t cache_line_byte_size = m_cache_line_byte_size;
> - const addr_t end_addr = (addr + size - 1);
> - const addr_t first_cache_line_addr = addr - (addr %
> cache_line_byte_size);
> - const addr_t last_cache_line_addr = end_addr - (end_addr %
> cache_line_byte_size);
> - // Watch for overflow where size will cause us to go off the end of
> the
> - // 64 bit address space
> - uint32_t num_cache_lines;
> - if (last_cache_line_addr >= first_cache_line_addr)
> - num_cache_lines = ((last_cache_line_addr -
> first_cache_line_addr)/cache_line_byte_size) + 1;
> - else
> - num_cache_lines = (UINT64_MAX - first_cache_line_addr +
> 1)/cache_line_byte_size;
> -
> - uint32_t cache_idx = 0;
> - for (addr_t curr_addr = first_cache_line_addr;
> - cache_idx < num_cache_lines;
> - curr_addr += cache_line_byte_size, ++cache_idx)
> - {
> - BlockMap::iterator pos = m_cache.find (curr_addr);
> - if (pos != m_cache.end())
> - m_cache.erase(pos);
> + // Erase any blocks from the L1 cache that intersect with the flush
> range
> + if (!m_L1_cache.empty())
> + {
> + AddrRange flush_range(addr, size);
> + BlockMap::iterator pos = m_L1_cache.lower_bound(addr);
> + while (pos != m_L1_cache.end())
> + {
> + AddrRange chunk_range(pos->first, pos->second->GetByteSize());
> + if (!chunk_range.DoesIntersect(flush_range))
> + break;
> + pos = m_L1_cache.erase(pos);
> + }
> + }
> +
> + if (!m_L2_cache.empty())
> + {
> + const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size;
> + const addr_t end_addr = (addr + size - 1);
> + const addr_t first_cache_line_addr = addr - (addr %
> cache_line_byte_size);
> + const addr_t last_cache_line_addr = end_addr - (end_addr %
> cache_line_byte_size);
> + // Watch for overflow where size will cause us to go off the end
> of the
> + // 64 bit address space
> + uint32_t num_cache_lines;
> + if (last_cache_line_addr >= first_cache_line_addr)
> + num_cache_lines = ((last_cache_line_addr -
> first_cache_line_addr)/cache_line_byte_size) + 1;
> + else
> + num_cache_lines = (UINT64_MAX - first_cache_line_addr +
> 1)/cache_line_byte_size;
> +
> + uint32_t cache_idx = 0;
> + for (addr_t curr_addr = first_cache_line_addr;
> + cache_idx < num_cache_lines;
> + curr_addr += cache_line_byte_size, ++cache_idx)
> + {
> + BlockMap::iterator pos = m_L2_cache.find (curr_addr);
> + if (pos != m_L2_cache.end())
> + m_L2_cache.erase(pos);
> + }
> }
> }
>
> @@ -122,6 +153,39 @@ MemoryCache::Read (addr_t addr,
> {
> size_t bytes_left = dst_len;
>
> + // Check the L1 cache for a range that contain the entire memory read.
> + // If we find a range in the L1 cache that does, we use it. Else we
> fall
> + // back to reading memory in m_L2_cache_line_byte_size byte sized
> chunks.
> + // The L1 cache contains chunks of memory that are not required to be
> + // m_L2_cache_line_byte_size bytes in size, so we don't try anything
> + // tricky when reading from them (no partial reads from the L1 cache).
> +
> + Mutex::Locker locker(m_mutex);
> + if (!m_L1_cache.empty())
> + {
> + AddrRange read_range(addr, dst_len);
> + BlockMap::iterator pos = m_L1_cache.lower_bound(addr);
> + if (pos != m_L1_cache.end())
> + {
> + AddrRange chunk_range(pos->first, pos->second->GetByteSize());
> + bool match = chunk_range.Contains(read_range);
> + if (!match && pos != m_L1_cache.begin())
> + {
> + --pos;
> + chunk_range.SetRangeBase(pos->first);
> + chunk_range.SetByteSize(pos->second->GetByteSize());
> + match = chunk_range.Contains(read_range);
> + }
> +
> + if (match)
> + {
> + memcpy(dst, pos->second->GetBytes() + addr -
> chunk_range.GetRangeBase(), dst_len);
> + return dst_len;
> + }
> + }
> + }
> +
> +
> // If this memory read request is larger than the cache line size,
> then
> // we (1) try to read as much of it at once as possible, and (2) don't
> // add the data to the memory cache. We don't want to split a big
> read
> @@ -129,19 +193,22 @@ MemoryCache::Read (addr_t addr,
> // request, it is unlikely that the caller function will ask for the
> next
> // 4 bytes after the large memory read - so there's little benefit to
> saving
> // it in the cache.
> - if (dst && dst_len > m_cache_line_byte_size)
> + if (dst && dst_len > m_L2_cache_line_byte_size)
> {
> - return m_process.ReadMemoryFromInferior (addr, dst, dst_len,
> error);
> + size_t bytes_read = m_process.ReadMemoryFromInferior (addr, dst,
> dst_len, error);
> + // Add this non block sized range to the L1 cache if we actually
> read anything
> + if (bytes_read > 0)
> + AddL1CacheData(addr, dst, bytes_read);
> + return bytes_read;
> }
>
> if (dst && bytes_left > 0)
> {
> - const uint32_t cache_line_byte_size = m_cache_line_byte_size;
> + const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size;
> uint8_t *dst_buf = (uint8_t *)dst;
> addr_t curr_addr = addr - (addr % cache_line_byte_size);
> addr_t cache_offset = addr - curr_addr;
> - Mutex::Locker locker (m_mutex);
> -
> +
> while (bytes_left > 0)
> {
> if (m_invalid_ranges.FindEntryThatContains(curr_addr))
> @@ -150,8 +217,8 @@ MemoryCache::Read (addr_t addr,
> return dst_len - bytes_left;
> }
>
> - BlockMap::const_iterator pos = m_cache.find (curr_addr);
> - BlockMap::const_iterator end = m_cache.end ();
> + BlockMap::const_iterator pos = m_L2_cache.find (curr_addr);
> + BlockMap::const_iterator end = m_L2_cache.end ();
>
> if (pos != end)
> {
> @@ -208,7 +275,7 @@ MemoryCache::Read (addr_t addr,
>
> if (process_bytes_read != cache_line_byte_size)
> data_buffer_heap_ap->SetByteSize (process_bytes_read);
> - m_cache[curr_addr] = DataBufferSP
> (data_buffer_heap_ap.release());
> + m_L2_cache[curr_addr] = DataBufferSP
> (data_buffer_heap_ap.release());
> // We have read data and put it into the cache, continue
> through the
> // loop again to get the data out of the cache...
> }
>
> Modified:
> lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj
> (original)
> +++ lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj Mon
> Jun 22 18:12:45 2015
> @@ -55,6 +55,7 @@
> 26203D1D1641EFB200A662F7 /*
> com.apple.debugserver.internal.plist */ = {isa = PBXFileReference;
> fileEncoding = 4; lastKnownFileType = text.plist.xml; path =
> com.apple.debugserver.internal.plist; sourceTree = "<group>"; };
> 26242C390DDBD33C0054A4CC /* debugserver-entitlements.plist
> */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType =
> text.plist.xml; path = "debugserver-entitlements.plist"; sourceTree =
> "<group>"; };
> 264D5D571293835600ED4C01 /* DNBArch.cpp */ = {isa =
> PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp;
> path = DNBArch.cpp; sourceTree = "<group>"; };
> + 264F679A1B2F9EB200140093 /* JSONGenerator.h */ = {isa =
> PBXFileReference; lastKnownFileType = sourcecode.c.h; path =
> JSONGenerator.h; sourceTree = "<group>"; };
> 26593A060D4931CC001C9FE3 /* ChangeLog */ = {isa =
> PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path =
> ChangeLog; sourceTree = "<group>"; };
> 2660D9CC1192280900958FBD /* StringExtractor.cpp */ = {isa
> = PBXFileReference; fileEncoding = 4; lastKnownFileType =
> sourcecode.cpp.cpp; name = StringExtractor.cpp; path =
> ../../source/Utility/StringExtractor.cpp; sourceTree = SOURCE_ROOT; };
> 2660D9CD1192280900958FBD /* StringExtractor.h */ = {isa =
> PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;
> name = StringExtractor.h; path = ../../source/Utility/StringExtractor.h;
> sourceTree = SOURCE_ROOT; };
> @@ -232,6 +233,7 @@
> 26C637E20C71334A0024798E /*
> DNBRegisterInfo.cpp */,
> 260E7332114BFFE600D1DFB3 /*
> DNBThreadResumeActions.h */,
> 260E7331114BFFE600D1DFB3 /*
> DNBThreadResumeActions.cpp */,
> + 264F679A1B2F9EB200140093 /*
> JSONGenerator.h */,
> AF67AC000D34604D0022D128 /*
> PseudoTerminal.h */,
> AF67ABFF0D34604D0022D128 /*
> PseudoTerminal.cpp */,
> 26C637FD0C71334A0024798E /*
> PThreadCondition.h */,
>
> Added: lldb/trunk/tools/debugserver/source/JSONGenerator.h
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/JSONGenerator.h?rev=240354&view=auto
>
> ==============================================================================
> --- lldb/trunk/tools/debugserver/source/JSONGenerator.h (added)
> +++ lldb/trunk/tools/debugserver/source/JSONGenerator.h Mon Jun 22
> 18:12:45 2015
> @@ -0,0 +1,490 @@
> +//===-- JSONGenerator.h ----------------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef __JSONGenerator_h_
> +#define __JSONGenerator_h_
> +
> +// C Includes
> +// C++ Includes
> +
> +#include <iomanip>
> +#include <sstream>
> +#include <string>
> +#include <utility>
> +#include <vector>
> +
> +//----------------------------------------------------------------------
> +/// @class JSONGenerator JSONGenerator.h
> +/// @brief A class which can construct structured data for the sole
> purpose
> +/// of printing it in JSON format.
> +///
> +/// A stripped down version of lldb's StructuredData objects which are
> much
> +/// general purpose. This variant is intended only for assembling
> information
> +/// and printing it as a JSON string.
> +//----------------------------------------------------------------------
> +
> +class JSONGenerator
> +{
> +public:
> +
> + class Object;
> + class Array;
> + class Integer;
> + class Float;
> + class Boolean;
> + class String;
> + class Dictionary;
> + class Generic;
> +
> + typedef std::shared_ptr<Object> ObjectSP;
> + typedef std::shared_ptr<Array> ArraySP;
> + typedef std::shared_ptr<Integer> IntegerSP;
> + typedef std::shared_ptr<Float> FloatSP;
> + typedef std::shared_ptr<Boolean> BooleanSP;
> + typedef std::shared_ptr<String> StringSP;
> + typedef std::shared_ptr<Dictionary> DictionarySP;
> + typedef std::shared_ptr<Generic> GenericSP;
> +
> + enum class Type
> + {
> + eTypeInvalid = -1,
> + eTypeNull = 0,
> + eTypeGeneric,
> + eTypeArray,
> + eTypeInteger,
> + eTypeFloat,
> + eTypeBoolean,
> + eTypeString,
> + eTypeDictionary
> + };
> +
> + class Object :
> + public std::enable_shared_from_this<Object>
> + {
> + public:
> +
> + Object (Type t = Type::eTypeInvalid) :
> + m_type (t)
> + {
> + }
> +
> + virtual ~Object ()
> + {
> + }
> +
> + virtual bool
> + IsValid() const
> + {
> + return true;
> + }
> +
> + virtual void
> + Clear ()
> + {
> + m_type = Type::eTypeInvalid;
> + }
> +
> + Type
> + GetType () const
> + {
> + return m_type;
> + }
> +
> + void
> + SetType (Type t)
> + {
> + m_type = t;
> + }
> +
> + Array *
> + GetAsArray ()
> + {
> + if (m_type == Type::eTypeArray)
> + return (Array *)this;
> + return NULL;
> + }
> +
> + Dictionary *
> + GetAsDictionary ()
> + {
> + if (m_type == Type::eTypeDictionary)
> + return (Dictionary *)this;
> + return NULL;
> + }
> +
> + Integer *
> + GetAsInteger ()
> + {
> + if (m_type == Type::eTypeInteger)
> + return (Integer *)this;
> + return NULL;
> + }
> +
> + Float *
> + GetAsFloat ()
> + {
> + if (m_type == Type::eTypeFloat)
> + return (Float *)this;
> + return NULL;
> + }
> +
> + Boolean *
> + GetAsBoolean ()
> + {
> + if (m_type == Type::eTypeBoolean)
> + return (Boolean *)this;
> + return NULL;
> + }
> +
> + String *
> + GetAsString ()
> + {
> + if (m_type == Type::eTypeString)
> + return (String *)this;
> + return NULL;
> + }
> +
> + Generic *
> + GetAsGeneric()
> + {
> + if (m_type == Type::eTypeGeneric)
> + return (Generic *)this;
> + return NULL;
> + }
> +
> + virtual void
> + Dump (std::ostream &s) const = 0;
> +
> + private:
> + Type m_type;
> + };
> +
> + class Array : public Object
> + {
> + public:
> + Array () :
> + Object (Type::eTypeArray)
> + {
> + }
> +
> + virtual
> + ~Array()
> + {
> + }
> +
> + void
> + AddItem(ObjectSP item)
> + {
> + m_items.push_back(item);
> + }
> +
> + void Dump(std::ostream &s) const override
> + {
> + s << "[";
> + const size_t arrsize = m_items.size();
> + for (size_t i = 0; i < arrsize; ++i)
> + {
> + m_items[i]->Dump(s);
> + if (i + 1 < arrsize)
> + s << ",";
> + }
> + s << "]";
> + }
> +
> + protected:
> + typedef std::vector<ObjectSP> collection;
> + collection m_items;
> + };
> +
> +
> + class Integer : public Object
> + {
> + public:
> + Integer (uint64_t value = 0) :
> + Object (Type::eTypeInteger),
> + m_value (value)
> + {
> + }
> +
> + virtual ~Integer()
> + {
> + }
> +
> + void
> + SetValue (uint64_t value)
> + {
> + m_value = value;
> + }
> +
> + void Dump(std::ostream &s) const override
> + {
> + s << m_value;
> + }
> +
> + protected:
> + uint64_t m_value;
> + };
> +
> + class Float : public Object
> + {
> + public:
> + Float (double d = 0.0) :
> + Object (Type::eTypeFloat),
> + m_value (d)
> + {
> + }
> +
> + virtual ~Float()
> + {
> + }
> +
> + void
> + SetValue (double value)
> + {
> + m_value = value;
> + }
> +
> + void Dump(std::ostream &s) const override
> + {
> + s << m_value;
> + }
> +
> + protected:
> + double m_value;
> + };
> +
> + class Boolean : public Object
> + {
> + public:
> + Boolean (bool b = false) :
> + Object (Type::eTypeBoolean),
> + m_value (b)
> + {
> + }
> +
> + virtual ~Boolean()
> + {
> + }
> +
> + void
> + SetValue (bool value)
> + {
> + m_value = value;
> + }
> +
> + void Dump(std::ostream &s) const override
> + {
> + if (m_value == true)
> + s << "true";
> + else
> + s << "false";
> + }
> +
> + protected:
> + bool m_value;
> + };
> +
> +
> +
> + class String : public Object
> + {
> + public:
> + String () :
> + Object (Type::eTypeString),
> + m_value ()
> + {
> + }
> +
> + String (const std::string &s) :
> + Object (Type::eTypeString),
> + m_value (s)
> + {
> + }
> +
> + String (const std::string &&s) :
> + Object (Type::eTypeString),
> + m_value (s)
> + {
> + }
> +
> + void
> + SetValue (const std::string &string)
> + {
> + m_value = string;
> + }
> +
> + void Dump(std::ostream &s) const override
> + {
> + std::string quoted;
> + const size_t strsize = m_value.size();
> + for (size_t i = 0; i < strsize ; ++i)
> + {
> + char ch = m_value[i];
> + if (ch == '"')
> + quoted.push_back ('\\');
> + quoted.push_back (ch);
> + }
> + s << '"' << quoted.c_str() << '"';
> + }
> +
> + protected:
> + std::string m_value;
> + };
> +
> + class Dictionary : public Object
> + {
> + public:
> + Dictionary () :
> + Object (Type::eTypeDictionary),
> + m_dict ()
> + {
> + }
> +
> + virtual ~Dictionary()
> + {
> + }
> +
> + void
> + AddItem (std::string key, ObjectSP value)
> + {
> + m_dict.push_back(Pair(key, value));
> + }
> +
> + void
> + AddIntegerItem (std::string key, uint64_t value)
> + {
> + AddItem (key, ObjectSP (new Integer(value)));
> + }
> +
> + void
> + AddFloatItem (std::string key, double value)
> + {
> + AddItem (key, ObjectSP (new Float(value)));
> + }
> +
> + void
> + AddStringItem (std::string key, std::string value)
> + {
> + AddItem (key, ObjectSP (new String(std::move(value))));
> + }
> +
> + void
> + AddBytesAsHexASCIIString (std::string key, const uint8_t *src,
> size_t src_len)
> + {
> + if (src && src_len)
> + {
> + std::ostringstream strm;
> + for (size_t i = 0; i < src_len; i++)
> + strm << std::setfill('0') << std::hex << std::right
> << std::setw(2) << ((uint32_t)(src[i]));
> + AddItem (key, ObjectSP (new
> String(std::move(strm.str()))));
> + }
> + else
> + {
> + AddItem (key, ObjectSP (new String()));
> + }
> + }
> +
> + void
> + AddBooleanItem (std::string key, bool value)
> + {
> + AddItem (key, ObjectSP (new Boolean(value)));
> + }
> +
> + void Dump(std::ostream &s) const override
> + {
> + bool have_printed_one_elem = false;
> + s << "{";
> + for (collection::const_iterator iter = m_dict.begin(); iter
> != m_dict.end(); ++iter)
> + {
> + if (have_printed_one_elem == false)
> + {
> + have_printed_one_elem = true;
> + }
> + else
> + {
> + s << ",";
> + }
> + s << "\"" << iter->first.c_str() << "\":";
> + iter->second->Dump(s);
> + }
> + s << "}";
> + }
> +
> + protected:
> + // Keep the dictionary as a vector so the dictionary doesn't
> reorder itself when you dump it
> + // We aren't accessing keys by name, so this won't affect
> performance
> + typedef std::pair<std::string, ObjectSP> Pair;
> + typedef std::vector<Pair> collection;
> + collection m_dict;
> + };
> +
> + class Null : public Object
> + {
> + public:
> + Null () :
> + Object (Type::eTypeNull)
> + {
> + }
> +
> + virtual ~Null()
> + {
> + }
> +
> + bool
> + IsValid() const override
> + {
> + return false;
> + }
> +
> + void Dump(std::ostream &s) const override
> + {
> + s << "null";
> + }
> +
> + protected:
> + };
> +
> + class Generic : public Object
> + {
> + public:
> + explicit Generic(void *object = nullptr)
> + : Object(Type::eTypeGeneric)
> + , m_object(object)
> + {
> + }
> +
> + void
> + SetValue(void *value)
> + {
> + m_object = value;
> + }
> +
> + void *
> + GetValue() const
> + {
> + return m_object;
> + }
> +
> + bool
> + IsValid() const override
> + {
> + return m_object != nullptr;
> + }
> +
> + void Dump(std::ostream &s) const override;
> +
> + private:
> + void *m_object;
> + };
> +
> +}; // class JSONGenerator
> +
> +
> +
> +#endif // __JSONGenerator_h_
>
> Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
> +++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Mon Jun 22 18:12:45
> 2015
> @@ -29,6 +29,7 @@
> #include "DNBDataRef.h"
> #include "DNBLog.h"
> #include "DNBThreadResumeActions.h"
> +#include "JSONGenerator.h"
> #include "RNBContext.h"
> #include "RNBServices.h"
> #include "RNBSocket.h"
> @@ -195,6 +196,7 @@ RNBRemote::CreatePacketTable ()
> t.push_back (Packet (query_process_info,
> &RNBRemote::HandlePacket_qProcessInfo, NULL, "qProcessInfo", "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 (json_query_thread_extended_info,
> &RNBRemote::HandlePacket_jThreadExtendedInfo, NULL,
> "jThreadExtendedInfo", "Replies with JSON data of thread extended
> information."));
> + t.push_back (Packet (json_query_threads_info,
> &RNBRemote::HandlePacket_jThreadsInfo , NULL, "jThreadsInfo",
> "Replies with JSON data with information about all threads."));
> t.push_back (Packet (start_noack_mode,
> &RNBRemote::HandlePacket_QStartNoAckMode , NULL, "QStartNoAckMode",
> "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol
> packets"));
> t.push_back (Packet (prefix_reg_packets_with_tid,
> &RNBRemote::HandlePacket_QThreadSuffixSupported , NULL,
> "QThreadSuffixSupported", "Check if thread specific packets (register
> packets 'g', 'G', 'p', and 'P') support having the thread ID appended to
> the end of the command"));
> t.push_back (Packet (set_logging_mode,
> &RNBRemote::HandlePacket_QSetLogging , NULL, "QSetLogging:",
> "Check if register packets ('g', 'G', 'p', and 'P' support having the
> thread ID prefix"));
> @@ -2452,6 +2454,52 @@ gdb_regnum_with_fixed_width_hex_register
> }
> }
>
> +struct StackMemory
> +{
> + uint8_t bytes[2*sizeof(nub_addr_t)];
> + nub_size_t length;
> +};
> +typedef std::map<nub_addr_t, StackMemory> StackMemoryMap;
> +
> +
> +static void
> +ReadStackMemory (nub_process_t pid, nub_thread_t tid, StackMemoryMap
> &stack_mmap)
> +{
> + DNBRegisterValue reg_value;
> + if (DNBThreadGetRegisterValueByID(pid, tid, REGISTER_SET_GENERIC,
> GENERIC_REGNUM_FP, ®_value))
> + {
> + uint32_t frame_count = 0;
> + uint64_t fp = 0;
> + if (reg_value.info.size == 4)
> + fp = reg_value.value.uint32;
> + else
> + fp = reg_value.value.uint64;
> + while (fp != 0)
> + {
> + // Make sure we never recurse more than 256 times so we don't
> recurse too far or
> + // store up too much memory in the expedited cache
> + if (++frame_count > 256)
> + break;
> +
> + const nub_size_t read_size = reg_value.info.size*2;
> + StackMemory stack_memory;
> + stack_memory.length = read_size;
> + if (DNBProcessMemoryRead(pid, fp, read_size,
> stack_memory.bytes) != read_size)
> + break;
> + // Make sure we don't try to put the same stack memory in
> more than once
> + if (stack_mmap.find(fp) != stack_mmap.end())
> + break;
> + // Put the entry into the cache
> + stack_mmap[fp] = stack_memory;
> + // Dereference the frame pointer to get to the previous frame
> pointer
> + if (reg_value.info.size == 4)
> + fp = ((uint32_t *)stack_memory.bytes)[0];
> + else
> + fp = ((uint64_t *)stack_memory.bytes)[0];
> + }
> + }
> +}
> +
> rnb_err_t
> RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid)
> {
> @@ -2578,11 +2626,26 @@ RNBRemote::SendStopReplyPacketForThread
> }
> else if (tid_stop_info.details.exception.type)
> {
> - ostrm << "metype:" << std::hex <<
> tid_stop_info.details.exception.type << ";";
> - ostrm << "mecount:" << std::hex <<
> tid_stop_info.details.exception.data_count << ";";
> + ostrm << "metype:" << std::hex <<
> tid_stop_info.details.exception.type << ';';
> + ostrm << "mecount:" << std::hex <<
> tid_stop_info.details.exception.data_count << ';';
> for (int i = 0; i <
> tid_stop_info.details.exception.data_count; ++i)
> - ostrm << "medata:" << std::hex <<
> tid_stop_info.details.exception.data[i] << ";";
> + ostrm << "medata:" << std::hex <<
> tid_stop_info.details.exception.data[i] << ';';
> }
> +
> + // Add expedited stack memory so stack backtracing doesn't need
> to read anything from the
> + // frame pointer chain.
> + StackMemoryMap stack_mmap;
> + ReadStackMemory (pid, tid, stack_mmap);
> + if (!stack_mmap.empty())
> + {
> + for (const auto &stack_memory : stack_mmap)
> + {
> + ostrm << "memory:" << HEXBASE << stack_memory.first <<
> '=';
> + append_hex_value (ostrm, stack_memory.second.bytes,
> stack_memory.second.length, false);
> + ostrm << ';';
> + }
> + }
> +
> return SendPacket (ostrm.str ());
> }
> return SendPacket("E51");
> @@ -4762,11 +4825,136 @@ get_integer_value_for_key_name_from_json
> }
>
> rnb_err_t
> +RNBRemote::HandlePacket_jThreadsInfo (const char *p)
> +{
> + JSONGenerator::Array threads_array;
> +
> + std::ostringstream json;
> + std::ostringstream reply_strm;
> + // If we haven't run the process yet, return an error.
> + if (m_ctx.HasValidProcessID())
> + {
> + nub_process_t pid = m_ctx.ProcessID();
> +
> + nub_size_t numthreads = DNBProcessGetNumThreads (pid);
> + for (nub_size_t i = 0; i < numthreads; ++i)
> + {
> + nub_thread_t tid = DNBProcessGetThreadAtIndex (pid, i);
> +
> + struct DNBThreadStopInfo tid_stop_info;
> +
> + 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))
> + {
> + switch (tid_stop_info.reason)
> + {
> + case eStopTypeInvalid:
> + break;
> + case eStopTypeSignal:
> + if (tid_stop_info.details.signal.signo != 0)
> + reason_value = "signal";
> + break;
> + case eStopTypeException:
> + if (tid_stop_info.details.exception.type != 0)
> + reason_value = "exception";
> + 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);
> +
> +
> + thread_identifier_info_data_t thread_ident_info;
> + if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info))
> + {
> + if (thread_ident_info.dispatch_qaddr != 0)
> + thread_dict_sp->AddIntegerItem("qaddr",
> thread_ident_info.dispatch_qaddr);
> + }
> + DNBRegisterValue reg_value;
> +
> + if (g_reg_entries != NULL)
> + {
> + JSONGenerator::DictionarySP registers_dict_sp(new
> JSONGenerator::Dictionary());
> +
> + for (uint32_t reg = 0; reg < g_num_reg_entries; reg++)
> + {
> + // Expedite all registers in the first register set
> that aren't
> + // contained in other registers
> + if (g_reg_entries[reg].nub_info.set == 1 &&
> + g_reg_entries[reg].nub_info.value_regs == NULL)
> + {
> + if (!DNBThreadGetRegisterValueByID (pid, tid,
> g_reg_entries[reg].nub_info.set, g_reg_entries[reg].nub_info.reg,
> ®_value))
> + continue;
> +
> + std::ostringstream reg_num;
> + reg_num << std::dec <<
> g_reg_entries[reg].gdb_regnum;
> + // Encode native byte ordered bytes as hex ascii
> +
> registers_dict_sp->AddBytesAsHexASCIIString(reg_num.str(),
> reg_value.value.v_uint8, g_reg_entries[reg].nub_info.size);
> + }
> + }
> + thread_dict_sp->AddItem("registers", registers_dict_sp);
> + }
> +
> + // Add expedited stack memory so stack backtracing doesn't
> need to read anything from the
> + // frame pointer chain.
> + StackMemoryMap stack_mmap;
> + ReadStackMemory (pid, tid, stack_mmap);
> + if (!stack_mmap.empty())
> + {
> + JSONGenerator::ArraySP memory_array_sp(new
> JSONGenerator::Array());
> +
> + for (const auto &stack_memory : stack_mmap)
> + {
> + JSONGenerator::DictionarySP stack_memory_sp(new
> JSONGenerator::Dictionary());
> + stack_memory_sp->AddIntegerItem("address",
> stack_memory.first);
> + stack_memory_sp->AddBytesAsHexASCIIString("bytes",
> stack_memory.second.bytes, stack_memory.second.length);
> + memory_array_sp->AddItem(stack_memory_sp);
> + }
> + thread_dict_sp->AddItem("memory", memory_array_sp);
> + }
> + threads_array.AddItem(thread_dict_sp);
> + }
> +
> + std::ostringstream strm;
> + threads_array.Dump (strm);
> + std::string binary_packet = binary_encode_string (strm.str());
> + if (!binary_packet.empty())
> + return SendPacket (binary_packet.c_str());
> + }
> + return SendPacket ("E85");
> +
> +}
> +
> +rnb_err_t
> RNBRemote::HandlePacket_jThreadExtendedInfo (const char *p)
> {
> nub_process_t pid;
> std::ostringstream json;
> - std::ostringstream reply_strm;
> // If we haven't run the process yet, return an error.
> if (!m_ctx.HasValidProcessID())
> {
> @@ -4996,8 +5184,7 @@ RNBRemote::HandlePacket_jThreadExtendedI
>
> json << "}";
> std::string json_quoted = binary_encode_string (json.str());
> - reply_strm << json_quoted;
> - return SendPacket (reply_strm.str());
> + return SendPacket (json_quoted);
> }
> }
> return SendPacket ("OK");
>
> Modified: lldb/trunk/tools/debugserver/source/RNBRemote.h
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.h?rev=240354&r1=240353&r2=240354&view=diff
>
> ==============================================================================
> --- lldb/trunk/tools/debugserver/source/RNBRemote.h (original)
> +++ lldb/trunk/tools/debugserver/source/RNBRemote.h Mon Jun 22 18:12:45
> 2015
> @@ -103,6 +103,7 @@ public:
> query_gdb_server_version, // 'qGDBServerVersion'
> query_process_info, // 'qProcessInfo'
> json_query_thread_extended_info,// 'jThreadExtendedInfo'
> + json_query_threads_info, // 'jThreadsInfo'
> pass_signals_to_inferior, // 'QPassSignals'
> start_noack_mode, // 'QStartNoAckMode'
> prefix_reg_packets_with_tid, //
> 'QPrefixRegisterPacketsWithThreadID
> @@ -190,6 +191,7 @@ public:
> rnb_err_t HandlePacket_qSyncThreadStateSupported (const char *p);
> rnb_err_t HandlePacket_qThreadInfo (const char *p);
> rnb_err_t HandlePacket_jThreadExtendedInfo (const char *p);
> + rnb_err_t HandlePacket_jThreadsInfo (const char *p);
> rnb_err_t HandlePacket_qThreadExtraInfo (const char *p);
> rnb_err_t HandlePacket_qThreadStopInfo (const char *p);
> rnb_err_t HandlePacket_qHostInfo (const char *p);
>
>
> _______________________________________________
> lldb-commits mailing list
> lldb-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20150622/74444263/attachment.html>
More information about the lldb-commits
mailing list