summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/docs/lldb-gdb-remote.txt157
-rw-r--r--lldb/include/lldb/API/SBTrace.h13
-rw-r--r--lldb/include/lldb/Core/TraceOptions.h5
-rw-r--r--lldb/include/lldb/Host/common/NativeProcessProtocol.h105
-rw-r--r--lldb/include/lldb/Target/Process.h27
-rw-r--r--lldb/include/lldb/Utility/StringExtractor.h2
-rw-r--r--lldb/source/API/SBProcess.cpp5
-rw-r--r--lldb/source/API/SBTrace.cpp28
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp206
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h21
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp242
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h8
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp26
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h16
-rw-r--r--lldb/source/Utility/StringExtractor.cpp9
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.cpp10
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.h6
-rw-r--r--lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp225
18 files changed, 1067 insertions, 44 deletions
diff --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index 80a44e866ca..a4427a70444 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -209,6 +209,163 @@ send packet: QListThreadsInStopReply
read packet: OK
//----------------------------------------------------------------------
+// jTraceStart:
+//
+// BRIEF
+// Packet for starting trace of type lldb::TraceType. The following
+// parameters should be appended to the packet formatted as a JSON
+// dictionary, where the schematic for the JSON dictionary in terms of
+// the recognized Keys is given below in the table.
+// Different tracing types could require different custom parameters.
+// Such custom tracing parameters if needed should be collectively
+// specified in a JSON dictionary and the dictionary can be appended
+// to this packet (as Value corresponding to "params"). Since sending
+// JSON data over gdb-remote protocol has certain limitations, binary
+// escaping convention should be used.
+//
+// Following is the list of parameters -
+//
+// Key Value (Integer) (O)Optional/
+// (except params which should be a (M)Mandatory
+// JSON dictionary)
+// ========== ====================================================
+//
+// type The type of trace to start (see M
+// lldb-enumerations for TraceType)
+//
+// buffersize The size of the buffer to allocate M
+// for trace gathering.
+//
+// threadid The id of the thread to start tracing O
+// on.
+//
+// metabuffersize The size of buffer to hold meta data O
+// used for decoding the trace data.
+//
+// params Any parameters that are specific to O
+// certain trace technologies should be
+// collectively specified as a JSON
+// dictionary
+// ========== ====================================================
+//
+// Each tracing instance is identified by a trace id which is returned
+// as the reply to this packet. In case the tracing failed to begin an
+// error code is returned instead.
+//----------------------------------------------------------------------
+
+send packet: jTraceStart:{"type":<type>,"buffersize":<buffersize>}]
+read packet: <trace id>/E<error code>
+
+//----------------------------------------------------------------------
+// jTraceStop:
+//
+// BRIEF
+// Stop tracing instance with trace id <trace id>, of course trace
+// needs to be started before. The following parameters should be
+// formatted as a JSON dictionary to the packet. Since sending
+// JSON data over gdb-remote protocol has certain limitations, binary
+// escaping convention should be used.
+//
+// Following is the list of parameters -
+//
+// Key Value (Integer) (O)Optional/
+// (M)Mandatory
+// ========== ====================================================
+//
+// traceid The trace id of the tracing instance M
+//
+// threadid The id of the thread to stop tracing O
+// on. Since <trace id> could map to
+// multiple trace instances (in case it
+// maps to the complete process), the
+// threadid of a particular thread could
+// be appended as "threadid:<thread id>;"
+// to stop tracing on that thread.
+// ========== ====================================================
+//
+// An OK response is sent in case of success else an error code is
+// returned.
+//----------------------------------------------------------------------
+
+send packet: jTraceStop:{"traceid":<trace id>}]
+read packet: <OK response>/E<error code>
+
+//----------------------------------------------------------------------
+// jTraceBufferRead:
+//
+// BRIEF
+// Packet for reading the trace for tracing instance <trace id>, i.e the
+// id obtained from StartTrace API. The following parameters should be
+// formatted as a JSON dictionary to the packet. Since sending
+// JSON data over gdb-remote protocol has certain limitations, binary
+// escaping convention should be used.
+//
+// Following is the list of parameters -
+//
+// Key Value (Integer) (O)Optional/
+// (M)Mandatory
+// ========== ====================================================
+// traceid The trace id of the tracing instance M
+//
+// offset The offset to start reading the data M
+// from.
+//
+// buffersize The size of the data intended to read. M
+//
+// threadid The id of the thread to retrieve data O
+// from.
+// ========== ====================================================
+//
+// The trace data is sent as raw binary data if the read was successful
+// else an error code is sent.
+//----------------------------------------------------------------------
+
+send packet: jTraceBufferRead:{"traceid":<trace id>,"offset":<byteoffset>,"buffersize":<byte_count>}]
+read packet: <binary trace data>/E<error code>
+
+//----------------------------------------------------------------------
+// jTraceMetaRead:
+//
+// BRIEF
+// Similar Packet as above except it reads meta data.
+//----------------------------------------------------------------------
+
+/----------------------------------------------------------------------
+// jTraceConfigRead:
+//
+// BRIEF
+// Request the trace configuration for the tracing instance with id
+// <trace id>.
+//
+// Following is the list of parameters -
+//
+// Key Value (Integer) (O)Optional/
+// (M)Mandatory
+// ========== ====================================================
+// traceid The trace id of the tracing instance M
+//
+// threadid The id of the thread to obtain trace O
+// configuration from. Since <trace id>
+// could map to multiple trace instances
+// (in case it maps to the complete
+// process), the threadid of a particular
+// thread could be appended as
+// "threadid:<thread id>;" to obtain the
+// trace configuration of that thread.
+// ========== ====================================================
+//
+// In the response packet the trace configuration is sent as text,
+// formatted as a JSON dictionary. Since sending JSON data over
+// gdb-remote protocol has certain limitations, binary escaping
+// convention is used.
+// In case the trace instance with the <trace id> was not found, an
+// error code is returned.
+//----------------------------------------------------------------------
+
+send packet: jTraceConfigRead:{"traceid":<trace id>}
+read packet: {"conf1":<conf1>,"conf2":<conf2>,"params":{"paramName":paramValue}]}];/E<error code>
+
+//----------------------------------------------------------------------
// "qRegisterInfo<hex-reg-id>"
//
// BRIEF
diff --git a/lldb/include/lldb/API/SBTrace.h b/lldb/include/lldb/API/SBTrace.h
index e29a5db7cc4..244a01e5ce1 100644
--- a/lldb/include/lldb/API/SBTrace.h
+++ b/lldb/include/lldb/API/SBTrace.h
@@ -40,7 +40,7 @@ public:
///
/// @param[in] thread_id
/// Tracing could be started for the complete process or a
- /// single thread, in the first case the uid obtained would
+ /// single thread, in the first case the traceid obtained would
/// map to all the threads existing within the process and the
/// ones spawning later. The thread_id parameter can be used in
/// such a scenario to select the trace data for a specific
@@ -68,16 +68,17 @@ public:
/// An error explaining what went wrong.
///
/// @param[in] thread_id
- /// The user id could map to a tracing instance for a thread
+ /// The trace id could map to a tracing instance for a thread
/// or could also map to a group of threads being traced with
/// the same trace options. A thread_id is normally optional
/// except in the case of tracing a complete process and tracing
/// needs to switched off on a particular thread.
/// A situation could occur where initially a thread (lets say
- /// thread A) is being individually traced with a particular uid
- /// and then tracing is started on the complete process, in this
- /// case thread A will continue without any change. All newly
- /// spawned threads would be traced with the uid of the process.
+ /// thread A) is being individually traced with a particular
+ /// trace id and then tracing is started on the complete
+ /// process, in this case thread A will continue without any
+ /// change. All newly spawned threads would be traced with the
+ /// trace id of the process.
/// Now if the StopTrace API is called for the whole process,
/// thread A will not be stopped and must be stopped separately.
//------------------------------------------------------------------
diff --git a/lldb/include/lldb/Core/TraceOptions.h b/lldb/include/lldb/Core/TraceOptions.h
index e875a531e87..91f48915c94 100644
--- a/lldb/include/lldb/Core/TraceOptions.h
+++ b/lldb/include/lldb/Core/TraceOptions.h
@@ -18,8 +18,7 @@
namespace lldb_private {
class TraceOptions {
public:
- TraceOptions()
- : m_trace_params(new StructuredData::Dictionary()) {}
+ TraceOptions() : m_trace_params(new StructuredData::Dictionary()) {}
const StructuredData::DictionarySP &getTraceParams() const {
return m_trace_params;
@@ -43,7 +42,7 @@ public:
void setThreadID(lldb::tid_t thread_id) { m_thread_id = thread_id; }
- lldb::tid_t getThreadID() { return m_thread_id; }
+ lldb::tid_t getThreadID() const { return m_thread_id; }
private:
lldb::TraceType m_type;
diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index 388edef0578..55eca0fa0b6 100644
--- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -10,6 +10,7 @@
#ifndef liblldb_NativeProcessProtocol_h_
#define liblldb_NativeProcessProtocol_h_
+#include "lldb/Core/TraceOptions.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-forward.h"
@@ -308,6 +309,108 @@ public:
static Status Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
+ //------------------------------------------------------------------
+ /// StartTracing API for starting a tracing instance with the
+ /// TraceOptions on a specific thread or process.
+ ///
+ /// @param[in] config
+ /// The configuration to use when starting tracing.
+ ///
+ /// @param[out] error
+ /// Status indicates what went wrong.
+ ///
+ /// @return
+ /// The API returns a user_id which can be used to get trace
+ /// data, trace configuration or stopping the trace instance.
+ /// The user_id is a key to identify and operate with a tracing
+ /// instance. It may refer to the complete process or a single
+ /// thread.
+ //------------------------------------------------------------------
+ virtual lldb::user_id_t StartTrace(const TraceOptions &config,
+ Status &error) {
+ error.SetErrorString("Not implemented");
+ return LLDB_INVALID_UID;
+ }
+
+ //------------------------------------------------------------------
+ /// StopTracing API as the name suggests stops a tracing instance.
+ ///
+ /// @param[in] uid
+ /// The user id of the trace intended to be stopped. Now a
+ /// user_id may map to multiple threads in which case this API
+ /// could be used to stop the tracing for a specific thread by
+ /// supplying its thread id.
+ ///
+ /// @param[in] thread
+ /// Thread is needed when the complete process is being traced
+ /// and the user wishes to stop tracing on a particular thread.
+ ///
+ /// @return
+ /// Status indicating what went wrong.
+ //------------------------------------------------------------------
+ virtual Status StopTrace(lldb::user_id_t uid,
+ lldb::tid_t thread = LLDB_INVALID_THREAD_ID) {
+ return Status("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// This API provides the trace data collected in the form of raw
+ /// data.
+ ///
+ /// @param[in] uid thread
+ /// The uid and thread provide the context for the trace
+ /// instance.
+ ///
+ /// @param[in] buffer
+ /// The buffer provides the destination buffer where the trace
+ /// data would be read to. The buffer should be truncated to the
+ /// filled length by this function.
+ ///
+ /// @param[in] offset
+ /// There is possibility to read partially the trace data from
+ /// a specified offset where in such cases the buffer provided
+ /// may be smaller than the internal trace collection container.
+ ///
+ /// @return
+ /// The size of the data actually read.
+ //------------------------------------------------------------------
+ virtual Status GetData(lldb::user_id_t uid, lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Status("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// Similar API as above except it aims to provide any extra data
+ /// useful for decoding the actual trace data.
+ //------------------------------------------------------------------
+ virtual Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Status("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// API to query the TraceOptions for a given user id
+ ///
+ /// @param[in] uid
+ /// The user id of the tracing instance.
+ ///
+ /// @param[in] config
+ /// The thread id of the tracing instance, in case configuration
+ /// for a specific thread is needed should be specified in the
+ /// config.
+ ///
+ /// @param[out] error
+ /// Status indicates what went wrong.
+ ///
+ /// @param[out] config
+ /// The actual configuration being used for tracing.
+ //------------------------------------------------------------------
+ virtual Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &config) {
+ return Status("Not implemented");
+ }
+
protected:
lldb::pid_t m_pid;
@@ -381,6 +484,6 @@ protected:
private:
void SynchronouslyNotifyProcessStateChanged(lldb::StateType state);
};
-}
+} // namespace lldb_private
#endif // #ifndef liblldb_NativeProcessProtocol_h_
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index d2ab85d1652..dbf6cba09f4 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -2781,7 +2781,7 @@ public:
/// GetTraceConfig should supply the actual used trace
/// configuration.
//------------------------------------------------------------------
- virtual lldb::user_id_t StartTrace(lldb::TraceOptionsSP &options,
+ virtual lldb::user_id_t StartTrace(const TraceOptions &options,
Status &error) {
error.SetErrorString("Not implemented");
return LLDB_INVALID_UID;
@@ -2796,9 +2796,8 @@ public:
/// In the other case that tracing on an individual thread needs
/// to be stopped a thread_id can be supplied.
//------------------------------------------------------------------
- virtual void StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id,
- Status &error) {
- error.SetErrorString("Not implemented");
+ virtual Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
+ return Status("Not implemented");
}
//------------------------------------------------------------------
@@ -2809,21 +2808,19 @@ public:
/// may not. The thread_id should be used to select a particular
/// thread for trace extraction.
//------------------------------------------------------------------
- virtual size_t GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
- Status &error, void *buf, size_t size,
+ virtual Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) {
- error.SetErrorString("Not implemented");
- return 0;
+ return Status("Not implemented");
}
//------------------------------------------------------------------
/// Similar API as above except for obtaining meta data
//------------------------------------------------------------------
- virtual size_t GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
- Status &error, void *buf, size_t size,
+ virtual Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) {
- error.SetErrorString("Not implemented");
- return 0;
+ return Status("Not implemented");
}
//------------------------------------------------------------------
@@ -2835,10 +2832,8 @@ public:
/// configuration used by a specific thread. The thread_id specified
/// should also match the uid otherwise an error will be returned.
//------------------------------------------------------------------
- virtual void GetTraceConfig(lldb::user_id_t uid, Status &error,
- lldb::TraceOptionsSP &options) {
- error.SetErrorString("Not implemented");
- return;
+ virtual Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) {
+ return Status("Not implemented");
}
protected:
diff --git a/lldb/include/lldb/Utility/StringExtractor.h b/lldb/include/lldb/Utility/StringExtractor.h
index 40c1ef79cff..311cec87e69 100644
--- a/lldb/include/lldb/Utility/StringExtractor.h
+++ b/lldb/include/lldb/Utility/StringExtractor.h
@@ -111,6 +111,8 @@ public:
size_t GetHexByteStringTerminatedBy(std::string &str, char terminator);
+ bool ConsumeFront(const llvm::StringRef &str);
+
const char *Peek() {
if (m_index < m_packet.size())
return m_packet.c_str() + m_index;
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index 8b79e521a37..caf07dbe3ce 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -363,10 +363,9 @@ lldb::SBTrace SBProcess::StartTrace(SBTraceOptions &options,
if (!process_sp) {
error.SetErrorString("invalid process");
} else {
-
- uid = process_sp->StartTrace(options.m_traceoptions_sp, error.ref());
+ uid = process_sp->StartTrace(*(options.m_traceoptions_sp), error.ref());
trace_instance.SetTraceUID(uid);
- LLDB_LOG(log, "SBProcess::returned uid - %" PRIx64, uid);
+ LLDB_LOG(log, "SBProcess::returned uid - {0}", uid);
}
return trace_instance;
}
diff --git a/lldb/source/API/SBTrace.cpp b/lldb/source/API/SBTrace.cpp
index 18f7d36e775..9a5fa4ed4f4 100644
--- a/lldb/source/API/SBTrace.cpp
+++ b/lldb/source/API/SBTrace.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Utility/Log.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/Log.h"
#include "lldb/API/SBTrace.h"
#include "lldb/API/SBTraceOptions.h"
@@ -25,37 +25,37 @@ lldb::ProcessSP SBTrace::GetSP() const { return m_opaque_wp.lock(); }
size_t SBTrace::GetTraceData(SBError &error, void *buf, size_t size,
size_t offset, lldb::tid_t thread_id) {
- size_t bytes_read = 0;
ProcessSP process_sp(GetSP());
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
error.Clear();
if (!process_sp) {
error.SetErrorString("invalid process");
} else {
- bytes_read = process_sp->GetData(GetTraceUID(), thread_id, error.ref(), buf,
- size, offset);
- LLDB_LOG(log, "SBTrace::bytes_read - %" PRIx64, bytes_read);
+ error.SetError(
+ process_sp->GetData(GetTraceUID(), thread_id, buffer, offset));
+ LLDB_LOG(log, "SBTrace::bytes_read - {0}", buffer.size());
}
- return bytes_read;
+ return buffer.size();
}
size_t SBTrace::GetMetaData(SBError &error, void *buf, size_t size,
size_t offset, lldb::tid_t thread_id) {
- size_t bytes_read = 0;
ProcessSP process_sp(GetSP());
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
error.Clear();
if (!process_sp) {
error.SetErrorString("invalid process");
} else {
- bytes_read = process_sp->GetMetaData(GetTraceUID(), thread_id, error.ref(),
- buf, size, offset);
- LLDB_LOG(log, "SBTrace::bytes_read - %" PRIx64, bytes_read);
+ error.SetError(
+ process_sp->GetMetaData(GetTraceUID(), thread_id, buffer, offset));
+ LLDB_LOG(log, "SBTrace::bytes_read - {0}", buffer.size());
}
- return bytes_read;
+ return buffer.size();
}
void SBTrace::StopTrace(SBError &error, lldb::tid_t thread_id) {
@@ -66,7 +66,7 @@ void SBTrace::StopTrace(SBError &error, lldb::tid_t thread_id) {
error.SetErrorString("invalid process");
return;
}
- process_sp->StopTrace(GetTraceUID(), thread_id, error.ref());
+ error.SetError(process_sp->StopTrace(GetTraceUID(), thread_id));
}
void SBTrace::GetTraceConfig(SBTraceOptions &options, SBError &error) {
@@ -76,8 +76,8 @@ void SBTrace::GetTraceConfig(SBTraceOptions &options, SBError &error) {
if (!process_sp) {
error.SetErrorString("invalid process");
} else {
- process_sp->GetTraceConfig(GetTraceUID(), error.ref(),
- options.m_traceoptions_sp);
+ error.SetError(process_sp->GetTraceConfig(GetTraceUID(),
+ *(options.m_traceoptions_sp)));
}
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 550ec0ea499..626ec66cd5e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -30,7 +30,6 @@
#include "lldb/Utility/JSON.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
-#include "lldb/Utility/StreamGDBRemote.h"
#include "lldb/Utility/StreamString.h"
// Project includes
@@ -3152,6 +3151,211 @@ bool GDBRemoteCommunicationClient::SyncThreadState(lldb::tid_t tid) {
response.IsOKResponse();
}
+lldb::user_id_t
+GDBRemoteCommunicationClient::SendStartTracePacket(const TraceOptions &options,
+ Status &error) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ lldb::user_id_t ret_uid = LLDB_INVALID_UID;
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jTraceStart:");
+
+ StructuredData::Dictionary json_packet;
+ json_packet.AddIntegerItem("type", options.getType());
+ json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize());
+ json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize());
+
+ if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+ json_packet.AddIntegerItem("threadid", options.getThreadID());
+
+ StructuredData::DictionarySP custom_params = options.getTraceParams();
+ if (custom_params)
+ json_packet.AddItem("params", custom_params);
+
+ StreamString json_string;
+ json_packet.Dump(json_string, false);
+ escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (!response.IsNormalResponse()) {
+ error.SetError(response.GetError(), eErrorTypeGeneric);
+ LLDB_LOG(log, "Target does not support Tracing");
+ } else {
+ ret_uid = response.GetHexMaxU64(false, LLDB_INVALID_UID);
+ }
+ } else {
+ LLDB_LOG(log, "failed to send packet");
+ error.SetErrorStringWithFormat("failed to send packet: '%s'",
+ escaped_packet.GetData());
+ }
+ return ret_uid;
+}
+
+Status
+GDBRemoteCommunicationClient::SendStopTracePacket(lldb::user_id_t uid,
+ lldb::tid_t thread_id) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ StringExtractorGDBRemote response;
+ Status error;
+
+ StructuredData::Dictionary json_packet;
+ StreamGDBRemote escaped_packet;
+ StreamString json_string;
+ escaped_packet.PutCString("jTraceStop:");
+
+ json_packet.AddIntegerItem("traceid", uid);
+
+ if (thread_id != LLDB_INVALID_THREAD_ID)
+ json_packet.AddIntegerItem("threadid", thread_id);
+
+ json_packet.Dump(json_string, false);
+
+ escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (!response.IsOKResponse()) {
+ error.SetError(response.GetError(), eErrorTypeGeneric);
+ LLDB_LOG(log, "stop tracing failed");
+ }
+ } else {
+ LLDB_LOG(log, "failed to send packet");
+ error.SetErrorStringWithFormat(
+ "failed to send packet: '%s' with error '%d'", escaped_packet.GetData(),
+ response.GetError());
+ }
+ return error;
+}
+
+Status GDBRemoteCommunicationClient::SendGetDataPacket(
+ lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jTraceBufferRead:");
+ return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
+}
+
+Status GDBRemoteCommunicationClient::SendGetMetaDataPacket(
+ lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jTraceMetaRead:");
+ return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
+}
+
+Status
+GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid,
+ TraceOptions &options) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ StringExtractorGDBRemote response;
+ Status error;
+
+ StreamString json_string;
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jTraceConfigRead:");
+
+ StructuredData::Dictionary json_packet;
+ json_packet.AddIntegerItem("traceid", uid);
+
+ if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+ json_packet.AddIntegerItem("threadid", options.getThreadID());
+
+ json_packet.Dump(json_string, false);
+ escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ uint64_t type = std::numeric_limits<uint64_t>::max();
+ uint64_t buffersize = std::numeric_limits<uint64_t>::max();
+ uint64_t metabuffersize = std::numeric_limits<uint64_t>::max();
+
+ auto json_object = StructuredData::ParseJSON(response.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != StructuredData::Type::eTypeDictionary) {
+ error.SetErrorString("Invalid Configuration obtained");
+ return error;
+ }
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("metabuffersize",
+ metabuffersize);
+ options.setMetaDataBufferSize(metabuffersize);
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("buffersize", buffersize);
+ options.setTraceBufferSize(buffersize);
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("type", type);
+ options.setType(static_cast<lldb::TraceType>(type));
+
+ StructuredData::ObjectSP custom_params_sp =
+ json_dict->GetValueForKey("params");
+ if (custom_params_sp) {
+ if (custom_params_sp->GetType() !=
+ StructuredData::Type::eTypeDictionary) {
+ error.SetErrorString("Invalid Configuration obtained");
+ return error;
+ } else
+ options.setTraceParams(
+ static_pointer_cast<StructuredData::Dictionary>(
+ custom_params_sp));
+ }
+ } else {
+ error.SetError(response.GetError(), eErrorTypeGeneric);
+ }
+ } else {
+ LLDB_LOG(log, "failed to send packet");
+ error.SetErrorStringWithFormat("failed to send packet: '%s'",
+ escaped_packet.GetData());
+ }
+ return error;
+}
+
+Status GDBRemoteCommunicationClient::SendGetTraceDataPacket(
+ StreamGDBRemote &packet, lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ Status error;
+
+ StructuredData::Dictionary json_packet;
+
+ json_packet.AddIntegerItem("traceid", uid);
+ json_packet.AddIntegerItem("offset", offset);
+ json_packet.AddIntegerItem("buffersize", buffer.size());
+
+ if (thread_id != LLDB_INVALID_THREAD_ID)
+ json_packet.AddIntegerItem("threadid", thread_id);
+
+ StreamString json_string;
+ json_packet.Dump(json_string, false);
+
+ packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response, true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ size_t filled_size = response.GetHexBytesAvail(buffer);
+ buffer = llvm::MutableArrayRef<uint8_t>(buffer.data(), filled_size);
+ } else {
+ error.SetError(response.GetError(), eErrorTypeGeneric);
+ buffer = buffer.slice(buffer.size());
+ }
+ } else {
+ LLDB_LOG(log, "failed to send packet");
+ error.SetErrorStringWithFormat("failed to send packet: '%s'",
+ packet.GetData());
+ buffer = buffer.slice(buffer.size());
+ }
+ return error;
+}
+
bool GDBRemoteCommunicationClient::GetModuleInfo(
const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec,
ModuleSpec &module_spec) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 08d0bd5d690..6306651da7a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -25,6 +25,7 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/StreamGDBRemote.h"
#include "llvm/ADT/Optional.h"
@@ -499,6 +500,21 @@ public:
ConfigureRemoteStructuredData(const ConstString &type_name,
const StructuredData::ObjectSP &config_sp);
+ lldb::user_id_t SendStartTracePacket(const TraceOptions &options,
+ Status &error);
+
+ Status SendStopTracePacket(lldb::user_id_t uid, lldb::tid_t thread_id);
+
+ Status SendGetDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0);
+
+ Status SendGetMetaDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0);
+
+ Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options);
+
protected:
LazyBool m_supports_not_sending_acks;
LazyBool m_supports_thread_suffix;
@@ -587,6 +603,11 @@ protected:
lldb::tid_t tid, StreamString &&payload,
StringExtractorGDBRemote &response, bool send_async);
+ Status SendGetTraceDataPacket(StreamGDBRemote &packet, lldb::user_id_t uid,
+ lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset);
+
private:
DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient);
};
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index ec7c2f5330d..0b3bbfec202 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -183,6 +183,22 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
StringExtractorGDBRemote::eServerPacketType_QPassSignals,
&GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceStart,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceStart);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceBufferRead,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceMetaRead,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceStop,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceStop);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead);
+
RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
[this](StringExtractorGDBRemote packet, Status &error,
bool &interrupt, bool &quit) {
@@ -1084,6 +1100,232 @@ void GDBRemoteCommunicationServerLLGS::SendProcessOutput() {
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceStart(
+ StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp ||
+ (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ if (!packet.ConsumeFront("jTraceStart:"))
+ return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
+
+ TraceOptions options;
+ uint64_t type = std::numeric_limits<uint64_t>::max();
+ uint64_t buffersize = std::numeric_limits<uint64_t>::max();
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ uint64_t metabuffersize = std::numeric_limits<uint64_t>::max();
+
+ auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != StructuredData::Type::eTypeDictionary)
+ return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("metabuffersize",
+ metabuffersize);
+ options.setMetaDataBufferSize(metabuffersize);
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("buffersize", buffersize);
+ options.setTraceBufferSize(buffersize);
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("type", type);
+ options.setType(static_cast<lldb::TraceType>(type));
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("threadid", tid);
+ options.setThreadID(tid);
+
+ StructuredData::ObjectSP custom_params_sp =
+ json_dict->GetValueForKey("params");
+ if (custom_params_sp &&
+ custom_params_sp->GetType() != StructuredData::Type::eTypeDictionary)
+ return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
+
+ options.setTraceParams(
+ static_pointer_cast<StructuredData::Dictionary>(custom_params_sp));
+
+ if (buffersize == std::numeric_limits<uint64_t>::max() ||
+ type != lldb::TraceType::eTraceTypeProcessorTrace) {
+ LLDB_LOG(log, "Ill formed packet buffersize = {0} type = {1}", buffersize,
+ type);
+ return SendIllFormedResponse(packet, "JTrace:start: Ill formed packet ");
+ }
+
+ Status error;
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+ uid = m_debugged_process_sp->StartTrace(options, error);
+ LLDB_LOG(log, "uid is {0} , error is {1}", uid, error.GetError());
+ if (error.Fail())
+ return SendErrorResponse(error.GetError());
+
+ StreamGDBRemote response;
+ response.Printf("%" PRIx64, uid);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceStop(
+ StringExtractorGDBRemote &packet) {
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp ||
+ (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ if (!packet.ConsumeFront("jTraceStop:"))
+ return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
+
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+
+ auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != StructuredData::Type::eTypeDictionary)
+ return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ if (!json_dict->GetValueForKeyAsInteger<lldb::user_id_t>("traceid", uid))
+ return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
+
+ json_dict->GetValueForKeyAsInteger<lldb::tid_t>("threadid", tid);
+
+ Status error = m_debugged_process_sp->StopTrace(uid, tid);
+
+ if (error.Fail())
+ return SendErrorResponse(error.GetError());
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp ||
+ (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ if (!packet.ConsumeFront("jTraceConfigRead:"))
+ return SendIllFormedResponse(packet,
+ "jTraceConfigRead: Ill formed packet ");
+
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+ lldb::tid_t threadid = LLDB_INVALID_THREAD_ID;
+
+ auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != StructuredData::Type::eTypeDictionary)
+ return SendIllFormedResponse(packet,
+ "jTraceConfigRead: Ill formed packet ");
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ if (!json_dict->GetValueForKeyAsInteger<lldb::user_id_t>("traceid", uid))
+ return SendIllFormedResponse(packet,
+ "jTraceConfigRead: Ill formed packet ");
+
+ json_dict->GetValueForKeyAsInteger<lldb::tid_t>("threadid", threadid);
+
+ TraceOptions options;
+ StreamGDBRemote response;
+
+ options.setThreadID(threadid);
+ Status error = m_debugged_process_sp->GetTraceConfig(uid, options);
+
+ if (error.Fail())
+ return SendErrorResponse(error.GetError());
+
+ StreamGDBRemote escaped_response;
+ StructuredData::Dictionary json_packet;
+
+ json_packet.AddIntegerItem("type", options.getType());
+ json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize());
+ json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize());
+
+ StructuredData::DictionarySP custom_params = options.getTraceParams();
+ if (custom_params)
+ json_packet.AddItem("params", custom_params);
+
+ StreamString json_string;
+ json_packet.Dump(json_string, false);
+ escaped_response.PutEscapedBytes(json_string.GetData(),
+ json_string.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceRead(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp ||
+ (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ enum PacketType { MetaData, BufferData };
+ PacketType tracetype = MetaData;
+
+ if (packet.ConsumeFront("jTraceBufferRead:"))
+ tracetype = BufferData;
+ else if (packet.ConsumeFront("jTraceMetaRead:"))
+ tracetype = MetaData;
+ else {
+ return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+ }
+
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+
+ size_t byte_count = std::numeric_limits<size_t>::max();
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ size_t offset = std::numeric_limits<size_t>::max();
+
+ auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != StructuredData::Type::eTypeDictionary)
+ return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ if (!json_dict->GetValueForKeyAsInteger<lldb::user_id_t>("traceid", uid) ||
+ !json_dict->GetValueForKeyAsInteger<uint64_t>("offset", offset) ||
+ !json_dict->GetValueForKeyAsInteger<uint64_t>("buffersize", byte_count))
+ return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+ json_dict->GetValueForKeyAsInteger<lldb::tid_t>("threadid", tid);
+
+ // Allocate the response buffer.
+ uint8_t *buffer = new (std::nothrow) uint8_t[byte_count];
+ if (buffer == nullptr)
+ return SendErrorResponse(0x78);
+
+ StreamGDBRemote response;
+ Status error;
+ llvm::MutableArrayRef<uint8_t> buf(buffer, byte_count);
+
+ if (tracetype == BufferData)
+ error = m_debugged_process_sp->GetData(uid, tid, buf, offset);
+ else if (tracetype == MetaData)
+ error = m_debugged_process_sp->GetMetaData(uid, tid, buf, offset);
+
+ if (error.Fail())
+ return SendErrorResponse(error.GetError());
+
+ for (size_t i = 0; i < buf.size(); ++i)
+ response.PutHex8(buf[i]);
+
+ StreamGDBRemote escaped_response;
+ escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo(
StringExtractorGDBRemote &packet) {
// Fail if we don't have a current process.
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index ebda9a911d3..a7d7850d454 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -189,6 +189,14 @@ protected:
PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet);
+ PacketResult Handle_jTraceStart(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jTraceRead(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jTraceStop(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet);
+
PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 64684c5963b..aeb7c742b4f 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1236,6 +1236,32 @@ Status ProcessGDBRemote::DoAttachToProcessWithName(
return error;
}
+lldb::user_id_t ProcessGDBRemote::StartTrace(const TraceOptions &options,
+ Status &error) {
+ return m_gdb_comm.SendStartTracePacket(options, error);
+}
+
+Status ProcessGDBRemote::StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
+ return m_gdb_comm.SendStopTracePacket(uid, thread_id);
+}
+
+Status ProcessGDBRemote::GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+ return m_gdb_comm.SendGetDataPacket(uid, thread_id, buffer, offset);
+}
+
+Status ProcessGDBRemote::GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+ return m_gdb_comm.SendGetMetaDataPacket(uid, thread_id, buffer, offset);
+}
+
+Status ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid,
+ TraceOptions &options) {
+ return m_gdb_comm.SendGetTraceConfigPacket(uid, options);
+}
+
void ProcessGDBRemote::DidExit() {
// When we exit, disconnect from the GDB server communications
m_gdb_comm.Disconnect();
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 60f0464f86b..d7a4e961b54 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -31,6 +31,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamGDBRemote.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringExtractor.h"
#include "lldb/Utility/StringList.h"
@@ -177,6 +178,21 @@ public:
Status GetWatchpointSupportInfo(uint32_t &num) override;
+ lldb::user_id_t StartTrace(const TraceOptions &options,
+ Status &error) override;
+
+ Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) override;
+
+ Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) override;
+
+ Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) override;
+
+ Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
+
Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
bool StartNoticingNewThreads() override;
diff --git a/lldb/source/Utility/StringExtractor.cpp b/lldb/source/Utility/StringExtractor.cpp
index a94f6bcd008..cf5c7e22744 100644
--- a/lldb/source/Utility/StringExtractor.cpp
+++ b/lldb/source/Utility/StringExtractor.cpp
@@ -280,6 +280,15 @@ uint64_t StringExtractor::GetHexMaxU64(bool little_endian,
return result;
}
+bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {
+ llvm::StringRef S = GetStringRef();
+ if (!S.startswith(str))
+ return false;
+ else
+ m_index += str.size();
+ return true;
+}
+
size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,
uint8_t fail_fill_value) {
size_t bytes_extracted = 0;
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 08226f4c8f9..3473a9e9668 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -286,6 +286,16 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_jSignalsInfo;
if (PACKET_MATCHES("jThreadsInfo"))
return eServerPacketType_jThreadsInfo;
+ if (PACKET_STARTS_WITH("jTraceBufferRead:"))
+ return eServerPacketType_jTraceBufferRead;
+ if (PACKET_STARTS_WITH("jTraceConfigRead:"))
+ return eServerPacketType_jTraceConfigRead;
+ if (PACKET_STARTS_WITH("jTraceMetaRead:"))
+ return eServerPacketType_jTraceMetaRead;
+ if (PACKET_STARTS_WITH("jTraceStart:"))
+ return eServerPacketType_jTraceStart;
+ if (PACKET_STARTS_WITH("jTraceStop:"))
+ return eServerPacketType_jTraceStop;
break;
case 'v':
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.h b/lldb/source/Utility/StringExtractorGDBRemote.h
index a5c0c8e803b..473cab04f80 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.h
+++ b/lldb/source/Utility/StringExtractorGDBRemote.h
@@ -164,6 +164,12 @@ public:
eServerPacketType__M,
eServerPacketType__m,
eServerPacketType_notify, // '%' notification
+
+ eServerPacketType_jTraceStart,
+ eServerPacketType_jTraceBufferRead,
+ eServerPacketType_jTraceMetaRead,
+ eServerPacketType_jTraceStop,
+ eServerPacketType_jTraceConfigRead,
};
ServerPacketType GetServerPacketType() const;
diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
index 56a7e74269a..71aeb789016 100644
--- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -13,6 +13,7 @@
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/StructuredData.h"
+#include "lldb/Core/TraceOptions.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Utility/DataBuffer.h"
@@ -370,3 +371,227 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
HandlePacket(server, "qMemoryRegionInfo:4000", "start:4000;size:0000;");
EXPECT_FALSE(result.get().Success());
}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ TraceOptions options;
+ Status error;
+
+ options.setType(lldb::TraceType::eTraceTypeProcessorTrace);
+ options.setMetaDataBufferSize(8192);
+ options.setTraceBufferSize(8192);
+ options.setThreadID(0x23);
+
+ StructuredData::DictionarySP custom_params =
+ std::make_shared<StructuredData::Dictionary>();
+ custom_params->AddStringItem("tracetech", "intel-pt");
+ custom_params->AddIntegerItem("psb", 0x01);
+
+ options.setTraceParams(custom_params);
+
+ std::future<lldb::user_id_t> result = std::async(std::launch::async, [&] {
+ return client.SendStartTracePacket(options, error);
+ });
+
+ // Since the line is exceeding 80 characters.
+ std::string expected_packet1 =
+ R"(jTraceStart:{"buffersize" : 8192,"metabuffersize" : 8192,"params" :)";
+ std::string expected_packet2 =
+ R"( {"psb" : 1,"tracetech" : "intel-pt"},"threadid" : 35,"type" : 1})";
+ HandlePacket(server, (expected_packet1 + expected_packet2), "1");
+ ASSERT_TRUE(error.Success());
+ ASSERT_EQ(result.get(), 1);
+
+ error.Clear();
+ result = std::async(std::launch::async, [&] {
+ return client.SendStartTracePacket(options, error);
+ });
+
+ HandlePacket(server, (expected_packet1 + expected_packet2), "E23");
+ ASSERT_EQ(result.get(), LLDB_INVALID_UID);
+ ASSERT_FALSE(error.Success());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendStopTracePacket) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ lldb::tid_t thread_id = 0x23;
+ lldb::user_id_t trace_id = 3;
+
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.SendStopTracePacket(trace_id, thread_id);
+ });
+
+ const char *expected_packet =
+ R"(jTraceStop:{"threadid" : 35,"traceid" : 3})";
+ HandlePacket(server, expected_packet, "OK");
+ ASSERT_TRUE(result.get().Success());
+
+ result = std::async(std::launch::async, [&] {
+ return client.SendStopTracePacket(trace_id, thread_id);
+ });
+
+ HandlePacket(server, expected_packet, "E23");
+ ASSERT_FALSE(result.get().Success());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ lldb::tid_t thread_id = 0x23;
+ lldb::user_id_t trace_id = 3;
+
+ uint8_t buf[32] = {};
+ llvm::MutableArrayRef<uint8_t> buffer(buf, 32);
+ size_t offset = 0;
+
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.SendGetDataPacket(trace_id, thread_id, buffer, offset);
+ });
+
+ std::string expected_packet1 =
+ R"(jTraceBufferRead:{"buffersize" : 32,"offset" : 0,"threadid" : 35,)";
+ std::string expected_packet2 = R"("traceid" : 3})";
+ HandlePacket(server, expected_packet1+expected_packet2, "123456");
+ ASSERT_TRUE(result.get().Success());
+ ASSERT_EQ(buffer.size(), 3);
+ ASSERT_EQ(buf[0], 0x12);
+ ASSERT_EQ(buf[1], 0x34);
+ ASSERT_EQ(buf[2], 0x56);
+
+ llvm::MutableArrayRef<uint8_t> buffer2(buf, 32);
+ result = std::async(std::launch::async, [&] {
+ return client.SendGetDataPacket(trace_id, thread_id, buffer2, offset);
+ });
+
+ HandlePacket(server, expected_packet1+expected_packet2, "E23");
+ ASSERT_FALSE(result.get().Success());
+ ASSERT_EQ(buffer2.size(), 0);
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ lldb::tid_t thread_id = 0x23;
+ lldb::user_id_t trace_id = 3;
+
+ uint8_t buf[32] = {};
+ llvm::MutableArrayRef<uint8_t> buffer(buf, 32);
+ size_t offset = 0;
+
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.SendGetMetaDataPacket(trace_id, thread_id, buffer, offset);
+ });
+
+ std::string expected_packet1 =
+ R"(jTraceMetaRead:{"buffersize" : 32,"offset" : 0,"threadid" : 35,)";
+ std::string expected_packet2 = R"("traceid" : 3})";
+ HandlePacket(server, expected_packet1+expected_packet2, "123456");
+ ASSERT_TRUE(result.get().Success());
+ ASSERT_EQ(buffer.size(), 3);
+ ASSERT_EQ(buf[0], 0x12);
+ ASSERT_EQ(buf[1], 0x34);
+ ASSERT_EQ(buf[2], 0x56);
+
+ llvm::MutableArrayRef<uint8_t> buffer2(buf, 32);
+ result = std::async(std::launch::async, [&] {
+ return client.SendGetMetaDataPacket(trace_id, thread_id, buffer2, offset);
+ });
+
+ HandlePacket(server, expected_packet1+expected_packet2, "E23");
+ ASSERT_FALSE(result.get().Success());
+ ASSERT_EQ(buffer2.size(), 0);
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ lldb::tid_t thread_id = 0x23;
+ lldb::user_id_t trace_id = 3;
+ TraceOptions options;
+ options.setThreadID(thread_id);
+
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.SendGetTraceConfigPacket(trace_id, options);
+ });
+
+ const char *expected_packet =
+ R"(jTraceConfigRead:{"threadid" : 35,"traceid" : 3})";
+ std::string response1 =
+ R"({"buffersize" : 8192,"params" : {"psb" : 1,"tracetech" : "intel-pt"})";
+ std::string response2 =
+ R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
+ HandlePacket(server, expected_packet, response1+response2);
+ ASSERT_TRUE(result.get().Success());
+ ASSERT_EQ(options.getTraceBufferSize(), 8192);
+ ASSERT_EQ(options.getMetaDataBufferSize(), 8192);
+ ASSERT_EQ(options.getType(), 1);
+
+ auto custom_params = options.getTraceParams();
+
+ uint64_t psb_value;
+ llvm::StringRef trace_tech_value;
+
+ ASSERT_TRUE(custom_params);
+ ASSERT_EQ(custom_params->GetType(), StructuredData::Type::eTypeDictionary);
+ ASSERT_TRUE(
+ custom_params->GetValueForKeyAsInteger<uint64_t>("psb", psb_value));
+ ASSERT_EQ(psb_value, 1);
+ ASSERT_TRUE(
+ custom_params->GetValueForKeyAsString("tracetech", trace_tech_value));
+ ASSERT_STREQ(trace_tech_value.data(), "intel-pt");
+
+ // Checking error response.
+ std::future<Status> result2 = std::async(std::launch::async, [&] {
+ return client.SendGetTraceConfigPacket(trace_id, options);
+ });
+
+ HandlePacket(server, expected_packet, "E23");
+ ASSERT_FALSE(result2.get().Success());
+
+ // Wrong JSON as response.
+ std::future<Status> result3 = std::async(std::launch::async, [&] {
+ return client.SendGetTraceConfigPacket(trace_id, options);
+ });
+
+ std::string incorrect_json1 =
+ R"("buffersize" : 8192,"params" : {"psb" : 1,"tracetech" : "intel-pt"})";
+ std::string incorrect_json2 =
+ R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
+ HandlePacket(server, expected_packet, incorrect_json1+incorrect_json2);
+ ASSERT_FALSE(result3.get().Success());
+
+ // Wrong JSON as custom_params.
+ std::future<Status> result4 = std::async(std::launch::async, [&] {
+ return client.SendGetTraceConfigPacket(trace_id, options);
+ });
+
+ std::string incorrect_custom_params1 =
+ R"({"buffersize" : 8192,"params" : "psb" : 1,"tracetech" : "intel-pt"})";
+ std::string incorrect_custom_params2 =
+ R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
+ HandlePacket(server, expected_packet, incorrect_custom_params1+
+ incorrect_custom_params2);
+ ASSERT_FALSE(result4.get().Success());
+} \ No newline at end of file
OpenPOWER on IntegriCloud