[Lldb-commits] [lldb] 0b69756 - [trace][intel-pt] Implement trace start and trace stop

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Tue Mar 30 17:31:45 PDT 2021


Author: Walter Erquinigo
Date: 2021-03-30T17:31:37-07:00
New Revision: 0b69756110db444282c40ea16929186b2910c3b1

URL: https://github.com/llvm/llvm-project/commit/0b69756110db444282c40ea16929186b2910c3b1
DIFF: https://github.com/llvm/llvm-project/commit/0b69756110db444282c40ea16929186b2910c3b1.diff

LOG: [trace][intel-pt] Implement trace start and trace stop

This implements the interactive trace start and stop methods.

This diff ended up being much larger than I anticipated because, by doing it, I found that I had implemented in the beginning many things in a non optimal way. In any case, the code is much better now.

There's a lot of boilerplate code due to the gdb-remote protocol, but the main changes are:

- New tracing packets: jLLDBTraceStop, jLLDBTraceStart, jLLDBTraceGetBinaryData. The gdb-remote packet definitions are quite comprehensive.
- Implementation of the "process trace start|stop" and "thread trace start|stop" commands.
- Implementaiton of an API in Trace.h to interact with live traces.
- Created an IntelPTDecoder for live threads, that use the debugger's stop id as checkpoint for its internal cache.
- Added a functionality to stop the process in case "process tracing" is enabled and a new thread can't traced.
- Added tests

I have some ideas to unify the code paths for post mortem and live threads, but I'll do that in another diff.

Differential Revision: https://reviews.llvm.org/D91679

Added: 
    lldb/include/lldb/Target/ThreadPostMortemTrace.h
    lldb/include/lldb/Utility/TraceGDBRemotePackets.h
    lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
    lldb/source/Plugins/Process/Linux/IntelPTManager.cpp
    lldb/source/Plugins/Process/Linux/IntelPTManager.h
    lldb/source/Plugins/Trace/intel-pt/forward-declarations.h
    lldb/source/Target/ThreadPostMortemTrace.cpp
    lldb/source/Utility/TraceGDBRemotePackets.cpp
    lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
    lldb/test/API/commands/trace/multiple-threads/Makefile
    lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
    lldb/test/API/commands/trace/multiple-threads/main.cpp
    lldb/unittests/Process/Linux/IntelPTManagerTests.cpp

Modified: 
    lldb/docs/lldb-gdb-remote.txt
    lldb/include/lldb/Core/PluginManager.h
    lldb/include/lldb/Host/common/NativeProcessProtocol.h
    lldb/include/lldb/Target/Process.h
    lldb/include/lldb/Target/ProcessTrace.h
    lldb/include/lldb/Target/StopInfo.h
    lldb/include/lldb/Target/Target.h
    lldb/include/lldb/Target/Trace.h
    lldb/include/lldb/Target/TraceSessionFileParser.h
    lldb/include/lldb/Utility/StringExtractorGDBRemote.h
    lldb/include/lldb/Utility/TraceOptions.h
    lldb/include/lldb/lldb-enumerations.h
    lldb/include/lldb/lldb-forward.h
    lldb/include/lldb/lldb-private-interfaces.h
    lldb/source/API/SBThread.cpp
    lldb/source/API/SBTrace.cpp
    lldb/source/Commands/CommandObjectProcess.cpp
    lldb/source/Commands/CommandObjectThread.cpp
    lldb/source/Commands/CommandObjectThreadUtil.cpp
    lldb/source/Commands/CommandObjectThreadUtil.h
    lldb/source/Commands/CommandObjectTrace.cpp
    lldb/source/Commands/CommandObjectTrace.h
    lldb/source/Core/PluginManager.cpp
    lldb/source/Interpreter/CommandInterpreter.cpp
    lldb/source/Plugins/Process/Linux/CMakeLists.txt
    lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
    lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
    lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.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/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
    lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
    lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
    lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
    lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
    lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
    lldb/source/Target/CMakeLists.txt
    lldb/source/Target/Process.cpp
    lldb/source/Target/ProcessTrace.cpp
    lldb/source/Target/StopInfo.cpp
    lldb/source/Target/Target.cpp
    lldb/source/Target/Thread.cpp
    lldb/source/Target/Trace.cpp
    lldb/source/Target/TraceSessionFileParser.cpp
    lldb/source/Utility/CMakeLists.txt
    lldb/source/Utility/StringExtractorGDBRemote.cpp
    lldb/test/API/commands/trace/TestTraceLoad.py
    lldb/test/API/commands/trace/TestTraceSchema.py
    lldb/test/API/commands/trace/TestTraceStartStop.py
    lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file-no-ld.json
    lldb/test/API/commands/trace/intelpt-trace/trace.json
    lldb/test/API/commands/trace/intelpt-trace/trace_2threads.json
    lldb/test/API/commands/trace/intelpt-trace/trace_bad.json
    lldb/test/API/commands/trace/intelpt-trace/trace_bad2.json
    lldb/test/API/commands/trace/intelpt-trace/trace_bad3.json
    lldb/test/API/commands/trace/intelpt-trace/trace_bad4.json
    lldb/test/API/commands/trace/intelpt-trace/trace_bad5.json
    lldb/test/API/commands/trace/intelpt-trace/trace_bad_image.json
    lldb/test/API/commands/trace/intelpt-trace/trace_wrong_cpu.json
    lldb/tools/lldb-vscode/JSONUtils.cpp
    lldb/tools/lldb-vscode/LLDBUtils.cpp
    lldb/unittests/Process/Linux/CMakeLists.txt
    lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp

Removed: 
    lldb/include/lldb/Target/ThreadTrace.h
    lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp
    lldb/source/Plugins/Process/Linux/ProcessorTrace.h
    lldb/source/Target/ThreadTrace.cpp
    lldb/source/Utility/TraceOptions.cpp
    lldb/unittests/Process/Linux/ProcessorTraceTest.cpp


################################################################################
diff  --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index 7d333c8c8e6e8..fb92c5665be6e 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -235,22 +235,23 @@ send packet: QListThreadsInStopReply
 read packet: OK
 
 //----------------------------------------------------------------------
-// jLLDBTraceSupportedType
+// jLLDBTraceSupported
 //
 // BRIEF
 //  Get the processor tracing type supported by the gdb-server for the current
 //  inferior. Responses might be 
diff erent depending on the architecture and
 //  capabilities of the underlying OS.
 //
-//  The return packet is a JSON object with the following schema
+//  OUTPUT SCHEMA
+//   {
+//     "name": <string>,
+//         Tracing technology name, e.g. intel-pt, arm-coresight.
+//     "description": <string>,
+//         Description for this technology.
+//   }
 //
-//  {
-//    "name": <tracing technology name, e.g. intel-pt, arm-coresight>
-//    "description": <description string for this technology>
-//  }
-//
-//  If no tracing technology is supported for the inferior, or no process is
-//  running, then an error should be returned.
+//   If no tracing technology is supported for the inferior, or no process is
+//   running, then an error message is returned.
 //
 // NOTE
 //  This packet is used by Trace plug-ins (see lldb_private::Trace.h) to
@@ -258,176 +259,217 @@ read packet: OK
 //  of the tracing technology returned by this packet.
 //----------------------------------------------------------------------
 
-send packet: jLLDBTraceSupportedType
-read packet: {"name": <name>, "description", <description>}/E<error code>;AAAAAAAAA
+send packet: jLLDBTraceSupported
+read packet: {"name":<name>, "description":<description>}/E<error code>;AAAAAAAAA
 
 //----------------------------------------------------------------------
-// jTraceStart:
-//
-// This packet is deprecated.
+// jLLDBTraceStart
 //
 // 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 
diff erent 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.
+//  Start tracing a process or its threads using a provided tracing technology.
+//  The input and output are specified as JSON objects. In case of success, an OK
+//  response is returned, or an error otherwise.
+//
+// PROCESS TRACING
+//  This traces existing and future threads of the current process. An error is
+//  returned if the process is already being traced.
 //
-//  Following is the list of parameters -
+// THREAD TRACING
+//  This traces specific threads.
 //
-//  Key             Value (Integer)                         (O)Optional/
-//                  (except params which should be a        (M)Mandatory
-//                  JSON dictionary)
-//  ==========      ====================================================
+// INPUT SCHEMA
+//  {
+//    "type": <string>,
+//        Tracing technology name, e.g. intel-pt, arm-coresight.
+//
+//    /* thread tracing only */
+//    "tids": [<decimal integer>],
+//        Individual threads to trace.
+//
+//    ... other parameters specific to the provided tracing type
+//  }
 //
-//  type            The type of trace to start (see          M
-//                  lldb-enumerations for TraceType)
+// NOTES
+//  - If "tids" is not provided, then the operation is "process tracing",
+//    otherwise it's "thread tracing".
+//  - Each tracing technology can have 
diff erent levels of support for "thread
+//    tracing" and "process tracing".
 //
-//  buffersize      The size of the buffer to allocate       M
-//                  for trace gathering.
+// INTEL-PT
+//  intel-pt supports both "thread tracing" and "process tracing".
 //
-//  threadid        The id of the thread to start tracing    O
-//                  on.
+//  "Process tracing" is implemented by tracing each thread individually, but
+//  managed by the same "process trace" instance.
+//  Each actual thread trace, either from "process tracing" or "thread tracing",
+//  is stored in an in-memory circular buffer, which keeps the most recent data.
 //
-//  metabuffersize  The size of buffer to hold meta data     O
-//                  used for decoding the trace data.
+//  Additional params in the input schema:
+//   {
+//     "threadBufferSize": <decimal integer>,
+//         Trace buffer size per thread in bytes. It must be a power of 2
+//         greater than or equal to 4096 (2^12) bytes.
 //
-//  params          Any parameters that are specific to      O
-//                  certain trace technologies should be
-//                  collectively specified as a JSON
-//                  dictionary
-//  ==========      ====================================================
+//     /* process tracing only */
+//     "processBufferSizeLimit": <decimal integer>,
+//         Maximum total buffer size per process in bytes.
+//         This limit applies to the sum of the sizes of all trace buffers for
+//         the current process, excluding the ones started with "thread tracing".
 //
-//  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 along with a hex encoded ASCII message is returned
-//  instead.
+//         Whenever a thread is attempted to be traced due to "process tracing"
+//         and the limit would be reached, the process is stopped with a
+//         "tracing" reason along with a meaningful description, so that the
+//         user can retrace the process if needed.
+//   }
+//
+//  Notes:
+//   - Modifying the parameters of an existing trace is not supported. The user
+//     needs to stop the trace and start a new one.
+//   - If "process tracing" is attempted and there are individual threads
+//     already being traced with "thread tracing", these traces are left
+//     unaffected and the threads not traced twice.
+//   - If "thread tracing" is attempted on a thread already being traced with
+//     either "thread tracing" or "process tracing", it fails.
 //----------------------------------------------------------------------
 
-send packet: jTraceStart:{"type":<type>,"buffersize":<buffersize>}]
-read packet: <trace id>/E<error code>;AAAAAAAAA
+Process tracing:
+send packet: jLLDBTraceStart:{"type":<type>,...other params}]
+read packet: OK/E<error code>;AAAAAAAAA
+
+Thread tracing:
+send packet: jLLDBTraceStart:{"type":<type>,"tids":<tids>,...other params}]
+read packet: OK/E<error code>;AAAAAAAAA
 
 //----------------------------------------------------------------------
-// jTraceStop:
-//
-// This packet is deprecated.
+// jLLDBTraceStop
 //
 // 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.
+//  Stop tracing a process or its threads using a provided tracing technology.
+//  The input and output are specified as JSON objects. In case of success, an OK
+//  response is returned, or an error otherwise.
+//
+// PROCESS TRACE STOPPING
+//  Stopping a process trace doesn't stop the active traces initiated with
+//  "thread tracing".
 //
-//  Following is the list of parameters -
+// THREAD TRACE STOPPING
+//  This is a best effort request, which tries to stop as many traces as
+//  possible.
 //
-//  Key             Value (Integer)                         (O)Optional/
-//                                                          (M)Mandatory
-//  ==========      ====================================================
+// INPUT SCHEMA
+//  The schema for the input is
 //
-//  traceid         The trace id of the tracing instance    M
+//  {
+//    "type": <string>
+//       Tracing technology name, e.g. intel-pt, arm-coresight.
+//
+//    /* thread trace stopping only */
+//    "tids":  [<decimal integer>]
+//       Individual thread traces to stop.
+//  }
 //
-//  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.
-//  ==========      ====================================================
+// NOTES
+//  - If "tids" is not provided, then the operation is "process trace stopping".
 //
-//  An OK response is sent in case of success else an error code along
-//  with a hex encoded ASCII message is returned.
+// INTEL PT
+//  Stopping a specific thread trace started with "process tracing" is allowed.
 //----------------------------------------------------------------------
 
-send packet: jTraceStop:{"traceid":<trace id>}]
-read packet: <OK response>/E<error code>;AAAAAAAAA
+Process trace stopping:
+send packet: jLLDBTraceStop:{"type":<type>}]
+read packet: OK/E<error code>;AAAAAAAAA
+
+Thread trace stopping:
+send packet: jLLDBTraceStop:{"type":<type>,"tids":<tids>}]
+read packet: OK/E<error code>;AAAAAAAAA
 
 //----------------------------------------------------------------------
-// jTraceBufferRead:
-//
-// This packet is deprecated.
+// jLLDBTraceGetState
 //
 // 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 -
+//  Get the current state of the process and its threads being traced by
+//  a given trace technology. The response is a JSON object with custom
+//  information depending on the trace technology. In case of errors, an
+//  error message is returned.
 //
-//  Key             Value (Integer)                         (O)Optional/
-//                                                          (M)Mandatory
-//  ==========      ====================================================
-//  traceid         The trace id of the tracing instance    M
+// INPUT SCHEMA
+//  {
+//     "type": <string>
+//        Tracing technology name, e.g. intel-pt, arm-coresight.
+//  }
 //
-//  offset          The offset to start reading the data    M
-//                  from.
+// OUTPUT SCHEMA
+//  {
+//    "tracedThreads": [{
+//      "tid": <decimal integer>,
+//      "binaryData": [
+//        {
+//          "kind": <string>,
+//              Identifier for some binary data related to this thread to
+//              fetch with the jLLDBTraceGetBinaryData packet.
+//          "size": <decimal integer>,
+//              Size in bytes of this thread data.
+//        },
+//      ]
+//    }],
+//    "processBinaryData": [
+//      {
+//        "kind": <string>,
+//            Identifier for some binary data related to this process to
+//            fetch with the jLLDBTraceGetBinaryData packet.
+//        "size": <decimal integer>,
+//            Size in bytes of this thread data.
+//      },
+//    }]
+//  }
 //
-//  buffersize      The size of the data intended to read.  M
+// NOTES
+//   - "traceThreads" includes all thread traced by both "process tracing" and
+//     "thread tracing".
 //
-//  threadid        The id of the thread to retrieve data   O
-//                  from.
-//  ==========      ====================================================
+// INTEL PT
 //
-//  The trace data is sent as raw binary data if the read was successful
-//  else an error code along with a hex encoded ASCII message is sent.
+//  Binary data kinds:
+//    - threadTraceBuffer: trace buffer for a thread.
+//    - cpuInfo: contents of the /proc/cpuinfo file.
 //----------------------------------------------------------------------
 
-send packet: jTraceBufferRead:{"traceid":<trace id>,"offset":<byteoffset>,"buffersize":<byte_count>}]
-read packet: <binary trace data>/E<error code>;AAAAAAAAA
+send packet: jLLDBTraceGetState:{"type":<type>}]
+read packet: {...object}/E<error code>;AAAAAAAAA
 
 //----------------------------------------------------------------------
-// jTraceMetaRead:
-//
-// This packet is deprecated.
+// jLLDBTraceGetBinaryData
 //
 // BRIEF
-//  Similar Packet as above except it reads meta data.
-//----------------------------------------------------------------------
-
-/----------------------------------------------------------------------
-// jTraceConfigRead:
+//  Get binary data given a trace technology and a data identifier.
+//  The input is specified as a JSON object and the response has the same format
+//  as the "binary memory read" (aka "x") packet. In case of failures, an error
+//  message is returned.
 //
-// This packet is deprecated.
+// SCHEMA
+//  The schema for the input is
 //
-// 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 along with a hex encoded ASCII message is returned.
-//----------------------------------------------------------------------
-
-send packet: jTraceConfigRead:{"traceid":<trace id>}
-read packet: {"conf1":<conf1>,"conf2":<conf2>,"params":{"paramName":paramValue}]}];/E<error code>;AAAAAAAAA
+//  {
+//   "type": <string>,
+//       Tracing technology name, e.g. intel-pt, arm-coresight.
+//   "kind": <string>,
+//       Identifier for the data.
+//   "tid"?: <Optional decimal>,
+//       Tid in decimal if the data belongs to a thread.
+//   "offset": <decimal>,
+//       Offset of the data in bytes.
+//   "size": <decimal>,
+//      Number of bytes in to read starting from the offset.
+//  }
+//
+// INTEL PT
+//
+//  Binary data kinds:
+//    - threadTraceBuffer: trace buffer for a thread.
+//    - cpuInfo: contents of the /proc/cpuinfo file.
+//----------------------------------------------------------------------
+
+send packet: jLLDBTraceGetBinaryData:{"type":<type>,"kind":<query>,"tid":<tid>,"offset":<offset>,"size":<size>}]
+read packet: <binary data>/E<error code>;AAAAAAAAA
 
 //----------------------------------------------------------------------
 // "qRegisterInfo<hex-reg-id>"

diff  --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
index 0ac8308d17588..4fc2ffe095ce5 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -331,18 +331,20 @@ class PluginManager {
   GetSymbolVendorCreateCallbackAtIndex(uint32_t idx);
 
   // Trace
-  static bool RegisterPlugin(ConstString name, const char *description,
-                             TraceCreateInstance create_callback,
-                             llvm::StringRef schema,
-                             TraceGetStartCommand get_start_command);
+  static bool RegisterPlugin(
+      ConstString name, const char *description,
+      TraceCreateInstanceForSessionFile create_callback_for_session_file,
+      TraceCreateInstanceForLiveProcess create_callback_for_live_process,
+      llvm::StringRef schema);
 
-  static bool UnregisterPlugin(TraceCreateInstance create_callback);
+  static bool
+  UnregisterPlugin(TraceCreateInstanceForSessionFile create_callback);
 
-  static TraceCreateInstance GetTraceCreateCallback(ConstString plugin_name);
+  static TraceCreateInstanceForSessionFile
+  GetTraceCreateCallback(ConstString plugin_name);
 
-  static lldb::CommandObjectSP
-  GetTraceStartCommand(llvm::StringRef plugin_name,
-                       CommandInterpreter &interpreter);
+  static TraceCreateInstanceForLiveProcess
+  GetTraceCreateCallbackForLiveProcess(ConstString plugin_name);
 
   /// Get the JSON schema for a trace session file corresponding to the given
   /// plugin.

diff  --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index 5be9cb657382a..36b22d72b1962 100644
--- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -16,7 +16,7 @@
 #include "lldb/Host/MainLoop.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/Status.h"
-#include "lldb/Utility/TraceOptions.h"
+#include "lldb/Utility/TraceGDBRemotePackets.h"
 #include "lldb/Utility/UnimplementedError.h"
 #include "lldb/lldb-private-forward.h"
 #include "lldb/lldb-types.h"
@@ -306,94 +306,55 @@ class NativeProcessProtocol {
            MainLoop &mainloop) const = 0;
   };
 
-  /// StartTracing API for starting a tracing instance with the
-  /// TraceOptions on a specific thread or process.
+  /// Start tracing a process or its threads.
   ///
-  /// \param[in] config
-  ///     The configuration to use when starting tracing.
+  /// \param[in] json_params
+  ///     JSON object with the information of what and how to trace.
+  ///     In the case of gdb-remote, this object should conform to the
+  ///     jLLDBTraceStart packet.
   ///
-  /// \param[out] error
-  ///     Status indicates what went wrong.
+  ///     This object should have a string entry called "type", which is the
+  ///     tracing technology name.
   ///
-  /// \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] traceid
-  ///     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.
+  /// \param[in] type
+  ///     Tracing technology type, as described in the \a json_params.
   ///
   /// \return
-  ///     Status indicating what went wrong.
-  virtual Status StopTrace(lldb::user_id_t traceid,
-                           lldb::tid_t thread = LLDB_INVALID_THREAD_ID) {
-    return Status("Not implemented");
+  ///     \a llvm::Error::success if the operation was successful, or an
+  ///     \a llvm::Error otherwise.
+  virtual llvm::Error TraceStart(llvm::StringRef json_params,
+                                 llvm::StringRef type) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Unsupported tracing type '%s'",
+                                   type.data());
   }
 
-  /// This API provides the trace data collected in the form of raw
-  /// data.
-  ///
-  /// \param[in] traceid thread
-  ///     The traceid 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 traceid, lldb::tid_t thread,
-                         llvm::MutableArrayRef<uint8_t> &buffer,
-                         size_t offset = 0) {
-    return Status("Not implemented");
+  /// \copydoc Process::TraceStop(const TraceStopRequest &)
+  virtual llvm::Error TraceStop(const TraceStopRequest &request) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Unsupported tracing type '%s'",
+                                   request.type.data());
   }
 
-  /// 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 traceid, lldb::tid_t thread,
-                             llvm::MutableArrayRef<uint8_t> &buffer,
-                             size_t offset = 0) {
-    return Status("Not implemented");
+  /// \copydoc Process::TraceGetState(llvm::StringRef type)
+  virtual llvm::Expected<llvm::json::Value>
+  TraceGetState(llvm::StringRef type) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Unsupported tracing type '%s'",
+                                   type.data());
   }
 
-  /// API to query the TraceOptions for a given user id
-  ///
-  /// \param[in] traceid
-  ///     The user id of the tracing instance.
-  ///
-  /// \param[out] config
-  ///     The configuration being used for tracing.
-  ///
-  /// \return A status indicating what went wrong.
-  virtual Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) {
-    return Status("Not implemented");
+  /// \copydoc Process::TraceGetBinaryData(const TraceGetBinaryDataRequest &)
+  virtual llvm::Expected<std::vector<uint8_t>>
+  TraceGetBinaryData(const TraceGetBinaryDataRequest &request) {
+    return llvm::createStringError(
+        llvm::inconvertibleErrorCode(),
+        "Unsupported data kind '%s' for the '%s' tracing technology",
+        request.kind.c_str(), request.type.c_str());
   }
 
-  /// \copydoc Process::GetSupportedTraceType()
-  virtual llvm::Expected<TraceTypeInfo> GetSupportedTraceType() {
+  /// \copydoc Process::TraceSupported()
+  virtual llvm::Expected<TraceSupportedResponse> TraceSupported() {
     return llvm::make_error<UnimplementedError>();
   }
 

diff  --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index fbdb5069b39fc..dbe61d892c499 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -46,7 +46,7 @@
 #include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/StructuredData.h"
-#include "lldb/Utility/TraceOptions.h"
+#include "lldb/Utility/TraceGDBRemotePackets.h"
 #include "lldb/Utility/UnimplementedError.h"
 #include "lldb/Utility/UserIDResolver.h"
 #include "lldb/lldb-private.h"
@@ -2455,6 +2455,8 @@ void PruneThreadPlans();
   lldb::StructuredDataPluginSP
   GetStructuredDataPlugin(ConstString type_name) const;
 
+  /// Deprecated
+  ///
   /// Starts tracing with the configuration provided in options. To enable
   /// tracing on the complete process the thread_id in the options should be
   /// set to LLDB_INVALID_THREAD_ID. The API returns a user_id which is needed
@@ -2469,6 +2471,8 @@ void PruneThreadPlans();
     return LLDB_INVALID_UID;
   }
 
+  /// Deprecated
+  ///
   /// Stops the tracing instance leading to deletion of the trace data. The
   /// tracing instance is identified by the user_id which is obtained when
   /// tracing was started from the StartTrace. In case tracing of the complete
@@ -2479,6 +2483,8 @@ void PruneThreadPlans();
     return Status("Not implemented");
   }
 
+  /// Deprecated
+  ///
   /// Provides the trace data as raw bytes. A buffer needs to be supplied to
   /// copy the trace data. The exact behavior of this API may vary across
   /// trace technology, as some may support partial reading of the trace data
@@ -2490,6 +2496,8 @@ void PruneThreadPlans();
     return Status("Not implemented");
   }
 
+  /// Deprecated
+  ///
   /// Similar API as above except for obtaining meta data
   virtual Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
                              llvm::MutableArrayRef<uint8_t> &buffer,
@@ -2497,17 +2505,8 @@ void PruneThreadPlans();
     return Status("Not implemented");
   }
 
-  /// API to obtain the trace configuration used by a trace instance.
-  /// Configurations that may be specific to some trace technology should be
-  /// stored in the custom parameters. The options are transported to the
-  /// server, which shall interpret accordingly. The thread_id can be
-  /// specified in the options to obtain the configuration used by a specific
-  /// thread. The thread_id specified should also match the uid otherwise an
-  /// error will be returned.
-  virtual Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) {
-    return Status("Not implemented");
-  }
-
+protected:
+  friend class Trace;
   ///  Get the processor tracing type supported for this process.
   ///  Responses might be 
diff erent depending on the architecture and
   ///  capabilities of the underlying OS.
@@ -2515,14 +2514,64 @@ void PruneThreadPlans();
   ///  \return
   ///     The supported trace type or an \a llvm::Error if tracing is
   ///     not supported for the inferior.
-  virtual llvm::Expected<TraceTypeInfo> GetSupportedTraceType();
+  virtual llvm::Expected<TraceSupportedResponse> TraceSupported();
+
+  /// Start tracing a process or its threads.
+  ///
+  /// \param[in] request
+  ///     JSON object with the information necessary to start tracing. In the
+  ///     case of gdb-remote processes, this JSON object should conform to the
+  ///     jLLDBTraceStart packet.
+  ///
+  /// \return
+  ///     \a llvm::Error::success if the operation was successful, or
+  ///     \a llvm::Error otherwise.
+  virtual llvm::Error TraceStart(const llvm::json::Value &request) {
+    return llvm::make_error<UnimplementedError>();
+  }
+
+  /// Stop tracing a live process or its threads.
+  ///
+  /// \param[in] request
+  ///     The information determining which threads or process to stop tracing.
+  ///
+  /// \return
+  ///     \a llvm::Error::success if the operation was successful, or
+  ///     \a llvm::Error otherwise.
+  virtual llvm::Error TraceStop(const TraceStopRequest &request) {
+    return llvm::make_error<UnimplementedError>();
+  }
+
+  /// Get the current tracing state of the process and its threads.
+  ///
+  /// \param[in] type
+  ///     Tracing technology type to consider.
+  ///
+  /// \return
+  ///     A JSON object string with custom data depending on the trace
+  ///     technology, or an \a llvm::Error in case of errors.
+  virtual llvm::Expected<std::string> TraceGetState(llvm::StringRef type) {
+    return llvm::make_error<UnimplementedError>();
+  }
+
+  /// Get binary data given a trace technology and a data identifier.
+  ///
+  /// \param[in] request
+  ///     Object with the params of the requested data.
+  ///
+  /// \return
+  ///     A vector of bytes with the requested data, or an \a llvm::Error in
+  ///     case of failures.
+  virtual llvm::Expected<std::vector<uint8_t>>
+  TraceGetBinaryData(const TraceGetBinaryDataRequest &request) {
+    return llvm::make_error<UnimplementedError>();
+  }
 
   // This calls a function of the form "void * (*)(void)".
   bool CallVoidArgVoidPtrReturn(const Address *address,
                                 lldb::addr_t &returned_func,
                                 bool trap_exceptions = false);
 
-protected:
   /// Update the thread list following process plug-in's specific logic.
   ///
   /// This method should only be invoked by \a UpdateThreadList.

diff  --git a/lldb/include/lldb/Target/ProcessTrace.h b/lldb/include/lldb/Target/ProcessTrace.h
index 55faba1576d00..7b9d6b13dd6f8 100644
--- a/lldb/include/lldb/Target/ProcessTrace.h
+++ b/lldb/include/lldb/Target/ProcessTrace.h
@@ -15,6 +15,8 @@
 
 namespace lldb_private {
 
+/// Class that represents a defunct process loaded on memory via the "trace
+/// load" command.
 class ProcessTrace : public PostMortemProcess {
 public:
   static void Initialize();
@@ -54,8 +56,6 @@ class ProcessTrace : public PostMortemProcess {
     return error;
   }
 
-  bool IsAlive() override;
-
   bool WarnBeforeDetach() const override { return false; }
 
   size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,

diff  --git a/lldb/include/lldb/Target/StopInfo.h b/lldb/include/lldb/Target/StopInfo.h
index 4378d2d637993..2039b3a6fcf11 100644
--- a/lldb/include/lldb/Target/StopInfo.h
+++ b/lldb/include/lldb/Target/StopInfo.h
@@ -129,6 +129,9 @@ class StopInfo {
 
   static lldb::StopInfoSP CreateStopReasonWithExec(Thread &thread);
 
+  static lldb::StopInfoSP
+  CreateStopReasonProcessorTrace(Thread &thread, const char *description);
+
   static lldb::ValueObjectSP
   GetReturnValueObject(lldb::StopInfoSP &stop_info_sp);
 

diff  --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 737efaf308829..0c2131a60b4bb 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -1126,7 +1126,12 @@ class Target : public std::enable_shared_from_this<Target>,
   ///
   /// \return
   ///   The trace object. It might be undefined.
-  const lldb::TraceSP &GetTrace();
+  lldb::TraceSP &GetTrace();
+
+  /// Similar to \a GetTrace, but this also tries to create a \a Trace object
+  /// if not available using the default supported tracing technology for
+  /// this process.
+  llvm::Expected<lldb::TraceSP &> GetTraceOrCreate();
 
   // Since expressions results can persist beyond the lifetime of a process,
   // and the const expression results are available after a process is gone, we

diff  --git a/lldb/include/lldb/Target/ThreadTrace.h b/lldb/include/lldb/Target/ThreadPostMortemTrace.h
similarity index 77%
rename from lldb/include/lldb/Target/ThreadTrace.h
rename to lldb/include/lldb/Target/ThreadPostMortemTrace.h
index fee09a742a4e5..9cfe754ae0e4e 100644
--- a/lldb/include/lldb/Target/ThreadTrace.h
+++ b/lldb/include/lldb/Target/ThreadPostMortemTrace.h
@@ -1,4 +1,4 @@
-//===-- ThreadTrace.h -------------------------------------------*- C++ -*-===//
+//===-- ThreadPostMortemTrace.h ---------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,21 +6,21 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLDB_TARGET_THREADTRACE_H
-#define LLDB_TARGET_THREADTRACE_H
+#ifndef LLDB_TARGET_THREADPOSTMORTEMTRACE_H
+#define LLDB_TARGET_THREADPOSTMORTEMTRACE_H
 
 #include "lldb/Target/Thread.h"
 
 namespace lldb_private {
 
-/// \class ThreadTrace ThreadTrace.h
+/// \class ThreadPostMortemTrace ThreadPostMortemTrace.h
 ///
 /// Thread implementation used for representing threads gotten from trace
 /// session files, which are similar to threads from core files.
 ///
 /// See \a TraceSessionFileParser for more information regarding trace session
 /// files.
-class ThreadTrace : public Thread {
+class ThreadPostMortemTrace : public Thread {
 public:
   /// \param[in] process
   ///     The process who owns this thread.
@@ -31,7 +31,8 @@ class ThreadTrace : public Thread {
   /// \param[in] trace_file
   ///     The file that contains the list of instructions that were traced when
   ///     this thread was being executed.
-  ThreadTrace(Process &process, lldb::tid_t tid, const FileSpec &trace_file)
+  ThreadPostMortemTrace(Process &process, lldb::tid_t tid,
+                        const FileSpec &trace_file)
       : Thread(process, tid), m_trace_file(trace_file) {}
 
   void RefreshStateAfterStop() override;
@@ -54,8 +55,6 @@ class ThreadTrace : public Thread {
   FileSpec m_trace_file;
 };
 
-typedef std::shared_ptr<ThreadTrace> ThreadTraceSP;
-
 } // namespace lldb_private
 
-#endif // LLDB_TARGET_THREADTRACE_H
+#endif // LLDB_TARGET_THREADPOSTMORTEMTRACE_H

diff  --git a/lldb/include/lldb/Target/Trace.h b/lldb/include/lldb/Target/Trace.h
index 3b127916a9171..403b1f868a594 100644
--- a/lldb/include/lldb/Target/Trace.h
+++ b/lldb/include/lldb/Target/Trace.h
@@ -9,10 +9,14 @@
 #ifndef LLDB_TARGET_TRACE_H
 #define LLDB_TARGET_TRACE_H
 
+#include <unordered_map>
+
 #include "llvm/Support/JSON.h"
 
 #include "lldb/Core/PluginInterface.h"
+#include "lldb/Target/Thread.h"
 #include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/TraceGDBRemotePackets.h"
 #include "lldb/Utility/UnimplementedError.h"
 #include "lldb/lldb-private.h"
 
@@ -36,7 +40,7 @@ namespace lldb_private {
 ///
 /// In order to support live tracing, the name of the plug-in should match the
 /// name of the tracing type returned by the gdb-remote packet
-/// \a jLLDBTraceSupportedType.
+/// \a jLLDBTraceSupported.
 class Trace : public PluginInterface,
               public std::enable_shared_from_this<Trace> {
 public:
@@ -94,8 +98,24 @@ class Trace : public PluginInterface,
   ///     The path to the directory that contains the session file. It's used to
   ///     resolved relative paths in the session file.
   static llvm::Expected<lldb::TraceSP>
-  FindPlugin(Debugger &debugger, const llvm::json::Value &trace_session_file,
-             llvm::StringRef session_file_dir);
+  FindPluginForPostMortemProcess(Debugger &debugger,
+                                 const llvm::json::Value &trace_session_file,
+                                 llvm::StringRef session_file_dir);
+
+  /// Find a trace plug-in to trace a live process.
+  ///
+  /// \param[in] plugin_name
+  ///     Plug-in name to search.
+  ///
+  /// \param[in] process
+  ///     Live process to trace.
+  ///
+  /// \return
+  ///     A \a TraceSP instance, or an \a llvm::Error if the plug-in name
+  ///     doesn't match any registered plug-ins or tracing couldn't be
+  ///     started.
+  static llvm::Expected<lldb::TraceSP>
+  FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process);
 
   /// Get the schema of a Trace plug-in given its name.
   ///
@@ -104,6 +124,14 @@ class Trace : public PluginInterface,
   static llvm::Expected<llvm::StringRef>
   FindPluginSchema(llvm::StringRef plugin_name);
 
+  /// Get the command handle for the "process trace start" command.
+  virtual lldb::CommandObjectSP
+  GetProcessTraceStartCommand(CommandInterpreter &interpreter) = 0;
+
+  /// Get the command handle for the "thread trace start" command.
+  virtual lldb::CommandObjectSP
+  GetThreadTraceStartCommand(CommandInterpreter &interpreter) = 0;
+
   /// \return
   ///     The JSON schema of this Trace plug-in.
   virtual llvm::StringRef GetSchema() = 0;
@@ -118,7 +146,7 @@ class Trace : public PluginInterface,
   ///
   /// \return
   ///     The current position of the thread's trace or \b 0 if empty.
-  virtual size_t GetCursorPosition(const Thread &thread) = 0;
+  virtual size_t GetCursorPosition(Thread &thread) = 0;
 
   /// Dump \a count instructions of the given thread's trace ending at the
   /// given \a end_position position.
@@ -172,30 +200,130 @@ class Trace : public PluginInterface,
   ///     The callback to execute on each instruction. If it returns \b false,
   ///     the iteration stops.
   virtual void TraverseInstructions(
-      const Thread &thread, size_t position, TraceDirection direction,
+      Thread &thread, size_t position, TraceDirection direction,
       std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)>
           callback) = 0;
 
-  /// Stop tracing a live thread
+  /// Get the number of available instructions in the trace of the given thread.
   ///
   /// \param[in] thread
-  ///     The thread object to stop tracing.
+  ///     The thread whose trace will be inspected.
   ///
   /// \return
-  ///     An \a llvm::Error if stopping tracing failed, or \b
-  ///     llvm::Error::success() otherwise.
-  virtual llvm::Error StopTracingThread(const Thread &thread) {
-    return llvm::make_error<UnimplementedError>();
-  }
+  ///     The total number of instructions in the trace.
+  virtual size_t GetInstructionCount(Thread &thread) = 0;
 
-  /// Get the number of available instructions in the trace of the given thread.
+  /// Check if a thread is currently traced by this object.
   ///
   /// \param[in] thread
-  ///     The thread whose trace will be inspected.
+  ///     The thread in question.
   ///
   /// \return
-  ///     The total number of instructions in the trace.
-  virtual size_t GetInstructionCount(const Thread &thread) = 0;
+  ///     \b true if the thread is traced by this instance, \b false otherwise.
+  virtual bool IsTraced(const Thread &thread) = 0;
+
+  /// Stop tracing live threads.
+  ///
+  /// \param[in] tids
+  ///     The threads to stop tracing on.
+  ///
+  /// \return
+  ///     \a llvm::Error::success if the operation was successful, or
+  ///     \a llvm::Error otherwise.
+  llvm::Error StopThreads(const std::vector<lldb::tid_t> &tids);
+
+  /// Stop tracing a live process.
+  ///
+  /// \param[in] request
+  ///     The information determining which threads or process to stop tracing.
+  ///
+  /// \return
+  ///     \a llvm::Error::success if the operation was successful, or
+  ///     \a llvm::Error otherwise.
+  llvm::Error StopProcess();
+
+  /// Get the trace file of the given post mortem thread.
+  llvm::Expected<const FileSpec &> GetPostMortemTraceFile(lldb::tid_t tid);
+
+protected:
+  /// Get binary data of a live thread given a data identifier.
+  ///
+  /// \param[in] tid
+  ///     The thread whose data is requested.
+  ///
+  /// \param[in] kind
+  ///     The kind of data requested.
+  ///
+  /// \return
+  ///     A vector of bytes with the requested data, or an \a llvm::Error in
+  ///     case of failures.
+  llvm::Expected<std::vector<uint8_t>>
+  GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind);
+
+  /// Get binary data of the current process given a data identifier.
+  ///
+  /// \param[in] kind
+  ///     The kind of data requested.
+  ///
+  /// \return
+  ///     A vector of bytes with the requested data, or an \a llvm::Error in
+  ///     case of failures.
+  llvm::Expected<std::vector<uint8_t>>
+  GetLiveProcessBinaryData(llvm::StringRef kind);
+
+  /// Get the size of the data returned by \a GetLiveThreadBinaryData
+  llvm::Optional<size_t> GetLiveThreadBinaryDataSize(lldb::tid_t tid,
+                                                     llvm::StringRef kind);
+
+  /// Get the size of the data returned by \a GetLiveProcessBinaryData
+  llvm::Optional<size_t> GetLiveProcessBinaryDataSize(llvm::StringRef kind);
+  /// Constructor for post mortem processes
+  Trace() = default;
+
+  /// Constructor for a live process
+  Trace(Process &live_process) : m_live_process(&live_process) {}
+
+  /// Start tracing a live process or its threads.
+  ///
+  /// \param[in] request
+  ///     JSON object with the information necessary to start tracing. In the
+  ///     case of gdb-remote processes, this JSON object should conform to the
+  ///     jLLDBTraceStart packet.
+  ///
+  /// \return
+  ///     \a llvm::Error::success if the operation was successful, or
+  ///     \a llvm::Error otherwise.
+  llvm::Error Start(const llvm::json::Value &request);
+
+  /// Get the current tracing state of a live process and its threads.
+  ///
+  /// \return
+  ///     A JSON object string with custom data depending on the trace
+  ///     technology, or an \a llvm::Error in case of errors.
+  llvm::Expected<std::string> GetLiveProcessState();
+
+  /// Method to be overriden by the plug-in to refresh its own state.
+  ///
+  /// This is invoked by RefreshLiveProcessState when a new state is found.
+  ///
+  /// \param[in] state
+  ///     The jLLDBTraceGetState response.
+  virtual void
+  DoRefreshLiveProcessState(llvm::Expected<TraceGetStateResponse> state) = 0;
+
+  /// Method to be invoked by the plug-in to refresh the live process state.
+  ///
+  /// The result is cached through the same process stop.
+  void RefreshLiveProcessState();
+
+  /// Process traced by this object if doing live tracing. Otherwise it's null.
+  int64_t m_stop_id = -1;
+  Process *m_live_process = nullptr;
+  /// tid -> data kind -> size
+  std::map<lldb::tid_t, std::unordered_map<std::string, size_t>>
+      m_live_thread_data;
+  /// data kind -> size
+  std::unordered_map<std::string, size_t> m_live_process_data;
 };
 
 } // namespace lldb_private

diff  --git a/lldb/include/lldb/Target/TraceSessionFileParser.h b/lldb/include/lldb/Target/TraceSessionFileParser.h
index 52cc27c1a485a..68abc7d006d34 100644
--- a/lldb/include/lldb/Target/TraceSessionFileParser.h
+++ b/lldb/include/lldb/Target/TraceSessionFileParser.h
@@ -11,7 +11,7 @@
 
 #include "llvm/Support/JSON.h"
 
-#include "lldb/Target/ThreadTrace.h"
+#include "lldb/Target/ThreadPostMortemTrace.h"
 
 namespace lldb_private {
 
@@ -68,7 +68,7 @@ class TraceSessionFileParser {
   /// Helper struct holding the objects created when parsing a process
   struct ParsedProcess {
     lldb::TargetSP target_sp;
-    std::vector<ThreadTraceSP> threads;
+    std::vector<lldb::ThreadPostMortemTraceSP> threads;
   };
 
   TraceSessionFileParser(Debugger &debugger, llvm::StringRef session_file_dir,
@@ -103,8 +103,8 @@ class TraceSessionFileParser {
   /// modifies the given file_spec.
   void NormalizePath(lldb_private::FileSpec &file_spec);
 
-  ThreadTraceSP ParseThread(lldb::ProcessSP &process_sp,
-                            const JSONThread &thread);
+  lldb::ThreadPostMortemTraceSP ParseThread(lldb::ProcessSP &process_sp,
+                                            const JSONThread &thread);
 
   llvm::Expected<ParsedProcess> ParseProcess(const JSONProcess &process);
 

diff  --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
index 4ef3cea1aeb3a..da73708b91d11 100644
--- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -162,13 +162,11 @@ class StringExtractorGDBRemote : public StringExtractor {
     eServerPacketType__m,
     eServerPacketType_notify, // '%' notification
 
-    eServerPacketType_jTraceStart,      // deprecated
-    eServerPacketType_jTraceBufferRead, // deprecated
-    eServerPacketType_jTraceMetaRead,   // deprecated
-    eServerPacketType_jTraceStop,       // deprecated
-    eServerPacketType_jTraceConfigRead, // deprecated
-
-    eServerPacketType_jLLDBTraceSupportedType,
+    eServerPacketType_jLLDBTraceSupported,
+    eServerPacketType_jLLDBTraceStart,
+    eServerPacketType_jLLDBTraceStop,
+    eServerPacketType_jLLDBTraceGetState,
+    eServerPacketType_jLLDBTraceGetBinaryData,
   };
 
   ServerPacketType GetServerPacketType() const;

diff  --git a/lldb/include/lldb/Utility/TraceGDBRemotePackets.h b/lldb/include/lldb/Utility/TraceGDBRemotePackets.h
new file mode 100644
index 0000000000000..66fa5e2f8b516
--- /dev/null
+++ b/lldb/include/lldb/Utility/TraceGDBRemotePackets.h
@@ -0,0 +1,151 @@
+//===-- TraceGDBRemotePackets.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_TRACEGDBREMOTEPACKETS_H
+#define LLDB_UTILITY_TRACEGDBREMOTEPACKETS_H
+
+#include "llvm/Support/JSON.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+
+/// See docs/lldb-gdb-remote.txt for more information.
+namespace lldb_private {
+
+/// jLLDBTraceSupported gdb-remote packet
+/// \{
+struct TraceSupportedResponse {
+  /// The name of the technology, e.g. intel-pt or arm-coresight.
+  ///
+  /// In order for a Trace plug-in (see \a lldb_private::Trace.h) to support the
+  /// trace technology given by this struct, it should match its name with this
+  /// field.
+  std::string name;
+  /// The description for the technology.
+  std::string description;
+};
+
+bool fromJSON(const llvm::json::Value &value, TraceSupportedResponse &info,
+              llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceSupportedResponse &packet);
+/// \}
+
+/// jLLDBTraceStart gdb-remote packet
+/// \{
+struct TraceStartRequest {
+  /// Tracing technology name, e.g. intel-pt, arm-coresight.
+  std::string type;
+  /// If \a llvm::None, then this starts tracing the whole process. Otherwise,
+  /// only tracing for the specified threads is enabled.
+  llvm::Optional<std::vector<int64_t>> tids;
+
+  bool IsProcessTracing() const;
+};
+
+bool fromJSON(const llvm::json::Value &value, TraceStartRequest &packet,
+              llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceStartRequest &packet);
+/// \}
+
+/// jLLDBTraceStop gdb-remote packet
+/// \{
+struct TraceStopRequest {
+  TraceStopRequest() {}
+
+  TraceStopRequest(llvm::StringRef type, const std::vector<lldb::tid_t> &tids);
+
+  TraceStopRequest(llvm::StringRef type) : type(type){};
+
+  bool IsProcessTracing() const;
+
+  /// Tracing technology name, e.g. intel-pt, arm-coresight.
+  std::string type;
+  /// If \a llvm::None, then this stops tracing the whole process. Otherwise,
+  /// only tracing for the specified threads is stopped.
+  llvm::Optional<std::vector<int64_t>> tids;
+};
+
+bool fromJSON(const llvm::json::Value &value, TraceStopRequest &packet,
+              llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceStopRequest &packet);
+///}
+
+/// jLLDBTraceGetState gdb-remote packet
+/// \{
+struct TraceGetStateRequest {
+  /// Tracing technology name, e.g. intel-pt, arm-coresight.
+  std::string type;
+};
+
+bool fromJSON(const llvm::json::Value &value, TraceGetStateRequest &packet,
+              llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceGetStateRequest &packet);
+
+struct TraceBinaryData {
+  /// Identifier of data to fetch with jLLDBTraceGetBinaryData.
+  std::string kind;
+  /// Size in bytes for this data.
+  int64_t size;
+};
+
+bool fromJSON(const llvm::json::Value &value, TraceBinaryData &packet,
+              llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceBinaryData &packet);
+
+struct TraceThreadState {
+  int64_t tid;
+  /// List of binary data objects for this thread.
+  std::vector<TraceBinaryData> binaryData;
+};
+
+bool fromJSON(const llvm::json::Value &value, TraceThreadState &packet,
+              llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceThreadState &packet);
+
+struct TraceGetStateResponse {
+  std::vector<TraceThreadState> tracedThreads;
+  std::vector<TraceBinaryData> processBinaryData;
+};
+
+bool fromJSON(const llvm::json::Value &value, TraceGetStateResponse &packet,
+              llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceGetStateResponse &packet);
+/// \}
+
+/// jLLDBTraceGetBinaryData gdb-remote packet
+/// \{
+struct TraceGetBinaryDataRequest {
+  /// Tracing technology name, e.g. intel-pt, arm-coresight.
+  std::string type;
+  /// Identifier for the data.
+  std::string kind;
+  /// Optional tid if the data is related to a thread.
+  llvm::Optional<int64_t> tid;
+  /// Offset in bytes from where to start reading the data.
+  int64_t offset;
+  /// Number of bytes to read.
+  int64_t size;
+};
+
+bool fromJSON(const llvm::json::Value &value,
+              lldb_private::TraceGetBinaryDataRequest &packet,
+              llvm::json::Path path);
+
+llvm::json::Value toJSON(const lldb_private::TraceGetBinaryDataRequest &packet);
+/// \}
+
+} // namespace lldb_private
+
+#endif // LLDB_UTILITY_TRACEGDBREMOTEPACKETS_H

diff  --git a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
new file mode 100644
index 0000000000000..95f4eeb27d3fa
--- /dev/null
+++ b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -0,0 +1,38 @@
+//===-- TraceIntelPTGDBRemotePackets.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_TRACEINTELPTGDBREMOTEPACKETS_H
+#define LLDB_UTILITY_TRACEINTELPTGDBREMOTEPACKETS_H
+
+#include "lldb/Utility/TraceGDBRemotePackets.h"
+
+/// See docs/lldb-gdb-remote.txt for more information.
+namespace lldb_private {
+
+/// jLLDBTraceStart gdb-remote packet
+/// \{
+struct TraceIntelPTStartRequest : TraceStartRequest {
+  /// Size in bytes to use for each thread's trace buffer.
+  int64_t threadBufferSize;
+  /// Required when doing "process tracing".
+  ///
+  /// Limit in bytes on all the thread traces started by this "process trace"
+  /// instance. When a thread is about to be traced and the limit would be hit,
+  /// then a "tracing" stop event is triggered.
+  llvm::Optional<int64_t> processBufferSizeLimit;
+};
+
+bool fromJSON(const llvm::json::Value &value, TraceIntelPTStartRequest &packet,
+              llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceIntelPTStartRequest &packet);
+/// \}
+
+} // namespace lldb_private
+
+#endif // LLDB_UTILITY_TRACEINTELPTGDBREMOTEPACKETS_H

diff  --git a/lldb/include/lldb/Utility/TraceOptions.h b/lldb/include/lldb/Utility/TraceOptions.h
index c9a8d12ce1251..677ba0eabea36 100644
--- a/lldb/include/lldb/Utility/TraceOptions.h
+++ b/lldb/include/lldb/Utility/TraceOptions.h
@@ -16,18 +16,7 @@
 
 namespace lldb_private {
 
-/// This struct represents a tracing technology.
-struct TraceTypeInfo {
-  /// The name of the technology, e.g. intel-pt or arm-coresight.
-  ///
-  /// In order for a Trace plug-in (see \a lldb_private::Trace.h) to support the
-  /// trace technology given by this struct, it should match its name with this
-  /// field.
-  std::string name;
-  /// A description for the technology.
-  std::string description;
-};
-
+/// Deprecated
 class TraceOptions {
 public:
   TraceOptions() : m_trace_params(new StructuredData::Dictionary()) {}
@@ -68,14 +57,7 @@ class TraceOptions {
   /// the lldb-server.
   StructuredData::DictionarySP m_trace_params;
 };
-}
-
-namespace llvm {
-namespace json {
-
-bool fromJSON(const Value &value, lldb_private::TraceTypeInfo &info, Path path);
 
-} // namespace json
-} // namespace llvm
+} // namespace lldb_private
 
 #endif // LLDB_UTILITY_TRACEOPTIONS_H

diff  --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 8283b14cdee5b..dcd022b38eb9b 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -247,7 +247,8 @@ enum StopReason {
   eStopReasonExec, ///< Program was re-exec'ed
   eStopReasonPlanComplete,
   eStopReasonThreadExiting,
-  eStopReasonInstrumentation
+  eStopReasonInstrumentation,
+  eStopReasonProcessorTrace,
 };
 
 /// Command Return Status Types.

diff  --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 3cf5754862776..a3cba953ea1ae 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -227,7 +227,7 @@ class ThreadPlanStepRange;
 class ThreadPlanStepThrough;
 class ThreadPlanTracer;
 class ThreadSpec;
-class ThreadTrace;
+class ThreadPostMortemTrace;
 class Trace;
 class TraceSessionFileParser;
 class TraceOptions;
@@ -437,6 +437,8 @@ typedef std::shared_ptr<lldb_private::Thread> ThreadSP;
 typedef std::weak_ptr<lldb_private::Thread> ThreadWP;
 typedef std::shared_ptr<lldb_private::ThreadCollection> ThreadCollectionSP;
 typedef std::shared_ptr<lldb_private::ThreadPlan> ThreadPlanSP;
+typedef std::shared_ptr<lldb_private::ThreadPostMortemTrace>
+    ThreadPostMortemTraceSP;
 typedef std::weak_ptr<lldb_private::ThreadPlan> ThreadPlanWP;
 typedef std::shared_ptr<lldb_private::ThreadPlanTracer> ThreadPlanTracerSP;
 typedef std::shared_ptr<lldb_private::Trace> TraceSP;

diff  --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h
index df33f8af0e142..3086a01942666 100644
--- a/lldb/include/lldb/lldb-private-interfaces.h
+++ b/lldb/include/lldb/lldb-private-interfaces.h
@@ -111,12 +111,11 @@ typedef lldb::REPLSP (*REPLCreateInstance)(Status &error,
                                            const char *repl_options);
 typedef int (*ComparisonFunction)(const void *, const void *);
 typedef void (*DebuggerInitializeCallback)(Debugger &debugger);
-typedef llvm::Expected<lldb::TraceSP> (*TraceCreateInstance)(
+typedef llvm::Expected<lldb::TraceSP> (*TraceCreateInstanceForSessionFile)(
     const llvm::json::Value &trace_session_file,
     llvm::StringRef session_file_dir, lldb_private::Debugger &debugger);
-typedef lldb::CommandObjectSP (*TraceGetStartCommand)(
-    CommandInterpreter &interpreter);
-
+typedef llvm::Expected<lldb::TraceSP> (*TraceCreateInstanceForLiveProcess)(
+    Process &process);
 } // namespace lldb_private
 
 #endif // #if defined(__cplusplus)

diff  --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index 0d50aceee5e41..4a1b53d4a5927 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -172,6 +172,7 @@ size_t SBThread::GetStopReasonDataCount() {
         case eStopReasonPlanComplete:
         case eStopReasonThreadExiting:
         case eStopReasonInstrumentation:
+        case eStopReasonProcessorTrace:
           // There is no data for these stop reasons.
           return 0;
 
@@ -223,6 +224,7 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
         case eStopReasonPlanComplete:
         case eStopReasonThreadExiting:
         case eStopReasonInstrumentation:
+        case eStopReasonProcessorTrace:
           // There is no data for these stop reasons.
           return 0;
 

diff  --git a/lldb/source/API/SBTrace.cpp b/lldb/source/API/SBTrace.cpp
index 3fdabaa29ac21..242a282f033e0 100644
--- a/lldb/source/API/SBTrace.cpp
+++ b/lldb/source/API/SBTrace.cpp
@@ -77,18 +77,7 @@ void SBTrace::StopTrace(SBError &error, lldb::tid_t thread_id) {
 }
 
 void SBTrace::GetTraceConfig(SBTraceOptions &options, SBError &error) {
-  LLDB_RECORD_METHOD(void, SBTrace, GetTraceConfig,
-                     (lldb::SBTraceOptions &, lldb::SBError &), options, error);
-
-  ProcessSP process_sp(GetSP());
-  error.Clear();
-
-  if (!process_sp) {
-    error.SetErrorString("invalid process");
-  } else {
-    error.SetError(process_sp->GetTraceConfig(GetTraceUID(),
-                                              *(options.m_traceoptions_sp)));
-  }
+  error.SetErrorString("deprecated");
 }
 
 lldb::user_id_t SBTrace::GetTraceUID() {

diff  --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 91ae4c64ab0e7..3e45b71cef085 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CommandObjectProcess.h"
+#include "CommandObjectTrace.h"
 #include "CommandOptionsProcessLaunch.h"
 #include "lldb/Breakpoint/Breakpoint.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
@@ -1577,6 +1578,71 @@ class CommandObjectProcessHandle : public CommandObjectParsed {
   CommandOptions m_options;
 };
 
+// Next are the subcommands of CommandObjectMultiwordProcessTrace
+
+// CommandObjectProcessTraceStart
+class CommandObjectProcessTraceStart : public CommandObjectTraceProxy {
+public:
+  CommandObjectProcessTraceStart(CommandInterpreter &interpreter)
+      : CommandObjectTraceProxy(
+            /*live_debug_session_only*/ true, interpreter,
+            "process trace start",
+            "Start tracing this process with the corresponding trace "
+            "plug-in.",
+            "process trace start [<trace-options>]") {}
+
+protected:
+  lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override {
+    return trace.GetProcessTraceStartCommand(m_interpreter);
+  }
+};
+
+// CommandObjectProcessTraceStop
+class CommandObjectProcessTraceStop : public CommandObjectParsed {
+public:
+  CommandObjectProcessTraceStop(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "process trace stop",
+                            "Stop tracing this process. This does not affect "
+                            "traces started with the "
+                            "\"thread trace start\" command.",
+                            "process trace stop",
+                            eCommandRequiresProcess | eCommandTryTargetAPILock |
+                                eCommandProcessMustBeLaunched |
+                                eCommandProcessMustBePaused |
+                                eCommandProcessMustBeTraced) {}
+
+  ~CommandObjectProcessTraceStop() override = default;
+
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    ProcessSP process_sp = m_exe_ctx.GetProcessSP();
+
+    TraceSP trace_sp = process_sp->GetTarget().GetTrace();
+
+    if (llvm::Error err = trace_sp->StopProcess())
+      result.SetError(toString(std::move(err)));
+    else
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+
+    return result.Succeeded();
+  }
+};
+
+// CommandObjectMultiwordProcessTrace
+class CommandObjectMultiwordProcessTrace : public CommandObjectMultiword {
+public:
+  CommandObjectMultiwordProcessTrace(CommandInterpreter &interpreter)
+      : CommandObjectMultiword(
+            interpreter, "trace", "Commands for tracing the current process.",
+            "process trace <subcommand> [<subcommand objects>]") {
+    LoadSubCommand("start", CommandObjectSP(new CommandObjectProcessTraceStart(
+                                interpreter)));
+    LoadSubCommand("stop", CommandObjectSP(
+                               new CommandObjectProcessTraceStop(interpreter)));
+  }
+
+  ~CommandObjectMultiwordProcessTrace() override = default;
+};
+
 // CommandObjectMultiwordProcess
 
 CommandObjectMultiwordProcess::CommandObjectMultiwordProcess(
@@ -1613,6 +1679,9 @@ CommandObjectMultiwordProcess::CommandObjectMultiwordProcess(
                  CommandObjectSP(new CommandObjectProcessPlugin(interpreter)));
   LoadSubCommand("save-core", CommandObjectSP(new CommandObjectProcessSaveCore(
                                   interpreter)));
+  LoadSubCommand(
+      "trace",
+      CommandObjectSP(new CommandObjectMultiwordProcessTrace(interpreter)));
 }
 
 CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess() = default;

diff  --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index f4ce5cc599cbc..a88fda9fa3d4f 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -11,6 +11,7 @@
 #include <sstream>
 
 #include "CommandObjectThreadUtil.h"
+#include "CommandObjectTrace.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Host/OptionParser.h"
@@ -1978,75 +1979,34 @@ class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword {
 
 // CommandObjectTraceStart
 
-/// This class works by delegating the logic to the actual trace plug-in that
-/// can support the current process.
-class CommandObjectTraceStart : public CommandObjectProxy {
+class CommandObjectTraceStart : public CommandObjectTraceProxy {
 public:
   CommandObjectTraceStart(CommandInterpreter &interpreter)
-      : CommandObjectProxy(interpreter, "thread trace start",
-                           "Start tracing threads with the corresponding trace "
-                           "plug-in for the current process.",
-                           "thread trace start [<trace-options>]") {}
+      : CommandObjectTraceProxy(
+            /*live_debug_session_only*/ true, interpreter, "thread trace start",
+            "Start tracing threads with the corresponding trace "
+            "plug-in for the current process.",
+            "thread trace start [<trace-options>]") {}
 
 protected:
-  llvm::Expected<CommandObjectSP> DoGetProxyCommandObject() {
-    ProcessSP process_sp = m_interpreter.GetExecutionContext().GetProcessSP();
-
-    if (!process_sp)
-      return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                     "Process not available.");
-    if (!process_sp->IsAlive())
-      return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                     "Process must be launched.");
-
-    llvm::Expected<TraceTypeInfo> trace_type =
-        process_sp->GetSupportedTraceType();
-
-    if (!trace_type)
-      return llvm::createStringError(
-          llvm::inconvertibleErrorCode(), "Tracing is not supported. %s",
-          llvm::toString(trace_type.takeError()).c_str());
-
-    CommandObjectSP delegate_sp =
-        PluginManager::GetTraceStartCommand(trace_type->name, m_interpreter);
-    if (!delegate_sp)
-      return llvm::createStringError(
-          llvm::inconvertibleErrorCode(),
-          "No trace plug-in matches the specified type: \"%s\"",
-          trace_type->name.c_str());
-    return delegate_sp;
+  lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override {
+    return trace.GetThreadTraceStartCommand(m_interpreter);
   }
-
-  CommandObject *GetProxyCommandObject() override {
-    if (llvm::Expected<CommandObjectSP> delegate = DoGetProxyCommandObject()) {
-      m_delegate_sp = *delegate;
-      m_delegate_error.clear();
-      return m_delegate_sp.get();
-    } else {
-      m_delegate_sp.reset();
-      m_delegate_error = llvm::toString(delegate.takeError());
-      return nullptr;
-    }
-  }
-
-private:
-  llvm::StringRef GetUnsupportedError() override { return m_delegate_error; }
-
-  CommandObjectSP m_delegate_sp;
-  std::string m_delegate_error;
 };
 
 // CommandObjectTraceStop
 
-class CommandObjectTraceStop : public CommandObjectIterateOverThreads {
+class CommandObjectTraceStop : public CommandObjectMultipleThreads {
 public:
   CommandObjectTraceStop(CommandInterpreter &interpreter)
-      : CommandObjectIterateOverThreads(
+      : CommandObjectMultipleThreads(
             interpreter, "thread trace stop",
-            "Stop tracing threads. "
+            "Stop tracing threads, including the ones traced with the "
+            "\"process trace start\" command."
             "Defaults to the current thread. Thread indices can be "
-            "specified as arguments.\n Use the thread-index \"all\" to trace "
-            "all threads.",
+            "specified as arguments.\n Use the thread-index \"all\" to stop "
+            "tracing "
+            "for all existing threads.",
             "thread trace stop [<thread-index> <thread-index> ...]",
             eCommandRequiresProcess | eCommandTryTargetAPILock |
                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
@@ -2054,20 +2014,18 @@ class CommandObjectTraceStop : public CommandObjectIterateOverThreads {
 
   ~CommandObjectTraceStop() override = default;
 
-  bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
-    const Thread &thread =
-        *m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
-    Trace &trace = *m_exe_ctx.GetTargetSP()->GetTrace();
+  bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
+                          const std::vector<lldb::tid_t> &tids) override {
+    ProcessSP process_sp = m_exe_ctx.GetProcessSP();
 
-    if (llvm::Error err = trace.StopTracingThread(thread)) {
-      result.AppendErrorWithFormat("Failed stopping thread %" PRIu64 ": %s\n",
-                                   tid, toString(std::move(err)).c_str());
-      result.SetStatus(eReturnStatusFailed);
-    }
+    TraceSP trace_sp = process_sp->GetTarget().GetTrace();
 
-    // We don't return false on errors to try to stop as many threads as
-    // possible.
-    return true;
+    if (llvm::Error err = trace_sp->StopThreads(tids))
+      result.SetError(toString(std::move(err)));
+    else
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+
+    return result.Succeeded();
   }
 };
 

diff  --git a/lldb/source/Commands/CommandObjectThreadUtil.cpp b/lldb/source/Commands/CommandObjectThreadUtil.cpp
index b93698c7be60b..b395f2d38b45a 100644
--- a/lldb/source/Commands/CommandObjectThreadUtil.cpp
+++ b/lldb/source/Commands/CommandObjectThreadUtil.cpp
@@ -156,3 +156,47 @@ bool CommandObjectIterateOverThreads::BucketThread(
   }
   return true;
 }
+
+bool CommandObjectMultipleThreads::DoExecute(Args &command,
+                                             CommandReturnObject &result) {
+  Process &process = m_exe_ctx.GetProcessRef();
+
+  std::vector<lldb::tid_t> tids;
+  const size_t num_args = command.GetArgumentCount();
+
+  std::lock_guard<std::recursive_mutex> guard(
+      process.GetThreadList().GetMutex());
+
+  if (num_args > 0 && ::strcmp(command.GetArgumentAtIndex(0), "all") == 0) {
+    for (ThreadSP thread_sp : process.Threads())
+      tids.push_back(thread_sp->GetID());
+  } else {
+    if (num_args == 0) {
+      Thread &thread = m_exe_ctx.GetThreadRef();
+      tids.push_back(thread.GetID());
+    }
+
+    for (size_t i = 0; i < num_args; i++) {
+      uint32_t thread_idx;
+      if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) {
+        result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
+                                     command.GetArgumentAtIndex(i));
+        result.SetStatus(eReturnStatusFailed);
+        return false;
+      }
+
+      ThreadSP thread = process.GetThreadList().FindThreadByIndexID(thread_idx);
+
+      if (!thread) {
+        result.AppendErrorWithFormat("no thread with index: \"%s\"\n",
+                                     command.GetArgumentAtIndex(i));
+        result.SetStatus(eReturnStatusFailed);
+        return false;
+      }
+
+      tids.push_back(thread->GetID());
+    }
+  }
+
+  return DoExecuteOnThreads(command, result, tids);
+}

diff  --git a/lldb/source/Commands/CommandObjectThreadUtil.h b/lldb/source/Commands/CommandObjectThreadUtil.h
index 7122982d89433..18f65813c6398 100644
--- a/lldb/source/Commands/CommandObjectThreadUtil.h
+++ b/lldb/source/Commands/CommandObjectThreadUtil.h
@@ -76,6 +76,26 @@ class CommandObjectIterateOverThreads : public CommandObjectParsed {
   bool m_add_return = true;
 };
 
+/// Class similar to \a CommandObjectIterateOverThreads, but which performs
+/// an action on multiple threads at once instead of iterating over each thread.
+class CommandObjectMultipleThreads : public CommandObjectParsed {
+public:
+  using CommandObjectParsed::CommandObjectParsed;
+
+  bool DoExecute(Args &command, CommandReturnObject &result) override;
+
+protected:
+  /// Method that handles the command after the main arguments have been parsed.
+  ///
+  /// \param[in] tids
+  ///     The thread ids passed as arguments.
+  ///
+  /// \return
+  ///     A boolean result similar to the one expected from \a DoExecute.
+  virtual bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
+                                  const std::vector<lldb::tid_t> &tids) = 0;
+};
+
 } // namespace lldb_private
 
 #endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTTHREADUTIL_H

diff  --git a/lldb/source/Commands/CommandObjectTrace.cpp b/lldb/source/Commands/CommandObjectTrace.cpp
index 9d87e8cc4017b..b151a4dc80559 100644
--- a/lldb/source/Commands/CommandObjectTrace.cpp
+++ b/lldb/source/Commands/CommandObjectTrace.cpp
@@ -23,6 +23,7 @@
 #include "lldb/Interpreter/OptionValueLanguage.h"
 #include "lldb/Interpreter/OptionValueString.h"
 #include "lldb/Interpreter/Options.h"
+#include "lldb/Target/Process.h"
 #include "lldb/Target/Trace.h"
 
 using namespace lldb;
@@ -113,8 +114,9 @@ class CommandObjectTraceLoad : public CommandObjectParsed {
       return end_with_failure(session_file.takeError());
 
     if (Expected<lldb::TraceSP> traceOrErr =
-            Trace::FindPlugin(GetDebugger(), *session_file,
-                              json_file.GetDirectory().AsCString())) {
+            Trace::FindPluginForPostMortemProcess(
+                GetDebugger(), *session_file,
+                json_file.GetDirectory().AsCString())) {
       lldb::TraceSP trace_sp = traceOrErr.get();
       if (m_options.m_verbose && trace_sp)
         result.AppendMessageWithFormat("loading trace with plugin %s\n",
@@ -303,3 +305,33 @@ CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter)
 }
 
 CommandObjectTrace::~CommandObjectTrace() = default;
+
+Expected<CommandObjectSP> CommandObjectTraceProxy::DoGetProxyCommandObject() {
+  ProcessSP process_sp = m_interpreter.GetExecutionContext().GetProcessSP();
+
+  if (!process_sp)
+    return createStringError(inconvertibleErrorCode(),
+                             "Process not available.");
+  if (m_live_debug_session_only && !process_sp->IsLiveDebugSession())
+    return createStringError(inconvertibleErrorCode(),
+                             "Process must be alive.");
+
+  if (Expected<TraceSP &> trace_sp = process_sp->GetTarget().GetTraceOrCreate())
+    return GetDelegateCommand(**trace_sp);
+  else
+    return createStringError(inconvertibleErrorCode(),
+                             "Tracing is not supported. %s",
+                             toString(trace_sp.takeError()).c_str());
+}
+
+CommandObject *CommandObjectTraceProxy::GetProxyCommandObject() {
+  if (Expected<CommandObjectSP> delegate = DoGetProxyCommandObject()) {
+    m_delegate_sp = *delegate;
+    m_delegate_error.clear();
+    return m_delegate_sp.get();
+  } else {
+    m_delegate_sp.reset();
+    m_delegate_error = toString(delegate.takeError());
+    return nullptr;
+  }
+}

diff  --git a/lldb/source/Commands/CommandObjectTrace.h b/lldb/source/Commands/CommandObjectTrace.h
index 2dca0e26b2434..b96a3094cefc8 100644
--- a/lldb/source/Commands/CommandObjectTrace.h
+++ b/lldb/source/Commands/CommandObjectTrace.h
@@ -9,7 +9,7 @@
 #ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTTRACE_H
 #define LLDB_SOURCE_COMMANDS_COMMANDOBJECTTRACE_H
 
-#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "CommandObjectThreadUtil.h"
 
 namespace lldb_private {
 
@@ -20,6 +20,32 @@ class CommandObjectTrace : public CommandObjectMultiword {
   ~CommandObjectTrace() override;
 };
 
+/// This class works by delegating the logic to the actual trace plug-in that
+/// can support the current process.
+class CommandObjectTraceProxy : public CommandObjectProxy {
+public:
+  CommandObjectTraceProxy(bool live_debug_session_only,
+                          CommandInterpreter &interpreter, const char *name,
+                          const char *help = nullptr,
+                          const char *syntax = nullptr, uint32_t flags = 0)
+      : CommandObjectProxy(interpreter, name, help, syntax, flags),
+        m_live_debug_session_only(live_debug_session_only) {}
+
+protected:
+  virtual lldb::CommandObjectSP GetDelegateCommand(Trace &trace) = 0;
+
+  llvm::Expected<lldb::CommandObjectSP> DoGetProxyCommandObject();
+
+  CommandObject *GetProxyCommandObject() override;
+
+private:
+  llvm::StringRef GetUnsupportedError() override { return m_delegate_error; }
+
+  bool m_live_debug_session_only;
+  lldb::CommandObjectSP m_delegate_sp;
+  std::string m_delegate_error;
+};
+
 } // namespace lldb_private
 
 #endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTTRACE_H

diff  --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index 97e1e8d14039e..a826e123459f9 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -1008,16 +1008,20 @@ PluginManager::GetSymbolVendorCreateCallbackAtIndex(uint32_t idx) {
 
 #pragma mark Trace
 
-struct TraceInstance : public PluginInstance<TraceCreateInstance> {
-  TraceInstance(ConstString name, std::string description,
-                CallbackType create_callback, llvm::StringRef schema,
-                TraceGetStartCommand get_start_command)
-      : PluginInstance<TraceCreateInstance>(name, std::move(description),
-                                            create_callback),
-        schema(schema), get_start_command(get_start_command) {}
+struct TraceInstance
+    : public PluginInstance<TraceCreateInstanceForSessionFile> {
+  TraceInstance(
+      ConstString name, std::string description,
+      CallbackType create_callback_for_session_file,
+      TraceCreateInstanceForLiveProcess create_callback_for_live_process,
+      llvm::StringRef schema)
+      : PluginInstance<TraceCreateInstanceForSessionFile>(
+            name, std::move(description), create_callback_for_session_file),
+        schema(schema),
+        create_callback_for_live_process(create_callback_for_live_process) {}
 
   llvm::StringRef schema;
-  TraceGetStartCommand get_start_command;
+  TraceCreateInstanceForLiveProcess create_callback_for_live_process;
 };
 
 typedef PluginInstances<TraceInstance> TraceInstances;
@@ -1027,37 +1031,40 @@ static TraceInstances &GetTracePluginInstances() {
   return g_instances;
 }
 
-bool PluginManager::RegisterPlugin(ConstString name, const char *description,
-                                   TraceCreateInstance create_callback,
-                                   llvm::StringRef schema,
-                                   TraceGetStartCommand get_start_command) {
+bool PluginManager::RegisterPlugin(
+    ConstString name, const char *description,
+    TraceCreateInstanceForSessionFile create_callback_for_session_file,
+    TraceCreateInstanceForLiveProcess create_callback_for_live_process,
+    llvm::StringRef schema) {
   return GetTracePluginInstances().RegisterPlugin(
-      name, description, create_callback, schema, get_start_command);
+      name, description, create_callback_for_session_file,
+      create_callback_for_live_process, schema);
 }
 
-bool PluginManager::UnregisterPlugin(TraceCreateInstance create_callback) {
-  return GetTracePluginInstances().UnregisterPlugin(create_callback);
+bool PluginManager::UnregisterPlugin(
+    TraceCreateInstanceForSessionFile create_callback_for_session_file) {
+  return GetTracePluginInstances().UnregisterPlugin(
+      create_callback_for_session_file);
 }
 
-TraceCreateInstance
+TraceCreateInstanceForSessionFile
 PluginManager::GetTraceCreateCallback(ConstString plugin_name) {
   return GetTracePluginInstances().GetCallbackForName(plugin_name);
 }
 
-llvm::StringRef PluginManager::GetTraceSchema(ConstString plugin_name) {
+TraceCreateInstanceForLiveProcess
+PluginManager::GetTraceCreateCallbackForLiveProcess(ConstString plugin_name) {
   for (const TraceInstance &instance : GetTracePluginInstances().GetInstances())
     if (instance.name == plugin_name)
-      return instance.schema;
-  return llvm::StringRef();
+      return instance.create_callback_for_live_process;
+  return nullptr;
 }
 
-CommandObjectSP
-PluginManager::GetTraceStartCommand(llvm::StringRef plugin_name,
-                                    CommandInterpreter &interpreter) {
+llvm::StringRef PluginManager::GetTraceSchema(ConstString plugin_name) {
   for (const TraceInstance &instance : GetTracePluginInstances().GetInstances())
-    if (instance.name.GetStringRef() == plugin_name)
-      return instance.get_start_command(interpreter);
-  return CommandObjectSP();
+    if (instance.name == plugin_name)
+      return instance.schema;
+  return llvm::StringRef();
 }
 
 llvm::StringRef PluginManager::GetTraceSchema(size_t index) {

diff  --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index eeef14bf36c27..a7aea8daf624e 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -2244,7 +2244,9 @@ bool CommandInterpreter::DidProcessStopAbnormally() const {
       return false;
 
     const StopReason reason = stop_info->GetStopReason();
-    if (reason == eStopReasonException || reason == eStopReasonInstrumentation)
+    if (reason == eStopReasonException ||
+        reason == eStopReasonInstrumentation ||
+        reason == eStopReasonProcessorTrace)
       return true;
 
     if (reason == eStopReasonSignal) {

diff  --git a/lldb/source/Plugins/Process/Linux/CMakeLists.txt b/lldb/source/Plugins/Process/Linux/CMakeLists.txt
index a68ff4ffd822a..c4edc57a8a2d8 100644
--- a/lldb/source/Plugins/Process/Linux/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Linux/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_lldb_library(lldbPluginProcessLinux
+  IntelPTManager.cpp
   NativeProcessLinux.cpp
   NativeRegisterContextLinux.cpp
   NativeRegisterContextLinux_arm.cpp
@@ -7,7 +8,6 @@ add_lldb_library(lldbPluginProcessLinux
   NativeRegisterContextLinux_s390x.cpp
   NativeRegisterContextLinux_x86_64.cpp
   NativeThreadLinux.cpp
-  ProcessorTrace.cpp
   SingleStepCheck.cpp
 
   LINK_LIBS

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTManager.cpp b/lldb/source/Plugins/Process/Linux/IntelPTManager.cpp
new file mode 100644
index 0000000000000..14b08a6aa93c0
--- /dev/null
+++ b/lldb/source/Plugins/Process/Linux/IntelPTManager.cpp
@@ -0,0 +1,554 @@
+//===-- IntelPTManager.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <algorithm>
+#include <fstream>
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+
+#include "IntelPTManager.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Host/linux/Support.h"
+#include "lldb/Utility/StreamString.h"
+
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace process_linux;
+using namespace llvm;
+
+const char *kOSEventIntelPTTypeFile =
+    "/sys/bus/event_source/devices/intel_pt/type";
+
+/// Return the Linux perf event type for Intel PT.
+static Expected<uint32_t> 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.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;
+}
+
+size_t IntelPTThreadTrace::GetTraceBufferSize() const {
+  return m_mmap_meta->aux_size;
+}
+
+Error IntelPTThreadTrace::StartTrace(lldb::pid_t pid, lldb::tid_t tid,
+                                     uint64_t buffer_size) {
+#ifndef PERF_ATTR_SIZE_VER5
+  llvm_unreachable("Intel PT Linux perf event not supported");
+#else
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+  m_tid = tid;
+  LLDB_LOG(log, "called thread id {0}", tid);
+  uint64_t page_size = getpagesize();
+
+  if (__builtin_popcount(buffer_size) != 1 || buffer_size < 4096) {
+    return createStringError(
+        inconvertibleErrorCode(),
+        "The trace buffer size must be a power of 2 greater than or equal to "
+        "4096 (2^12) bytes. It was %" PRIu64 ".",
+        buffer_size);
+  }
+  uint64_t numpages = static_cast<uint64_t>(
+      llvm::PowerOf2Floor((buffer_size + page_size - 1) / page_size));
+  numpages = std::max<uint64_t>(1, numpages);
+  buffer_size = page_size * numpages;
+
+  perf_event_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.size = sizeof(attr);
+  attr.exclude_kernel = 1;
+  attr.sample_type = PERF_SAMPLE_TIME;
+  attr.sample_id_all = 1;
+  attr.exclude_hv = 1;
+  attr.exclude_idle = 1;
+  attr.mmap = 1;
+  attr.config = 0;
+
+  Expected<uint32_t> intel_pt_type = GetOSEventType();
+
+  if (!intel_pt_type)
+    return intel_pt_type.takeError();
+
+  LLDB_LOG(log, "intel pt type {0}", *intel_pt_type);
+  attr.type = *intel_pt_type;
+
+  LLDB_LOG(log, "buffer size {0} ", buffer_size);
+
+  errno = 0;
+  auto fd =
+      syscall(SYS_perf_event_open, &attr, static_cast<::tid_t>(tid), -1, -1, 0);
+  if (fd == -1) {
+    LLDB_LOG(log, "syscall error {0}", errno);
+    return createStringError(inconvertibleErrorCode(),
+                             "perf event syscall failed");
+  }
+
+  m_fd = std::unique_ptr<int, file_close>(new int(fd), file_close());
+
+  errno = 0;
+  auto base =
+      mmap(nullptr, (buffer_size + page_size), PROT_WRITE, MAP_SHARED, fd, 0);
+
+  if (base == MAP_FAILED) {
+    LLDB_LOG(log, "mmap base error {0}", errno);
+    return createStringError(inconvertibleErrorCode(),
+                             "Meta buffer allocation failed");
+  }
+
+  m_mmap_meta = std::unique_ptr<perf_event_mmap_page, munmap_delete>(
+      reinterpret_cast<perf_event_mmap_page *>(base),
+      munmap_delete(buffer_size + page_size));
+
+  m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size;
+  m_mmap_meta->aux_size = buffer_size;
+
+  errno = 0;
+  auto mmap_aux = mmap(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd,
+                       static_cast<long int>(m_mmap_meta->aux_offset));
+
+  if (mmap_aux == MAP_FAILED) {
+    LLDB_LOG(log, "second mmap done {0}", errno);
+    return createStringError(inconvertibleErrorCode(),
+                             "Trace buffer allocation failed");
+  }
+  m_mmap_aux = std::unique_ptr<uint8_t, munmap_delete>(
+      reinterpret_cast<uint8_t *>(mmap_aux), munmap_delete(buffer_size));
+  return Error::success();
+#endif
+}
+
+llvm::MutableArrayRef<uint8_t> IntelPTThreadTrace::GetDataBuffer() const {
+#ifndef PERF_ATTR_SIZE_VER5
+  llvm_unreachable("Intel PT Linux perf event not supported");
+#else
+  return MutableArrayRef<uint8_t>(
+      (reinterpret_cast<uint8_t *>(m_mmap_meta.get()) +
+       m_mmap_meta->data_offset),
+      m_mmap_meta->data_size);
+#endif
+}
+
+llvm::MutableArrayRef<uint8_t> IntelPTThreadTrace::GetAuxBuffer() const {
+#ifndef PERF_ATTR_SIZE_VER5
+  llvm_unreachable("Intel PT Linux perf event not supported");
+#else
+  return MutableArrayRef<uint8_t>(m_mmap_aux.get(), m_mmap_meta->aux_size);
+#endif
+}
+
+Expected<ArrayRef<uint8_t>> IntelPTThreadTrace::GetCPUInfo() {
+  static llvm::Optional<std::vector<uint8_t>> cpu_info;
+  if (!cpu_info) {
+    auto buffer_or_error = getProcFile("cpuinfo");
+    if (!buffer_or_error)
+      return Status(buffer_or_error.getError()).ToError();
+    MemoryBuffer &buffer = **buffer_or_error;
+    cpu_info = std::vector<uint8_t>(
+        reinterpret_cast<const uint8_t *>(buffer.getBufferStart()),
+        reinterpret_cast<const uint8_t *>(buffer.getBufferEnd()));
+  }
+  return *cpu_info;
+}
+
+llvm::Expected<IntelPTThreadTraceUP>
+IntelPTThreadTrace::Create(lldb::pid_t pid, lldb::tid_t tid,
+                           size_t buffer_size) {
+  IntelPTThreadTraceUP thread_trace_up(new IntelPTThreadTrace());
+
+  if (llvm::Error err = thread_trace_up->StartTrace(pid, tid, buffer_size))
+    return std::move(err);
+
+  return std::move(thread_trace_up);
+}
+
+Expected<std::vector<uint8_t>>
+IntelPTThreadTrace::GetIntelPTBuffer(size_t offset, size_t size) const {
+  std::vector<uint8_t> data(size, 0);
+  MutableArrayRef<uint8_t> buffer_ref(data);
+  Status error = ReadPerfTraceAux(buffer_ref, 0);
+  if (error.Fail())
+    return error.ToError();
+  return data;
+}
+
+Status
+IntelPTThreadTrace::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
+                                     size_t offset) const {
+#ifndef PERF_ATTR_SIZE_VER5
+  llvm_unreachable("perf event not supported");
+#else
+  // Disable the perf event to force a flush out of the CPU's internal buffer.
+  // Besides, we can guarantee that the CPU won't override any data as we are
+  // reading the buffer.
+  //
+  // The Intel documentation says:
+  //
+  // Packets are first buffered internally and then written out asynchronously.
+  // To collect packet output for postprocessing, a collector needs first to
+  // ensure that all packet data has been flushed from internal buffers.
+  // Software can ensure this by stopping packet generation by clearing
+  // IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in
+  // Section 35.2.7.2).
+  //
+  // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned
+  // in the man page of perf_event_open.
+  ioctl(*m_fd, PERF_EVENT_IOC_DISABLE);
+
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+  Status error;
+  uint64_t head = m_mmap_meta->aux_head;
+
+  LLDB_LOG(log, "Aux size -{0} , Head - {1}", m_mmap_meta->aux_size, head);
+
+  /**
+   * When configured as ring buffer, the aux buffer keeps wrapping around
+   * the buffer and its not possible to detect how many times the buffer
+   * wrapped. Initially the buffer is filled with zeros,as shown below
+   * so in order to get complete buffer we first copy firstpartsize, followed
+   * by any left over part from beginning to aux_head
+   *
+   * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size
+   *                 aux_head->||<- firstpartsize  ->|
+   *
+   * */
+
+  ReadCyclicBuffer(buffer, GetAuxBuffer(), static_cast<size_t>(head), offset);
+  LLDB_LOG(log, "ReadCyclic BUffer Done");
+
+  // Reenable tracing now we have read the buffer
+  ioctl(*m_fd, PERF_EVENT_IOC_ENABLE);
+  return error;
+#endif
+}
+
+Status
+IntelPTThreadTrace::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
+                                      size_t offset) const {
+#ifndef PERF_ATTR_SIZE_VER5
+  llvm_unreachable("perf event not supported");
+#else
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+  uint64_t bytes_remaining = buffer.size();
+  Status error;
+
+  uint64_t head = m_mmap_meta->data_head;
+
+  /*
+   * The data buffer and aux buffer have 
diff erent implementations
+   * with respect to their definition of head pointer. In the case
+   * of Aux data buffer the head always wraps around the aux buffer
+   * and we don't need to care about it, whereas the data_head keeps
+   * increasing and needs to be wrapped by modulus operator
+   */
+
+  LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining);
+
+  auto data_buffer = GetDataBuffer();
+
+  if (head > data_buffer.size()) {
+    head = head % data_buffer.size();
+    LLDB_LOG(log, "Data size -{0} Head - {1}", m_mmap_meta->data_size, head);
+
+    ReadCyclicBuffer(buffer, data_buffer, static_cast<size_t>(head), offset);
+    bytes_remaining -= buffer.size();
+  } else {
+    LLDB_LOG(log, "Head - {0}", head);
+    if (offset >= head) {
+      LLDB_LOG(log, "Invalid Offset ");
+      error.SetErrorString("invalid offset");
+      buffer = buffer.slice(buffer.size());
+      return error;
+    }
+
+    auto data = data_buffer.slice(offset, (head - offset));
+    auto remaining = std::copy(data.begin(), data.end(), buffer.begin());
+    bytes_remaining -= (remaining - buffer.begin());
+  }
+  buffer = buffer.drop_back(bytes_remaining);
+  return error;
+#endif
+}
+
+void IntelPTThreadTrace::ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
+                                          llvm::MutableArrayRef<uint8_t> src,
+                                          size_t src_cyc_index, size_t offset) {
+
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+  if (dst.empty() || src.empty()) {
+    dst = dst.drop_back(dst.size());
+    return;
+  }
+
+  if (dst.data() == nullptr || src.data() == nullptr) {
+    dst = dst.drop_back(dst.size());
+    return;
+  }
+
+  if (src_cyc_index > src.size()) {
+    dst = dst.drop_back(dst.size());
+    return;
+  }
+
+  if (offset >= src.size()) {
+    LLDB_LOG(log, "Too Big offset ");
+    dst = dst.drop_back(dst.size());
+    return;
+  }
+
+  llvm::SmallVector<MutableArrayRef<uint8_t>, 2> parts = {
+      src.slice(src_cyc_index), src.take_front(src_cyc_index)};
+
+  if (offset > parts[0].size()) {
+    parts[1] = parts[1].slice(offset - parts[0].size());
+    parts[0] = parts[0].drop_back(parts[0].size());
+  } else if (offset == parts[0].size()) {
+    parts[0] = parts[0].drop_back(parts[0].size());
+  } else {
+    parts[0] = parts[0].slice(offset);
+  }
+  auto next = dst.begin();
+  auto bytes_left = dst.size();
+  for (auto part : parts) {
+    size_t chunk_size = std::min(part.size(), bytes_left);
+    next = std::copy_n(part.begin(), chunk_size, next);
+    bytes_left -= chunk_size;
+  }
+  dst = dst.drop_back(bytes_left);
+}
+
+TraceThreadState IntelPTThreadTrace::GetState() const {
+  return {static_cast<int64_t>(m_tid),
+          {TraceBinaryData{"threadTraceBuffer",
+                           static_cast<int64_t>(GetTraceBufferSize())}}};
+}
+
+/// IntelPTThreadTraceCollection
+
+bool IntelPTThreadTraceCollection::TracesThread(lldb::tid_t tid) const {
+  return m_thread_traces.count(tid);
+}
+
+Error IntelPTThreadTraceCollection::TraceStop(lldb::tid_t tid) {
+  auto it = m_thread_traces.find(tid);
+  if (it == m_thread_traces.end())
+    return createStringError(inconvertibleErrorCode(),
+                             "Thread %" PRIu64 " not currently traced", tid);
+  m_total_buffer_size -= it->second->GetTraceBufferSize();
+  m_thread_traces.erase(tid);
+  return Error::success();
+}
+
+Error IntelPTThreadTraceCollection::TraceStart(
+    lldb::tid_t tid, const TraceIntelPTStartRequest &request) {
+  if (TracesThread(tid))
+    return createStringError(inconvertibleErrorCode(),
+                             "Thread %" PRIu64 " already traced", tid);
+
+  Expected<IntelPTThreadTraceUP> trace_up =
+      IntelPTThreadTrace::Create(m_pid, tid, request.threadBufferSize);
+  if (!trace_up)
+    return trace_up.takeError();
+
+  m_total_buffer_size += (*trace_up)->GetTraceBufferSize();
+  m_thread_traces.try_emplace(tid, std::move(*trace_up));
+  return Error::success();
+}
+
+size_t IntelPTThreadTraceCollection::GetTotalBufferSize() const {
+  return m_total_buffer_size;
+}
+
+std::vector<TraceThreadState>
+IntelPTThreadTraceCollection::GetThreadStates() const {
+  std::vector<TraceThreadState> states;
+  for (const auto &it : m_thread_traces)
+    states.push_back(it.second->GetState());
+  return states;
+}
+
+Expected<const IntelPTThreadTrace &>
+IntelPTThreadTraceCollection::GetTracedThread(lldb::tid_t tid) const {
+  auto it = m_thread_traces.find(tid);
+  if (it == m_thread_traces.end())
+    return createStringError(inconvertibleErrorCode(),
+                             "Thread %" PRIu64 " not currently traced", tid);
+  return *it->second.get();
+}
+
+void IntelPTThreadTraceCollection::Clear() {
+  m_thread_traces.clear();
+  m_total_buffer_size = 0;
+}
+
+/// IntelPTProcessTrace
+
+bool IntelPTProcessTrace::TracesThread(lldb::tid_t tid) const {
+  return m_thread_traces.TracesThread(tid);
+}
+
+Error IntelPTProcessTrace::TraceStop(lldb::tid_t tid) {
+  return m_thread_traces.TraceStop(tid);
+}
+
+Error IntelPTProcessTrace::TraceStart(lldb::tid_t tid) {
+  if (m_thread_traces.GetTotalBufferSize() + m_tracing_params.threadBufferSize >
+      static_cast<size_t>(*m_tracing_params.processBufferSizeLimit))
+    return createStringError(
+        inconvertibleErrorCode(),
+        "Thread %" PRIu64 " can't be traced as the process trace size limit "
+        "has been reached. Consider retracing with a higher "
+        "limit.",
+        tid);
+
+  return m_thread_traces.TraceStart(tid, m_tracing_params);
+}
+
+const IntelPTThreadTraceCollection &
+IntelPTProcessTrace::GetThreadTraces() const {
+  return m_thread_traces;
+}
+
+/// IntelPTManager
+
+Error IntelPTManager::TraceStop(lldb::tid_t tid) {
+  if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
+    return m_process_trace->TraceStop(tid);
+  return m_thread_traces.TraceStop(tid);
+}
+
+Error IntelPTManager::TraceStop(const TraceStopRequest &request) {
+  if (request.IsProcessTracing()) {
+    if (!IsProcessTracingEnabled()) {
+      return createStringError(inconvertibleErrorCode(),
+                               "Process not currently traced");
+    }
+    ClearProcessTracing();
+    return Error::success();
+  } else {
+    Error error = Error::success();
+    for (int64_t tid : *request.tids)
+      error = joinErrors(std::move(error),
+                         TraceStop(static_cast<lldb::tid_t>(tid)));
+    return error;
+  }
+}
+
+Error IntelPTManager::TraceStart(
+    const TraceIntelPTStartRequest &request,
+    const std::vector<lldb::tid_t> &process_threads) {
+  if (request.IsProcessTracing()) {
+    if (IsProcessTracingEnabled()) {
+      return createStringError(
+          inconvertibleErrorCode(),
+          "Process currently traced. Stop process tracing first");
+    }
+    m_process_trace = IntelPTProcessTrace(m_pid, request);
+
+    Error error = Error::success();
+    for (lldb::tid_t tid : process_threads)
+      error = joinErrors(std::move(error), m_process_trace->TraceStart(tid));
+    return error;
+  } else {
+    Error error = Error::success();
+    for (int64_t tid : *request.tids)
+      error = joinErrors(std::move(error),
+                         m_thread_traces.TraceStart(tid, request));
+    return error;
+  }
+}
+
+Error IntelPTManager::OnThreadCreated(lldb::tid_t tid) {
+  if (!IsProcessTracingEnabled())
+    return Error::success();
+  return m_process_trace->TraceStart(tid);
+}
+
+Error IntelPTManager::OnThreadDestroyed(lldb::tid_t tid) {
+  if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
+    return m_process_trace->TraceStop(tid);
+  else if (m_thread_traces.TracesThread(tid))
+    return m_thread_traces.TraceStop(tid);
+  return Error::success();
+}
+
+Expected<json::Value> IntelPTManager::GetState() const {
+  Expected<ArrayRef<uint8_t>> cpu_info = IntelPTThreadTrace::GetCPUInfo();
+  if (!cpu_info)
+    return cpu_info.takeError();
+
+  TraceGetStateResponse state;
+  state.processBinaryData.push_back(
+      {"cpuInfo", static_cast<int64_t>(cpu_info->size())});
+
+  std::vector<TraceThreadState> thread_states =
+      m_thread_traces.GetThreadStates();
+  state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
+                             thread_states.end());
+
+  if (IsProcessTracingEnabled()) {
+    thread_states = m_process_trace->GetThreadTraces().GetThreadStates();
+    state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
+                               thread_states.end());
+  }
+  return toJSON(state);
+}
+
+Expected<const IntelPTThreadTrace &>
+IntelPTManager::GetTracedThread(lldb::tid_t tid) const {
+  if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
+    return m_process_trace->GetThreadTraces().GetTracedThread(tid);
+  return m_thread_traces.GetTracedThread(tid);
+}
+
+Expected<std::vector<uint8_t>>
+IntelPTManager::GetBinaryData(const TraceGetBinaryDataRequest &request) const {
+  if (request.kind == "threadTraceBuffer") {
+    if (Expected<const IntelPTThreadTrace &> trace =
+            GetTracedThread(*request.tid))
+      return trace->GetIntelPTBuffer(request.offset, request.size);
+    else
+      return trace.takeError();
+  } else if (request.kind == "cpuInfo") {
+    return IntelPTThreadTrace::GetCPUInfo();
+  }
+  return createStringError(inconvertibleErrorCode(),
+                           "Unsuported trace binary data kind: %s",
+                           request.kind.c_str());
+}
+
+void IntelPTManager::ClearProcessTracing() { m_process_trace = None; }
+
+bool IntelPTManager::IsSupported() { return (bool)GetOSEventType(); }
+
+bool IntelPTManager::IsProcessTracingEnabled() const {
+  return (bool)m_process_trace;
+}
+
+void IntelPTManager::Clear() {
+  ClearProcessTracing();
+  m_thread_traces.Clear();
+}

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTManager.h b/lldb/source/Plugins/Process/Linux/IntelPTManager.h
new file mode 100644
index 0000000000000..807798a811db6
--- /dev/null
+++ b/lldb/source/Plugins/Process/Linux/IntelPTManager.h
@@ -0,0 +1,254 @@
+//===-- IntelPTManager.h -------------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_IntelPTManager_H_
+#define liblldb_IntelPTManager_H_
+
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+
+#include <linux/perf_event.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+namespace lldb_private {
+
+namespace process_linux {
+
+/// This class keeps track of one tracing instance of
+/// Intel(R) Processor Trace on Linux OS at thread level.
+///
+/// The kernel interface for us is the perf_event_open.
+class IntelPTThreadTrace;
+typedef std::unique_ptr<IntelPTThreadTrace> IntelPTThreadTraceUP;
+
+class IntelPTThreadTrace {
+
+  class munmap_delete {
+    size_t m_length;
+
+  public:
+    munmap_delete(size_t length) : m_length(length) {}
+    void operator()(void *ptr) {
+      if (m_length)
+        munmap(ptr, m_length);
+    }
+  };
+
+  class file_close {
+
+  public:
+    file_close() = default;
+    void operator()(int *ptr) {
+      if (ptr == nullptr)
+        return;
+      if (*ptr == -1)
+        return;
+      close(*ptr);
+      std::default_delete<int>()(ptr);
+    }
+  };
+
+  std::unique_ptr<perf_event_mmap_page, munmap_delete> m_mmap_meta;
+  std::unique_ptr<uint8_t, munmap_delete> m_mmap_aux;
+  std::unique_ptr<int, file_close> m_fd;
+  lldb::tid_t m_tid;
+
+  /// Start tracing a thread
+  ///
+  /// \param[in] pid
+  ///     The pid of the process whose thread will be traced.
+  ///
+  /// \param[in] buffer_size
+  ///     Size of the thread buffer in bytes.
+  ///
+  /// \return
+  ///     \a llvm::Error::success if tracing was successful, or an
+  ///     \a llvm::Error otherwise.
+  llvm::Error StartTrace(lldb::pid_t pid, lldb::tid_t tid,
+                         uint64_t buffer_size);
+
+  llvm::MutableArrayRef<uint8_t> GetAuxBuffer() const;
+  llvm::MutableArrayRef<uint8_t> GetDataBuffer() const;
+
+  IntelPTThreadTrace()
+      : m_mmap_meta(nullptr, munmap_delete(0)),
+        m_mmap_aux(nullptr, munmap_delete(0)), m_fd(nullptr, file_close()) {}
+
+public:
+  /// Get the content of /proc/cpuinfo that can be later used to decode traces.
+  static llvm::Expected<llvm::ArrayRef<uint8_t>> GetCPUInfo();
+
+  /// Start tracing a thread.
+  ///
+  /// See \a StartTrace.
+  ///
+  /// \return
+  ///   A \a IntelPTThreadTrace instance if tracing was successful, or
+  ///   an \a llvm::Error otherwise.
+  static llvm::Expected<IntelPTThreadTraceUP>
+  Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size);
+
+  /// Read the trace buffer of the currently traced thread.
+  ///
+  /// \param[in] offset
+  ///     Offset of the data to read.
+  ///
+  /// \param[in] size
+  ///     Number of bytes to read.
+  ///
+  /// \return
+  ///     A vector with the requested binary data. The vector will have the
+  ///     size of the requested \a size. Non-available positions will be
+  ///     filled with zeroes.
+  llvm::Expected<std::vector<uint8_t>> GetIntelPTBuffer(size_t offset,
+                                                        size_t size) const;
+
+  Status ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
+                          size_t offset = 0) const;
+
+  Status ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
+                           size_t offset = 0) const;
+
+  /// Get the size in bytes of the aux section of the thread or process traced
+  /// by this object.
+  size_t GetTraceBufferSize() const;
+
+  /// Read data from a cyclic buffer
+  ///
+  /// \param[in] [out] buf
+  ///     Destination buffer, the buffer will be truncated to written size.
+  ///
+  /// \param[in] src
+  ///     Source buffer which must be a cyclic buffer.
+  ///
+  /// \param[in] src_cyc_index
+  ///     The index pointer (start of the valid data in the cyclic
+  ///     buffer).
+  ///
+  /// \param[in] offset
+  ///     The offset to begin reading the data in the cyclic buffer.
+  static void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
+                               llvm::MutableArrayRef<uint8_t> src,
+                               size_t src_cyc_index, size_t offset);
+
+  /// Return the thread-specific part of the jLLDBTraceGetState packet.
+  TraceThreadState GetState() const;
+};
+
+/// Manages a list of thread traces.
+class IntelPTThreadTraceCollection {
+public:
+  IntelPTThreadTraceCollection(lldb::pid_t pid) : m_pid(pid) {}
+
+  /// Dispose of all traces
+  void Clear();
+
+  bool TracesThread(lldb::tid_t tid) const;
+
+  size_t GetTotalBufferSize() const;
+
+  std::vector<TraceThreadState> GetThreadStates() const;
+
+  llvm::Expected<const IntelPTThreadTrace &>
+  GetTracedThread(lldb::tid_t tid) const;
+
+  llvm::Error TraceStart(lldb::tid_t tid,
+                         const TraceIntelPTStartRequest &request);
+
+  llvm::Error TraceStop(lldb::tid_t tid);
+
+private:
+  lldb::pid_t m_pid;
+  llvm::DenseMap<lldb::tid_t, IntelPTThreadTraceUP> m_thread_traces;
+  /// Total actual thread buffer size in bytes
+  size_t m_total_buffer_size = 0;
+};
+
+/// Manages a "process trace" instance.
+class IntelPTProcessTrace {
+public:
+  IntelPTProcessTrace(lldb::pid_t pid, const TraceIntelPTStartRequest &request)
+      : m_thread_traces(pid), m_tracing_params(request) {}
+
+  bool TracesThread(lldb::tid_t tid) const;
+
+  const IntelPTThreadTraceCollection &GetThreadTraces() const;
+
+  llvm::Error TraceStart(lldb::tid_t tid);
+
+  llvm::Error TraceStop(lldb::tid_t tid);
+
+private:
+  IntelPTThreadTraceCollection m_thread_traces;
+  /// Params used to trace threads when the user started "process tracing".
+  TraceIntelPTStartRequest m_tracing_params;
+};
+
+/// Main class that manages intel-pt process and thread tracing.
+class IntelPTManager {
+public:
+  IntelPTManager(lldb::pid_t pid) : m_pid(pid), m_thread_traces(pid) {}
+
+  static bool IsSupported();
+
+  /// If "process tracing" is enabled, then trace the given thread.
+  llvm::Error OnThreadCreated(lldb::tid_t tid);
+
+  /// Stops tracing a tracing upon a destroy event.
+  llvm::Error OnThreadDestroyed(lldb::tid_t tid);
+
+  /// Implementation of the jLLDBTraceStop packet
+  llvm::Error TraceStop(const TraceStopRequest &request);
+
+  /// Implementation of the jLLDBTraceStart packet
+  ///
+  /// \param[in] process_threads
+  ///     A list of all threads owned by the process.
+  llvm::Error TraceStart(const TraceIntelPTStartRequest &request,
+                         const std::vector<lldb::tid_t> &process_threads);
+
+  /// Implementation of the jLLDBTraceGetState packet
+  llvm::Expected<llvm::json::Value> GetState() const;
+
+  /// Implementation of the jLLDBTraceGetBinaryData packet
+  llvm::Expected<std::vector<uint8_t>>
+  GetBinaryData(const TraceGetBinaryDataRequest &request) const;
+
+  /// Dispose of all traces
+  void Clear();
+
+private:
+  llvm::Error TraceStop(lldb::tid_t tid);
+
+  /// Start tracing a specific thread.
+  llvm::Error TraceStart(lldb::tid_t tid,
+                         const TraceIntelPTStartRequest &request);
+
+  llvm::Expected<const IntelPTThreadTrace &>
+  GetTracedThread(lldb::tid_t tid) const;
+
+  bool IsProcessTracingEnabled() const;
+
+  void ClearProcessTracing();
+
+  lldb::pid_t m_pid;
+  /// Threads traced due to "thread tracing"
+  IntelPTThreadTraceCollection m_thread_traces;
+  /// Threads traced due to "process tracing". Only one active "process tracing"
+  /// instance is assumed for a single process.
+  llvm::Optional<IntelPTProcessTrace> m_process_trace;
+};
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // liblldb_IntelPTManager_H_

diff  --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index aed0d32f23640..5a876ce5befec 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -286,7 +286,8 @@ NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd,
                                        NativeDelegate &delegate,
                                        const ArchSpec &arch, MainLoop &mainloop,
                                        llvm::ArrayRef<::pid_t> tids)
-    : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) {
+    : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
+      m_intel_pt_manager(pid) {
   if (m_terminal_fd != -1) {
     Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
     assert(status.Success());
@@ -298,8 +299,7 @@ NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd,
   assert(m_sigchld_handle && status.Success());
 
   for (const auto &tid : tids) {
-    NativeThreadLinux &thread = AddThread(tid);
-    thread.SetStoppedBySignal(SIGSTOP);
+    NativeThreadLinux &thread = AddThread(tid, /*resume*/ false);
     ThreadWasCreated(thread);
   }
 
@@ -444,10 +444,7 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited,
     LLDB_LOG(log, "tid {0}, si_code: {1}, si_pid: {2}", pid, info.si_code,
              info.si_pid);
 
-    NativeThreadLinux &thread = AddThread(pid);
-
-    // Resume the newly created thread.
-    ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
+    NativeThreadLinux &thread = AddThread(pid, /*resume*/ true);
     ThreadWasCreated(thread);
     return;
   }
@@ -550,9 +547,8 @@ void NativeProcessLinux::WaitForNewThread(::pid_t tid) {
   }
 
   LLDB_LOG(log, "pid = {0}: tracking new thread tid {1}", GetID(), tid);
-  NativeThreadLinux &new_thread = AddThread(tid);
+  NativeThreadLinux &new_thread = AddThread(tid, /*resume*/ true);
 
-  ResumeThread(new_thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
   ThreadWasCreated(new_thread);
 }
 
@@ -954,8 +950,7 @@ Status NativeProcessLinux::Detach() {
           e; // Save the error, but still attempt to detach from other threads.
   }
 
-  m_processor_trace_monitor.clear();
-  m_pt_proces_trace_id = LLDB_INVALID_UID;
+  m_intel_pt_manager.Clear();
 
   return error;
 }
@@ -1511,12 +1506,33 @@ bool NativeProcessLinux::StopTrackingThread(lldb::tid_t thread_id) {
   }
 
   if (found)
-    StopTracingForThread(thread_id);
+    NotifyTracersOfThreadDestroyed(thread_id);
+
   SignalIfAllThreadsStopped();
   return found;
 }
 
-NativeThreadLinux &NativeProcessLinux::AddThread(lldb::tid_t thread_id) {
+Status NativeProcessLinux::NotifyTracersOfNewThread(lldb::tid_t tid) {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+  Status error(m_intel_pt_manager.OnThreadCreated(tid));
+  if (error.Fail())
+    LLDB_LOG(log, "Failed to trace a new thread with intel-pt, tid = {0}. {1}",
+             tid, error.AsCString());
+  return error;
+}
+
+Status NativeProcessLinux::NotifyTracersOfThreadDestroyed(lldb::tid_t tid) {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+  Status error(m_intel_pt_manager.OnThreadDestroyed(tid));
+  if (error.Fail())
+    LLDB_LOG(log,
+             "Failed to stop a destroyed thread with intel-pt, tid = {0}. {1}",
+             tid, error.AsCString());
+  return error;
+}
+
+NativeThreadLinux &NativeProcessLinux::AddThread(lldb::tid_t thread_id,
+                                                 bool resume) {
   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
   LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
 
@@ -1528,22 +1544,19 @@ NativeThreadLinux &NativeProcessLinux::AddThread(lldb::tid_t thread_id) {
     SetCurrentThreadID(thread_id);
 
   m_threads.push_back(std::make_unique<NativeThreadLinux>(*this, thread_id));
+  NativeThreadLinux &thread =
+      static_cast<NativeThreadLinux &>(*m_threads.back());
+
+  Status tracing_error = NotifyTracersOfNewThread(thread.GetID());
+  if (tracing_error.Fail()) {
+    thread.SetStoppedByProcessorTrace(tracing_error.AsCString());
+    StopRunningThreads(thread.GetID());
+  } else if (resume)
+    ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
+  else
+    thread.SetStoppedBySignal(SIGSTOP);
 
-  if (m_pt_proces_trace_id != LLDB_INVALID_UID) {
-    auto traceMonitor = ProcessorTraceMonitor::Create(
-        GetID(), thread_id, m_pt_process_trace_config, true);
-    if (traceMonitor) {
-      m_pt_traced_thread_group.insert(thread_id);
-      m_processor_trace_monitor.insert(
-          std::make_pair(thread_id, std::move(*traceMonitor)));
-    } else {
-      LLDB_LOG(log, "failed to start trace on thread {0}", thread_id);
-      Status error(traceMonitor.takeError());
-      LLDB_LOG(log, "error {0}", error);
-    }
-  }
-
-  return static_cast<NativeThreadLinux &>(*m_threads.back());
+  return thread;
 }
 
 Status NativeProcessLinux::GetLoadedModuleFileSpec(const char *module_path,
@@ -1761,263 +1774,43 @@ Status NativeProcessLinux::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
   return error;
 }
 
-llvm::Expected<ProcessorTraceMonitor &>
-NativeProcessLinux::LookupProcessorTraceInstance(lldb::user_id_t traceid,
-                                                 lldb::tid_t thread) {
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-  if (thread == LLDB_INVALID_THREAD_ID && traceid == m_pt_proces_trace_id) {
-    LLDB_LOG(log, "thread not specified: {0}", traceid);
-    return Status("tracing not active thread not specified").ToError();
-  }
-
-  for (auto& iter : m_processor_trace_monitor) {
-    if (traceid == iter.second->GetTraceID() &&
-        (thread == iter.first || thread == LLDB_INVALID_THREAD_ID))
-      return *(iter.second);
-  }
-
-  LLDB_LOG(log, "traceid not being traced: {0}", traceid);
-  return Status("tracing not active for this thread").ToError();
+llvm::Expected<TraceSupportedResponse> NativeProcessLinux::TraceSupported() {
+  if (IntelPTManager::IsSupported())
+    return TraceSupportedResponse{"intel-pt", "Intel Processor Trace"};
+  return NativeProcessProtocol::TraceSupported();
 }
 
-Status NativeProcessLinux::GetMetaData(lldb::user_id_t traceid,
-                                       lldb::tid_t thread,
-                                       llvm::MutableArrayRef<uint8_t> &buffer,
-                                       size_t offset) {
-  TraceOptions trace_options;
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-  Status error;
-
-  LLDB_LOG(log, "traceid {0}", traceid);
-
-  auto perf_monitor = LookupProcessorTraceInstance(traceid, thread);
-  if (!perf_monitor) {
-    LLDB_LOG(log, "traceid not being traced: {0}", traceid);
-    buffer = buffer.slice(buffer.size());
-    error = perf_monitor.takeError();
-    return error;
-  }
-  return (*perf_monitor).ReadPerfTraceData(buffer, offset);
-}
-
-Status NativeProcessLinux::GetData(lldb::user_id_t traceid, lldb::tid_t thread,
-                                   llvm::MutableArrayRef<uint8_t> &buffer,
-                                   size_t offset) {
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-  Status error;
-
-  LLDB_LOG(log, "traceid {0}", traceid);
-
-  auto perf_monitor = LookupProcessorTraceInstance(traceid, thread);
-  if (!perf_monitor) {
-    LLDB_LOG(log, "traceid not being traced: {0}", traceid);
-    buffer = buffer.slice(buffer.size());
-    error = perf_monitor.takeError();
-    return error;
-  }
-  return (*perf_monitor).ReadPerfTraceAux(buffer, offset);
-}
-
-Status NativeProcessLinux::GetTraceConfig(lldb::user_id_t traceid,
-                                          TraceOptions &config) {
-  Status error;
-  if (config.getThreadID() == LLDB_INVALID_THREAD_ID &&
-      m_pt_proces_trace_id == traceid) {
-    if (m_pt_proces_trace_id == LLDB_INVALID_UID) {
-      error.SetErrorString("tracing not active for this process");
-      return error;
-    }
-    config = m_pt_process_trace_config;
-  } else {
-    auto perf_monitor =
-        LookupProcessorTraceInstance(traceid, config.getThreadID());
-    if (!perf_monitor) {
-      error = perf_monitor.takeError();
-      return error;
-    }
-    error = (*perf_monitor).GetTraceConfig(config);
-  }
-  return error;
-}
-
-llvm::Expected<TraceTypeInfo> NativeProcessLinux::GetSupportedTraceType() {
-  if (ProcessorTraceMonitor::IsSupported())
-    return TraceTypeInfo{"intel-pt", "Intel Processor Trace"};
-  return NativeProcessProtocol::GetSupportedTraceType();
-}
-
-lldb::user_id_t
-NativeProcessLinux::StartTraceGroup(const TraceOptions &config,
-                                           Status &error) {
-
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-  if (config.getType() != TraceType::eTraceTypeProcessorTrace)
-    return LLDB_INVALID_UID;
-
-  if (m_pt_proces_trace_id != LLDB_INVALID_UID) {
-    error.SetErrorString("tracing already active on this process");
-    return m_pt_proces_trace_id;
-  }
-
-  for (const auto &thread_sp : m_threads) {
-    if (auto traceInstance = ProcessorTraceMonitor::Create(
-            GetID(), thread_sp->GetID(), config, true)) {
-      m_pt_traced_thread_group.insert(thread_sp->GetID());
-      m_processor_trace_monitor.insert(
-          std::make_pair(thread_sp->GetID(), std::move(*traceInstance)));
-    }
-  }
-
-  m_pt_process_trace_config = config;
-  error = ProcessorTraceMonitor::GetCPUType(m_pt_process_trace_config);
-
-  // Trace on Complete process will have traceid of 0
-  m_pt_proces_trace_id = 0;
-
-  LLDB_LOG(log, "Process Trace ID {0}", m_pt_proces_trace_id);
-  return m_pt_proces_trace_id;
-}
-
-lldb::user_id_t NativeProcessLinux::StartTrace(const TraceOptions &config,
-                                               Status &error) {
-  if (config.getType() != TraceType::eTraceTypeProcessorTrace)
-    return NativeProcessProtocol::StartTrace(config, error);
-
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-
-  lldb::tid_t threadid = config.getThreadID();
-
-  if (threadid == LLDB_INVALID_THREAD_ID)
-    return StartTraceGroup(config, error);
-
-  auto thread_sp = GetThreadByID(threadid);
-  if (!thread_sp) {
-    // Thread not tracked by lldb so don't trace.
-    error.SetErrorString("invalid thread id");
-    return LLDB_INVALID_UID;
-  }
-
-  const auto &iter = m_processor_trace_monitor.find(threadid);
-  if (iter != m_processor_trace_monitor.end()) {
-    LLDB_LOG(log, "Thread already being traced");
-    error.SetErrorString("tracing already active on this thread");
-    return LLDB_INVALID_UID;
-  }
-
-  auto traceMonitor =
-      ProcessorTraceMonitor::Create(GetID(), threadid, config, false);
-  if (!traceMonitor) {
-    error = traceMonitor.takeError();
-    LLDB_LOG(log, "error {0}", error);
-    return LLDB_INVALID_UID;
-  }
-  lldb::user_id_t ret_trace_id = (*traceMonitor)->GetTraceID();
-  m_processor_trace_monitor.insert(
-      std::make_pair(threadid, std::move(*traceMonitor)));
-  return ret_trace_id;
-}
-
-Status NativeProcessLinux::StopTracingForThread(lldb::tid_t thread) {
-  Status error;
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-  LLDB_LOG(log, "Thread {0}", thread);
-
-  const auto& iter = m_processor_trace_monitor.find(thread);
-  if (iter == m_processor_trace_monitor.end()) {
-    error.SetErrorString("tracing not active for this thread");
-    return error;
-  }
-
-  if (iter->second->GetTraceID() == m_pt_proces_trace_id) {
-    // traceid maps to the whole process so we have to erase it from the thread
-    // group.
-    LLDB_LOG(log, "traceid maps to process");
-    m_pt_traced_thread_group.erase(thread);
+Error NativeProcessLinux::TraceStart(StringRef json_request, StringRef type) {
+  if (type == "intel-pt") {
+    if (Expected<TraceIntelPTStartRequest> request =
+            json::parse<TraceIntelPTStartRequest>(json_request,
+                                                  "TraceIntelPTStartRequest")) {
+      std::vector<lldb::tid_t> process_threads;
+      for (auto &thread : m_threads)
+        process_threads.push_back(thread->GetID());
+      return m_intel_pt_manager.TraceStart(*request, process_threads);
+    } else
+      return request.takeError();
   }
-  m_processor_trace_monitor.erase(iter);
 
-  return error;
+  return NativeProcessProtocol::TraceStart(json_request, type);
 }
 
-Status NativeProcessLinux::StopTrace(lldb::user_id_t traceid,
-                                     lldb::tid_t thread) {
-  Status error;
-
-  TraceOptions trace_options;
-  trace_options.setThreadID(thread);
-  error = NativeProcessLinux::GetTraceConfig(traceid, trace_options);
-
-  if (error.Fail())
-    return error;
-
-  switch (trace_options.getType()) {
-  case lldb::TraceType::eTraceTypeProcessorTrace:
-    if (traceid == m_pt_proces_trace_id &&
-        thread == LLDB_INVALID_THREAD_ID)
-      StopProcessorTracingOnProcess();
-    else
-      error = StopProcessorTracingOnThread(traceid, thread);
-    break;
-  default:
-    error.SetErrorString("trace not supported");
-    break;
-  }
-
-  return error;
+Error NativeProcessLinux::TraceStop(const TraceStopRequest &request) {
+  if (request.type == "intel-pt")
+    return m_intel_pt_manager.TraceStop(request);
+  return NativeProcessProtocol::TraceStop(request);
 }
 
-void NativeProcessLinux::StopProcessorTracingOnProcess() {
-  for (auto thread_id_iter : m_pt_traced_thread_group)
-    m_processor_trace_monitor.erase(thread_id_iter);
-  m_pt_traced_thread_group.clear();
-  m_pt_proces_trace_id = LLDB_INVALID_UID;
+Expected<json::Value> NativeProcessLinux::TraceGetState(StringRef type) {
+  if (type == "intel-pt")
+    return m_intel_pt_manager.GetState();
+  return NativeProcessProtocol::TraceGetState(type);
 }
 
-Status NativeProcessLinux::StopProcessorTracingOnThread(lldb::user_id_t traceid,
-                                                        lldb::tid_t thread) {
-  Status error;
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-
-  if (thread == LLDB_INVALID_THREAD_ID) {
-    for (auto& iter : m_processor_trace_monitor) {
-      if (iter.second->GetTraceID() == traceid) {
-        // Stopping a trace instance for an individual thread hence there will
-        // only be one traceid that can match.
-        m_processor_trace_monitor.erase(iter.first);
-        return error;
-      }
-      LLDB_LOG(log, "Trace ID {0}", iter.second->GetTraceID());
-    }
-
-    LLDB_LOG(log, "Invalid TraceID");
-    error.SetErrorString("invalid trace id");
-    return error;
-  }
-
-  // thread is specified so we can use find function on the map.
-  const auto& iter = m_processor_trace_monitor.find(thread);
-  if (iter == m_processor_trace_monitor.end()) {
-    // thread not found in our map.
-    LLDB_LOG(log, "thread not being traced");
-    error.SetErrorString("tracing not active for this thread");
-    return error;
-  }
-  if (iter->second->GetTraceID() != traceid) {
-    // traceid did not match so it has to be invalid.
-    LLDB_LOG(log, "Invalid TraceID");
-    error.SetErrorString("invalid trace id");
-    return error;
-  }
-
-  LLDB_LOG(log, "UID - {0} , Thread -{1}", traceid, thread);
-
-  if (traceid == m_pt_proces_trace_id) {
-    // traceid maps to the whole process so we have to erase it from the thread
-    // group.
-    LLDB_LOG(log, "traceid maps to process");
-    m_pt_traced_thread_group.erase(thread);
-  }
-  m_processor_trace_monitor.erase(iter);
-
-  return error;
+Expected<std::vector<uint8_t>> NativeProcessLinux::TraceGetBinaryData(
+    const TraceGetBinaryDataRequest &request) {
+  if (request.type == "intel-pt")
+    return m_intel_pt_manager.GetBinaryData(request);
+  return NativeProcessProtocol::TraceGetBinaryData(request);
 }

diff  --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
index 077c62d362342..77905a193c2b7 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -20,10 +20,10 @@
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/lldb-types.h"
 
+#include "IntelPTManager.h"
 #include "NativeThreadLinux.h"
 #include "Plugins/Process/POSIX/NativeProcessELF.h"
 #include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
-#include "ProcessorTrace.h"
 
 namespace lldb_private {
 class Status;
@@ -103,23 +103,22 @@ class NativeProcessLinux : public NativeProcessELF,
     return getProcFile(GetID(), "auxv");
   }
 
-  lldb::user_id_t StartTrace(const TraceOptions &config,
-                             Status &error) override;
+  /// Tracing
+  /// These methods implement the jLLDBTrace packets
+  /// \{
+  llvm::Error TraceStart(llvm::StringRef json_request,
+                         llvm::StringRef type) override;
 
-  Status StopTrace(lldb::user_id_t traceid,
-                   lldb::tid_t thread) override;
+  llvm::Error TraceStop(const TraceStopRequest &request) override;
 
-  Status GetData(lldb::user_id_t traceid, lldb::tid_t thread,
-                 llvm::MutableArrayRef<uint8_t> &buffer,
-                 size_t offset = 0) override;
+  llvm::Expected<llvm::json::Value>
+  TraceGetState(llvm::StringRef type) override;
 
-  Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread,
-                     llvm::MutableArrayRef<uint8_t> &buffer,
-                     size_t offset = 0) override;
+  llvm::Expected<std::vector<uint8_t>>
+  TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override;
 
-  Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) override;
-
-  virtual llvm::Expected<TraceTypeInfo> GetSupportedTraceType() override;
+  llvm::Expected<TraceSupportedResponse> TraceSupported() override;
+  /// }
 
   // Interface used by NativeRegisterContext-derived classes.
   static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
@@ -175,7 +174,28 @@ class NativeProcessLinux : public NativeProcessELF,
 
   bool StopTrackingThread(lldb::tid_t thread_id);
 
-  NativeThreadLinux &AddThread(lldb::tid_t thread_id);
+  /// Create a new thread.
+  ///
+  /// If process tracing is enabled and the thread can't be traced, then the
+  /// thread is left stopped with a \a eStopReasonProcessorTrace status, and
+  /// then the process is stopped.
+  ///
+  /// \param[in] resume
+  ///     If a tracing error didn't happen, then resume the thread after
+  ///     creation if \b true, or leave it stopped with SIGSTOP if \b false.
+  NativeThreadLinux &AddThread(lldb::tid_t thread_id, bool resume);
+
+  /// Start tracing a new thread if process tracing is enabled.
+  ///
+  /// Trace mechanisms should modify this method to provide automatic tracing
+  /// for new threads.
+  Status NotifyTracersOfNewThread(lldb::tid_t tid);
+
+  /// Stop tracing threads upon a destroy event.
+  ///
+  /// Trace mechanisms should modify this method to provide automatic trace
+  /// stopping for threads being destroyed.
+  Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid);
 
   /// Writes a siginfo_t structure corresponding to the given thread ID to the
   /// memory region pointed to by \p siginfo.
@@ -212,42 +232,8 @@ class NativeProcessLinux : public NativeProcessELF,
 
   Status PopulateMemoryRegionCache();
 
-  lldb::user_id_t StartTraceGroup(const TraceOptions &config,
-                                         Status &error);
-
-  // This function is intended to be used to stop tracing
-  // on a thread that exited.
-  Status StopTracingForThread(lldb::tid_t thread);
-
-  // The below function as the name suggests, looks up a ProcessorTrace
-  // instance from the m_processor_trace_monitor map. In the case of
-  // process tracing where the traceid passed would map to the complete
-  // process, it is mandatory to provide a threadid to obtain a trace
-  // instance (since ProcessorTrace is tied to a thread). In the other
-  // scenario that an individual thread is being traced, just the traceid
-  // is sufficient to obtain the actual ProcessorTrace instance.
-  llvm::Expected<ProcessorTraceMonitor &>
-  LookupProcessorTraceInstance(lldb::user_id_t traceid, lldb::tid_t thread);
-
-  // Stops tracing on individual threads being traced. Not intended
-  // to be used to stop tracing on complete process.
-  Status StopProcessorTracingOnThread(lldb::user_id_t traceid,
-                                      lldb::tid_t thread);
-
-  // Intended to stop tracing on complete process.
-  // Should not be used for stopping trace on
-  // individual threads.
-  void StopProcessorTracingOnProcess();
-
-  llvm::DenseMap<lldb::tid_t, ProcessorTraceMonitorUP>
-      m_processor_trace_monitor;
-
-  // Set for tracking threads being traced under
-  // same process user id.
-  llvm::DenseSet<lldb::tid_t> m_pt_traced_thread_group;
-
-  lldb::user_id_t m_pt_proces_trace_id = LLDB_INVALID_UID;
-  TraceOptions m_pt_process_trace_config;
+  /// Manages Intel PT process and thread traces.
+  IntelPTManager m_intel_pt_manager;
 };
 
 } // namespace process_linux

diff  --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
index 5aec98bdeca6a..fcc96e274d224 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -77,6 +77,9 @@ void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info,
   case eStopReasonInstrumentation:
     log.Printf("%s: %s instrumentation", __FUNCTION__, header);
     return;
+  case eStopReasonProcessorTrace:
+    log.Printf("%s: %s processor trace", __FUNCTION__, header);
+    return;
   default:
     log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header,
                static_cast<uint32_t>(stop_info.reason));
@@ -398,6 +401,15 @@ void NativeThreadLinux::SetStoppedWithNoReason() {
   m_stop_info.details.signal.signo = 0;
 }
 
+void NativeThreadLinux::SetStoppedByProcessorTrace(
+    llvm::StringRef description) {
+  SetStopped();
+
+  m_stop_info.reason = StopReason::eStopReasonProcessorTrace;
+  m_stop_info.details.signal.signo = 0;
+  m_stop_description = description.str();
+}
+
 void NativeThreadLinux::SetExited() {
   const StateType new_state = StateType::eStateExited;
   MaybeLogStateChange(new_state);

diff  --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
index 5cf473e89052a..fe42270abed5c 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -14,6 +14,8 @@
 #include "lldb/Host/common/NativeThreadProtocol.h"
 #include "lldb/lldb-private-forward.h"
 
+#include "llvm/ADT/StringRef.h"
+
 #include <csignal>
 #include <map>
 #include <memory>
@@ -85,6 +87,8 @@ class NativeThreadLinux : public NativeThreadProtocol {
 
   void SetStoppedWithNoReason();
 
+  void SetStoppedByProcessorTrace(llvm::StringRef description);
+
   void SetExited();
 
   Status RequestStop();

diff  --git a/lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp b/lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp
deleted file mode 100644
index 1a8aa36b3edd9..0000000000000
--- a/lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp
+++ /dev/null
@@ -1,428 +0,0 @@
-//===-- ProcessorTrace.cpp ------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include <algorithm>
-#include <fstream>
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/MathExtras.h"
-
-#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
-#include "ProcessorTrace.h"
-#include "lldb/Host/linux/Support.h"
-
-#include <sys/ioctl.h>
-#include <sys/syscall.h>
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace process_linux;
-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
-  llvm_unreachable("perf event not supported");
-#else
-  Status error;
-
-  config.setType(lldb::TraceType::eTraceTypeProcessorTrace);
-  config.setMetaDataBufferSize(m_mmap_meta->data_size);
-
-  config.setTraceBufferSize(m_mmap_meta->aux_size);
-
-  error = GetCPUType(config);
-
-  return error;
-#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.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
-  llvm_unreachable("perf event not supported");
-#else
-  Status error;
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-
-  LLDB_LOG(log, "called thread id {0}", tid);
-  uint64_t page_size = getpagesize();
-  uint64_t bufsize = config.getTraceBufferSize();
-  uint64_t metabufsize = config.getMetaDataBufferSize();
-
-  uint64_t numpages = static_cast<uint64_t>(
-      llvm::PowerOf2Floor((bufsize + page_size - 1) / page_size));
-  numpages = std::max<uint64_t>(1, numpages);
-  bufsize = page_size * numpages;
-
-  numpages = static_cast<uint64_t>(
-      llvm::PowerOf2Floor((metabufsize + page_size - 1) / page_size));
-  metabufsize = page_size * numpages;
-
-  perf_event_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.size = sizeof(attr);
-  attr.exclude_kernel = 1;
-  attr.sample_type = PERF_SAMPLE_TIME;
-  attr.sample_id_all = 1;
-  attr.exclude_hv = 1;
-  attr.exclude_idle = 1;
-  attr.mmap = 1;
-
-  Expected<uint32_t> intel_pt_type = GetOSEventType();
-
-  if (!intel_pt_type) {
-    error = intel_pt_type.takeError();
-    return error;
-  }
-
-  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);
-
-  if (error.Fail()) {
-    LLDB_LOG(log, "Status in custom config");
-
-    return error;
-  }
-
-  errno = 0;
-  auto fd =
-      syscall(SYS_perf_event_open, &attr, static_cast<::tid_t>(tid), -1, -1, 0);
-  if (fd == -1) {
-    LLDB_LOG(log, "syscall error {0}", errno);
-    error.SetErrorString("perf event syscall Failed");
-    return error;
-  }
-
-  m_fd = std::unique_ptr<int, file_close>(new int(fd), file_close());
-
-  errno = 0;
-  auto base =
-      mmap(nullptr, (metabufsize + page_size), PROT_WRITE, MAP_SHARED, fd, 0);
-
-  if (base == MAP_FAILED) {
-    LLDB_LOG(log, "mmap base error {0}", errno);
-    error.SetErrorString("Meta buffer allocation failed");
-    return error;
-  }
-
-  m_mmap_meta = std::unique_ptr<perf_event_mmap_page, munmap_delete>(
-      reinterpret_cast<perf_event_mmap_page *>(base),
-      munmap_delete(metabufsize + page_size));
-
-  m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size;
-  m_mmap_meta->aux_size = bufsize;
-
-  errno = 0;
-  auto mmap_aux = mmap(nullptr, bufsize, PROT_READ, MAP_SHARED, fd,
-                       static_cast<long int>(m_mmap_meta->aux_offset));
-
-  if (mmap_aux == MAP_FAILED) {
-    LLDB_LOG(log, "second mmap done {0}", errno);
-    error.SetErrorString("Trace buffer allocation failed");
-    return error;
-  }
-  m_mmap_aux = std::unique_ptr<uint8_t, munmap_delete>(
-      reinterpret_cast<uint8_t *>(mmap_aux), munmap_delete(bufsize));
-  return error;
-#endif
-}
-
-llvm::MutableArrayRef<uint8_t> ProcessorTraceMonitor::GetDataBuffer() {
-#ifndef PERF_ATTR_SIZE_VER5
-  llvm_unreachable("perf event not supported");
-#else
-  return MutableArrayRef<uint8_t>(
-      (reinterpret_cast<uint8_t *>(m_mmap_meta.get()) +
-       m_mmap_meta->data_offset),
-      m_mmap_meta->data_size);
-#endif
-}
-
-llvm::MutableArrayRef<uint8_t> ProcessorTraceMonitor::GetAuxBuffer() {
-#ifndef PERF_ATTR_SIZE_VER5
-  llvm_unreachable("perf event not supported");
-#else
-  return MutableArrayRef<uint8_t>(m_mmap_aux.get(), m_mmap_meta->aux_size);
-#endif
-}
-
-Status ProcessorTraceMonitor::GetCPUType(TraceOptions &config) {
-
-  Status error;
-  uint64_t cpu_family = -1;
-  uint64_t model = -1;
-  uint64_t stepping = -1;
-  std::string vendor_id;
-
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-
-  auto BufferOrError = getProcFile("cpuinfo");
-  if (!BufferOrError)
-    return BufferOrError.getError();
-
-  LLDB_LOG(log, "GetCPUType Function");
-
-  StringRef Rest = BufferOrError.get()->getBuffer();
-  while (!Rest.empty()) {
-    StringRef Line;
-    std::tie(Line, Rest) = Rest.split('\n');
-
-    SmallVector<StringRef, 2> columns;
-    Line.split(columns, StringRef(":"), -1, false);
-
-    if (columns.size() < 2)
-      continue; // continue searching
-
-    columns[1] = columns[1].trim(" ");
-    if (columns[0].contains("cpu family") &&
-        columns[1].getAsInteger(10, cpu_family))
-      continue;
-
-    else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
-      continue;
-
-    else if (columns[0].contains("stepping") &&
-             columns[1].getAsInteger(10, stepping))
-      continue;
-
-    else if (columns[0].contains("vendor_id")) {
-      vendor_id = columns[1].str();
-      if (!vendor_id.empty())
-        continue;
-    }
-    LLDB_LOG(log, "{0}:{1}:{2}:{3}", cpu_family, model, stepping, vendor_id);
-
-    if ((cpu_family != static_cast<uint64_t>(-1)) &&
-        (model != static_cast<uint64_t>(-1)) &&
-        (stepping != static_cast<uint64_t>(-1)) && (!vendor_id.empty())) {
-      auto params_dict = std::make_shared<StructuredData::Dictionary>();
-      params_dict->AddIntegerItem("cpu_family", cpu_family);
-      params_dict->AddIntegerItem("cpu_model", model);
-      params_dict->AddIntegerItem("cpu_stepping", stepping);
-      params_dict->AddStringItem("cpu_vendor", vendor_id);
-
-      llvm::StringRef intel_custom_params_key("intel-pt");
-
-      auto intel_custom_params = std::make_shared<StructuredData::Dictionary>();
-      intel_custom_params->AddItem(
-          intel_custom_params_key,
-          StructuredData::ObjectSP(std::move(params_dict)));
-
-      config.setTraceParams(intel_custom_params);
-      return error; // we are done
-    }
-  }
-
-  error.SetErrorString("cpu info not found");
-  return error;
-}
-
-llvm::Expected<ProcessorTraceMonitorUP>
-ProcessorTraceMonitor::Create(lldb::pid_t pid, lldb::tid_t tid,
-                              const TraceOptions &config,
-                              bool useProcessSettings) {
-
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-
-  Status error;
-  if (tid == LLDB_INVALID_THREAD_ID) {
-    error.SetErrorString("thread not specified");
-    return error.ToError();
-  }
-
-  ProcessorTraceMonitorUP pt_monitor_up(new ProcessorTraceMonitor);
-
-  error = pt_monitor_up->StartTrace(pid, tid, config);
-  if (error.Fail())
-    return error.ToError();
-
-  pt_monitor_up->SetThreadID(tid);
-
-  if (useProcessSettings) {
-    pt_monitor_up->SetTraceID(0);
-  } else {
-    pt_monitor_up->SetTraceID(m_trace_num++);
-    LLDB_LOG(log, "Trace ID {0}", m_trace_num);
-  }
-  return std::move(pt_monitor_up);
-}
-
-Status
-ProcessorTraceMonitor::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
-                                        size_t offset) {
-#ifndef PERF_ATTR_SIZE_VER5
-  llvm_unreachable("perf event not supported");
-#else
-  // Disable the perf event to force a flush out of the CPU's internal buffer.
-  // Besides, we can guarantee that the CPU won't override any data as we are
-  // reading the buffer.
-  //
-  // The Intel documentation says:
-  //
-  // Packets are first buffered internally and then written out asynchronously.
-  // To collect packet output for postprocessing, a collector needs first to
-  // ensure that all packet data has been flushed from internal buffers.
-  // Software can ensure this by stopping packet generation by clearing
-  // IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in
-  // Section 35.2.7.2).
-  //
-  // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned
-  // in the man page of perf_event_open.
-  ioctl(*m_fd, PERF_EVENT_IOC_DISABLE);
-
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-  Status error;
-  uint64_t head = m_mmap_meta->aux_head;
-
-  LLDB_LOG(log, "Aux size -{0} , Head - {1}", m_mmap_meta->aux_size, head);
-
-  /**
-   * When configured as ring buffer, the aux buffer keeps wrapping around
-   * the buffer and its not possible to detect how many times the buffer
-   * wrapped. Initially the buffer is filled with zeros,as shown below
-   * so in order to get complete buffer we first copy firstpartsize, followed
-   * by any left over part from beginning to aux_head
-   *
-   * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size
-   *                 aux_head->||<- firstpartsize  ->|
-   *
-   * */
-
-  ReadCyclicBuffer(buffer, GetAuxBuffer(), static_cast<size_t>(head), offset);
-  LLDB_LOG(log, "ReadCyclic BUffer Done");
-
-  // Reenable tracing now we have read the buffer
-  ioctl(*m_fd, PERF_EVENT_IOC_ENABLE);
-  return error;
-#endif
-}
-
-Status
-ProcessorTraceMonitor::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
-                                         size_t offset) {
-#ifndef PERF_ATTR_SIZE_VER5
-  llvm_unreachable("perf event not supported");
-#else
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-  uint64_t bytes_remaining = buffer.size();
-  Status error;
-
-  uint64_t head = m_mmap_meta->data_head;
-
-  /*
-   * The data buffer and aux buffer have 
diff erent implementations
-   * with respect to their definition of head pointer. In the case
-   * of Aux data buffer the head always wraps around the aux buffer
-   * and we don't need to care about it, whereas the data_head keeps
-   * increasing and needs to be wrapped by modulus operator
-   */
-
-  LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining);
-
-  auto data_buffer = GetDataBuffer();
-
-  if (head > data_buffer.size()) {
-    head = head % data_buffer.size();
-    LLDB_LOG(log, "Data size -{0} Head - {1}", m_mmap_meta->data_size, head);
-
-    ReadCyclicBuffer(buffer, data_buffer, static_cast<size_t>(head), offset);
-    bytes_remaining -= buffer.size();
-  } else {
-    LLDB_LOG(log, "Head - {0}", head);
-    if (offset >= head) {
-      LLDB_LOG(log, "Invalid Offset ");
-      error.SetErrorString("invalid offset");
-      buffer = buffer.slice(buffer.size());
-      return error;
-    }
-
-    auto data = data_buffer.slice(offset, (head - offset));
-    auto remaining = std::copy(data.begin(), data.end(), buffer.begin());
-    bytes_remaining -= (remaining - buffer.begin());
-  }
-  buffer = buffer.drop_back(bytes_remaining);
-  return error;
-#endif
-}
-
-void ProcessorTraceMonitor::ReadCyclicBuffer(
-    llvm::MutableArrayRef<uint8_t> &dst, llvm::MutableArrayRef<uint8_t> src,
-    size_t src_cyc_index, size_t offset) {
-
-  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-
-  if (dst.empty() || src.empty()) {
-    dst = dst.drop_back(dst.size());
-    return;
-  }
-
-  if (dst.data() == nullptr || src.data() == nullptr) {
-    dst = dst.drop_back(dst.size());
-    return;
-  }
-
-  if (src_cyc_index > src.size()) {
-    dst = dst.drop_back(dst.size());
-    return;
-  }
-
-  if (offset >= src.size()) {
-    LLDB_LOG(log, "Too Big offset ");
-    dst = dst.drop_back(dst.size());
-    return;
-  }
-
-  llvm::SmallVector<MutableArrayRef<uint8_t>, 2> parts = {
-      src.slice(src_cyc_index), src.take_front(src_cyc_index)};
-
-  if (offset > parts[0].size()) {
-    parts[1] = parts[1].slice(offset - parts[0].size());
-    parts[0] = parts[0].drop_back(parts[0].size());
-  } else if (offset == parts[0].size()) {
-    parts[0] = parts[0].drop_back(parts[0].size());
-  } else {
-    parts[0] = parts[0].slice(offset);
-  }
-  auto next = dst.begin();
-  auto bytes_left = dst.size();
-  for (auto part : parts) {
-    size_t chunk_size = std::min(part.size(), bytes_left);
-    next = std::copy_n(part.begin(), chunk_size, next);
-    bytes_left -= chunk_size;
-  }
-  dst = dst.drop_back(bytes_left);
-}

diff  --git a/lldb/source/Plugins/Process/Linux/ProcessorTrace.h b/lldb/source/Plugins/Process/Linux/ProcessorTrace.h
deleted file mode 100644
index 29f98cc5be658..0000000000000
--- a/lldb/source/Plugins/Process/Linux/ProcessorTrace.h
+++ /dev/null
@@ -1,140 +0,0 @@
-//===-- ProcessorTrace.h -------------------------------------- -*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_ProcessorTrace_H_
-#define liblldb_ProcessorTrace_H_
-
-#include "lldb/Utility/Status.h"
-#include "lldb/Utility/TraceOptions.h"
-#include "lldb/lldb-types.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
-
-#include <linux/perf_event.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-namespace lldb_private {
-
-namespace process_linux {
-
-// This class keeps track of one tracing instance of
-// Intel(R) Processor Trace on Linux OS. There is a map keeping track
-// of 
diff erent tracing instances on each thread, which enables trace
-// gathering on a per thread level.
-//
-// The tracing instance is linked with a trace id. The trace id acts like
-// a key to the tracing instance and trace manipulations could be
-// performed using the trace id.
-//
-// The trace id could map to trace instances for a group of threads
-// (spanning to all the threads in the process) or a single thread.
-// The kernel interface for us is the perf_event_open.
-
-class ProcessorTraceMonitor;
-typedef std::unique_ptr<ProcessorTraceMonitor> ProcessorTraceMonitorUP;
-
-class ProcessorTraceMonitor {
-
-  class munmap_delete {
-    size_t m_length;
-
-  public:
-    munmap_delete(size_t length) : m_length(length) {}
-    void operator()(void *ptr) {
-      if (m_length)
-        munmap(ptr, m_length);
-    }
-  };
-
-  class file_close {
-
-  public:
-    file_close() = default;
-    void operator()(int *ptr) {
-      if (ptr == nullptr)
-        return;
-      if (*ptr == -1)
-        return;
-      close(*ptr);
-      std::default_delete<int>()(ptr);
-    }
-  };
-
-  std::unique_ptr<perf_event_mmap_page, munmap_delete> m_mmap_meta;
-  std::unique_ptr<uint8_t, munmap_delete> m_mmap_aux;
-  std::unique_ptr<int, file_close> m_fd;
-
-  // perf_event_mmap_page *m_mmap_base;
-  lldb::user_id_t m_traceid;
-  lldb::tid_t m_thread_id;
-
-  // Counter to track trace instances.
-  static lldb::user_id_t m_trace_num;
-
-  void SetTraceID(lldb::user_id_t traceid) { m_traceid = traceid; }
-
-  Status StartTrace(lldb::pid_t pid, lldb::tid_t tid,
-                    const TraceOptions &config);
-
-  llvm::MutableArrayRef<uint8_t> GetAuxBuffer();
-  llvm::MutableArrayRef<uint8_t> GetDataBuffer();
-
-  ProcessorTraceMonitor()
-      : m_mmap_meta(nullptr, munmap_delete(0)),
-        m_mmap_aux(nullptr, munmap_delete(0)), m_fd(nullptr, file_close()),
-        m_traceid(LLDB_INVALID_UID), m_thread_id(LLDB_INVALID_THREAD_ID){};
-
-  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>
-  Create(lldb::pid_t pid, lldb::tid_t tid, const TraceOptions &config,
-         bool useProcessSettings);
-
-  Status ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
-                          size_t offset = 0);
-
-  Status ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
-                           size_t offset = 0);
-
-  ~ProcessorTraceMonitor() = default;
-
-  lldb::tid_t GetThreadID() const { return m_thread_id; }
-
-  lldb::user_id_t GetTraceID() const { return m_traceid; }
-
-  Status GetTraceConfig(TraceOptions &config) const;
-
-  /// Read data from a cyclic buffer
-  ///
-  /// \param[in] [out] buf
-  ///     Destination buffer, the buffer will be truncated to written size.
-  ///
-  /// \param[in] src
-  ///     Source buffer which must be a cyclic buffer.
-  ///
-  /// \param[in] src_cyc_index
-  ///     The index pointer (start of the valid data in the cyclic
-  ///     buffer).
-  ///
-  /// \param[in] offset
-  ///     The offset to begin reading the data in the cyclic buffer.
-  static void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
-                               llvm::MutableArrayRef<uint8_t> src,
-                               size_t src_cyc_index, size_t offset);
-};
-} // namespace process_linux
-} // namespace lldb_private
-#endif

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 9218f8a63c01e..22e05c04b3a08 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -3372,110 +3372,78 @@ bool GDBRemoteCommunicationClient::SyncThreadState(lldb::tid_t tid) {
          response.IsOKResponse();
 }
 
-lldb::user_id_t
-GDBRemoteCommunicationClient::SendStartTracePacket(const TraceOptions &options,
-                                                   Status &error) {
+llvm::Expected<TraceSupportedResponse>
+GDBRemoteCommunicationClient::SendTraceSupported() {
   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());
+  escaped_packet.PutCString("jLLDBTraceSupported");
 
   StringExtractorGDBRemote response;
   if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
                                    true) ==
       GDBRemoteCommunication::PacketResult::Success) {
-    if (!response.IsNormalResponse()) {
-      error = response.GetStatus();
-      LLDB_LOG(log, "Target does not support Tracing , error {0}", error);
-    } 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());
+    if (response.IsErrorResponse())
+      return response.GetStatus().ToError();
+    if (response.IsUnsupportedResponse())
+      return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                     "jLLDBTraceSupported is unsupported");
+
+    return llvm::json::parse<TraceSupportedResponse>(response.Peek(),
+                                                     "TraceSupportedResponse");
   }
-  return ret_uid;
+  LLDB_LOG(log, "failed to send packet: jLLDBTraceSupported");
+  return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                 "failed to send packet: jLLDBTraceSupported");
 }
 
-Status
-GDBRemoteCommunicationClient::SendStopTracePacket(lldb::user_id_t uid,
-                                                  lldb::tid_t thread_id) {
+llvm::Error
+GDBRemoteCommunicationClient::SendTraceStop(const TraceStopRequest &request) {
   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);
+  escaped_packet.PutCString("jLLDBTraceStop:");
 
-  if (thread_id != LLDB_INVALID_THREAD_ID)
-    json_packet.AddIntegerItem("threadid", thread_id);
+  std::string json_string;
+  llvm::raw_string_ostream os(json_string);
+  os << toJSON(request);
+  os.flush();
 
-  json_packet.Dump(json_string, false);
-
-  escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+  escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size());
 
+  StringExtractorGDBRemote response;
   if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
                                    true) ==
       GDBRemoteCommunication::PacketResult::Success) {
-    if (!response.IsOKResponse()) {
-      error = response.GetStatus();
-      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());
+    if (response.IsErrorResponse())
+      return response.GetStatus().ToError();
+    if (response.IsUnsupportedResponse())
+      return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                     "jLLDBTraceStop is unsupported");
+    if (response.IsOKResponse())
+      return llvm::Error::success();
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Invalid jLLDBTraceStart response");
   }
-  return error;
+  LLDB_LOG(log, "failed to send packet: jLLDBTraceStop");
+  return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                 "failed to send packet: jLLDBTraceStop '%s'",
+                                 escaped_packet.GetData());
 }
 
-Status GDBRemoteCommunicationClient::SendGetDataPacket(
-    lldb::user_id_t uid, lldb::tid_t thread_id,
-    llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+llvm::Error
+GDBRemoteCommunicationClient::SendTraceStart(const llvm::json::Value &params) {
+  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
 
   StreamGDBRemote escaped_packet;
-  escaped_packet.PutCString("jTraceBufferRead:");
-  return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
-}
+  escaped_packet.PutCString("jLLDBTraceStart:");
 
-Status GDBRemoteCommunicationClient::SendGetMetaDataPacket(
-    lldb::user_id_t uid, lldb::tid_t thread_id,
-    llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+  std::string json_string;
+  llvm::raw_string_ostream os(json_string);
+  os << params;
+  os.flush();
 
-  StreamGDBRemote escaped_packet;
-  escaped_packet.PutCString("jTraceMetaRead:");
-  return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
-}
-
-llvm::Expected<TraceTypeInfo>
-GDBRemoteCommunicationClient::SendGetSupportedTraceType() {
-  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
-
-  StreamGDBRemote escaped_packet;
-  escaped_packet.PutCString("jLLDBTraceSupportedType");
+  escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size());
 
   StringExtractorGDBRemote response;
   if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
@@ -3485,127 +3453,84 @@ GDBRemoteCommunicationClient::SendGetSupportedTraceType() {
       return response.GetStatus().ToError();
     if (response.IsUnsupportedResponse())
       return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                     "jLLDBTraceSupportedType is unsupported");
-
-    if (llvm::Expected<TraceTypeInfo> type =
-            llvm::json::parse<TraceTypeInfo>(response.Peek()))
-      return *type;
-    else
-      return type.takeError();
+                                     "jLLDBTraceStart is unsupported");
+    if (response.IsOKResponse())
+      return llvm::Error::success();
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Invalid jLLDBTraceStart response");
   }
-  LLDB_LOG(log, "failed to send packet: jLLDBTraceSupportedType");
-  return llvm::createStringError(
-      llvm::inconvertibleErrorCode(),
-      "failed to send packet: jLLDBTraceSupportedType");
+  LLDB_LOG(log, "failed to send packet: jLLDBTraceStart");
+  return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                 "failed to send packet: jLLDBTraceStart '%s'",
+                                 escaped_packet.GetData());
 }
 
-Status
-GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid,
-                                                       TraceOptions &options) {
+llvm::Expected<std::string>
+GDBRemoteCommunicationClient::SendTraceGetState(llvm::StringRef type) {
   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
-  StringExtractorGDBRemote response;
-  Status error;
 
-  StreamString json_string;
   StreamGDBRemote escaped_packet;
-  escaped_packet.PutCString("jTraceConfigRead:");
+  escaped_packet.PutCString("jLLDBTraceGetState:");
 
-  StructuredData::Dictionary json_packet;
-  json_packet.AddIntegerItem("traceid", uid);
+  std::string json_string;
+  llvm::raw_string_ostream os(json_string);
+  os << toJSON(TraceGetStateRequest{type.str()});
+  os.flush();
 
-  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());
+  escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size());
 
+  StringExtractorGDBRemote response;
   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() != lldb::eStructuredDataTypeDictionary) {
-        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() !=
-            lldb::eStructuredDataTypeDictionary) {
-          error.SetErrorString("Invalid Configuration obtained");
-          return error;
-        } else
-          options.setTraceParams(
-              std::static_pointer_cast<StructuredData::Dictionary>(
-                  custom_params_sp));
-      }
-    } else {
-      error = response.GetStatus();
-    }
-  } else {
-    LLDB_LOG(log, "failed to send packet");
-    error.SetErrorStringWithFormat("failed to send packet: '%s'",
-                                   escaped_packet.GetData());
+    if (response.IsErrorResponse())
+      return response.GetStatus().ToError();
+    if (response.IsUnsupportedResponse())
+      return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                     "jLLDBTraceGetState is unsupported");
+    return std::string(response.Peek());
   }
-  return error;
+
+  LLDB_LOG(log, "failed to send packet: jLLDBTraceGetState");
+  return llvm::createStringError(
+      llvm::inconvertibleErrorCode(),
+      "failed to send packet: jLLDBTraceGetState '%s'",
+      escaped_packet.GetData());
 }
 
-Status GDBRemoteCommunicationClient::SendGetTraceDataPacket(
-    StreamGDBRemote &packet, lldb::user_id_t uid, lldb::tid_t thread_id,
-    llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+llvm::Expected<std::vector<uint8_t>>
+GDBRemoteCommunicationClient::SendTraceGetBinaryData(
+    const TraceGetBinaryDataRequest &request) {
   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());
+  StreamGDBRemote escaped_packet;
+  escaped_packet.PutCString("jLLDBTraceGetBinaryData:");
 
-  if (thread_id != LLDB_INVALID_THREAD_ID)
-    json_packet.AddIntegerItem("threadid", thread_id);
+  std::string json_string;
+  llvm::raw_string_ostream os(json_string);
+  os << toJSON(request);
+  os.flush();
 
-  StreamString json_string;
-  json_packet.Dump(json_string, false);
+  escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size());
 
-  packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
   StringExtractorGDBRemote response;
-  if (SendPacketAndWaitForResponse(packet.GetString(), response, true) ==
+  if (SendPacketAndWaitForResponse(escaped_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 = response.GetStatus();
-      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());
+    if (response.IsErrorResponse())
+      return response.GetStatus().ToError();
+    if (response.IsUnsupportedResponse())
+      return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                     "jLLDBTraceGetBinaryData is unsupported");
+    std::string data;
+    response.GetEscapedBinaryData(data);
+    return std::vector<uint8_t>(data.begin(), data.end());
   }
-  return error;
+  LLDB_LOG(log, "failed to send packet: jLLDBTraceGetBinaryData");
+  return llvm::createStringError(
+      llvm::inconvertibleErrorCode(),
+      "failed to send packet: jLLDBTraceGetBinaryData '%s'",
+      escaped_packet.GetData());
 }
 
 llvm::Optional<QOffsets> GDBRemoteCommunicationClient::GetQOffsets() {

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 3eab71388067a..aaa6f7890fb14 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -22,7 +22,7 @@
 #include "lldb/Utility/GDBRemote.h"
 #include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/StructuredData.h"
-#include "lldb/Utility/TraceOptions.h"
+#include "lldb/Utility/TraceGDBRemotePackets.h"
 #if defined(_WIN32)
 #include "lldb/Host/windows/PosixApi.h"
 #endif
@@ -505,22 +505,16 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
   ConfigureRemoteStructuredData(ConstString type_name,
                                 const StructuredData::ObjectSP &config_sp);
 
-  lldb::user_id_t SendStartTracePacket(const TraceOptions &options,
-                                       Status &error);
+  llvm::Expected<TraceSupportedResponse> SendTraceSupported();
 
-  Status SendStopTracePacket(lldb::user_id_t uid, lldb::tid_t thread_id);
+  llvm::Error SendTraceStart(const llvm::json::Value &request);
 
-  Status SendGetDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id,
-                           llvm::MutableArrayRef<uint8_t> &buffer,
-                           size_t offset = 0);
+  llvm::Error SendTraceStop(const TraceStopRequest &request);
 
-  Status SendGetMetaDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id,
-                               llvm::MutableArrayRef<uint8_t> &buffer,
-                               size_t offset = 0);
+  llvm::Expected<std::string> SendTraceGetState(llvm::StringRef type);
 
-  Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options);
-
-  llvm::Expected<TraceTypeInfo> SendGetSupportedTraceType();
+  llvm::Expected<std::vector<uint8_t>>
+  SendTraceGetBinaryData(const TraceGetBinaryDataRequest &request);
 
 protected:
   LazyBool m_supports_not_sending_acks;

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index 60548efc0f33f..2996717dae6a0 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -16,11 +16,13 @@
 #include "lldb/Utility/StreamString.h"
 #include "lldb/Utility/StringExtractorGDBRemote.h"
 #include "lldb/Utility/UnimplementedError.h"
+#include "llvm/Support/JSON.h"
 #include <cstring>
 
 using namespace lldb;
 using namespace lldb_private;
 using namespace lldb_private::process_gdb_remote;
+using namespace llvm;
 
 GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(
     const char *comm_name, const char *listener_name)
@@ -151,3 +153,21 @@ GDBRemoteCommunicationServer::SendOKResponse() {
 bool GDBRemoteCommunicationServer::HandshakeWithClient() {
   return GetAck() == PacketResult::Success;
 }
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendJSONResponse(const json::Value &value) {
+  std::string json_string;
+  raw_string_ostream os(json_string);
+  os << value;
+  os.flush();
+  StreamGDBRemote escaped_response;
+  escaped_response.PutEscapedBytes(json_string.c_str(), json_string.size());
+  return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendJSONResponse(Expected<json::Value> value) {
+  if (!value)
+    return SendErrorResponse(value.takeError());
+  return SendJSONResponse(*value);
+}

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index a1cf70f9cd1ab..68448eae2b9f8 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -72,6 +72,13 @@ class GDBRemoteCommunicationServer : public GDBRemoteCommunication {
 
   PacketResult SendOKResponse();
 
+  /// Serialize and send a JSON object response.
+  PacketResult SendJSONResponse(const llvm::json::Value &value);
+
+  /// Serialize and send a JSON object response, or respond with an error if the
+  /// input object is an \a llvm::Error.
+  PacketResult SendJSONResponse(llvm::Expected<llvm::json::Value> value);
+
 private:
   GDBRemoteCommunicationServer(const GDBRemoteCommunicationServer &) = delete;
   const GDBRemoteCommunicationServer &

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index b665610a54a5f..2f615866a2f43 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -186,23 +186,20 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
       &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
 
   RegisterMemberFunctionHandler(
-      StringExtractorGDBRemote::eServerPacketType_jTraceStart,
-      &GDBRemoteCommunicationServerLLGS::Handle_jTraceStart);
+      StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupported,
+      &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported);
   RegisterMemberFunctionHandler(
-      StringExtractorGDBRemote::eServerPacketType_jTraceBufferRead,
-      &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead);
+      StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStart,
+      &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart);
   RegisterMemberFunctionHandler(
-      StringExtractorGDBRemote::eServerPacketType_jTraceMetaRead,
-      &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead);
+      StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStop,
+      &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop);
   RegisterMemberFunctionHandler(
-      StringExtractorGDBRemote::eServerPacketType_jTraceStop,
-      &GDBRemoteCommunicationServerLLGS::Handle_jTraceStop);
+      StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetState,
+      &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState);
   RegisterMemberFunctionHandler(
-      StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
-      &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead);
-  RegisterMemberFunctionHandler(
-      StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupportedType,
-      &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType);
+      StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetBinaryData,
+      &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData);
 
   RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
                                 &GDBRemoteCommunicationServerLLGS::Handle_g);
@@ -648,6 +645,8 @@ static const char *GetStopReasonString(StopReason stop_reason) {
     return "exception";
   case eStopReasonExec:
     return "exec";
+  case eStopReasonProcessorTrace:
+    return "processor trace";
   case eStopReasonInstrumentation:
   case eStopReasonInvalid:
   case eStopReasonPlanComplete:
@@ -1170,108 +1169,39 @@ void GDBRemoteCommunicationServerLLGS::SendProcessOutput() {
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServerLLGS::Handle_jTraceStart(
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported(
     StringExtractorGDBRemote &packet) {
-  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
   // 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);
-
-  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() != lldb::eStructuredDataTypeDictionary)
-    return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
-
-  auto json_dict = json_object->GetAsDictionary();
-
-  json_dict->GetValueForKeyAsInteger("metabuffersize", metabuffersize);
-  options.setMetaDataBufferSize(metabuffersize);
-
-  json_dict->GetValueForKeyAsInteger("buffersize", buffersize);
-  options.setTraceBufferSize(buffersize);
-
-  json_dict->GetValueForKeyAsInteger("type", type);
-  options.setType(static_cast<lldb::TraceType>(type));
-
-  json_dict->GetValueForKeyAsInteger("threadid", tid);
-  options.setThreadID(tid);
-
-  StructuredData::ObjectSP custom_params_sp =
-      json_dict->GetValueForKey("params");
-  if (custom_params_sp &&
-      custom_params_sp->GetType() != lldb::eStructuredDataTypeDictionary)
-    return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
-
-  options.setTraceParams(
-      std::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_up->StartTrace(options, error);
-  LLDB_LOG(log, "uid is {0} , error is {1}", uid, error.GetError());
-  if (error.Fail())
-    return SendErrorResponse(error);
+    return SendErrorResponse(Status("Process not running."));
 
-  StreamGDBRemote response;
-  response.Printf("%" PRIx64, uid);
-  return SendPacketNoLock(response.GetString());
+  return SendJSONResponse(m_debugged_process_up->TraceSupported());
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServerLLGS::Handle_jTraceStop(
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop(
     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);
-
-  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() != lldb::eStructuredDataTypeDictionary)
-    return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
-
-  auto json_dict = json_object->GetAsDictionary();
-
-  if (!json_dict->GetValueForKeyAsInteger("traceid", uid))
-    return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
-
-  json_dict->GetValueForKeyAsInteger("threadid", tid);
+    return SendErrorResponse(Status("Process not running."));
 
-  Status error = m_debugged_process_up->StopTrace(uid, tid);
+  packet.ConsumeFront("jLLDBTraceStop:");
+  Expected<TraceStopRequest> stop_request =
+      json::parse<TraceStopRequest>(packet.Peek(), "TraceStopRequest");
+  if (!stop_request)
+    return SendErrorResponse(stop_request.takeError());
 
-  if (error.Fail())
-    return SendErrorResponse(error);
+  if (Error err = m_debugged_process_up->TraceStop(*stop_request))
+    return SendErrorResponse(std::move(err));
 
   return SendOKResponse();
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType(
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart(
     StringExtractorGDBRemote &packet) {
 
   // Fail if we don't have a current process.
@@ -1279,146 +1209,60 @@ GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType(
       (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
     return SendErrorResponse(Status("Process not running."));
 
-  llvm::Expected<TraceTypeInfo> supported_trace_type =
-      m_debugged_process_up->GetSupportedTraceType();
-  if (!supported_trace_type)
-    return SendErrorResponse(supported_trace_type.takeError());
-
-  StreamGDBRemote escaped_response;
-  StructuredData::Dictionary json_packet;
+  packet.ConsumeFront("jLLDBTraceStart:");
+  Expected<TraceStartRequest> request =
+      json::parse<TraceStartRequest>(packet.Peek(), "TraceStartRequest");
+  if (!request)
+    return SendErrorResponse(request.takeError());
 
-  json_packet.AddStringItem("name", supported_trace_type->name);
-  json_packet.AddStringItem("description", supported_trace_type->description);
+  if (Error err =
+          m_debugged_process_up->TraceStart(packet.Peek(), request->type))
+    return SendErrorResponse(std::move(err));
 
-  StreamString json_string;
-  json_packet.Dump(json_string, false);
-  escaped_response.PutEscapedBytes(json_string.GetData(),
-                                   json_string.GetSize());
-  return SendPacketNoLock(escaped_response.GetString());
+  return SendOKResponse();
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead(
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState(
     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);
-
-  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() != lldb::eStructuredDataTypeDictionary)
-    return SendIllFormedResponse(packet,
-                                 "jTraceConfigRead: Ill formed packet ");
-
-  auto json_dict = json_object->GetAsDictionary();
-
-  if (!json_dict->GetValueForKeyAsInteger("traceid", uid))
-    return SendIllFormedResponse(packet,
-                                 "jTraceConfigRead: Ill formed packet ");
-
-  json_dict->GetValueForKeyAsInteger("threadid", threadid);
-
-  TraceOptions options;
-  StreamGDBRemote response;
-
-  options.setThreadID(threadid);
-  Status error = m_debugged_process_up->GetTraceConfig(uid, options);
-
-  if (error.Fail())
-    return SendErrorResponse(error);
-
-  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());
+    return SendErrorResponse(Status("Process not running."));
 
-  StructuredData::DictionarySP custom_params = options.getTraceParams();
-  if (custom_params)
-    json_packet.AddItem("params", custom_params);
+  packet.ConsumeFront("jLLDBTraceGetState:");
+  Expected<TraceGetStateRequest> request =
+      json::parse<TraceGetStateRequest>(packet.Peek(), "TraceGetStateRequest");
+  if (!request)
+    return SendErrorResponse(request.takeError());
 
-  StreamString json_string;
-  json_packet.Dump(json_string, false);
-  escaped_response.PutEscapedBytes(json_string.GetData(),
-                                   json_string.GetSize());
-  return SendPacketNoLock(escaped_response.GetString());
+  return SendJSONResponse(m_debugged_process_up->TraceGetState(request->type));
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServerLLGS::Handle_jTraceRead(
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData(
     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);
-
-  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;
-
-  uint64_t byte_count = std::numeric_limits<uint64_t>::max();
-  lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
-  uint64_t offset = std::numeric_limits<uint64_t>::max();
-
-  auto json_object = StructuredData::ParseJSON(packet.Peek());
-
-  if (!json_object ||
-      json_object->GetType() != lldb::eStructuredDataTypeDictionary)
-    return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
-
-  auto json_dict = json_object->GetAsDictionary();
-
-  if (!json_dict->GetValueForKeyAsInteger("traceid", uid) ||
-      !json_dict->GetValueForKeyAsInteger("offset", offset) ||
-      !json_dict->GetValueForKeyAsInteger("buffersize", byte_count))
-    return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
-
-  json_dict->GetValueForKeyAsInteger("threadid", tid);
-
-  // Allocate the response buffer.
-  std::unique_ptr<uint8_t[]> buffer (new (std::nothrow) uint8_t[byte_count]);
-  if (!buffer)
-    return SendErrorResponse(0x78);
-
-  StreamGDBRemote response;
-  Status error;
-  llvm::MutableArrayRef<uint8_t> buf(buffer.get(), byte_count);
-
-  if (tracetype == BufferData)
-    error = m_debugged_process_up->GetData(uid, tid, buf, offset);
-  else if (tracetype == MetaData)
-    error = m_debugged_process_up->GetMetaData(uid, tid, buf, offset);
-
-  if (error.Fail())
-    return SendErrorResponse(error);
+    return SendErrorResponse(Status("Process not running."));
 
-  for (auto i : buf)
-    response.PutHex8(i);
+  packet.ConsumeFront("jLLDBTraceGetBinaryData:");
+  llvm::Expected<TraceGetBinaryDataRequest> request =
+      llvm::json::parse<TraceGetBinaryDataRequest>(packet.Peek(),
+                                                   "TraceGetBinaryDataRequest");
+  if (!request)
+    return SendErrorResponse(Status(request.takeError()));
 
-  StreamGDBRemote escaped_response;
-  escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
-  return SendPacketNoLock(escaped_response.GetString());
+  if (Expected<std::vector<uint8_t>> bytes =
+          m_debugged_process_up->TraceGetBinaryData(*request)) {
+    StreamGDBRemote response;
+    response.PutEscapedBytes(bytes->data(), bytes->size());
+    return SendPacketNoLock(response.GetString());
+  } else
+    return SendErrorResponse(bytes.takeError());
 }
 
 GDBRemoteCommunication::PacketResult

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index a35932680d165..ef7d4471acf6c 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -167,15 +167,15 @@ class GDBRemoteCommunicationServerLLGS
 
   PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet);
 
-  PacketResult Handle_jTraceStart(StringExtractorGDBRemote &packet);
+  PacketResult Handle_jLLDBTraceSupported(StringExtractorGDBRemote &packet);
 
-  PacketResult Handle_jTraceRead(StringExtractorGDBRemote &packet);
+  PacketResult Handle_jLLDBTraceStart(StringExtractorGDBRemote &packet);
 
-  PacketResult Handle_jTraceStop(StringExtractorGDBRemote &packet);
+  PacketResult Handle_jLLDBTraceStop(StringExtractorGDBRemote &packet);
 
-  PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet);
+  PacketResult Handle_jLLDBTraceGetState(StringExtractorGDBRemote &packet);
 
-  PacketResult Handle_jLLDBTraceSupportedType(StringExtractorGDBRemote &packet);
+  PacketResult Handle_jLLDBTraceGetBinaryData(StringExtractorGDBRemote &packet);
 
   PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
 

diff  --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 4a8eb07778862..7363c156da0bc 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1203,34 +1203,26 @@ Status ProcessGDBRemote::DoAttachToProcessWithName(
   return error;
 }
 
-lldb::user_id_t ProcessGDBRemote::StartTrace(const TraceOptions &options,
-                                             Status &error) {
-  return m_gdb_comm.SendStartTracePacket(options, error);
+llvm::Expected<TraceSupportedResponse> ProcessGDBRemote::TraceSupported() {
+  return m_gdb_comm.SendTraceSupported();
 }
 
-Status ProcessGDBRemote::StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
-  return m_gdb_comm.SendStopTracePacket(uid, thread_id);
+llvm::Error ProcessGDBRemote::TraceStop(const TraceStopRequest &request) {
+  return m_gdb_comm.SendTraceStop(request);
 }
 
-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);
+llvm::Error ProcessGDBRemote::TraceStart(const llvm::json::Value &request) {
+  return m_gdb_comm.SendTraceStart(request);
 }
 
-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);
+llvm::Expected<std::string>
+ProcessGDBRemote::TraceGetState(llvm::StringRef type) {
+  return m_gdb_comm.SendTraceGetState(type);
 }
 
-Status ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid,
-                                        TraceOptions &options) {
-  return m_gdb_comm.SendGetTraceConfigPacket(uid, options);
-}
-
-llvm::Expected<TraceTypeInfo> ProcessGDBRemote::GetSupportedTraceType() {
-  return m_gdb_comm.SendGetSupportedTraceType();
+llvm::Expected<std::vector<uint8_t>>
+ProcessGDBRemote::TraceGetBinaryData(const TraceGetBinaryDataRequest &request) {
+  return m_gdb_comm.SendTraceGetBinaryData(request);
 }
 
 void ProcessGDBRemote::DidExit() {
@@ -1906,6 +1898,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
               thread_sp->SetStopInfo(
                   StopInfo::CreateStopReasonWithExec(*thread_sp));
               handled = true;
+            } else if (reason == "processor trace") {
+              thread_sp->SetStopInfo(StopInfo::CreateStopReasonProcessorTrace(
+                  *thread_sp, description.c_str()));
             }
           } else if (!signo) {
             addr_t pc = thread_sp->GetRegisterContext()->GetPC();

diff  --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 9c74369fd6c59..aafe1c3fc7aa8 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -165,22 +165,16 @@ class ProcessGDBRemote : public Process,
 
   Status GetWatchpointSupportInfo(uint32_t &num) override;
 
-  lldb::user_id_t StartTrace(const TraceOptions &options,
-                             Status &error) override;
+  llvm::Expected<TraceSupportedResponse> TraceSupported() override;
 
-  Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) override;
+  llvm::Error TraceStop(const TraceStopRequest &request) override;
 
-  Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
-                 llvm::MutableArrayRef<uint8_t> &buffer,
-                 size_t offset = 0) override;
+  llvm::Error TraceStart(const llvm::json::Value &request) override;
 
-  Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
-                     llvm::MutableArrayRef<uint8_t> &buffer,
-                     size_t offset = 0) override;
+  llvm::Expected<std::string> TraceGetState(llvm::StringRef type) override;
 
-  llvm::Expected<TraceTypeInfo> GetSupportedTraceType() override;
-
-  Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
+  llvm::Expected<std::vector<uint8_t>>
+  TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override;
 
   Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
 

diff  --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
index e1758dfcfc415..a21e5a2f04fc0 100644
--- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
@@ -8,7 +8,9 @@
 
 #include "CommandObjectTraceStartIntelPT.h"
 
+#include "TraceIntelPT.h"
 #include "lldb/Host/OptionParser.h"
+#include "lldb/Target/Process.h"
 #include "lldb/Target/Trace.h"
 
 using namespace lldb;
@@ -16,10 +18,12 @@ using namespace lldb_private;
 using namespace lldb_private::trace_intel_pt;
 using namespace llvm;
 
+// CommandObjectThreadTraceStartIntelPT
+
 #define LLDB_OPTIONS_thread_trace_start_intel_pt
 #include "TraceIntelPTCommandOptions.inc"
 
-Status CommandObjectTraceStartIntelPT::CommandOptions::SetOptionValue(
+Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue(
     uint32_t option_idx, llvm::StringRef option_arg,
     ExecutionContext *execution_context) {
   Status error;
@@ -27,23 +31,73 @@ Status CommandObjectTraceStartIntelPT::CommandOptions::SetOptionValue(
 
   switch (short_option) {
   case 's': {
-    int32_t size_in_kb;
-    if (option_arg.empty() || option_arg.getAsInteger(0, size_in_kb) ||
-        size_in_kb < 0)
+    int64_t thread_buffer_size;
+    if (option_arg.empty() || option_arg.getAsInteger(0, thread_buffer_size) ||
+        thread_buffer_size < 0)
       error.SetErrorStringWithFormat("invalid integer value for option '%s'",
                                      option_arg.str().c_str());
     else
-      m_size_in_kb = size_in_kb;
+      m_thread_buffer_size = thread_buffer_size;
     break;
   }
-  case 'c': {
-    int32_t custom_config;
-    if (option_arg.empty() || option_arg.getAsInteger(0, custom_config) ||
-        custom_config < 0)
+  default:
+    llvm_unreachable("Unimplemented option");
+  }
+  return error;
+}
+
+void CommandObjectThreadTraceStartIntelPT::CommandOptions::
+    OptionParsingStarting(ExecutionContext *execution_context) {
+  m_thread_buffer_size = 4 * 1024; // 4KB
+}
+
+llvm::ArrayRef<OptionDefinition>
+CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() {
+  return llvm::makeArrayRef(g_thread_trace_start_intel_pt_options);
+}
+
+bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads(
+    Args &command, CommandReturnObject &result,
+    const std::vector<lldb::tid_t> &tids) {
+  if (Error err = m_trace.Start(tids, m_options.m_thread_buffer_size))
+    result.SetError(toString(std::move(err)));
+  else
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+
+  return result.Succeeded();
+}
+
+/// CommandObjectProcessTraceStartIntelPT
+
+#define LLDB_OPTIONS_process_trace_start_intel_pt
+#include "TraceIntelPTCommandOptions.inc"
+
+Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue(
+    uint32_t option_idx, llvm::StringRef option_arg,
+    ExecutionContext *execution_context) {
+  Status error;
+  const int short_option = m_getopt_table[option_idx].val;
+
+  switch (short_option) {
+  case 's': {
+    int64_t thread_buffer_size;
+    if (option_arg.empty() || option_arg.getAsInteger(0, thread_buffer_size) ||
+        thread_buffer_size < 0)
       error.SetErrorStringWithFormat("invalid integer value for option '%s'",
                                      option_arg.str().c_str());
     else
-      m_custom_config = custom_config;
+      m_thread_buffer_size = thread_buffer_size;
+    break;
+  }
+  case 'l': {
+    int64_t process_buffer_size_limit;
+    if (option_arg.empty() ||
+        option_arg.getAsInteger(0, process_buffer_size_limit) ||
+        process_buffer_size_limit < 0)
+      error.SetErrorStringWithFormat("invalid integer value for option '%s'",
+                                     option_arg.str().c_str());
+    else
+      m_process_buffer_size_limit = process_buffer_size_limit;
     break;
   }
   default:
@@ -52,22 +106,24 @@ Status CommandObjectTraceStartIntelPT::CommandOptions::SetOptionValue(
   return error;
 }
 
-void CommandObjectTraceStartIntelPT::CommandOptions::OptionParsingStarting(
-    ExecutionContext *execution_context) {
-  m_size_in_kb = 4;
-  m_custom_config = 0;
+void CommandObjectProcessTraceStartIntelPT::CommandOptions::
+    OptionParsingStarting(ExecutionContext *execution_context) {
+  m_thread_buffer_size = 4 * 1024;               // 4KB
+  m_process_buffer_size_limit = 5 * 1024 * 1024; // 500MB
 }
 
 llvm::ArrayRef<OptionDefinition>
-CommandObjectTraceStartIntelPT::CommandOptions::GetDefinitions() {
-  return llvm::makeArrayRef(g_thread_trace_start_intel_pt_options);
+CommandObjectProcessTraceStartIntelPT::CommandOptions::GetDefinitions() {
+  return llvm::makeArrayRef(g_process_trace_start_intel_pt_options);
 }
 
-bool CommandObjectTraceStartIntelPT::HandleOneThread(
-    lldb::tid_t tid, CommandReturnObject &result) {
-  result.AppendMessageWithFormat(
-      "would trace tid %" PRIu64 " with size_in_kb %zu and custom_config %d\n",
-      tid, m_options.m_size_in_kb, m_options.m_custom_config);
-  result.SetStatus(eReturnStatusSuccessFinishResult);
+bool CommandObjectProcessTraceStartIntelPT::DoExecute(
+    Args &command, CommandReturnObject &result) {
+  if (Error err = m_trace.Start(m_options.m_thread_buffer_size,
+                                m_options.m_process_buffer_size_limit))
+    result.SetError(toString(std::move(err)));
+  else
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+
   return result.Succeeded();
 }

diff  --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
index 265569c553fa3..7049e4ecbf406 100644
--- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
@@ -9,21 +9,21 @@
 #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H
 #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H
 
-#include "../../../../source/Commands/CommandObjectThreadUtil.h"
+#include "../../../../source/Commands/CommandObjectTrace.h"
+#include "TraceIntelPT.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 
 namespace lldb_private {
 namespace trace_intel_pt {
 
-class CommandObjectTraceStartIntelPT : public CommandObjectIterateOverThreads {
+class CommandObjectThreadTraceStartIntelPT
+    : public CommandObjectMultipleThreads {
 public:
   class CommandOptions : public Options {
   public:
     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
 
-    ~CommandOptions() override = default;
-
     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
                           ExecutionContext *execution_context) override;
 
@@ -31,31 +31,72 @@ class CommandObjectTraceStartIntelPT : public CommandObjectIterateOverThreads {
 
     llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
 
-    size_t m_size_in_kb;
-    uint32_t m_custom_config;
+    size_t m_thread_buffer_size;
   };
 
-  CommandObjectTraceStartIntelPT(CommandInterpreter &interpreter)
-      : CommandObjectIterateOverThreads(
+  CommandObjectThreadTraceStartIntelPT(TraceIntelPT &trace,
+                                       CommandInterpreter &interpreter)
+      : CommandObjectMultipleThreads(
             interpreter, "thread trace start",
             "Start tracing one or more threads with intel-pt. "
             "Defaults to the current thread. Thread indices can be "
             "specified as arguments.\n Use the thread-index \"all\" to trace "
-            "all threads.",
+            "all threads including future threads.",
             "thread trace start [<thread-index> <thread-index> ...] "
             "[<intel-pt-options>]",
             lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock |
                 lldb::eCommandProcessMustBeLaunched |
                 lldb::eCommandProcessMustBePaused),
-        m_options() {}
+        m_trace(trace), m_options() {}
+
+  Options *GetOptions() override { return &m_options; }
+
+protected:
+  bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
+                          const std::vector<lldb::tid_t> &tids) override;
+
+  TraceIntelPT &m_trace;
+  CommandOptions m_options;
+};
+
+class CommandObjectProcessTraceStartIntelPT : public CommandObjectParsed {
+public:
+  class CommandOptions : public Options {
+  public:
+    CommandOptions() : Options() { OptionParsingStarting(nullptr); }
 
-  ~CommandObjectTraceStartIntelPT() override = default;
+    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+                          ExecutionContext *execution_context) override;
+
+    void OptionParsingStarting(ExecutionContext *execution_context) override;
+
+    llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
+
+    size_t m_thread_buffer_size;
+    size_t m_process_buffer_size_limit;
+  };
+
+  CommandObjectProcessTraceStartIntelPT(TraceIntelPT &trace,
+                                        CommandInterpreter &interpreter)
+      : CommandObjectParsed(
+            interpreter, "process trace start",
+            "Start tracing this process with intel-pt, including future "
+            "threads. "
+            "This is implemented by tracing each thread independently. "
+            "Threads traced with the \"thread trace start\" command are left "
+            "unaffected ant not retraced.",
+            "process trace start [<intel-pt-options>]",
+            lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock |
+                lldb::eCommandProcessMustBeLaunched |
+                lldb::eCommandProcessMustBePaused),
+        m_trace(trace), m_options() {}
 
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override;
+  bool DoExecute(Args &command, CommandReturnObject &result) override;
 
+  TraceIntelPT &m_trace;
   CommandOptions m_options;
 };
 

diff  --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
index 6b8b065640522..c65fa692e7d67 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -62,3 +62,8 @@ size_t DecodedThread::SetCursorPosition(size_t new_position) {
   m_position = std::min(new_position, GetLastPosition());
   return m_position;
 }
+
+DecodedThread::DecodedThread(Error error) {
+  m_instructions.emplace_back(std::move(error));
+  m_position = GetLastPosition();
+}

diff  --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
index 3c7e030414cb2..aabd85bcfd314 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
@@ -15,6 +15,7 @@
 #include "llvm/Support/Error.h"
 
 #include "lldb/Target/Trace.h"
+#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
 
 #include "intel-pt.h"
 
@@ -111,6 +112,10 @@ class DecodedThread {
       : m_instructions(std::move(instructions)), m_position(GetLastPosition()) {
   }
 
+  /// Constructor with a single error signaling a complete failure of the
+  /// decoding process.
+  DecodedThread(llvm::Error error);
+
   /// Get the instructions from the decoded trace. Some of them might indicate
   /// errors (i.e. gaps) in the trace.
   ///

diff  --git a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
index b6e8ae808632e..5d9aa0a1c743c 100644
--- a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
@@ -1,5 +1,4 @@
-//===-- IntelPTDecoder.cpp --------------------------------------*- C++ -*-===//
-//
+//===-- IntelPTDecoder.cpp --======----------------------------------------===//
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -10,10 +9,12 @@
 
 #include "llvm/Support/MemoryBuffer.h"
 
+#include "TraceIntelPT.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Target/Target.h"
-#include "lldb/Target/ThreadTrace.h"
+#include "lldb/Target/ThreadPostMortemTrace.h"
+#include "lldb/Utility/StringExtractor.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -85,7 +86,7 @@ static int ProcessPTEvents(pt_insn_decoder &decoder, int errcode) {
       return errcode;
   }
   return 0;
-};
+}
 
 /// Decode all the instructions from a configured decoder.
 /// The decoding flow is based on
@@ -158,39 +159,26 @@ static int ReadProcessMemory(uint8_t *buffer, size_t size,
   return bytes_read;
 }
 
-static std::vector<IntelPTInstruction> makeInstructionListFromError(Error err) {
-  std::vector<IntelPTInstruction> instructions;
-  instructions.emplace_back(std::move(err));
-  return instructions;
-}
-
-static std::vector<IntelPTInstruction>
-CreateDecoderAndDecode(Process &process, const pt_cpu &pt_cpu,
-                       const FileSpec &trace_file) {
-  ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
-      MemoryBuffer::getFile(trace_file.GetPath());
-  if (std::error_code err = trace_or_error.getError())
-    return makeInstructionListFromError(errorCodeToError(err));
-
-  MemoryBuffer &trace = **trace_or_error;
+static Expected<std::vector<IntelPTInstruction>>
+DecodeInMemoryTrace(Process &process, TraceIntelPT &trace_intel_pt,
+                    MutableArrayRef<uint8_t> buffer) {
+  Expected<pt_cpu> cpu_info = trace_intel_pt.GetCPUInfo();
+  if (!cpu_info)
+    return cpu_info.takeError();
 
   pt_config config;
   pt_config_init(&config);
-  config.cpu = pt_cpu;
+  config.cpu = *cpu_info;
 
   if (int errcode = pt_cpu_errata(&config.errata, &config.cpu))
-    return makeInstructionListFromError(make_error<IntelPTError>(errcode));
+    return make_error<IntelPTError>(errcode);
 
-  // The libipt library does not modify the trace buffer, hence the following
-  // cast is safe.
-  config.begin =
-      reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferStart()));
-  config.end =
-      reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferEnd()));
+  config.begin = buffer.data();
+  config.end = buffer.data() + buffer.size();
 
   pt_insn_decoder *decoder = pt_insn_alloc_decoder(&config);
   if (!decoder)
-    return makeInstructionListFromError(make_error<IntelPTError>(-pte_nomem));
+    return make_error<IntelPTError>(-pte_nomem);
 
   pt_image *image = pt_insn_get_image(decoder);
 
@@ -204,12 +192,62 @@ CreateDecoderAndDecode(Process &process, const pt_cpu &pt_cpu,
   return instructions;
 }
 
-const DecodedThread &ThreadTraceDecoder::Decode() {
-  if (!m_decoded_thread.hasValue()) {
-    m_decoded_thread = DecodedThread(
-        CreateDecoderAndDecode(*m_trace_thread->GetProcess(), m_pt_cpu,
-                               m_trace_thread->GetTraceFile()));
-  }
+static Expected<std::vector<IntelPTInstruction>>
+DecodeTraceFile(Process &process, TraceIntelPT &trace_intel_pt,
+                const FileSpec &trace_file) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
+      MemoryBuffer::getFile(trace_file.GetPath());
+  if (std::error_code err = trace_or_error.getError())
+    return errorCodeToError(err);
 
+  MemoryBuffer &trace = **trace_or_error;
+  MutableArrayRef<uint8_t> trace_data(
+      // The libipt library does not modify the trace buffer, hence the
+      // following cast is safe.
+      reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferStart())),
+      trace.getBufferSize());
+  return DecodeInMemoryTrace(process, trace_intel_pt, trace_data);
+}
+
+static Expected<std::vector<IntelPTInstruction>>
+DecodeLiveThread(Thread &thread, TraceIntelPT &trace) {
+  Expected<std::vector<uint8_t>> buffer =
+      trace.GetLiveThreadBuffer(thread.GetID());
+  if (!buffer)
+    return buffer.takeError();
+  if (Expected<pt_cpu> cpu_info = trace.GetCPUInfo())
+    return DecodeInMemoryTrace(*thread.GetProcess(), trace,
+                               MutableArrayRef<uint8_t>(*buffer));
+  else
+    return cpu_info.takeError();
+}
+
+const DecodedThread &ThreadDecoder::Decode() {
+  if (!m_decoded_thread.hasValue())
+    m_decoded_thread = DoDecode();
   return *m_decoded_thread;
 }
+
+PostMortemThreadDecoder::PostMortemThreadDecoder(
+    const lldb::ThreadPostMortemTraceSP &trace_thread, TraceIntelPT &trace)
+    : m_trace_thread(trace_thread), m_trace(trace) {}
+
+DecodedThread PostMortemThreadDecoder::DoDecode() {
+  if (Expected<std::vector<IntelPTInstruction>> instructions =
+          DecodeTraceFile(*m_trace_thread->GetProcess(), m_trace,
+                          m_trace_thread->GetTraceFile()))
+    return DecodedThread(std::move(*instructions));
+  else
+    return DecodedThread(instructions.takeError());
+}
+
+LiveThreadDecoder::LiveThreadDecoder(Thread &thread, TraceIntelPT &trace)
+    : m_thread_sp(thread.shared_from_this()), m_trace(trace) {}
+
+DecodedThread LiveThreadDecoder::DoDecode() {
+  if (Expected<std::vector<IntelPTInstruction>> instructions =
+          DecodeLiveThread(*m_thread_sp, m_trace))
+    return DecodedThread(std::move(*instructions));
+  else
+    return DecodedThread(instructions.takeError());
+}

diff  --git a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h
index 2e67f9bf6da70..3768a8d80a2bf 100644
--- a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h
@@ -12,40 +12,75 @@
 #include "intel-pt.h"
 
 #include "DecodedThread.h"
+#include "forward-declarations.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Utility/FileSpec.h"
 
 namespace lldb_private {
 namespace trace_intel_pt {
 
-/// \a lldb_private::ThreadTrace decoder that stores the output from decoding,
-/// avoiding recomputations, as decoding is expensive.
-class ThreadTraceDecoder {
+/// Base class that handles the decoding of a thread and caches the result.
+class ThreadDecoder {
 public:
-  /// \param[in] trace_thread
-  ///     The thread whose trace file will be decoded.
-  ///
-  /// \param[in] pt_cpu
-  ///     The libipt cpu used when recording the trace.
-  ThreadTraceDecoder(const std::shared_ptr<ThreadTrace> &trace_thread,
-                     const pt_cpu &pt_cpu)
-      : m_trace_thread(trace_thread), m_pt_cpu(pt_cpu), m_decoded_thread() {}
+  virtual ~ThreadDecoder() = default;
+
+  ThreadDecoder() = default;
 
-  /// Decode the thread and store the result internally.
+  /// Decode the thread and store the result internally, to avoid
+  /// recomputations.
   ///
   /// \return
   ///     A \a DecodedThread instance.
   const DecodedThread &Decode();
 
-private:
-  ThreadTraceDecoder(const ThreadTraceDecoder &other) = delete;
-  ThreadTraceDecoder &operator=(const ThreadTraceDecoder &other) = delete;
+  ThreadDecoder(const ThreadDecoder &other) = delete;
+  ThreadDecoder &operator=(const ThreadDecoder &other) = delete;
+
+protected:
+  /// Decode the thread.
+  ///
+  /// \return
+  ///     A \a DecodedThread instance.
+  virtual DecodedThread DoDecode() = 0;
 
-  std::shared_ptr<ThreadTrace> m_trace_thread;
-  pt_cpu m_pt_cpu;
   llvm::Optional<DecodedThread> m_decoded_thread;
 };
 
+/// Decoder implementation for \a lldb_private::ThreadPostMortemTrace, which are
+/// non-live processes that come trace session files.
+class PostMortemThreadDecoder : public ThreadDecoder {
+public:
+  /// \param[in] trace_thread
+  ///     The thread whose trace file will be decoded.
+  ///
+  /// \param[in] trace
+  ///     The main Trace object who owns this decoder and its data.
+  PostMortemThreadDecoder(const lldb::ThreadPostMortemTraceSP &trace_thread,
+                          TraceIntelPT &trace);
+
+private:
+  DecodedThread DoDecode() override;
+
+  lldb::ThreadPostMortemTraceSP m_trace_thread;
+  TraceIntelPT &m_trace;
+};
+
+class LiveThreadDecoder : public ThreadDecoder {
+public:
+  /// \param[in] thread
+  ///     The thread whose traces will be decoded.
+  ///
+  /// \param[in] trace
+  ///     The main Trace object who owns this decoder and its data.
+  LiveThreadDecoder(Thread &thread, TraceIntelPT &trace);
+
+private:
+  DecodedThread DoDecode() override;
+
+  lldb::ThreadSP m_thread_sp;
+  TraceIntelPT &m_trace;
+};
+
 } // namespace trace_intel_pt
 } // namespace lldb_private
 

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index 63a8b2dff4a76..96c4a89bd1cb8 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -13,7 +13,7 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
-#include "lldb/Target/ThreadTrace.h"
+#include "lldb/Target/ThreadPostMortemTrace.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -22,18 +22,27 @@ using namespace llvm;
 
 LLDB_PLUGIN_DEFINE(TraceIntelPT)
 
-CommandObjectSP GetStartCommand(CommandInterpreter &interpreter) {
-  return CommandObjectSP(new CommandObjectTraceStartIntelPT(interpreter));
+lldb::CommandObjectSP
+TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) {
+  return CommandObjectSP(
+      new CommandObjectProcessTraceStartIntelPT(*this, interpreter));
+}
+
+lldb::CommandObjectSP
+TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {
+  return CommandObjectSP(
+      new CommandObjectThreadTraceStartIntelPT(*this, interpreter));
 }
 
 void TraceIntelPT::Initialize() {
-  PluginManager::RegisterPlugin(
-      GetPluginNameStatic(), "Intel Processor Trace", CreateInstance,
-      TraceIntelPTSessionFileParser::GetSchema(), GetStartCommand);
+  PluginManager::RegisterPlugin(GetPluginNameStatic(), "Intel Processor Trace",
+                                CreateInstanceForSessionFile,
+                                CreateInstanceForLiveProcess,
+                                TraceIntelPTSessionFileParser::GetSchema());
 }
 
 void TraceIntelPT::Terminate() {
-  PluginManager::UnregisterPlugin(CreateInstance);
+  PluginManager::UnregisterPlugin(CreateInstanceForSessionFile);
 }
 
 ConstString TraceIntelPT::GetPluginNameStatic() {
@@ -55,34 +64,41 @@ uint32_t TraceIntelPT::GetPluginVersion() { return 1; }
 
 void TraceIntelPT::Dump(Stream *s) const {}
 
-Expected<TraceSP>
-TraceIntelPT::CreateInstance(const json::Value &trace_session_file,
-                             StringRef session_file_dir, Debugger &debugger) {
+Expected<TraceSP> TraceIntelPT::CreateInstanceForSessionFile(
+    const json::Value &trace_session_file, StringRef session_file_dir,
+    Debugger &debugger) {
   return TraceIntelPTSessionFileParser(debugger, trace_session_file,
                                        session_file_dir)
       .Parse();
 }
 
+Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
+  TraceSP instance(new TraceIntelPT(process));
+  process.GetTarget().SetTrace(instance);
+  return instance;
+}
+
 TraceIntelPT::TraceIntelPT(
-    const pt_cpu &pt_cpu,
-    const std::vector<std::shared_ptr<ThreadTrace>> &traced_threads)
-    : m_pt_cpu(pt_cpu) {
-  for (const std::shared_ptr<ThreadTrace> &thread : traced_threads)
-    m_trace_threads.emplace(
-        std::piecewise_construct,
-        std::forward_as_tuple(thread->GetProcess()->GetID(), thread->GetID()),
-        std::forward_as_tuple(thread, pt_cpu));
-}
-
-const DecodedThread *TraceIntelPT::Decode(const Thread &thread) {
-  auto it = m_trace_threads.find(
-      std::make_pair(thread.GetProcess()->GetID(), thread.GetID()));
-  if (it == m_trace_threads.end())
+    const pt_cpu &cpu_info,
+    const std::vector<ThreadPostMortemTraceSP> &traced_threads)
+    : m_cpu_info(cpu_info) {
+  for (const ThreadPostMortemTraceSP &thread : traced_threads)
+    m_thread_decoders.emplace(
+        thread.get(), std::make_unique<PostMortemThreadDecoder>(thread, *this));
+}
+
+const DecodedThread *TraceIntelPT::Decode(Thread &thread) {
+  RefreshLiveProcessState();
+  if (m_failed_live_threads_decoder.hasValue())
+    return &*m_failed_live_threads_decoder;
+
+  auto it = m_thread_decoders.find(&thread);
+  if (it == m_thread_decoders.end())
     return nullptr;
-  return &it->second.Decode();
+  return &it->second->Decode();
 }
 
-size_t TraceIntelPT::GetCursorPosition(const Thread &thread) {
+size_t TraceIntelPT::GetCursorPosition(Thread &thread) {
   const DecodedThread *decoded_thread = Decode(thread);
   if (!decoded_thread)
     return 0;
@@ -90,7 +106,7 @@ size_t TraceIntelPT::GetCursorPosition(const Thread &thread) {
 }
 
 void TraceIntelPT::TraverseInstructions(
-    const Thread &thread, size_t position, TraceDirection direction,
+    Thread &thread, size_t position, TraceDirection direction,
     std::function<bool(size_t index, Expected<lldb::addr_t> load_addr)>
         callback) {
   const DecodedThread *decoded_thread = Decode(thread);
@@ -106,9 +122,117 @@ void TraceIntelPT::TraverseInstructions(
       break;
 }
 
-size_t TraceIntelPT::GetInstructionCount(const Thread &thread) {
+size_t TraceIntelPT::GetInstructionCount(Thread &thread) {
   if (const DecodedThread *decoded_thread = Decode(thread))
     return decoded_thread->GetInstructions().size();
   else
     return 0;
 }
+
+Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {
+  Expected<std::vector<uint8_t>> cpu_info = GetLiveProcessBinaryData("cpuInfo");
+  if (!cpu_info)
+    return cpu_info.takeError();
+
+  int64_t cpu_family = -1;
+  int64_t model = -1;
+  int64_t stepping = -1;
+  std::string vendor_id;
+
+  StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),
+                 cpu_info->size());
+  while (!rest.empty()) {
+    StringRef line;
+    std::tie(line, rest) = rest.split('\n');
+
+    SmallVector<StringRef, 2> columns;
+    line.split(columns, StringRef(":"), -1, false);
+
+    if (columns.size() < 2)
+      continue; // continue searching
+
+    columns[1] = columns[1].trim(" ");
+    if (columns[0].contains("cpu family") &&
+        columns[1].getAsInteger(10, cpu_family))
+      continue;
+
+    else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
+      continue;
+
+    else if (columns[0].contains("stepping") &&
+             columns[1].getAsInteger(10, stepping))
+      continue;
+
+    else if (columns[0].contains("vendor_id")) {
+      vendor_id = columns[1].str();
+      if (!vendor_id.empty())
+        continue;
+    }
+
+    if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
+        (!vendor_id.empty())) {
+      return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,
+                    static_cast<uint16_t>(cpu_family),
+                    static_cast<uint8_t>(model),
+                    static_cast<uint8_t>(stepping)};
+    }
+  }
+  return createStringError(inconvertibleErrorCode(),
+                           "Failed parsing the target's /proc/cpuinfo file");
+}
+
+Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {
+  if (!m_cpu_info) {
+    if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())
+      m_cpu_info = *cpu_info;
+    else
+      return cpu_info.takeError();
+  }
+  return *m_cpu_info;
+}
+
+void TraceIntelPT::DoRefreshLiveProcessState(
+    Expected<TraceGetStateResponse> state) {
+  m_thread_decoders.clear();
+
+  if (!state) {
+    m_failed_live_threads_decoder = DecodedThread(state.takeError());
+    return;
+  }
+
+  for (const TraceThreadState &thread_state : state->tracedThreads) {
+    Thread &thread =
+        *m_live_process->GetThreadList().FindThreadByID(thread_state.tid);
+    m_thread_decoders.emplace(
+        &thread, std::make_unique<LiveThreadDecoder>(thread, *this));
+  }
+}
+
+bool TraceIntelPT::IsTraced(const Thread &thread) {
+  return m_thread_decoders.count(&thread);
+}
+
+Error TraceIntelPT::Start(size_t thread_buffer_size,
+                          size_t total_buffer_size_limit) {
+  TraceIntelPTStartRequest request;
+  request.threadBufferSize = thread_buffer_size;
+  request.processBufferSizeLimit = total_buffer_size_limit;
+  request.type = GetPluginName().AsCString();
+  return Trace::Start(toJSON(request));
+}
+
+llvm::Error TraceIntelPT::Start(const std::vector<lldb::tid_t> &tids,
+                                size_t thread_buffer_size) {
+  TraceIntelPTStartRequest request;
+  request.threadBufferSize = thread_buffer_size;
+  request.type = GetPluginName().AsCString();
+  request.tids.emplace();
+  for (lldb::tid_t tid : tids)
+    request.tids->push_back(tid);
+  return Trace::Start(toJSON(request));
+}
+
+Expected<std::vector<uint8_t>>
+TraceIntelPT::GetLiveThreadBuffer(lldb::tid_t tid) {
+  return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer");
+}

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
index 5058e6fd32f24..f19e516498e9f 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -45,33 +45,93 @@ class TraceIntelPT : public Trace {
   /// \return
   ///     A trace instance or an error in case of failures.
   static llvm::Expected<lldb::TraceSP>
-  CreateInstance(const llvm::json::Value &trace_session_file,
-                 llvm::StringRef session_file_dir, Debugger &debugger);
+  CreateInstanceForSessionFile(const llvm::json::Value &trace_session_file,
+                               llvm::StringRef session_file_dir,
+                               Debugger &debugger);
+
+  static llvm::Expected<lldb::TraceSP>
+  CreateInstanceForLiveProcess(Process &process);
 
   static ConstString GetPluginNameStatic();
 
   uint32_t GetPluginVersion() override;
   /// \}
 
+  lldb::CommandObjectSP
+  GetProcessTraceStartCommand(CommandInterpreter &interpreter) override;
+
+  lldb::CommandObjectSP
+  GetThreadTraceStartCommand(CommandInterpreter &interpreter) override;
+
   llvm::StringRef GetSchema() override;
 
   void TraverseInstructions(
-      const Thread &thread, size_t position, TraceDirection direction,
+      Thread &thread, size_t position, TraceDirection direction,
       std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)>
           callback) override;
 
-  size_t GetInstructionCount(const Thread &thread) override;
+  size_t GetInstructionCount(Thread &thread) override;
+
+  size_t GetCursorPosition(Thread &thread) override;
+
+  void DoRefreshLiveProcessState(
+      llvm::Expected<TraceGetStateResponse> state) override;
+
+  bool IsTraced(const Thread &thread) override;
+
+  /// Start tracing a live process.
+  ///
+  /// \param[in] thread_buffer_size
+  ///     Trace size per thread in bytes.
+  ///
+  /// \param[in] total_buffer_size_limit
+  ///     Maximum total trace size per process in bytes. This limit applies to
+  ///     the sum of the sizes of all thread traces of this process, excluding
+  ///     the threads traced explicitly.
+  ///
+  ///     Whenever a thread is attempted to be traced due to this operation and
+  ///     the limit would be reached, the process is stopped with a "tracing"
+  ///     reason, so that the user can retrace the process if needed.
+  ///
+  /// \return
+  ///     \a llvm::Error::success if the operation was successful, or
+  ///     \a llvm::Error otherwise.
+  llvm::Error Start(size_t thread_buffer_size, size_t total_buffer_size_limit);
+
+  /// Start tracing a live threads.
+  ///
+  /// \param[in] tids
+  ///     Threads to trace.
+  ///
+  /// \param[in] thread_buffer_size
+  ///     Trace size per thread in bytes.
+  ///
+  /// \return
+  ///     \a llvm::Error::success if the operation was successful, or
+  ///     \a llvm::Error otherwise.
+  llvm::Error Start(const std::vector<lldb::tid_t> &tids,
+                    size_t thread_buffer_size);
+
+  /// Get the thread buffer content for a live thread
+  llvm::Expected<std::vector<uint8_t>> GetLiveThreadBuffer(lldb::tid_t tid);
 
-  size_t GetCursorPosition(const Thread &thread) override;
+  llvm::Expected<pt_cpu> GetCPUInfo();
 
 private:
   friend class TraceIntelPTSessionFileParser;
 
+  llvm::Expected<pt_cpu> GetCPUInfoForLiveProcess();
+
   /// \param[in] trace_threads
   ///     ThreadTrace instances, which are not live-processes and whose trace
   ///     files are fixed.
-  TraceIntelPT(const pt_cpu &pt_cpu,
-               const std::vector<std::shared_ptr<ThreadTrace>> &traced_threads);
+  TraceIntelPT(
+      const pt_cpu &cpu_info,
+      const std::vector<lldb::ThreadPostMortemTraceSP> &traced_threads);
+
+  /// Constructor for live processes
+  TraceIntelPT(Process &live_process)
+      : Trace(live_process), m_thread_decoders(){};
 
   /// Decode the trace of the given thread that, i.e. recontruct the traced
   /// instructions. That trace must be managed by this class.
@@ -83,11 +143,15 @@ class TraceIntelPT : public Trace {
   /// \return
   ///     A \a DecodedThread instance if decoding was successful, or a \b
   ///     nullptr if the thread's trace is not managed by this class.
-  const DecodedThread *Decode(const Thread &thread);
-
-  pt_cpu m_pt_cpu;
-  std::map<std::pair<lldb::pid_t, lldb::tid_t>, ThreadTraceDecoder>
-      m_trace_threads;
+  const DecodedThread *Decode(Thread &thread);
+
+  /// It is provided by either a session file or a live process' "cpuInfo"
+  /// binary data.
+  llvm::Optional<pt_cpu> m_cpu_info;
+  std::map<const Thread *, std::unique_ptr<ThreadDecoder>> m_thread_decoders;
+  /// Dummy DecodedThread used when decoding threads after there were errors
+  /// when refreshing the live process state.
+  llvm::Optional<DecodedThread> m_failed_live_threads_decoder;
 };
 
 } // namespace trace_intel_pt

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
index 6ffe949dbe7bc..0dd835bac649c 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
@@ -4,13 +4,25 @@ let Command = "thread trace start intel pt" in {
   def thread_trace_start_intel_pt_size: Option<"size", "s">,
     Group<1>,
     Arg<"Value">,
-    Desc<"The size of the trace in KB. The kernel rounds it down to the nearest"
-         " multiple of 4. Defaults to 4.">;
-  def thread_trace_start_intel_pt_custom_config: Option<"custom-config", "c">,
+    Desc<"Trace size in bytes per thread. It must be a power of 2 greater "
+         "than or equal to 4096 (2^12). The trace is circular keeping "
+         "the most recent data. Defaults to 4096 bytes.">;
+}
+
+let Command = "process trace start intel pt" in {
+  def process_trace_start_intel_pt_thread_size: Option<"thread-size", "s">,
+    Group<1>,
+    Arg<"Value">,
+    Desc<"Trace size in bytes per thread. It must be a power of 2 greater "
+         "than or equal to 4096 (2^12). The trace is circular keeping "
+         "the most recent data. Defaults to 4096 bytes.">;
+  def process_trace_start_intel_pt_process_size_limit: Option<"total-size-limit", "l">,
     Group<1>,
     Arg<"Value">,
-    Desc<"Low level bitmask configuration for the kernel based on the values "
-         "in `grep -H  /sys/bus/event_source/devices/intel_pt/format/*`. "
-         "See https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/perf-intel-pt.txt"
-         " for more information. Defaults to 0.">;
+    Desc<"Maximum total trace size per process in bytes. This limit applies to "
+         "the sum of the sizes of all thread traces of this process, excluding "
+         "the ones created with the \"thread trace start\" command. "
+         "Whenever a thread is attempted to be traced due to this command and "
+         "the limit would be reached, the process is stopped with a \"tracing\" "
+         "reason, so that the user can retrace the process if needed.">;
 }

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
index beef5c3968eae..2883381422632 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
@@ -12,7 +12,8 @@
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/ThreadList.h"
-#include "lldb/Target/ThreadTrace.h"
+#include "lldb/Target/ThreadPostMortemTrace.h"
+#include "lldb/Utility/TraceOptions.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -24,7 +25,7 @@ StringRef TraceIntelPTSessionFileParser::GetSchema() {
   if (schema.empty()) {
     schema = TraceSessionFileParser::BuildSchema(R"({
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel" | "unknown",
       "family": integer,
       "model": integer,
@@ -35,21 +36,22 @@ StringRef TraceIntelPTSessionFileParser::GetSchema() {
   return schema;
 }
 
-pt_cpu TraceIntelPTSessionFileParser::ParsePTCPU(const JSONPTCPU &pt_cpu) {
-  return {pt_cpu.vendor.compare("intel") == 0 ? pcv_intel : pcv_unknown,
-          static_cast<uint16_t>(pt_cpu.family),
-          static_cast<uint8_t>(pt_cpu.model),
-          static_cast<uint8_t>(pt_cpu.stepping)};
+pt_cpu TraceIntelPTSessionFileParser::ParsePTCPU(
+    const JSONTraceIntelPTCPUInfo &cpu_info) {
+  return {cpu_info.vendor.compare("intel") == 0 ? pcv_intel : pcv_unknown,
+          static_cast<uint16_t>(cpu_info.family),
+          static_cast<uint8_t>(cpu_info.model),
+          static_cast<uint8_t>(cpu_info.stepping)};
 }
 
 TraceSP TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance(
-    const pt_cpu &pt_cpu, std::vector<ParsedProcess> &parsed_processes) {
-  std::vector<ThreadTraceSP> threads;
+    const pt_cpu &cpu_info, std::vector<ParsedProcess> &parsed_processes) {
+  std::vector<ThreadPostMortemTraceSP> threads;
   for (const ParsedProcess &parsed_process : parsed_processes)
     threads.insert(threads.end(), parsed_process.threads.begin(),
                    parsed_process.threads.end());
 
-  TraceSP trace_instance(new TraceIntelPT(pt_cpu, threads));
+  TraceSP trace_instance(new TraceIntelPT(cpu_info, threads));
   for (const ParsedProcess &parsed_process : parsed_processes)
     parsed_process.target_sp->SetTrace(trace_instance);
 
@@ -64,7 +66,7 @@ Expected<TraceSP> TraceIntelPTSessionFileParser::Parse() {
 
   if (Expected<std::vector<ParsedProcess>> parsed_processes =
           ParseCommonSessionFile(session))
-    return CreateTraceIntelPTInstance(ParsePTCPU(session.trace.pt_cpu),
+    return CreateTraceIntelPTInstance(ParsePTCPU(session.trace.cpuInfo),
                                       *parsed_processes);
   else
     return parsed_processes.takeError();
@@ -73,25 +75,34 @@ Expected<TraceSP> TraceIntelPTSessionFileParser::Parse() {
 namespace llvm {
 namespace json {
 
-bool fromJSON(const Value &value,
-              TraceIntelPTSessionFileParser::JSONPTCPU &pt_cpu, Path path) {
-  ObjectMapper o(value, path);
-  return o && o.map("vendor", pt_cpu.vendor) &&
-         o.map("family", pt_cpu.family) && o.map("model", pt_cpu.model) &&
-         o.map("stepping", pt_cpu.stepping);
-}
-
 bool fromJSON(
     const Value &value,
     TraceIntelPTSessionFileParser::JSONTraceIntelPTSettings &plugin_settings,
     Path path) {
   ObjectMapper o(value, path);
-  return o && o.map("pt_cpu", plugin_settings.pt_cpu) &&
+  return o && o.map("cpuInfo", plugin_settings.cpuInfo) &&
          fromJSON(
              value,
              (TraceSessionFileParser::JSONTracePluginSettings &)plugin_settings,
              path);
 }
 
+bool fromJSON(const json::Value &value,
+              TraceIntelPTSessionFileParser::JSONTraceIntelPTCPUInfo &cpu_info,
+              Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("vendor", cpu_info.vendor) &&
+         o.map("family", cpu_info.family) && o.map("model", cpu_info.model) &&
+         o.map("stepping", cpu_info.stepping);
+}
+
+Value toJSON(
+    const TraceIntelPTSessionFileParser::JSONTraceIntelPTCPUInfo &cpu_info) {
+  return Value(Object{{"family", cpu_info.family},
+                      {"model", cpu_info.model},
+                      {"stepping", cpu_info.stepping},
+                      {"vendor", cpu_info.vendor}});
+}
+
 } // namespace json
 } // namespace llvm

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
index 6a896de09d000..ad902782ff68a 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
@@ -19,16 +19,16 @@ class TraceIntelPT;
 
 class TraceIntelPTSessionFileParser : public TraceSessionFileParser {
 public:
-  struct JSONPTCPU {
-    std::string vendor;
+  struct JSONTraceIntelPTCPUInfo {
     int64_t family;
     int64_t model;
     int64_t stepping;
+    std::string vendor;
   };
 
   struct JSONTraceIntelPTSettings
       : TraceSessionFileParser::JSONTracePluginSettings {
-    JSONPTCPU pt_cpu;
+    JSONTraceIntelPTCPUInfo cpuInfo;
   };
 
   /// See \a TraceSessionFileParser::TraceSessionFileParser for the description
@@ -52,11 +52,11 @@ class TraceIntelPTSessionFileParser : public TraceSessionFileParser {
   llvm::Expected<lldb::TraceSP> Parse();
 
   lldb::TraceSP
-  CreateTraceIntelPTInstance(const pt_cpu &pt_cpu,
+  CreateTraceIntelPTInstance(const pt_cpu &cpu_info,
                              std::vector<ParsedProcess> &parsed_processes);
 
 private:
-  pt_cpu ParsePTCPU(const JSONPTCPU &pt_cpu);
+  static pt_cpu ParsePTCPU(const JSONTraceIntelPTCPUInfo &cpu_info);
 
   const llvm::json::Value &m_trace_session_file;
 };
@@ -67,17 +67,20 @@ class TraceIntelPTSessionFileParser : public TraceSessionFileParser {
 namespace llvm {
 namespace json {
 
-bool fromJSON(
-    const Value &value,
-    lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::JSONPTCPU
-        &pt_cpu,
-    Path path);
-
 bool fromJSON(const Value &value,
               lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::
                   JSONTraceIntelPTSettings &plugin_settings,
               Path path);
 
+bool fromJSON(const llvm::json::Value &value,
+              lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::
+                  JSONTraceIntelPTCPUInfo &packet,
+              llvm::json::Path path);
+
+llvm::json::Value
+toJSON(const lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::
+           JSONTraceIntelPTCPUInfo &packet);
+
 } // namespace json
 } // namespace llvm
 

diff  --git a/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h b/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h
new file mode 100644
index 0000000000000..3c5f811acc10e
--- /dev/null
+++ b/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h
@@ -0,0 +1,20 @@
+//===-- forward-declarations.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H
+#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H
+
+namespace lldb_private {
+namespace trace_intel_pt {
+
+class TraceIntelPT;
+class ThreadDecoder;
+
+} // namespace trace_intel_pt
+} // namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H

diff  --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index 383ac5a6c53c2..ef92d26ef465d 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -66,7 +66,7 @@ add_lldb_library(lldbTarget
   ThreadPlanTracer.cpp
   ThreadPlanStack.cpp
   ThreadSpec.cpp
-  ThreadTrace.cpp
+  ThreadPostMortemTrace.cpp
   Trace.cpp
   TraceSessionFileParser.cpp
   UnixSignals.cpp

diff  --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 63673735ea836..6db410fa6bf0e 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -802,6 +802,7 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp,
             case eStopReasonExec:
             case eStopReasonThreadExiting:
             case eStopReasonInstrumentation:
+            case eStopReasonProcessorTrace:
               if (!other_thread)
                 other_thread = thread;
               break;
@@ -5958,7 +5959,7 @@ UtilityFunction *Process::GetLoadImageUtilityFunction(
   return m_dlopen_utility_func_up.get();
 }
 
-llvm::Expected<TraceTypeInfo> Process::GetSupportedTraceType() {
+llvm::Expected<TraceSupportedResponse> Process::TraceSupported() {
   if (!IsLiveDebugSession())
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "Can't trace a non-live process.");

diff  --git a/lldb/source/Target/ProcessTrace.cpp b/lldb/source/Target/ProcessTrace.cpp
index 95f87745b7249..c878a2ac4eb9c 100644
--- a/lldb/source/Target/ProcessTrace.cpp
+++ b/lldb/source/Target/ProcessTrace.cpp
@@ -87,8 +87,6 @@ void ProcessTrace::RefreshStateAfterStop() {}
 
 Status ProcessTrace::DoDestroy() { return Status(); }
 
-bool ProcessTrace::IsAlive() { return true; }
-
 size_t ProcessTrace::ReadMemory(addr_t addr, void *buf, size_t size,
                                 Status &error) {
   // Don't allow the caching that lldb_private::Process::ReadMemory does since

diff  --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 95efd0a17127b..ae29b42e0e50c 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -1044,6 +1044,30 @@ class StopInfoException : public StopInfo {
   }
 };
 
+// StopInfoProcessorTrace
+
+class StopInfoProcessorTrace : public StopInfo {
+public:
+  StopInfoProcessorTrace(Thread &thread, const char *description)
+      : StopInfo(thread, LLDB_INVALID_UID) {
+    if (description)
+      SetDescription(description);
+  }
+
+  ~StopInfoProcessorTrace() override = default;
+
+  StopReason GetStopReason() const override {
+    return eStopReasonProcessorTrace;
+  }
+
+  const char *GetDescription() override {
+    if (m_description.empty())
+      return "processor trace event";
+    else
+      return m_description.c_str();
+  }
+};
+
 // StopInfoThreadPlan
 
 class StopInfoThreadPlan : public StopInfo {
@@ -1161,6 +1185,11 @@ StopInfoSP StopInfo::CreateStopReasonWithException(Thread &thread,
   return StopInfoSP(new StopInfoException(thread, description));
 }
 
+StopInfoSP StopInfo::CreateStopReasonProcessorTrace(Thread &thread,
+                                                    const char *description) {
+  return StopInfoSP(new StopInfoProcessorTrace(thread, description));
+}
+
 StopInfoSP StopInfo::CreateStopReasonWithExec(Thread &thread) {
   return StopInfoSP(new StopInfoExec(thread));
 }

diff  --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index c6667ce942cd0..7c62904302c90 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -3075,7 +3075,27 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
 
 void Target::SetTrace(const TraceSP &trace_sp) { m_trace_sp = trace_sp; }
 
-const TraceSP &Target::GetTrace() { return m_trace_sp; }
+TraceSP &Target::GetTrace() { return m_trace_sp; }
+
+llvm::Expected<TraceSP &> Target::GetTraceOrCreate() {
+  if (!m_trace_sp && m_process_sp) {
+    llvm::Expected<TraceSupportedResponse> trace_type =
+        m_process_sp->TraceSupported();
+    if (!trace_type)
+      return llvm::createStringError(
+          llvm::inconvertibleErrorCode(), "Tracing is not supported. %s",
+          llvm::toString(trace_type.takeError()).c_str());
+    if (llvm::Expected<TraceSP> trace_sp =
+            Trace::FindPluginForLiveProcess(trace_type->name, *m_process_sp))
+      m_trace_sp = *trace_sp;
+    else
+      return llvm::createStringError(
+          llvm::inconvertibleErrorCode(),
+          "Couldn't start tracing the process. %s",
+          llvm::toString(trace_type.takeError()).c_str());
+  }
+  return m_trace_sp;
+}
 
 Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
   auto state = eStateInvalid;

diff  --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index e5271ccbe5148..57cfaddac6d23 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -1685,6 +1685,8 @@ std::string Thread::StopReasonAsString(lldb::StopReason reason) {
     return "thread exiting";
   case eStopReasonInstrumentation:
     return "instrumentation break";
+  case eStopReasonProcessorTrace:
+    return "processor trace";
   }
 
   return "StopReason = " + std::to_string(reason);

diff  --git a/lldb/source/Target/ThreadTrace.cpp b/lldb/source/Target/ThreadPostMortemTrace.cpp
similarity index 65%
rename from lldb/source/Target/ThreadTrace.cpp
rename to lldb/source/Target/ThreadPostMortemTrace.cpp
index 346f36a737d72..f8eb3e4f1f2d7 100644
--- a/lldb/source/Target/ThreadTrace.cpp
+++ b/lldb/source/Target/ThreadPostMortemTrace.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadTrace.cpp ---------------------------------------------------===//
+//===-- ThreadPostMortemTrace.cpp -----------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "lldb/Target/ThreadTrace.h"
+#include "lldb/Target/ThreadPostMortemTrace.h"
 
 #include <memory>
 
@@ -17,9 +17,9 @@
 using namespace lldb;
 using namespace lldb_private;
 
-void ThreadTrace::RefreshStateAfterStop() {}
+void ThreadPostMortemTrace::RefreshStateAfterStop() {}
 
-RegisterContextSP ThreadTrace::GetRegisterContext() {
+RegisterContextSP ThreadPostMortemTrace::GetRegisterContext() {
   if (!m_reg_context_sp)
     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
 
@@ -27,13 +27,15 @@ RegisterContextSP ThreadTrace::GetRegisterContext() {
 }
 
 RegisterContextSP
-ThreadTrace::CreateRegisterContextForFrame(StackFrame *frame) {
+ThreadPostMortemTrace::CreateRegisterContextForFrame(StackFrame *frame) {
   // Eventually this will calculate the register context based on the current
   // trace position.
   return std::make_shared<RegisterContextHistory>(
       *this, 0, GetProcess()->GetAddressByteSize(), LLDB_INVALID_ADDRESS);
 }
 
-bool ThreadTrace::CalculateStopInfo() { return false; }
+bool ThreadPostMortemTrace::CalculateStopInfo() { return false; }
 
-const FileSpec &ThreadTrace::GetTraceFile() const { return m_trace_file; }
+const FileSpec &ThreadPostMortemTrace::GetTraceFile() const {
+  return m_trace_file;
+}

diff  --git a/lldb/source/Target/Trace.cpp b/lldb/source/Target/Trace.cpp
index d19115b2d1f9a..e862d17e73c51 100644
--- a/lldb/source/Target/Trace.cpp
+++ b/lldb/source/Target/Trace.cpp
@@ -16,6 +16,7 @@
 #include "lldb/Target/Process.h"
 #include "lldb/Target/SectionLoadList.h"
 #include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPostMortemTrace.h"
 #include "lldb/Utility/Stream.h"
 
 using namespace lldb;
@@ -57,9 +58,10 @@ static Error createInvalidPlugInError(StringRef plugin_name) {
       plugin_name.data());
 }
 
-Expected<lldb::TraceSP> Trace::FindPlugin(Debugger &debugger,
-                                          const json::Value &trace_session_file,
-                                          StringRef session_file_dir) {
+Expected<lldb::TraceSP>
+Trace::FindPluginForPostMortemProcess(Debugger &debugger,
+                                      const json::Value &trace_session_file,
+                                      StringRef session_file_dir) {
   JSONSimpleTraceSession json_session;
   json::Path::Root root("traceSession");
   if (!json::fromJSON(trace_session_file, json_session, root))
@@ -72,6 +74,20 @@ Expected<lldb::TraceSP> Trace::FindPlugin(Debugger &debugger,
   return createInvalidPlugInError(json_session.trace.type);
 }
 
+Expected<lldb::TraceSP>
+Trace::FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process) {
+  if (!process.IsLiveDebugSession())
+    return createStringError(inconvertibleErrorCode(),
+                             "Can't trace non-live processes");
+
+  ConstString name(plugin_name);
+  if (auto create_callback =
+          PluginManager::GetTraceCreateCallbackForLiveProcess(name))
+    return create_callback(process);
+
+  return createInvalidPlugInError(plugin_name);
+}
+
 Expected<StringRef> Trace::FindPluginSchema(StringRef name) {
   ConstString plugin_name(name);
   StringRef schema = PluginManager::GetTraceSchema(plugin_name);
@@ -204,6 +220,12 @@ DumpInstructionInfo(Stream &s, const SymbolContext &sc,
 
 void Trace::DumpTraceInstructions(Thread &thread, Stream &s, size_t count,
                                   size_t end_position, bool raw) {
+  if (!IsTraced(thread)) {
+    s.Printf("thread #%u: tid = %" PRIu64 ", not traced\n", thread.GetIndexID(),
+             thread.GetID());
+    return;
+  }
+
   size_t instructions_count = GetInstructionCount(thread);
   s.Printf("thread #%u: tid = %" PRIu64 ", total instructions = %zu\n",
            thread.GetIndexID(), thread.GetID(), instructions_count);
@@ -266,3 +288,121 @@ void Trace::DumpTraceInstructions(Thread &thread, Stream &s, size_t count,
         return index < end_position;
       });
 }
+
+Error Trace::Start(const llvm::json::Value &request) {
+  if (!m_live_process)
+    return createStringError(inconvertibleErrorCode(),
+                             "Tracing requires a live process.");
+  return m_live_process->TraceStart(request);
+}
+
+Error Trace::StopProcess() {
+  if (!m_live_process)
+    return createStringError(inconvertibleErrorCode(),
+                             "Tracing requires a live process.");
+  return m_live_process->TraceStop(
+      TraceStopRequest(GetPluginName().AsCString()));
+}
+
+Error Trace::StopThreads(const std::vector<lldb::tid_t> &tids) {
+  if (!m_live_process)
+    return createStringError(inconvertibleErrorCode(),
+                             "Tracing requires a live process.");
+  return m_live_process->TraceStop(
+      TraceStopRequest(GetPluginName().AsCString(), tids));
+}
+
+Expected<std::string> Trace::GetLiveProcessState() {
+  if (!m_live_process)
+    return createStringError(inconvertibleErrorCode(),
+                             "Tracing requires a live process.");
+  return m_live_process->TraceGetState(GetPluginName().AsCString());
+}
+
+Optional<size_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid,
+                                                    llvm::StringRef kind) {
+  auto it = m_live_thread_data.find(tid);
+  if (it == m_live_thread_data.end())
+    return None;
+  std::unordered_map<std::string, size_t> &single_thread_data = it->second;
+  auto single_thread_data_it = single_thread_data.find(kind.str());
+  if (single_thread_data_it == single_thread_data.end())
+    return None;
+  return single_thread_data_it->second;
+}
+
+Optional<size_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
+  auto data_it = m_live_process_data.find(kind.str());
+  if (data_it == m_live_process_data.end())
+    return None;
+  return data_it->second;
+}
+
+Expected<std::vector<uint8_t>>
+Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
+  if (!m_live_process)
+    return createStringError(inconvertibleErrorCode(),
+                             "Tracing requires a live process.");
+  llvm::Optional<size_t> size = GetLiveThreadBinaryDataSize(tid, kind);
+  if (!size)
+    return createStringError(
+        inconvertibleErrorCode(),
+        "Tracing data \"%s\" is not available for thread %" PRIu64 ".",
+        kind.data(), tid);
+
+  TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(),
+                                    static_cast<int64_t>(tid), 0,
+                                    static_cast<int64_t>(*size)};
+  return m_live_process->TraceGetBinaryData(request);
+}
+
+Expected<std::vector<uint8_t>>
+Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
+  if (!m_live_process)
+    return createStringError(inconvertibleErrorCode(),
+                             "Tracing requires a live process.");
+  llvm::Optional<size_t> size = GetLiveProcessBinaryDataSize(kind);
+  if (!size)
+    return createStringError(
+        inconvertibleErrorCode(),
+        "Tracing data \"%s\" is not available for the process.", kind.data());
+
+  TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(),
+                                    None, 0, static_cast<int64_t>(*size)};
+  return m_live_process->TraceGetBinaryData(request);
+}
+
+void Trace::RefreshLiveProcessState() {
+  if (!m_live_process)
+    return;
+
+  uint32_t new_stop_id = m_live_process->GetStopID();
+  if (new_stop_id == m_stop_id)
+    return;
+
+  m_stop_id = new_stop_id;
+  m_live_thread_data.clear();
+
+  Expected<std::string> json_string = GetLiveProcessState();
+  if (!json_string) {
+    DoRefreshLiveProcessState(json_string.takeError());
+    return;
+  }
+  Expected<TraceGetStateResponse> live_process_state =
+      json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse");
+  if (!live_process_state) {
+    DoRefreshLiveProcessState(live_process_state.takeError());
+    return;
+  }
+
+  for (const TraceThreadState &thread_state :
+       live_process_state->tracedThreads) {
+    for (const TraceBinaryData &item : thread_state.binaryData)
+      m_live_thread_data[thread_state.tid][item.kind] = item.size;
+  }
+
+  for (const TraceBinaryData &item : live_process_state->processBinaryData)
+    m_live_process_data[item.kind] = item.size;
+
+  DoRefreshLiveProcessState(std::move(live_process_state));
+}

diff  --git a/lldb/source/Target/TraceSessionFileParser.cpp b/lldb/source/Target/TraceSessionFileParser.cpp
index 713fadc1eb4fe..006d74b28e8b0 100644
--- a/lldb/source/Target/TraceSessionFileParser.cpp
+++ b/lldb/source/Target/TraceSessionFileParser.cpp
@@ -14,7 +14,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
-#include "lldb/Target/ThreadTrace.h"
+#include "lldb/Target/ThreadPostMortemTrace.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -96,15 +96,16 @@ std::string TraceSessionFileParser::BuildSchema(StringRef plugin_schema) {
   return schema_builder.str();
 }
 
-ThreadTraceSP TraceSessionFileParser::ParseThread(ProcessSP &process_sp,
-                                                  const JSONThread &thread) {
+ThreadPostMortemTraceSP
+TraceSessionFileParser::ParseThread(ProcessSP &process_sp,
+                                    const JSONThread &thread) {
   lldb::tid_t tid = static_cast<lldb::tid_t>(thread.tid);
 
   FileSpec trace_file(thread.trace_file);
   NormalizePath(trace_file);
 
-  ThreadTraceSP thread_sp =
-      std::make_shared<ThreadTrace>(*process_sp, tid, trace_file);
+  ThreadPostMortemTraceSP thread_sp =
+      std::make_shared<ThreadPostMortemTrace>(*process_sp, tid, trace_file);
   process_sp->GetThreadList().AddThread(thread_sp);
   return thread_sp;
 }

diff  --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt
index 3aca72de6c659..6790e47d69f25 100644
--- a/lldb/source/Utility/CMakeLists.txt
+++ b/lldb/source/Utility/CMakeLists.txt
@@ -65,7 +65,8 @@ add_lldb_library(lldbUtility
   StructuredData.cpp
   TildeExpressionResolver.cpp
   Timer.cpp
-  TraceOptions.cpp
+  TraceGDBRemotePackets.cpp
+  TraceIntelPTGDBRemotePackets.cpp
   UnimplementedError.cpp
   UUID.cpp
   UriParser.cpp

diff  --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 211026535518d..6815ddf989840 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -303,18 +303,17 @@ 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;
-    if (PACKET_MATCHES("jLLDBTraceSupportedType"))
-      return eServerPacketType_jLLDBTraceSupportedType;
+
+    if (PACKET_MATCHES("jLLDBTraceSupported"))
+      return eServerPacketType_jLLDBTraceSupported;
+    if (PACKET_STARTS_WITH("jLLDBTraceStop:"))
+      return eServerPacketType_jLLDBTraceStop;
+    if (PACKET_STARTS_WITH("jLLDBTraceStart:"))
+      return eServerPacketType_jLLDBTraceStart;
+    if (PACKET_STARTS_WITH("jLLDBTraceGetState:"))
+      return eServerPacketType_jLLDBTraceGetState;
+    if (PACKET_STARTS_WITH("jLLDBTraceGetBinaryData:"))
+      return eServerPacketType_jLLDBTraceGetBinaryData;
     break;
 
   case 'v':

diff  --git a/lldb/source/Utility/TraceGDBRemotePackets.cpp b/lldb/source/Utility/TraceGDBRemotePackets.cpp
new file mode 100644
index 0000000000000..5c1326a5f353a
--- /dev/null
+++ b/lldb/source/Utility/TraceGDBRemotePackets.cpp
@@ -0,0 +1,130 @@
+//===-- TraceGDBRemotePackets.cpp -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/TraceGDBRemotePackets.h"
+
+using namespace llvm;
+using namespace llvm::json;
+
+namespace lldb_private {
+/// jLLDBTraceSupported
+/// \{
+bool fromJSON(const json::Value &value, TraceSupportedResponse &packet,
+              Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("description", packet.description) &&
+         o.map("name", packet.name);
+}
+
+json::Value toJSON(const TraceSupportedResponse &packet) {
+  return json::Value(
+      Object{{"description", packet.description}, {"name", packet.name}});
+}
+/// \}
+
+/// jLLDBTraceStart
+/// \{
+bool TraceStartRequest::IsProcessTracing() const { return !(bool)tids; }
+
+bool fromJSON(const json::Value &value, TraceStartRequest &packet, Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("type", packet.type) && o.map("tids", packet.tids);
+}
+
+json::Value toJSON(const TraceStartRequest &packet) {
+  return json::Value(Object{{"tids", packet.tids}, {"type", packet.type}});
+}
+/// \}
+
+/// jLLDBTraceStop
+/// \{
+TraceStopRequest::TraceStopRequest(llvm::StringRef type,
+                                   const std::vector<lldb::tid_t> &tids_)
+    : type(type) {
+  tids.emplace();
+  for (lldb::tid_t tid : tids_)
+    tids->push_back(static_cast<int64_t>(tid));
+}
+
+bool TraceStopRequest::IsProcessTracing() const { return !(bool)tids; }
+
+bool fromJSON(const json::Value &value, TraceStopRequest &packet, Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("type", packet.type) && o.map("tids", packet.tids);
+}
+
+json::Value toJSON(const TraceStopRequest &packet) {
+  return json::Value(Object{{"type", packet.type}, {"tids", packet.tids}});
+}
+/// \}
+
+/// jLLDBTraceGetState
+/// \{
+bool fromJSON(const json::Value &value, TraceGetStateRequest &packet,
+              Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("type", packet.type);
+}
+
+json::Value toJSON(const TraceGetStateRequest &packet) {
+  return json::Value(Object{{"type", packet.type}});
+}
+
+bool fromJSON(const json::Value &value, TraceBinaryData &packet, Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("kind", packet.kind) && o.map("size", packet.size);
+}
+
+json::Value toJSON(const TraceBinaryData &packet) {
+  return json::Value(Object{{"kind", packet.kind}, {"size", packet.size}});
+}
+
+bool fromJSON(const json::Value &value, TraceThreadState &packet, Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("tid", packet.tid) &&
+         o.map("binaryData", packet.binaryData);
+}
+
+json::Value toJSON(const TraceThreadState &packet) {
+  return json::Value(
+      Object{{"tid", packet.tid}, {"binaryData", packet.binaryData}});
+}
+
+bool fromJSON(const json::Value &value, TraceGetStateResponse &packet,
+              Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("tracedThreads", packet.tracedThreads) &&
+         o.map("processBinaryData", packet.processBinaryData);
+}
+
+json::Value toJSON(const TraceGetStateResponse &packet) {
+  return json::Value(Object{{"tracedThreads", packet.tracedThreads},
+                            {"processBinaryData", packet.processBinaryData}});
+}
+/// \}
+
+/// jLLDBTraceGetBinaryData
+/// \{
+json::Value toJSON(const TraceGetBinaryDataRequest &packet) {
+  return json::Value(Object{{"type", packet.type},
+                            {"kind", packet.kind},
+                            {"offset", packet.offset},
+                            {"tid", packet.tid},
+                            {"size", packet.size}});
+}
+
+bool fromJSON(const json::Value &value, TraceGetBinaryDataRequest &packet,
+              Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("type", packet.type) && o.map("kind", packet.kind) &&
+         o.map("tid", packet.tid) && o.map("offset", packet.offset) &&
+         o.map("size", packet.size);
+}
+/// \}
+
+} // namespace lldb_private

diff  --git a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
new file mode 100644
index 0000000000000..69f773f673bb2
--- /dev/null
+++ b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
@@ -0,0 +1,42 @@
+//===-- TraceIntelPTGDBRemotePackets.cpp ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
+
+using namespace llvm;
+using namespace llvm::json;
+
+namespace lldb_private {
+
+bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet,
+              Path path) {
+  ObjectMapper o(value, path);
+  if (!o || !fromJSON(value, (TraceStartRequest &)packet, path) ||
+      !o.map("threadBufferSize", packet.threadBufferSize) ||
+      !o.map("processBufferSizeLimit", packet.processBufferSizeLimit))
+    return false;
+  if (packet.tids && packet.processBufferSizeLimit) {
+    path.report("processBufferSizeLimit must be provided");
+    return false;
+  }
+  if (!packet.tids && !packet.processBufferSizeLimit) {
+    path.report("processBufferSizeLimit must not be provided");
+    return false;
+  }
+  return true;
+}
+
+json::Value toJSON(const TraceIntelPTStartRequest &packet) {
+  json::Value base = toJSON((const TraceStartRequest &)packet);
+  base.getAsObject()->try_emplace("threadBufferSize", packet.threadBufferSize);
+  base.getAsObject()->try_emplace("processBufferSizeLimit",
+                                  packet.processBufferSizeLimit);
+  return base;
+}
+
+} // namespace lldb_private

diff  --git a/lldb/source/Utility/TraceOptions.cpp b/lldb/source/Utility/TraceOptions.cpp
deleted file mode 100644
index 292fb600e6ed9..0000000000000
--- a/lldb/source/Utility/TraceOptions.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- TraceOptions.cpp ----------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/TraceOptions.h"
-
-using namespace lldb_private;
-
-namespace llvm {
-namespace json {
-
-bool fromJSON(const Value &value, TraceTypeInfo &info, Path path) {
-  ObjectMapper o(value, path);
-  if (!o)
-    return false;
-  o.map("description", info.description);
-  return o.map("name", info.name);
-}
-
-} // namespace json
-} // namespace llvm

diff  --git a/lldb/test/API/commands/trace/TestTraceLoad.py b/lldb/test/API/commands/trace/TestTraceLoad.py
index c48d468ce7845..66cb3b0a10568 100644
--- a/lldb/test/API/commands/trace/TestTraceLoad.py
+++ b/lldb/test/API/commands/trace/TestTraceLoad.py
@@ -59,7 +59,7 @@ def testLoadInvalidTraces(self):
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel" | "unknown",
       "family": integer,
       "model": integer,
@@ -73,13 +73,13 @@ def testLoadInvalidTraces(self):
 
         # Now we test a missing field in the intel-pt settings
         self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad4.json"), error=True,
-            substrs=['''error: missing value at traceSession.trace.pt_cpu.family
+            substrs=['''error: missing value at traceSession.trace.cpuInfo.family
 
 Context:
 {
   "processes": [],
   "trace": {
-    "pt_cpu": /* error: missing value */ {
+    "cpuInfo": /* error: missing value */ {
       "model": 79,
       "stepping": 1,
       "vendor": "intel"

diff  --git a/lldb/test/API/commands/trace/TestTraceSchema.py b/lldb/test/API/commands/trace/TestTraceSchema.py
index b30ed329152de..d0379014cd2aa 100644
--- a/lldb/test/API/commands/trace/TestTraceSchema.py
+++ b/lldb/test/API/commands/trace/TestTraceSchema.py
@@ -25,7 +25,7 @@ def testAllSchemas(self):
         self.expect("trace schema all", substrs=['''{
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel" | "unknown",
       "family": integer,
       "model": integer,

diff  --git a/lldb/test/API/commands/trace/TestTraceStartStop.py b/lldb/test/API/commands/trace/TestTraceStartStop.py
index 4984365cb898c..ad301a575b8f6 100644
--- a/lldb/test/API/commands/trace/TestTraceStartStop.py
+++ b/lldb/test/API/commands/trace/TestTraceStartStop.py
@@ -3,7 +3,9 @@
 from lldbsuite.test import lldbutil
 from lldbsuite.test.decorators import *
 
-class TestTraceLoad(TestBase):
+ADDRESS_REGEX = '0x[0-9a-fA-F]*'
+
+class TestTraceStartStop(TestBase):
 
     mydir = TestBase.compute_mydir(__file__)
     NO_DEBUG_INFO_TESTCASE = True
@@ -21,14 +23,30 @@ def testStartStopSessionFileThreads(self):
         # it should fail for processes from json session files
         self.expect("trace load -v " + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"))
         self.expect("thread trace start", error=True,
-            substrs=["error: Tracing is not supported. Can't trace a non-live process"])
+            substrs=["error: Process must be alive"])
 
         # the help command should be the generic one, as it's not a live process
         self.expectGenericHelpMessageForStartCommand()
 
-        # this should fail because 'trace stop' is not yet implemented
-        self.expect("thread trace stop", error=True,
-            substrs=["error: Failed stopping thread 3842849"])
+        self.expect("thread trace stop", error=True)
+
+    def testStartWithNoProcess(self):
+        self.expect("thread trace start", error=True, 
+            substrs=["error: Process not available."])
+
+
+    def testStartSessionWithWrongSize(self):
+        self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out"))
+        self.expect("b main")
+        self.expect("r")
+        self.expect("thread trace start -s 2000", error=True, 
+            substrs=["The trace buffer size must be a power of 2", "It was 2000"])
+        self.expect("thread trace start -s 5000", error=True,
+            substrs=["The trace buffer size must be a power of 2", "It was 5000"])
+        self.expect("thread trace start -s 0", error=True,
+            substrs=["The trace buffer size must be a power of 2", "It was 0"])
+        self.expect("thread trace start -s 1048576")
+        
 
     @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
     def testStartStopLiveThreads(self):
@@ -49,20 +67,58 @@ def testStartStopLiveThreads(self):
 
         self.expect("r")
 
+        # This fails because "trace start" hasn't been called yet
+        self.expect("thread trace stop", error=True,
+            substrs=["error: Process is not being traced"])
+
+
         # the help command should be the intel-pt one now
         self.expect("help thread trace start",
             substrs=["Start tracing one or more threads with intel-pt.",
                      "Syntax: thread trace start [<thread-index> <thread-index> ...] [<intel-pt-options>]"])
 
-        self.expect("thread trace start",
-            patterns=["would trace tid .* with size_in_kb 4 and custom_config 0"])
-
-        self.expect("thread trace start --size 20 --custom-config 1",
-            patterns=["would trace tid .* with size_in_kb 20 and custom_config 1"])
-
-        # This fails because "trace stop" is not yet implemented.
+        # We start tracing with a small buffer size
+        self.expect("thread trace start 1 --size 4096")
+        
+        # We fail if we try to trace again
+        self.expect("thread trace start", error=True, 
+            substrs=["error: Thread ", "already traced"])
+
+        # We can reconstruct the single instruction executed in the first line
+        self.expect("n")
+        self.expect("thread trace dump instructions", 
+            patterns=[f'''thread #1: tid = .*, total instructions = 1
+  a.out`main \+ 4 at main.cpp:2
+    \[0\] {ADDRESS_REGEX}    movl'''])
+
+        # We can reconstruct the instructions up to the second line
+        self.expect("n")
+        self.expect("thread trace dump instructions", 
+            patterns=[f'''thread #1: tid = .*, total instructions = 5
+  a.out`main \+ 4 at main.cpp:2
+    \[0\] {ADDRESS_REGEX}    movl .*
+  a.out`main \+ 11 at main.cpp:4
+    \[1\] {ADDRESS_REGEX}    movl .*
+    \[2\] {ADDRESS_REGEX}    jmp  .* ; <\+28> at main.cpp:4
+  a.out`main \+ 28 at main.cpp:4
+    \[3\] {ADDRESS_REGEX}    cmpl .*
+    \[4\] {ADDRESS_REGEX}    jle  .* ; <\+20> at main.cpp:5'''])
+
+        # We stop tracing
+        self.expect("thread trace stop")
+
+        # We can't stop twice
         self.expect("thread trace stop", error=True,
-            substrs=["error: Process is not being traced"])
+            substrs=["error: Thread ", "not currently traced"])
+
+        # We trace again from scratch, this time letting LLDB to pick the current
+        # thread
+        self.expect("thread trace start")
+        self.expect("n")
+        self.expect("thread trace dump instructions", 
+            patterns=[f'''thread #1: tid = .*, total instructions = 1
+  a.out`main \+ 20 at main.cpp:5
+    \[0\] {ADDRESS_REGEX}    xorl'''])
 
         self.expect("c")
         # Now the process has finished, so the commands should fail

diff  --git a/lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file-no-ld.json b/lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file-no-ld.json
index 5a553dc9dade7..b8c6d32473dbd 100644
--- a/lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file-no-ld.json
+++ b/lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file-no-ld.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "family": 6,
       "model": 79,

diff  --git a/lldb/test/API/commands/trace/intelpt-trace/trace.json b/lldb/test/API/commands/trace/intelpt-trace/trace.json
index 543b71d0cefec..9104c572e3fb7 100644
--- a/lldb/test/API/commands/trace/intelpt-trace/trace.json
+++ b/lldb/test/API/commands/trace/intelpt-trace/trace.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "family": 6,
       "model": 79,

diff  --git a/lldb/test/API/commands/trace/intelpt-trace/trace_2threads.json b/lldb/test/API/commands/trace/intelpt-trace/trace_2threads.json
index 87609f2e3b277..f73944d1fa186 100644
--- a/lldb/test/API/commands/trace/intelpt-trace/trace_2threads.json
+++ b/lldb/test/API/commands/trace/intelpt-trace/trace_2threads.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "family": 6,
       "model": 79,

diff  --git a/lldb/test/API/commands/trace/intelpt-trace/trace_bad.json b/lldb/test/API/commands/trace/intelpt-trace/trace_bad.json
index 9d00a82ebcf78..0232f9ffb80d4 100644
--- a/lldb/test/API/commands/trace/intelpt-trace/trace_bad.json
+++ b/lldb/test/API/commands/trace/intelpt-trace/trace_bad.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "family": 6,
       "model": 79,

diff  --git a/lldb/test/API/commands/trace/intelpt-trace/trace_bad2.json b/lldb/test/API/commands/trace/intelpt-trace/trace_bad2.json
index 16ece129c8d8b..f944c7362d048 100644
--- a/lldb/test/API/commands/trace/intelpt-trace/trace_bad2.json
+++ b/lldb/test/API/commands/trace/intelpt-trace/trace_bad2.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "family": 6,
       "model": 79,

diff  --git a/lldb/test/API/commands/trace/intelpt-trace/trace_bad3.json b/lldb/test/API/commands/trace/intelpt-trace/trace_bad3.json
index dc587a8a4c523..63eafbc13efbf 100644
--- a/lldb/test/API/commands/trace/intelpt-trace/trace_bad3.json
+++ b/lldb/test/API/commands/trace/intelpt-trace/trace_bad3.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "family": 6,
       "model": 79,

diff  --git a/lldb/test/API/commands/trace/intelpt-trace/trace_bad4.json b/lldb/test/API/commands/trace/intelpt-trace/trace_bad4.json
index 08084829eda60..7224ee5f1f3c2 100644
--- a/lldb/test/API/commands/trace/intelpt-trace/trace_bad4.json
+++ b/lldb/test/API/commands/trace/intelpt-trace/trace_bad4.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "model": 79,
       "stepping": 1

diff  --git a/lldb/test/API/commands/trace/intelpt-trace/trace_bad5.json b/lldb/test/API/commands/trace/intelpt-trace/trace_bad5.json
index b75db43554598..1664072aa3b8d 100644
--- a/lldb/test/API/commands/trace/intelpt-trace/trace_bad5.json
+++ b/lldb/test/API/commands/trace/intelpt-trace/trace_bad5.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "family": 6,
       "model": 79,

diff  --git a/lldb/test/API/commands/trace/intelpt-trace/trace_bad_image.json b/lldb/test/API/commands/trace/intelpt-trace/trace_bad_image.json
index 013e4c5bd2bf6..901f41901842c 100644
--- a/lldb/test/API/commands/trace/intelpt-trace/trace_bad_image.json
+++ b/lldb/test/API/commands/trace/intelpt-trace/trace_bad_image.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "family": 6,
       "model": 79,

diff  --git a/lldb/test/API/commands/trace/intelpt-trace/trace_wrong_cpu.json b/lldb/test/API/commands/trace/intelpt-trace/trace_wrong_cpu.json
index a39edc8a335e6..318aaba8154ff 100644
--- a/lldb/test/API/commands/trace/intelpt-trace/trace_wrong_cpu.json
+++ b/lldb/test/API/commands/trace/intelpt-trace/trace_wrong_cpu.json
@@ -1,7 +1,7 @@
 {
   "trace": {
     "type": "intel-pt",
-    "pt_cpu": {
+    "cpuInfo": {
       "vendor": "intel",
       "family": 2123123,
       "model": 12123123,

diff  --git a/lldb/test/API/commands/trace/multiple-threads/Makefile b/lldb/test/API/commands/trace/multiple-threads/Makefile
new file mode 100644
index 0000000000000..d45370002a4bd
--- /dev/null
+++ b/lldb/test/API/commands/trace/multiple-threads/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+ENABLE_THREADS = YES
+
+include Makefile.rules

diff  --git a/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py b/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
new file mode 100644
index 0000000000000..d3fdb47605bd6
--- /dev/null
+++ b/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
@@ -0,0 +1,152 @@
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+from lldbsuite.test.decorators import *
+
+ADDRESS_REGEX = '0x[0-9a-fA-F]*'
+
+class TestTraceStartStopMultipleThreads(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def setUp(self):
+        TestBase.setUp(self)
+        if 'intel-pt' not in configuration.enabled_plugins:
+            self.skipTest("The intel-pt test plugin is not enabled")
+
+    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
+    def testStartMultipleLiveThreads(self):
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        self.expect("b main")
+        self.expect("b 6")
+        self.expect("b 11")
+
+        self.expect("r")
+        self.expect("proce trace start")
+
+
+        # We'll see here the first thread
+        self.expect("continue")
+        self.expect("thread trace dump instructions", substrs=['main.cpp:9'])
+        
+        # We'll see here the second thread
+        self.expect("continue")
+        self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
+
+    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
+    def testStartMultipleLiveThreadsWithStops(self):
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        self.expect("b main")
+        self.expect("b 6")
+        self.expect("b 11")
+
+        self.expect("r")
+        self.expect("process trace start")
+
+
+        # We'll see here the first thread
+        self.expect("continue")
+
+        # We are in thread 2
+        self.expect("thread trace dump instructions", substrs=['main.cpp:9'])
+        self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
+
+        # We stop tracing it
+        self.expect("thread trace stop 2")
+
+        # The trace is still in memory
+        self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
+        
+        # We'll stop at the next breakpoint, thread 2 will be still alive, but not traced. Thread 3 will be traced
+        self.expect("continue")
+        self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
+        self.expect("thread trace dump instructions 3", substrs=['main.cpp:4'])
+
+        self.expect("thread trace dump instructions 2", substrs=['not traced'])
+
+    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
+    def testStartMultipleLiveThreadsWithStops(self):
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        self.expect("b main")
+        self.expect("b 6")
+        self.expect("b 11")
+
+        self.expect("r")
+        self.expect("process trace start")
+
+        # We'll see here the first thread
+        self.expect("continue")
+
+        # We are in thread 2
+        self.expect("thread trace dump instructions", substrs=['main.cpp:9'])
+        self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
+
+        # We stop tracing all
+        self.expect("thread trace stop all")
+
+        # The trace is still in memory
+        self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
+        
+        # We'll stop at the next breakpoint in thread 3, thread 2 and 3 will be alive, but only 3 traced.
+        self.expect("continue")
+        self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
+        self.expect("thread trace dump instructions 3", substrs=['main.cpp:4'])
+        self.expect("thread trace dump instructions 1", substrs=['not traced'])
+        self.expect("thread trace dump instructions 2", substrs=['not traced'])
+
+    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
+    def testStartMultipleLiveThreadsWithThreadStartAll(self):
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        self.expect("b main")
+        self.expect("b 6")
+        self.expect("b 11")
+
+        self.expect("r")
+
+        self.expect("continue")
+        # We are in thread 2
+        self.expect("thread trace start all")
+        # Now we have instructions in thread's 2 trace
+        self.expect("n")
+
+        self.expect("thread trace dump instructions 2", substrs=['main.cpp:11'])
+
+        # We stop tracing all
+        self.runCmd("thread trace stop all")
+
+        # The trace is still in memory
+        self.expect("thread trace dump instructions 2", substrs=['main.cpp:11'])
+        
+        # We'll stop at the next breakpoint in thread 3, and nothing should be traced
+        self.expect("continue")
+        self.expect("thread trace dump instructions 3", substrs=['not traced'])
+        self.expect("thread trace dump instructions 1", substrs=['not traced'])
+        self.expect("thread trace dump instructions 2", substrs=['not traced'])
+
+    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
+    def testStartMultipleLiveThreadsWithSmallTotalLimit(self):
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        self.expect("b main")
+        self.expect("r")
+        # trace the entire process with enough total size for 1 thread trace
+        self.expect("process trace start -l 5000")
+        # we get the stop event when trace 2 appears and can't be traced
+        self.expect("c", substrs=['Thread', "can't be traced"])
+        # we get the stop event when trace 3 appears and can't be traced
+        self.expect("c", substrs=['Thread', "can't be traced"])

diff  --git a/lldb/test/API/commands/trace/multiple-threads/main.cpp b/lldb/test/API/commands/trace/multiple-threads/main.cpp
new file mode 100644
index 0000000000000..f6c58af9cbf71
--- /dev/null
+++ b/lldb/test/API/commands/trace/multiple-threads/main.cpp
@@ -0,0 +1,20 @@
+#include <chrono>
+#include <thread>
+
+void f3() {
+  int m;
+  m = 2; // thread 3
+}
+
+void f2() {
+  int n;
+  n = 1; // thread 2
+  std::thread t3(f3);
+  t3.join();
+}
+
+int main() { // main
+  std::thread t2(f2);
+  t2.join();
+  return 0;
+}

diff  --git a/lldb/tools/lldb-vscode/JSONUtils.cpp b/lldb/tools/lldb-vscode/JSONUtils.cpp
index 0b37967e37a9d..3a9240749a7ff 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.cpp
+++ b/lldb/tools/lldb-vscode/JSONUtils.cpp
@@ -867,9 +867,10 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
   case lldb::eStopReasonInstrumentation:
     body.try_emplace("reason", "breakpoint");
     break;
-  case lldb::eStopReasonSignal:
-    body.try_emplace("reason", "exception");
+  case lldb::eStopReasonProcessorTrace:
+    body.try_emplace("reason", "processor trace");
     break;
+  case lldb::eStopReasonSignal:
   case lldb::eStopReasonException:
     body.try_emplace("reason", "exception");
     break;

diff  --git a/lldb/tools/lldb-vscode/LLDBUtils.cpp b/lldb/tools/lldb-vscode/LLDBUtils.cpp
index 81b5a789d1da0..a5bc400dfccce 100644
--- a/lldb/tools/lldb-vscode/LLDBUtils.cpp
+++ b/lldb/tools/lldb-vscode/LLDBUtils.cpp
@@ -55,6 +55,7 @@ bool ThreadHasStopReason(lldb::SBThread &thread) {
   case lldb::eStopReasonSignal:
   case lldb::eStopReasonException:
   case lldb::eStopReasonExec:
+  case lldb::eStopReasonProcessorTrace:
     return true;
   case lldb::eStopReasonThreadExiting:
   case lldb::eStopReasonInvalid:

diff  --git a/lldb/unittests/Process/Linux/CMakeLists.txt b/lldb/unittests/Process/Linux/CMakeLists.txt
index ab6eaa4454165..ae021023cf7f5 100644
--- a/lldb/unittests/Process/Linux/CMakeLists.txt
+++ b/lldb/unittests/Process/Linux/CMakeLists.txt
@@ -1,9 +1,9 @@
-add_lldb_unittest(ProcessorTraceTests
-  ProcessorTraceTest.cpp
+add_lldb_unittest(TraceIntelPTTests
+  IntelPTManagerTests.cpp
 
   LINK_LIBS
     lldbPluginProcessLinux
   )
 
-target_include_directories(ProcessorTraceTests PRIVATE
+target_include_directories(TraceIntelPTTests PRIVATE
   ${LLDB_SOURCE_DIR}/source/Plugins/Process/Linux)

diff  --git a/lldb/unittests/Process/Linux/ProcessorTraceTest.cpp b/lldb/unittests/Process/Linux/IntelPTManagerTests.cpp
similarity index 96%
rename from lldb/unittests/Process/Linux/ProcessorTraceTest.cpp
rename to lldb/unittests/Process/Linux/IntelPTManagerTests.cpp
index 3615135cccb46..76eb78a51935d 100644
--- a/lldb/unittests/Process/Linux/ProcessorTraceTest.cpp
+++ b/lldb/unittests/Process/Linux/IntelPTManagerTests.cpp
@@ -1,4 +1,4 @@
-//===-- ProcessorTraceMonitorTest.cpp -------------------------------------===//
+//===-- IntelPTManagerTests.cpp -------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -8,7 +8,7 @@
 
 #include "gtest/gtest.h"
 
-#include "ProcessorTrace.h"
+#include "IntelPTManager.h"
 #include "llvm/ADT/ArrayRef.h"
 
 
@@ -22,7 +22,7 @@ size_t ReadCylicBufferWrapper(void *buf, size_t buf_size, void *cyc_buf,
                                      buf_size);
   llvm::MutableArrayRef<uint8_t> src(reinterpret_cast<uint8_t *>(cyc_buf),
                                      cyc_buf_size);
-  ProcessorTraceMonitor::ReadCyclicBuffer(dst, src, cyc_start, offset);
+  IntelPTThreadTrace::ReadCyclicBuffer(dst, src, cyc_start, offset);
   return dst.size();
 }
 

diff  --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
index 2cca197f63a1e..0a9a42a81fde3 100644
--- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -381,12 +381,12 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
   EXPECT_FALSE(result.get().Success());
 }
 
-TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedTypePacket) {
-  TraceTypeInfo trace_type;
+TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedPacket) {
+  TraceSupportedResponse trace_type;
   std::string error_message;
   auto callback = [&] {
-    if (llvm::Expected<TraceTypeInfo> trace_type_or_err =
-            client.SendGetSupportedTraceType()) {
+    if (llvm::Expected<TraceSupportedResponse> trace_type_or_err =
+            client.SendTraceSupported()) {
       trace_type = *trace_type_or_err;
       error_message = "";
       return true;
@@ -402,7 +402,7 @@ TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedTypePacket) {
     std::future<bool> result = std::async(std::launch::async, callback);
 
     HandlePacket(
-        server, "jLLDBTraceSupportedType",
+        server, "jLLDBTraceSupported",
         R"({"name":"intel-pt","description":"Intel Processor Trace"}])");
 
     EXPECT_TRUE(result.get());
@@ -414,17 +414,17 @@ TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedTypePacket) {
   {
     std::future<bool> result = std::async(std::launch::async, callback);
 
-    HandlePacket(server, "jLLDBTraceSupportedType", R"({"type":"intel-pt"}])");
+    HandlePacket(server, "jLLDBTraceSupported", R"({"type":"intel-pt"}])");
 
     EXPECT_FALSE(result.get());
-    ASSERT_STREQ(error_message.c_str(), "missing value at (root).name");
+    ASSERT_STREQ(error_message.c_str(), "missing value at (root).description");
   }
 
   // Error response
   {
     std::future<bool> result = std::async(std::launch::async, callback);
 
-    HandlePacket(server, "jLLDBTraceSupportedType", "E23");
+    HandlePacket(server, "jLLDBTraceSupported", "E23");
 
     EXPECT_FALSE(result.get());
   }
@@ -433,7 +433,7 @@ TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedTypePacket) {
   {
     std::future<bool> result = std::async(std::launch::async, callback);
 
-    HandlePacket(server, "jLLDBTraceSupportedType",
+    HandlePacket(server, "jLLDBTraceSupported",
                  "E23;50726F63657373206E6F742072756E6E696E672E");
 
     EXPECT_FALSE(result.get());
@@ -441,197 +441,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedTypePacket) {
   }
 }
 
-TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
-  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(), 1u);
-
-  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) {
-  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) {
-  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(), 3u);
-  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(), 0u);
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) {
-  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(), 3u);
-  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(), 0u);
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) {
-  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(), 8192u);
-  ASSERT_EQ(options.getMetaDataBufferSize(), 8192u);
-  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(), eStructuredDataTypeDictionary);
-  ASSERT_TRUE(custom_params->GetValueForKeyAsInteger("psb", psb_value));
-  ASSERT_EQ(psb_value, 1u);
-  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());
-}
-
 TEST_F(GDBRemoteCommunicationClientTest, GetQOffsets) {
   const auto &GetQOffsets = [&](llvm::StringRef response) {
     std::future<Optional<QOffsets>> result = std::async(


        


More information about the lldb-commits mailing list