wallace created this revision. wallace added a reviewer: clayborg. Herald added a project: LLDB. Herald added a subscriber: lldb-commits. wallace requested review of this revision. Herald added a subscriber: JDevlieghere.
Depends on D89283 <https://reviews.llvm.org/D89283>. The goal of this packet (jTraceGetSupportedType) is to be able to query the gdb-server for the tracing technology that can work for the current debuggeer, which can make the user experience simpler but allowing the user to simply type thread trace start to start tracing the current thread without even telling the debugger to use "intel-pt", for example. Similarly, `thread trace start [args...]` would accept args beloging to the working trace type. Also, if the user typed help thread trace start We could directly show the help information of the trace type that is supported for the target, or mention instead that no tracing is supported, if that's the case. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D90490 Files: lldb/docs/lldb-gdb-remote.txt lldb/include/lldb/Host/common/NativeProcessProtocol.h lldb/include/lldb/Target/Process.h lldb/include/lldb/Utility/StringExtractorGDBRemote.h lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp lldb/source/Plugins/Process/Linux/NativeProcessLinux.h lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp lldb/source/Plugins/Process/Linux/ProcessorTrace.h lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h lldb/source/Utility/StringExtractorGDBRemote.cpp lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
Index: lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp =================================================================== --- lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -362,6 +362,30 @@ EXPECT_FALSE(result.get().Success()); } +TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedTypePacket) { + // Success response + { + std::future<llvm::Expected<lldb::TraceType>> result = std::async( + std::launch::async, [&] { return client.SendGetSupportedTraceType(); }); + + HandlePacket(server, "jTraceSupportedType", "1"); + llvm::Expected<lldb::TraceType> trace_type_or_err = result.get(); + EXPECT_THAT_EXPECTED( + trace_type_or_err, + llvm::HasValue(lldb::TraceType::eTraceTypeProcessorTrace)); + } + + // Error response + { + std::future<llvm::Expected<lldb::TraceType>> result = std::async( + std::launch::async, [&] { return client.SendGetSupportedTraceType(); }); + + HandlePacket(server, "jTraceSupportedType", "E23"); + llvm::Expected<lldb::TraceType> trace_type_or_err = result.get(); + ASSERT_THAT_EXPECTED(trace_type_or_err, llvm::Failed()); + } +} + TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) { TraceOptions options; Status error; Index: lldb/source/Utility/StringExtractorGDBRemote.cpp =================================================================== --- lldb/source/Utility/StringExtractorGDBRemote.cpp +++ lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -310,6 +310,8 @@ return eServerPacketType_jTraceStart; if (PACKET_STARTS_WITH("jTraceStop:")) return eServerPacketType_jTraceStop; + if (PACKET_MATCHES("jTraceSupportedType")) + return eServerPacketType_jTraceSupportedType; break; case 'v': Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -175,6 +175,8 @@ llvm::MutableArrayRef<uint8_t> &buffer, size_t offset = 0) override; + llvm::Expected<lldb::TraceType> GetSupportedTraceType() override; + Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override; Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override; Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1224,6 +1224,10 @@ return m_gdb_comm.SendGetTraceConfigPacket(uid, options); } +llvm::Expected<lldb::TraceType> ProcessGDBRemote::GetSupportedTraceType() { + return m_gdb_comm.SendGetSupportedTraceType(); +} + void ProcessGDBRemote::DidExit() { // When we exit, disconnect from the GDB server communications m_gdb_comm.Disconnect(); Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -164,6 +164,8 @@ PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet); + PacketResult Handle_jTraceSupportedType(StringExtractorGDBRemote &packet); + PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet); PacketResult Handle_vAttach(StringExtractorGDBRemote &packet); Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -191,6 +191,9 @@ RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead, &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_jTraceSupportedType, + &GDBRemoteCommunicationServerLLGS::Handle_jTraceSupportedType); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g, &GDBRemoteCommunicationServerLLGS::Handle_g); @@ -1226,6 +1229,23 @@ return SendOKResponse(); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_jTraceSupportedType( + StringExtractorGDBRemote &packet) { + + // Fail if we don't have a current process. + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(68); + + lldb::TraceType supported_trace_type = + m_debugged_process_up->GetSupportedTraceType(); + + StreamGDBRemote response; + response.Printf("%" PRIu32, static_cast<uint32_t>(supported_trace_type)); + return SendPacketNoLock(response.GetString()); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead( StringExtractorGDBRemote &packet) { Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -519,6 +519,8 @@ Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options); + llvm::Expected<lldb::TraceType> SendGetSupportedTraceType(); + protected: LazyBool m_supports_not_sending_acks; LazyBool m_supports_thread_suffix; Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -43,6 +43,7 @@ using namespace lldb; using namespace lldb_private::process_gdb_remote; using namespace lldb_private; +using namespace llvm; using namespace std::chrono; llvm::raw_ostream &process_gdb_remote::operator<<(llvm::raw_ostream &os, @@ -3454,6 +3455,28 @@ return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset); } +llvm::Expected<lldb::TraceType> +GDBRemoteCommunicationClient::SendGetSupportedTraceType() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + + StreamGDBRemote escaped_packet; + escaped_packet.PutCString("jTraceSupportedType"); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, + true) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsNormalResponse()) + return static_cast<lldb::TraceType>( + response.GetU32(lldb::eTraceTypeNone, 10)); + else + return response.GetStatus().ToError(); + } + LLDB_LOG(log, "failed to send packet: jTraceSupportedType"); + return createStringError(inconvertibleErrorCode(), + "failed to send packet: jTraceSupportedType"); +} + Status GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options) { Index: lldb/source/Plugins/Process/Linux/ProcessorTrace.h =================================================================== --- lldb/source/Plugins/Process/Linux/ProcessorTrace.h +++ lldb/source/Plugins/Process/Linux/ProcessorTrace.h @@ -93,6 +93,10 @@ void SetThreadID(lldb::tid_t tid) { m_thread_id = tid; } public: + static llvm::Expected<uint32_t> GetOSEventType(); + + static bool IsSupported(); + static Status GetCPUType(TraceOptions &config); static llvm::Expected<ProcessorTraceMonitorUP> Index: lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp =================================================================== --- lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp +++ lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp @@ -26,6 +26,8 @@ using namespace llvm; lldb::user_id_t ProcessorTraceMonitor::m_trace_num = 1; +const char *kOSEventIntelPTTypeFile = + "/sys/bus/event_source/devices/intel_pt/type"; Status ProcessorTraceMonitor::GetTraceConfig(TraceOptions &config) const { #ifndef PERF_ATTR_SIZE_VER5 @@ -44,6 +46,27 @@ #endif } +Expected<uint32_t> ProcessorTraceMonitor::GetOSEventType() { + auto intel_pt_type_text = + llvm::MemoryBuffer::getFileAsStream(kOSEventIntelPTTypeFile); + + if (!intel_pt_type_text) + return createStringError(inconvertibleErrorCode(), + "Can't open the file '%s'", + kOSEventIntelPTTypeFile); + + uint32_t intel_pt_type = 0; + StringRef buffer = intel_pt_type_text.get()->getBuffer(); + if (buffer.empty() || buffer.trim().getAsInteger(10, intel_pt_type)) + return createStringError( + inconvertibleErrorCode(), + "The file '%s' has a invalid value. It should be an unsigned int.", + kOSEventIntelPTTypeFile); + return intel_pt_type; +} + +bool ProcessorTraceMonitor::IsSupported() { return (bool)GetOSEventType(); } + Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid, const TraceOptions &config) { #ifndef PERF_ATTR_SIZE_VER5 @@ -76,25 +99,15 @@ attr.exclude_idle = 1; attr.mmap = 1; - int intel_pt_type = 0; - - auto ret = llvm::MemoryBuffer::getFileAsStream( - "/sys/bus/event_source/devices/intel_pt/type"); - if (!ret) { - LLDB_LOG(log, "failed to open Config file"); - return ret.getError(); - } + Expected<uint32_t> intel_pt_type = GetOSEventType(); - StringRef rest = ret.get()->getBuffer(); - if (rest.empty() || rest.trim().getAsInteger(10, intel_pt_type)) { - LLDB_LOG(log, "failed to read Config file"); - error.SetErrorString("invalid file"); + if (!intel_pt_type) { + error = intel_pt_type.takeError(); return error; } - rest.trim().getAsInteger(10, intel_pt_type); - LLDB_LOG(log, "intel pt type {0}", intel_pt_type); - attr.type = intel_pt_type; + LLDB_LOG(log, "intel pt type {0}", *intel_pt_type); + attr.type = *intel_pt_type; LLDB_LOG(log, "meta buffer size {0}", metabufsize); LLDB_LOG(log, "buffer size {0} ", bufsize); Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.h =================================================================== --- lldb/source/Plugins/Process/Linux/NativeProcessLinux.h +++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -117,6 +117,8 @@ Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) override; + virtual lldb::TraceType GetSupportedTraceType() override; + // Interface used by NativeRegisterContext-derived classes. static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, void *data = nullptr, size_t data_size = 0, Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -1995,6 +1995,12 @@ return error; } +lldb::TraceType NativeProcessLinux::GetSupportedTraceType() { + if (ProcessorTraceMonitor::IsSupported()) + return eTraceTypeProcessorTrace; + return eTraceTypeNone; +} + lldb::user_id_t NativeProcessLinux::StartTraceGroup(const TraceOptions &config, Status &error) { Index: lldb/include/lldb/Utility/StringExtractorGDBRemote.h =================================================================== --- lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -167,6 +167,7 @@ eServerPacketType_jTraceMetaRead, eServerPacketType_jTraceStop, eServerPacketType_jTraceConfigRead, + eServerPacketType_jTraceSupportedType, }; ServerPacketType GetServerPacketType() const; Index: lldb/include/lldb/Target/Process.h =================================================================== --- lldb/include/lldb/Target/Process.h +++ lldb/include/lldb/Target/Process.h @@ -2542,6 +2542,18 @@ return Status("Not implemented"); } + /// Get the tracing type supported by the gdb-server for the current + /// inferior. Responses might be different depending on the architecture and + /// capabilities of the the underlying OS. + /// + /// \return + /// The supported trace type or \a lldb::eTraceTypeNone if tracing is not + /// supported for the inferior. In case of errors communicating with the + /// gdb-server, an \a llvm::Error object is returned. + virtual llvm::Expected<lldb::TraceType> GetSupportedTraceType() { + return lldb::eTraceTypeNone; + } + // This calls a function of the form "void * (*)(void)". bool CallVoidArgVoidPtrReturn(const Address *address, lldb::addr_t &returned_func, Index: lldb/include/lldb/Host/common/NativeProcessProtocol.h =================================================================== --- lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ lldb/include/lldb/Host/common/NativeProcessProtocol.h @@ -392,6 +392,11 @@ return Status("Not implemented"); } + /// \copydoc Process::GetSupportedTraceType() + virtual lldb::TraceType GetSupportedTraceType() { + return lldb::eTraceTypeNone; + } + protected: struct SoftwareBreakpoint { uint32_t ref_count; Index: lldb/docs/lldb-gdb-remote.txt =================================================================== --- lldb/docs/lldb-gdb-remote.txt +++ lldb/docs/lldb-gdb-remote.txt @@ -234,6 +234,25 @@ send packet: QListThreadsInStopReply read packet: OK +//---------------------------------------------------------------------- +// jTraceSupportedType +// +// BRIEF +// Get the tracing type supported by the gdb-server for the current inferior. +// Responses might be different depending on the architecture and capabilities +// of the underlying OS. +// +// See lldb-enumerations for the list of available TraceType's. +// +// If no tracing technology is supported for the inferior, then +// lldb::eTraceTypeNone should be returned. +// +// If there's no process running, an error should be returned. +//---------------------------------------------------------------------- + +send packet: jTraceSupportedType +read packet: <trace type>/E<error code>;AAAAAAAAA + //---------------------------------------------------------------------- // jTraceStart: //
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits