ravitheja updated this revision to Diff 98599.
ravitheja added a comment.
Changes for the feedback recieved in first round of review.
https://reviews.llvm.org/D32585
Files:
docs/lldb-gdb-remote.txt
include/lldb/API/SBTrace.h
include/lldb/Core/TraceOptions.h
include/lldb/Host/common/NativeProcessProtocol.h
include/lldb/Target/Process.h
include/lldb/Utility/StringExtractor.h
source/API/SBProcess.cpp
source/API/SBTrace.cpp
source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
source/Utility/StringExtractor.cpp
source/Utility/StringExtractorGDBRemote.cpp
source/Utility/StringExtractorGDBRemote.h
Index: source/Utility/StringExtractorGDBRemote.h
===================================================================
--- source/Utility/StringExtractorGDBRemote.h
+++ source/Utility/StringExtractorGDBRemote.h
@@ -164,6 +164,12 @@
eServerPacketType__M,
eServerPacketType__m,
eServerPacketType_notify, // '%' notification
+
+ eServerPacketType_JTrace_Start,
+ eServerPacketType_jTraceBufferRead,
+ eServerPacketType_jTraceMetaRead,
+ eServerPacketType_JTrace_Stop,
+ eServerPacketType_jTraceConfigRead,
};
ServerPacketType GetServerPacketType() const;
Index: source/Utility/StringExtractorGDBRemote.cpp
===================================================================
--- source/Utility/StringExtractorGDBRemote.cpp
+++ source/Utility/StringExtractorGDBRemote.cpp
@@ -279,13 +279,26 @@
}
break;
+ case 'J':
+ if (PACKET_STARTS_WITH("JTrace:start:"))
+ return eServerPacketType_JTrace_Start;
+ if (PACKET_STARTS_WITH("JTrace:stop:"))
+ return eServerPacketType_JTrace_Stop;
+ break;
+
case 'j':
if (PACKET_STARTS_WITH("jModulesInfo:"))
return eServerPacketType_jModulesInfo;
if (PACKET_MATCHES("jSignalsInfo"))
return eServerPacketType_jSignalsInfo;
if (PACKET_MATCHES("jThreadsInfo"))
return eServerPacketType_jThreadsInfo;
+ if (PACKET_STARTS_WITH("jTrace:buffer:read:"))
+ return eServerPacketType_jTraceBufferRead;
+ if (PACKET_STARTS_WITH("jTrace:conf:read:"))
+ return eServerPacketType_jTraceConfigRead;
+ if (PACKET_STARTS_WITH("jTrace:meta:read:"))
+ return eServerPacketType_jTraceMetaRead;
break;
case 'v':
Index: source/Utility/StringExtractor.cpp
===================================================================
--- source/Utility/StringExtractor.cpp
+++ source/Utility/StringExtractor.cpp
@@ -280,6 +280,15 @@
return result;
}
+bool StringExtractor::Consume_front(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;
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -175,6 +175,21 @@
Error DisableWatchpoint(Watchpoint *wp, bool notify = true) override;
+ lldb::user_id_t StartTrace(const TraceOptions &options,
+ Error &error) override;
+
+ Error StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) override;
+
+ Error GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) override;
+
+ Error GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) override;
+
+ Error GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
+
Error GetWatchpointSupportInfo(uint32_t &num) override;
Error GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
@@ -407,6 +422,10 @@
std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
uint64_t m_last_signals_version = 0;
+ Error GetTraceData(StreamString &packet, lldb::user_id_t uid,
+ lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer, size_t offset);
+
static bool NewThreadNotifyBreakpointHit(void *baton,
StoppointCallbackContext *context,
lldb::user_id_t break_id,
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -65,6 +65,7 @@
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Utility/CleanUp.h"
#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/StreamGDBRemote.h"
#include "lldb/Utility/StreamString.h"
// Project includes
@@ -1236,6 +1237,181 @@
return error;
}
+lldb::user_id_t ProcessGDBRemote::StartTrace(const TraceOptions &options,
+ Error &error) {
+
+ StreamString packet;
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ lldb::user_id_t ret_uid = LLDB_INVALID_UID;
+
+ packet.PutCString("JTrace:start:");
+ packet.Printf("type:%" PRIx32 ";", options.getType());
+ packet.Printf("buffersize:%" PRIx64 ";", options.getTraceBufferSize());
+ packet.Printf("metabuffersize:%" PRIx64 ";", options.getMetaDataBufferSize());
+
+ if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+ packet.Printf("threadid:%" PRIx64 ";", options.getThreadID());
+
+ StructuredData::DictionarySP custom_params = options.getTraceParams();
+ if (custom_params) {
+ packet.Printf("jparams:");
+ custom_params->Dump(packet, false);
+ packet.PutCString(";");
+ }
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutEscapedBytes(packet.GetData(), packet.GetSize());
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.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;
+}
+
+Error ProcessGDBRemote::StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ StringExtractorGDBRemote response;
+ Error error;
+
+ StreamString packet;
+ packet.PutCString("JTrace:stop:");
+ packet.Printf("traceid:%" PRIx64 ";", uid);
+
+ if (thread_id != LLDB_INVALID_THREAD_ID)
+ packet.Printf("threadid:%" PRIx64 ";", thread_id);
+
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (!response.IsNormalResponse()) {
+ 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'",
+ packet.GetData());
+ }
+ return error;
+}
+
+Error ProcessGDBRemote::GetTraceData(StreamString &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));
+ Error error;
+
+ packet.Printf("traceid:%" PRIx64 ";", uid);
+ packet.Printf("offset:%" PRIx64 ";", offset);
+ packet.Printf("buffersize:%" PRIx64 ";", buffer.size());
+
+ if (thread_id != LLDB_INVALID_THREAD_ID)
+ packet.Printf("threadid:%" PRIx64 ";", thread_id);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.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;
+}
+
+Error ProcessGDBRemote::GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+
+ StreamString packet;
+ packet.PutCString("jTrace:buffer:read:");
+ return GetTraceData(packet, uid, thread_id, buffer, offset);
+}
+
+Error ProcessGDBRemote::GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+ StreamString packet;
+ packet.PutCString("jTrace:meta:read:");
+ return GetTraceData(packet, uid, thread_id, buffer, offset);
+}
+
+Error ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid,
+ TraceOptions &options) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ StringExtractorGDBRemote response;
+ Error error;
+
+ StreamString packet;
+ packet.PutCString("jTrace:conf:read:");
+ packet.Printf("traceid:%" PRIx64 ";", uid);
+
+ if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+ packet.Printf("threadid:%" PRIx64 ";", options.getThreadID());
+
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ llvm::StringRef name, value;
+ StructuredData::ObjectSP json_object;
+ while (response.GetNameColonValue(name, value)) {
+ uint64_t extracted_value;
+ value.getAsInteger(16, extracted_value);
+
+ if (name.equals("buffersize")) {
+ options.setTraceBufferSize(extracted_value);
+ } else if (name.equals("metabuffersize")) {
+ options.setMetaDataBufferSize(extracted_value);
+ } else if (name.equals("type")) {
+ options.setType(static_cast<lldb::TraceType>(extracted_value));
+ } else if (name.equals("jparams")) {
+ auto json_object = StructuredData::ParseJSON(value.data());
+ if (!json_object ||
+ json_object->GetType() != StructuredData::Type::eTypeDictionary) {
+ error.SetErrorString("Invalid Configuration obtained");
+ break;
+ }
+ options.setTraceParams(
+ std::static_pointer_cast<StructuredData::Dictionary>(
+ json_object));
+ } else {
+ error.SetErrorString("Invalid Configuration obtained");
+ break;
+ }
+ }
+ } else {
+ error.SetError(response.GetError(), eErrorTypeGeneric);
+ }
+ } else {
+ LLDB_LOG(log, "failed to send packet");
+ error.SetErrorStringWithFormat("failed to send packet: '%s'",
+ packet.GetData());
+ }
+ return error;
+}
+
void ProcessGDBRemote::DidExit() {
// When we exit, disconnect from the GDB server communications
m_gdb_comm.Disconnect();
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -189,6 +189,14 @@
PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet);
+ PacketResult Handle_JTrace_start(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jTrace_read(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_JTrace_stop(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jTrace_conf_read(StringExtractorGDBRemote &packet);
+
PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -183,6 +183,22 @@
StringExtractorGDBRemote::eServerPacketType_QPassSignals,
&GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_JTrace_Start,
+ &GDBRemoteCommunicationServerLLGS::Handle_JTrace_start);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceBufferRead,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTrace_read);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceMetaRead,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTrace_read);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_JTrace_Stop,
+ &GDBRemoteCommunicationServerLLGS::Handle_JTrace_stop);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTrace_conf_read);
+
RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
[this](StringExtractorGDBRemote packet, Error &error,
bool &interrupt, bool &quit) {
@@ -1083,6 +1099,284 @@
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_JTrace_start(
+ 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.Consume_front("JTrace:start:"))
+ return SendIllFormedResponse(packet, "JTrace:start: 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();
+ bool error_encountered = false;
+
+ llvm::StringRef name, value;
+ StructuredData::ObjectSP json_object;
+
+ while (packet.GetNameColonValue(name, value)) {
+ uint64_t extracted_value;
+ value.getAsInteger(16, extracted_value);
+
+ if (name.equals("type"))
+ type = extracted_value;
+
+ else if (name.equals("threadid"))
+ tid = extracted_value;
+
+ else if (name.equals("buffersize"))
+ buffersize = extracted_value;
+
+ else if (name.equals("metabuffersize"))
+ metabuffersize = extracted_value;
+
+ else if (name.equals("jparams")) {
+ json_object = StructuredData::ParseJSON(value.data());
+ }
+
+ else {
+ error_encountered = true;
+ break;
+ }
+ }
+
+ if (!json_object ||
+ json_object->GetType() != StructuredData::Type::eTypeDictionary)
+ error_encountered = true;
+
+ if (error_encountered || buffersize == std::numeric_limits<uint64_t>::max() ||
+ type != lldb::TraceType::eTraceTypeProcessorTrace ||
+ packet.GetBytesLeft()) {
+ LLDB_LOG(log,
+ "Ill formed packet error_encountered = {0} buffersize = {1} type "
+ "= {2} packet empty = { 3 } ",
+ error_encountered, buffersize, type, packet.Empty());
+ return SendIllFormedResponse(packet, "JTrace:start: Ill formed packet ");
+ }
+
+ options.setMetaDataBufferSize(metabuffersize);
+ options.setTraceBufferSize(buffersize);
+ options.setType(static_cast<lldb::TraceType>(type));
+ options.setThreadID(tid);
+ options.setTraceParams(
+ std::static_pointer_cast<StructuredData::Dictionary>(json_object));
+
+ Error error;
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+ uid = m_debugged_process_sp->StartTrace(options, error);
+
+ if (error.Fail())
+ return SendErrorResponse(error.GetError());
+
+ StreamGDBRemote response;
+ response.Printf("%" PRIx64, uid);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_JTrace_stop(
+ 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.Consume_front("JTrace:stop:"))
+ return SendIllFormedResponse(packet, "JTrace:stop: Ill formed packet ");
+
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ bool error_encountered = false;
+
+ llvm::StringRef name, value;
+ while (packet.GetNameColonValue(name, value)) {
+ uint64_t extracted_value;
+ if (!value.getAsInteger(16, extracted_value)) {
+ if (name.equals("threadid"))
+ tid = extracted_value;
+
+ else if (name.equals("traceid"))
+ uid = extracted_value;
+
+ else {
+ error_encountered = true;
+ break;
+ }
+ }
+
+ else {
+ error_encountered = true;
+ break;
+ }
+ }
+
+ if (error_encountered || uid == LLDB_INVALID_UID || packet.GetBytesLeft())
+ return SendIllFormedResponse(packet, "JTrace:stop: Ill formed packet ");
+
+ Error error = m_debugged_process_sp->StopTrace(uid, tid);
+
+ if (error.Fail())
+ return SendErrorResponse(error.GetError());
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTrace_conf_read(
+ 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.Consume_front("jTrace:conf:read:"))
+ return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+ lldb::tid_t threadid = LLDB_INVALID_THREAD_ID;
+ bool error_encountered = false;
+
+ llvm::StringRef name, value;
+ while (packet.GetNameColonValue(name, value)) {
+ uint64_t extracted_value;
+
+ if (!value.getAsInteger(16, extracted_value)) {
+ if (name.equals("threadid"))
+ threadid = extracted_value;
+
+ else if (name.equals("traceid"))
+ uid = extracted_value;
+
+ else {
+ error_encountered = true;
+ break;
+ }
+ } else {
+ error_encountered = true;
+ break;
+ }
+ }
+
+ if (error_encountered || uid == LLDB_INVALID_UID || packet.GetBytesLeft())
+ return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+ TraceOptions options;
+ StreamGDBRemote response;
+
+ options.setThreadID(threadid);
+ Error error = m_debugged_process_sp->GetTraceConfig(uid, options);
+
+ if (error.Fail())
+ return SendErrorResponse(error.GetError());
+
+ response.Printf("type:%" PRIx32 ";", options.getType());
+ response.Printf("buffersize:%" PRIx64 ";", options.getTraceBufferSize());
+ response.Printf("metabuffersize:%" PRIx64 ";",
+ options.getMetaDataBufferSize());
+
+ const StructuredData::DictionarySP custom_params = options.getTraceParams();
+ if (custom_params) {
+ response.Printf("jparams:");
+ custom_params->Dump(response, false);
+ response.PutChar(';');
+ }
+ StreamGDBRemote escaped_response;
+ escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTrace_read(
+ 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.Consume_front("jTrace:buffer:read:"))
+ tracetype = BufferData;
+ else if (packet.Consume_front("jTrace:meta:read:"))
+ 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();
+ bool error_encountered = false;
+ llvm::StringRef name, value;
+
+ while (packet.GetNameColonValue(name, value)) {
+ uint64_t extracted_value;
+
+ if (!value.getAsInteger(16, extracted_value)) {
+ if (name.equals("buffersize"))
+ byte_count = extracted_value;
+
+ else if (name.equals("threadid"))
+ tid = extracted_value;
+
+ else if (name.equals("offset"))
+ offset = extracted_value;
+
+ else if (name.equals("traceid"))
+ uid = extracted_value;
+
+ else {
+ error_encountered = true;
+ break;
+ }
+ } else {
+ error_encountered = true;
+ break;
+ }
+ }
+
+ if (error_encountered || uid == LLDB_INVALID_UID || packet.GetBytesLeft() ||
+ byte_count == std::numeric_limits<size_t>::max() ||
+ offset == std::numeric_limits<size_t>::max())
+ return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+ // Allocate the response buffer.
+ std::vector<uint8_t> buffer(byte_count, '\0');
+ if (buffer.empty())
+ return SendErrorResponse(0x78);
+
+ StreamGDBRemote response;
+ Error error;
+ llvm::MutableArrayRef<uint8_t> buf(buffer);
+
+ 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.
Index: source/API/SBTrace.cpp
===================================================================
--- source/API/SBTrace.cpp
+++ source/API/SBTrace.cpp
@@ -25,37 +25,37 @@
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 @@
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 @@
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)));
}
}
Index: source/API/SBProcess.cpp
===================================================================
--- source/API/SBProcess.cpp
+++ source/API/SBProcess.cpp
@@ -363,10 +363,9 @@
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;
}
Index: include/lldb/Utility/StringExtractor.h
===================================================================
--- include/lldb/Utility/StringExtractor.h
+++ include/lldb/Utility/StringExtractor.h
@@ -111,6 +111,8 @@
size_t GetHexByteStringTerminatedBy(std::string &str, char terminator);
+ bool Consume_front(const llvm::StringRef &str);
+
const char *Peek() {
if (m_index < m_packet.size())
return m_packet.c_str() + m_index;
Index: include/lldb/Target/Process.h
===================================================================
--- include/lldb/Target/Process.h
+++ include/lldb/Target/Process.h
@@ -2780,7 +2780,7 @@
/// 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,
Error &error) {
error.SetErrorString("Not implemented");
return LLDB_INVALID_UID;
@@ -2795,9 +2795,8 @@
/// 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,
- Error &error) {
- error.SetErrorString("Not implemented");
+ virtual Error StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
+ return Error("Not implemented");
}
//------------------------------------------------------------------
@@ -2808,21 +2807,19 @@
/// 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,
- Error &error, void *buf, size_t size,
- size_t offset = 0) {
- error.SetErrorString("Not implemented");
- return 0;
+ virtual Error GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Error("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,
- Error &error, void *buf, size_t size,
- size_t offset = 0) {
- error.SetErrorString("Not implemented");
- return 0;
+ virtual Error GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Error("Not implemented");
}
//------------------------------------------------------------------
@@ -2834,10 +2831,8 @@
/// 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, Error &error,
- lldb::TraceOptionsSP &options) {
- error.SetErrorString("Not implemented");
- return;
+ virtual Error GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) {
+ return Error("Not implemented");
}
protected:
Index: include/lldb/Host/common/NativeProcessProtocol.h
===================================================================
--- include/lldb/Host/common/NativeProcessProtocol.h
+++ 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/Error.h"
#include "lldb/lldb-private-forward.h"
@@ -308,6 +309,109 @@
static Error 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.
+ ///
+ /// @param[in] thread
+ /// The thread to start tracing on, in case whole process needs
+ /// to be traced use INVALID_THREAD_ID.
+ ///
+ /// @param[in] config
+ /// The configuration to use when starting tracing.
+ ///
+ /// @param[out] error
+ /// Error 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, Error &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
+ /// Error indicating what went wrong.
+ //------------------------------------------------------------------
+ virtual Error StopTrace(lldb::user_id_t uid,
+ lldb::tid_t thread = LLDB_INVALID_THREAD_ID) {
+ return Error("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] buf buf_size
+ /// The buf and buf_size provide the destination buffer
+ /// where the trace data would be read to.
+ ///
+ /// @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 Error GetData(lldb::user_id_t uid, lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Error("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// Similar API as above except it aims to provide any extra data
+ /// useful for decoding the actual trace data.
+ //------------------------------------------------------------------
+ virtual Error GetMetaData(lldb::user_id_t uid, lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Error("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// API to query the TraceOptions for a given user id
+ ///
+ /// @param[in] uid
+ /// The user id of the tracing instance.
+ ///
+ /// @param[in] threadid
+ /// The thread id of the tracing instance, in case configuration
+ /// for a specific thread is needed.
+ ///
+ /// @param[out] error
+ /// Error indicates what went wrong.
+ ///
+ /// @param[out] config
+ /// The actual configuration being used for tracing.
+ //------------------------------------------------------------------
+ virtual Error GetTraceConfig(lldb::user_id_t uid, TraceOptions &config) {
+ return Error("Not implemented");
+ }
+
protected:
lldb::pid_t m_pid;
Index: include/lldb/Core/TraceOptions.h
===================================================================
--- include/lldb/Core/TraceOptions.h
+++ 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 @@
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;
Index: include/lldb/API/SBTrace.h
===================================================================
--- include/lldb/API/SBTrace.h
+++ include/lldb/API/SBTrace.h
@@ -40,7 +40,7 @@
///
/// @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 @@
/// 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.
//------------------------------------------------------------------
Index: docs/lldb-gdb-remote.txt
===================================================================
--- docs/lldb-gdb-remote.txt
+++ docs/lldb-gdb-remote.txt
@@ -209,6 +209,161 @@
read packet: OK
//----------------------------------------------------------------------
+// JTrace:start:
+//
+// BRIEF
+// Packet for starting trace of type lldb::TraceType. The following
+// parameters (mandatory and optional) should be appended to the packet
+// although there is no specific order imposed. The parameters need to
+// formatted as a semi-colon seperated list of "Name:Value" pairs.
+// 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 "jparams"). Since sending
+// JSON data over gdb-remote protocol has certain limitations, binary
+// escaping convention is used for JSON data.
+//
+// Following is the list of parameters -
+//
+// Name Value (Hex Encoded 64-bit integer) (O)Optional/
+// (except jparams 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.
+//
+// jparams 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: JTrace:start:type:<type>;buffersize:<buffersize>;
+read packet: <trace id>/E<error code>
+
+//----------------------------------------------------------------------
+// JTrace:stop:
+//
+// BRIEF
+// Stop tracing instance with trace id <trace id>, of course trace
+// needs to be started before.
+//
+// Following is the list of parameters -
+//
+// Name Value (Hex Encoded 64-bit 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: JTrace:stop:traceid:<trace id>;
+read packet: <OK response>/E<error code>
+
+//----------------------------------------------------------------------
+// jTrace:buffer:read:
+//
+// BRIEF
+// Packet for reading the trace for tracing instance <trace id>, i.e the
+// id obtained from StartTrace API.
+//
+// Following is the list of parameters -
+//
+// Name Value (Hex Encoded 64-bit 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: jTrace:buffer:read:traceid:<trace id>;offset:<byteoffset>;buffersize:<byte_count>;
+read packet: <binary trace data>/E<error code>
+
+//----------------------------------------------------------------------
+// jTrace:meta:read:traceid:<trace id>;
+//
+// BRIEF
+// Similar Packet as above except it reads meta data.
+//----------------------------------------------------------------------
+
+/----------------------------------------------------------------------
+// jTrace:conf:read:
+//
+// BRIEF
+// Request the trace configuration for the tracing instance with id
+// <trace id>.
+//
+// Following is the list of parameters -
+//
+// Name Value (Hex Encoded 64-bit 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.
+// ========== ====================================================
+//
+// The numerical values are Hex Encoded 64-bit integers (including the
+// values obtained in the response).
+// In the response packet the trace configuration is sent as text,
+// formatted as "Name:Value" pair seperated by a semi colon (in the
+// case of custom parameters the value should be a JSON Structure with
+// Name as "jparams"). Since sending JSON data over gdb-remote protocol
+// has certain limitations, binary escaping convention is used for JSON
+// data.
+// In case the trace instance with the <trace id> was not found, an
+// error code is returned.
+//----------------------------------------------------------------------
+
+send packet: jTrace:conf:read:traceid:<trace id>;
+read packet: conf1:<conf1>;conf2:<conf2>;jparams:{"paramName":paramValue}];/E<error code>
+
+//----------------------------------------------------------------------
// "qRegisterInfo<hex-reg-id>"
//
// BRIEF
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits