wallace updated this revision to Diff 298768.
wallace added a comment.

removing unwanted changes in lldb/tools/intel-features/intel-pt/Decoder.cpp


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D89283/new/

https://reviews.llvm.org/D89283

Files:
  lldb/include/lldb/Target/ProcessTrace.h
  lldb/include/lldb/Target/Trace.h
  lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt
  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/Target/ProcessTrace.cpp
  lldb/source/Target/Trace.cpp
  lldb/source/Target/TraceSessionFileParser.cpp
  lldb/test/API/commands/trace/TestTraceDumpInstructions.py
  lldb/test/API/commands/trace/intelpt-trace-multi-file/a.out
  lldb/test/API/commands/trace/intelpt-trace-multi-file/bar.cpp
  lldb/test/API/commands/trace/intelpt-trace-multi-file/bar.h
  lldb/test/API/commands/trace/intelpt-trace-multi-file/foo.cpp
  lldb/test/API/commands/trace/intelpt-trace-multi-file/foo.h
  lldb/test/API/commands/trace/intelpt-trace-multi-file/ld-2.17.so
  lldb/test/API/commands/trace/intelpt-trace-multi-file/libbar.so
  lldb/test/API/commands/trace/intelpt-trace-multi-file/libfoo.so
  lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp
  lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file-no-ld.json
  lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file.json
  lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file.trace
  lldb/test/API/commands/trace/intelpt-trace/trace_bad_image.json
  lldb/test/API/commands/trace/intelpt-trace/trace_wrong_cpu.json
  llvm/include/llvm/Support/Error.h

Index: llvm/include/llvm/Support/Error.h
===================================================================
--- llvm/include/llvm/Support/Error.h
+++ llvm/include/llvm/Support/Error.h
@@ -1007,6 +1007,17 @@
   handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
 }
 
+/// Consume an Expected without doing anything. This method should be used
+/// only where the expected result is irrelevant.
+///
+/// Uses of this method are potentially indicative of design problems: If it's
+/// legitimate to do nothing while processing an "expected", the
+/// expected-producer might be more clearly refactored to return an Optional<T>.
+template <typename T> inline void consumeExpected(Expected<T> E) {
+  if (!E)
+    consumeError(E.takeError());
+}
+
 /// Convert an Expected to an Optional without doing anything. This method
 /// should be used only where an error can be considered a reasonable and
 /// expected return value.
Index: lldb/test/API/commands/trace/intelpt-trace/trace_wrong_cpu.json
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace/trace_wrong_cpu.json
@@ -0,0 +1,31 @@
+{
+  "trace": {
+    "type": "intel-pt",
+    "pt_cpu": {
+      "vendor": "intel",
+      "family": 2123123,
+      "model": 12123123,
+      "stepping": 1231231
+    }
+  },
+  "processes": [
+    {
+      "pid": 1234,
+      "triple": "x86_64-*-linux",
+      "threads": [
+        {
+          "tid": 3842849,
+          "traceFile": "3842849.trace"
+        }
+      ],
+      "modules": [
+        {
+          "file": "a.out",
+          "systemPath": "a.out",
+          "loadAddress": "0x0000000000400000",
+          "uuid": "6AA9A4E2-6F28-2F33-377D-59FECE874C71-5B41261A"
+        }
+      ]
+    }
+  ]
+}
Index: lldb/test/API/commands/trace/intelpt-trace/trace_bad_image.json
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace/trace_bad_image.json
@@ -0,0 +1,31 @@
+{
+  "trace": {
+    "type": "intel-pt",
+    "pt_cpu": {
+      "vendor": "intel",
+      "family": 6,
+      "model": 79,
+      "stepping": 1
+    }
+  },
+  "processes": [
+    {
+      "pid": 1234,
+      "triple": "x86_64-*-linux",
+      "threads": [
+        {
+          "tid": 3842849,
+          "traceFile": "3842849.trace"
+        }
+      ],
+      "modules": [
+        {
+          "file": "a.out",
+          "systemPath": "a.out",
+          "loadAddress": "0x0000000000FFFFF0",
+          "uuid": "6AA9A4E2-6F28-2F33-377D-59FECE874C71-5B41261A"
+        }
+      ]
+    }
+  ]
+}
Index: lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file.json
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file.json
@@ -0,0 +1,49 @@
+{
+  "trace": {
+    "type": "intel-pt",
+    "pt_cpu": {
+      "vendor": "intel",
+      "family": 6,
+      "model": 79,
+      "stepping": 1
+    }
+  },
+  "processes": [
+    {
+      "pid": 815455,
+      "triple": "x86_64-*-linux",
+      "threads": [
+        {
+          "tid": 815455,
+          "traceFile": "multi-file.trace"
+        }
+      ],
+      "modules": [
+        {
+          "file": "a.out",
+          "systemPath": "a.out",
+          "loadAddress": "0x0000000000400000",
+          "uuid": "729BF711-43CB-0017-AADF-83304FEA5EC4-D46B45DD"
+        },
+        {
+          "file": "libfoo.so",
+          "systemPath": "libfoo.so",
+          "loadAddress": "0x00007ffff7bd9000",
+          "uuid": "B30FFEDA-8BB2-3D08-4580-C5937ED11E2B-21BE778C"
+        },
+        {
+          "file": "libbar.so",
+          "systemPath": "libbar.so",
+          "loadAddress": "0x00007ffff79d7000",
+          "uuid": "6633B038-EA73-D1A6-FF9A-7D0C0EDF733D-95FEA2CC"
+        },
+        {
+          "file": "ld-2.17.so",
+          "systemPath": "ld-2.17.so",
+          "loadAddress": "0x00007ffff7ddb000",
+          "uuid": "27FFD1FB-C695-69C7-76E6-66474EED7233-95E6D727"
+        }
+      ]
+    }
+  ]
+}
Index: lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file-no-ld.json
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace-multi-file/multi-file-no-ld.json
@@ -0,0 +1,43 @@
+{
+  "trace": {
+    "type": "intel-pt",
+    "pt_cpu": {
+      "vendor": "intel",
+      "family": 6,
+      "model": 79,
+      "stepping": 1
+    }
+  },
+  "processes": [
+    {
+      "pid": 815455,
+      "triple": "x86_64-*-linux",
+      "threads": [
+        {
+          "tid": 815455,
+          "traceFile": "multi-file.trace"
+        }
+      ],
+      "modules": [
+        {
+          "file": "a.out",
+          "systemPath": "a.out",
+          "loadAddress": "0x0000000000400000",
+          "uuid": "729BF711-43CB-0017-AADF-83304FEA5EC4-D46B45DD"
+        },
+        {
+          "file": "libfoo.so",
+          "systemPath": "libfoo.so",
+          "loadAddress": "0x00007ffff7bd9000",
+          "uuid": "B30FFEDA-8BB2-3D08-4580-C5937ED11E2B-21BE778C"
+        },
+        {
+          "file": "libbar.so",
+          "systemPath": "libbar.so",
+          "loadAddress": "0x00007ffff79d7000",
+          "uuid": "6633B038-EA73-D1A6-FF9A-7D0C0EDF733D-95FEA2CC"
+        }
+      ]
+    }
+  ]
+}
Index: lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp
@@ -0,0 +1,7 @@
+#include "foo.h"
+
+int main() {
+  int res = foo();
+  res++;
+  return res;
+}
Index: lldb/test/API/commands/trace/intelpt-trace-multi-file/foo.h
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace-multi-file/foo.h
@@ -0,0 +1 @@
+int foo();
Index: lldb/test/API/commands/trace/intelpt-trace-multi-file/foo.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace-multi-file/foo.cpp
@@ -0,0 +1,7 @@
+#include "bar.h"
+
+int foo() {
+  int y = bar();
+  y++;
+  return y;
+}
Index: lldb/test/API/commands/trace/intelpt-trace-multi-file/bar.h
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace-multi-file/bar.h
@@ -0,0 +1 @@
+int bar();
Index: lldb/test/API/commands/trace/intelpt-trace-multi-file/bar.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace-multi-file/bar.cpp
@@ -0,0 +1,5 @@
+int bar() {
+  int x = 1;
+  x++;
+  return x;
+}
Index: lldb/test/API/commands/trace/TestTraceDumpInstructions.py
===================================================================
--- lldb/test/API/commands/trace/TestTraceDumpInstructions.py
+++ lldb/test/API/commands/trace/TestTraceDumpInstructions.py
@@ -12,7 +12,7 @@
         TestBase.setUp(self)
         if 'intel-pt' not in configuration.enabled_plugins:
             self.skipTest("The intel-pt test plugin is not enabled")
-
+  
     def testErrorMessages(self):
         # We first check the output when there are no targets
         self.expect("thread trace dump instructions",
@@ -39,18 +39,41 @@
             substrs=["intel-pt"])
 
         self.expect("thread trace dump instructions",
-            substrs=['thread #1: tid = 3842849, total instructions = 1000',
-                     'would print 20 instructions from position 0'])
+            substrs=['''thread #1: tid = 3842849, total instructions = 21
+  [ 0] 0x40052d
+  [ 1] 0x400529
+  [ 2] 0x400525
+  [ 3] 0x400521
+  [ 4] 0x40052d
+  [ 5] 0x400529
+  [ 6] 0x400525
+  [ 7] 0x400521
+  [ 8] 0x40052d
+  [ 9] 0x400529
+  [10] 0x400525
+  [11] 0x400521
+  [12] 0x40052d
+  [13] 0x400529
+  [14] 0x400525
+  [15] 0x400521
+  [16] 0x40052d
+  [17] 0x400529
+  [18] 0x40051f
+  [19] 0x400518'''])
 
         # We check if we can pass count and offset
         self.expect("thread trace dump instructions --count 5 --start-position 10",
-            substrs=['thread #1: tid = 3842849, total instructions = 1000',
-                     'would print 5 instructions from position 10'])
+            substrs=['''thread #1: tid = 3842849, total instructions = 21
+  [10] 0x400525
+  [11] 0x400521
+  [12] 0x40052d
+  [13] 0x400529
+  [14] 0x400525'''])
 
         # We check if we can access the thread by index id
         self.expect("thread trace dump instructions 1",
-            substrs=['thread #1: tid = 3842849, total instructions = 1000',
-                     'would print 20 instructions from position 0'])
+            substrs=['''thread #1: tid = 3842849, total instructions = 21
+  [ 0] 0x40052d'''])
 
         # We check that we get an error when using an invalid thread index id
         self.expect("thread trace dump instructions 10", error=True,
@@ -61,32 +84,141 @@
         self.expect("trace load -v " + os.path.join(self.getSourceDir(), "intelpt-trace", "trace_2threads.json"))
 
         # We print the instructions of two threads simultaneously
-        self.expect("thread trace dump instructions 1 2",
-            substrs=['''thread #1: tid = 3842849, total instructions = 1000
-  would print 20 instructions from position 0
-thread #2: tid = 3842850, total instructions = 1000
-  would print 20 instructions from position 0'''])
+        self.expect("thread trace dump instructions 1 2 --count 2",
+            substrs=['''thread #1: tid = 3842849, total instructions = 21
+  [0] 0x40052d
+  [1] 0x400529
+thread #2: tid = 3842850, total instructions = 21
+  [0] 0x40052d
+  [1] 0x400529'''])
 
         # We use custom --count and --start-position, saving the command to history for later
         ci = self.dbg.GetCommandInterpreter()
 
         result = lldb.SBCommandReturnObject()
-        ci.HandleCommand("thread trace dump instructions 1 2 --count 12 --start-position 5", result, True)
-        self.assertIn('''thread #1: tid = 3842849, total instructions = 1000
-  would print 12 instructions from position 5
-thread #2: tid = 3842850, total instructions = 1000
-  would print 12 instructions from position 5''', result.GetOutput())
+        ci.HandleCommand("thread trace dump instructions 1 2 --count 4 --start-position 5", result, True)
+        self.assertIn('''thread #1: tid = 3842849, total instructions = 21
+  [5] 0x400529
+  [6] 0x400525
+  [7] 0x400521
+  [8] 0x40052d
+thread #2: tid = 3842850, total instructions = 21
+  [5] 0x400529
+  [6] 0x400525
+  [7] 0x400521
+  [8] 0x40052d''', result.GetOutput())
 
         # We use a repeat command and ensure the previous count is used and the start-position has moved to the next position
+
         result = lldb.SBCommandReturnObject()
         ci.HandleCommand("", result)
-        self.assertIn('''thread #1: tid = 3842849, total instructions = 1000
-  would print 12 instructions from position 17
-thread #2: tid = 3842850, total instructions = 1000
-  would print 12 instructions from position 17''', result.GetOutput())
+        self.assertIn('''thread #1: tid = 3842849, total instructions = 21
+  [ 9] 0x400529
+  [10] 0x400525
+  [11] 0x400521
+  [12] 0x40052d
+thread #2: tid = 3842850, total instructions = 21
+  [ 9] 0x400529
+  [10] 0x400525
+  [11] 0x400521
+  [12] 0x40052d''', result.GetOutput())
 
+        result = lldb.SBCommandReturnObject()
         ci.HandleCommand("", result)
-        self.assertIn('''thread #1: tid = 3842849, total instructions = 1000
-  would print 12 instructions from position 29
-thread #2: tid = 3842850, total instructions = 1000
-  would print 12 instructions from position 29''', result.GetOutput())
+        self.assertIn('''thread #1: tid = 3842849, total instructions = 21
+  [13] 0x400529
+  [14] 0x400525
+  [15] 0x400521
+  [16] 0x40052d
+thread #2: tid = 3842850, total instructions = 21
+  [13] 0x400529
+  [14] 0x400525
+  [15] 0x400521
+  [16] 0x40052d''', result.GetOutput())
+
+    def testInvalidBounds(self):
+        self.expect("trace load -v " + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"))
+
+        # The output should be truncated if asking for too many instructions
+        self.expect("thread trace dump instructions --count 20 --start-position 20",
+            substrs=['''thread #1: tid = 3842849, total instructions = 21
+  [20] 0x400511'''])
+        
+        # Should print no instructions if the start-position is out of bounds
+        self.expect("thread trace dump instructions --start-position 23",
+            endstr='thread #1: tid = 3842849, total instructions = 21\n')
+
+        # Should fail with negative bounds
+        self.expect("thread trace dump instructions --start-position -1", error=True)
+        self.expect("thread trace dump instructions --count -1", error=True)
+
+    def testWrongImage(self):
+        self.expect("trace load " + os.path.join(self.getSourceDir(), "intelpt-trace", "trace_bad_image.json"))
+        self.expect("thread trace dump instructions",
+            substrs=['''thread #1: tid = 3842849, total instructions = 2
+  [0] no memory mapped at this address: 0x400518
+  [1] no memory mapped at this address: 0x400511'''])
+
+    def testWrongCPU(self):
+        self.expect("trace load " + os.path.join(self.getSourceDir(), "intelpt-trace", "trace_wrong_cpu.json"))
+        self.expect("thread trace dump instructions",
+            substrs=['''thread #1: tid = 3842849, total instructions = 0
+  [0] Intel PT decoding error -27: 'unknown cpu'''])
+
+    def testMultiFileTraceWithMissingModule(self):
+        self.expect("trace load " + os.path.join(self.getSourceDir(), "intelpt-trace-multi-file", "multi-file-no-ld.json"))
+        
+        # The trace will be composed of the first and last instructions of main.cpp, with an unmapped region in between
+        # corresponding to the dynamic linker, which is missing in the json file. Because of this error, the decoder moves
+        # to the next synchronization point, skipping the instructions of bar.cpp and foo.cpp.
+        self.expect("thread trace dump instructions",
+            substrs=['''thread #1: tid = 815455, total instructions = 11
+  [ 0] 0x40065f
+  [ 1] 0x40065a
+  [ 2] 0x400657
+  [ 3] 0x400654
+  [ 4] no memory mapped at this address: 0x7ffff7df1950
+  [ 5] 0x400516
+  [ 6] 0x400510
+  [ 7] 0x40054b
+  [ 8] 0x400546
+  [ 9] 0x400540
+  [10] 0x40064f'''])
+
+    def testMultiFileTrace(self):
+        self.expect("trace load " + os.path.join(self.getSourceDir(), "intelpt-trace-multi-file", "multi-file.json"))
+        
+        # last instructions of main.cpp
+        self.expect("thread trace dump instructions --count 3",
+            substrs=['''thread #1: tid = 815455, total instructions = 1153''', '''
+  [0] 0x40065f
+  [1] 0x40065a
+  [2] 0x400657'''])
+
+        # bar.cpp
+        self.expect("thread trace dump instructions --count 3 --start-position 4",
+            substrs=['''
+  [4] 0x7ffff7bd9703
+  [5] 0x7ffff7bd9702
+  [6] 0x7ffff7bd96fe'''])
+
+        # foo.cpp
+        self.expect("thread trace dump instructions --count 3 --start-position 13",
+            substrs=['''
+  [13] 0x7ffff79d76a9
+  [14] 0x7ffff79d76a6
+  [15] 0x7ffff79d76a3'''])
+
+        # ld 
+        self.expect("thread trace dump instructions --count 3 --start-position 21",
+            substrs=[ '''
+  [21] 0x7ffff7df1a16
+  [22] 0x7ffff7df1a12
+  [23] 0x7ffff7df1a0e'''])
+
+        # first instructions of main.cpp
+        self.expect("thread trace dump instructions --count 3 --start-position 1150",
+            substrs=[ '''
+  [1150] 0x400546
+  [1151] 0x400540
+  [1152] 0x40064f'''])
Index: lldb/source/Target/TraceSessionFileParser.cpp
===================================================================
--- lldb/source/Target/TraceSessionFileParser.cpp
+++ lldb/source/Target/TraceSessionFileParser.cpp
@@ -37,7 +37,6 @@
   ModuleSpec module_spec;
   module_spec.GetFileSpec() = local_file_spec;
   module_spec.GetPlatformFileSpec() = system_file_spec;
-  module_spec.SetObjectOffset(module.load_address.value);
 
   if (module.uuid.hasValue())
     module_spec.GetUUID().SetFromStringRef(*module.uuid);
@@ -45,7 +44,14 @@
   Status error;
   ModuleSP module_sp =
       target_sp->GetOrCreateModule(module_spec, /*notify*/ false, &error);
-  return error.ToError();
+
+  if (error.Fail())
+    return error.ToError();
+
+  bool load_addr_changed = false;
+  module_sp->SetLoadAddress(*target_sp, module.load_address.value, false,
+                            load_addr_changed);
+  return llvm::Error::success();
 }
 
 Error TraceSessionFileParser::CreateJSONError(json::Path::Root &root,
Index: lldb/source/Target/Trace.cpp
===================================================================
--- lldb/source/Target/Trace.cpp
+++ lldb/source/Target/Trace.cpp
@@ -8,8 +8,6 @@
 
 #include "lldb/Target/Trace.h"
 
-#include <sstream>
-
 #include "llvm/Support/Format.h"
 
 #include "lldb/Core/PluginManager.h"
@@ -79,10 +77,47 @@
   return createInvalidPlugInError(name);
 }
 
+static int GetNumberOfDigits(size_t num) {
+  int digits_count = 0;
+  do {
+    digits_count++;
+    num /= 10;
+  } while (num);
+  return digits_count;
+}
+
 void Trace::DumpTraceInstructions(Thread &thread, Stream &s, size_t count,
-                                  size_t start_position) const {
-  s.Printf("thread #%u: tid = %" PRIu64 ", total instructions = 1000\n",
-           thread.GetIndexID(), thread.GetID());
-  s.Printf("  would print %zu instructions from position %zu\n", count,
-           start_position);
+                                  size_t start_position) {
+  s.Printf("thread #%u: tid = %" PRIu64 "", thread.GetIndexID(),
+           thread.GetID());
+
+  // Used later for formatting the instruction indices
+  int digits_count = GetNumberOfDigits(start_position + count);
+
+  if (SupportsInstructionsCount()) {
+    size_t instructions_count = GetInstructionCount(thread);
+    s.Printf(", total instructions = %zu", instructions_count);
+    digits_count =
+        std::min(digits_count, GetNumberOfDigits(instructions_count));
+  }
+
+  s.Printf("\n");
+
+  TraverseInstructions(
+      thread, start_position, TraceDirection::Backwards,
+      [&](size_t index, Expected<lldb::addr_t> load_address) -> bool {
+        if (index >= start_position + count) {
+          consumeExpected(std::move(load_address));
+          return false;
+        }
+
+        s.Printf("  [%*zu]", digits_count, index);
+        if (load_address)
+          s.Printf(" 0x%" PRIx64, *load_address);
+        else
+          s.Printf(" %s", toString(load_address.takeError()).c_str());
+        s.Printf("\n");
+
+        return true;
+      });
 }
Index: lldb/source/Target/ProcessTrace.cpp
===================================================================
--- lldb/source/Target/ProcessTrace.cpp
+++ lldb/source/Target/ProcessTrace.cpp
@@ -12,6 +12,8 @@
 
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/SectionLoadList.h"
 #include "lldb/Target/Target.h"
 
 using namespace lldb;
@@ -121,5 +123,9 @@
 
 size_t ProcessTrace::DoReadMemory(addr_t addr, void *buf, size_t size,
                                   Status &error) {
-  return 0;
+  Address resolved_address;
+  GetTarget().GetSectionLoadList().ResolveLoadAddress(addr, resolved_address);
+
+  return GetTarget().ReadMemoryFromFileCache(resolved_address, buf, size,
+                                             error);
 }
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -9,12 +9,8 @@
 #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H
 #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H
 
-#include "intel-pt.h"
-#include "llvm/ADT/Optional.h"
-
+#include "IntelPTDecoder.h"
 #include "TraceIntelPTSessionFileParser.h"
-#include "lldb/Target/Trace.h"
-#include "lldb/lldb-private.h"
 
 namespace lldb_private {
 namespace trace_intel_pt {
@@ -59,6 +55,15 @@
 
   llvm::StringRef GetSchema() override;
 
+  void TraverseInstructions(
+      const Thread &thread, size_t position, TraceDirection direction,
+      std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)>
+          callback) override;
+
+  bool SupportsInstructionsCount() override;
+
+  size_t GetInstructionCount(const Thread &thread) override;
+
 private:
   friend class TraceIntelPTSessionFileParser;
 
@@ -68,8 +73,21 @@
   TraceIntelPT(const pt_cpu &pt_cpu,
                const std::vector<std::shared_ptr<ThreadTrace>> &traced_threads);
 
+  /// Decode the trace of the given thread that, i.e. recontruct the traced
+  /// instructions. That trace must be managed by this class.
+  ///
+  /// \param[in] thread
+  ///     If \a thread is a \a ThreadTrace, then its internal trace file will be
+  ///     decoded. Live threads are not currently supported.
+  ///
+  /// \return
+  ///   A \a DecodedThread instance if decoding was successful, or an error if
+  ///   the thread's trace is not managed by this class or if the trace couldn't
+  ///   be decoded.
+  llvm::Expected<DecodedThread &> Decode(const Thread &thread);
+
   pt_cpu m_pt_cpu;
-  std::map<std::pair<lldb::pid_t, lldb::tid_t>, std::shared_ptr<ThreadTrace>>
+  std::map<std::pair<lldb::pid_t, lldb::tid_t>, ThreadTraceDecoder>
       m_trace_threads;
 };
 
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -64,5 +64,49 @@
     : m_pt_cpu(pt_cpu) {
   for (const std::shared_ptr<ThreadTrace> &thread : traced_threads)
     m_trace_threads.emplace(
-        std::make_pair(thread->GetProcess()->GetID(), thread->GetID()), thread);
+        std::piecewise_construct,
+        std::forward_as_tuple(
+            std::make_pair(thread->GetProcess()->GetID(), thread->GetID())),
+        std::forward_as_tuple(thread, pt_cpu));
+}
+
+Expected<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())
+    return createStringError(std::errc::invalid_argument,
+                             "The thread %" PRIu64 " is not traced.",
+                             thread.GetID());
+
+  return it->second.Decode();
+}
+
+void TraceIntelPT::TraverseInstructions(
+    const Thread &thread, size_t position, TraceDirection direction,
+    std::function<bool(size_t index, Expected<lldb::addr_t> load_addr)>
+        callback) {
+  Expected<DecodedThread &> decoded_thread = Decode(thread);
+  if (!decoded_thread) {
+    callback(position, decoded_thread.takeError());
+    return;
+  }
+
+  std::vector<IntelPTInstruction> instructions =
+      decoded_thread->GetInstructions();
+
+  int delta = direction == TraceDirection::Forwards ? -1 : 1;
+  for (uint64_t i = position; i < instructions.size() && i >= 0; i += delta)
+    if (!callback(i, instructions[i].GetLoadAddress()))
+      break;
+}
+
+bool TraceIntelPT::SupportsInstructionsCount() { return true; }
+
+size_t TraceIntelPT::GetInstructionCount(const Thread &thread) {
+  if (Expected<DecodedThread &> decoded_thread = Decode(thread))
+    return decoded_thread->GetInstructions().size();
+  else {
+    consumeError(decoded_thread.takeError());
+    return 0;
+  }
 }
Index: lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h
@@ -0,0 +1,78 @@
+//===-- IntelPTDecoder.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_DECODER_H
+#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H
+
+#include "intel-pt.h"
+
+#include "DecodedThread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
+
+namespace lldb_private {
+namespace trace_intel_pt {
+
+class IntelPTDecoder {
+public:
+  /// \param[in] process
+  ///     The process associated with the traces to decode.
+  ///
+  /// \param[in] pt_cpu
+  ///     The libipt \a pt_cpu information of the CPU where the traces were
+  ///     recorded.
+  IntelPTDecoder(Process &process, const pt_cpu &pt_cpu)
+      : m_process(process), m_pt_cpu(pt_cpu) {}
+
+  /// Decode a single-thread trace file.
+  ///
+  /// \param[in] trace_file
+  ///     The binary trace file obtained from tracing a thread.
+  ///
+  /// \return
+  ///     A \a DecodedTrace instance, or an error if decoding failed.
+  llvm::Expected<DecodedThread>
+  DecodeSingleThreadTraceFile(const FileSpec &trace_file);
+
+private:
+  Process &m_process;
+  pt_cpu m_pt_cpu;
+};
+
+/// \a lldb_private::ThreadTrace decoder that stores the output from decoding,
+/// avoiding recomputations, as decoding is expensive.
+class ThreadTraceDecoder {
+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() {}
+
+  /// Decode the thread and store the result internally.
+  ///
+  /// \return
+  ///     A \a DecodedThread instance or an error in case of failures.
+  llvm::Expected<DecodedThread &> Decode();
+
+private:
+  ThreadTraceDecoder(const ThreadTraceDecoder &other) = delete;
+
+  std::shared_ptr<ThreadTrace> m_trace_thread;
+  pt_cpu m_pt_cpu;
+  llvm::Optional<DecodedThread> m_decoded_thread;
+  llvm::Optional<std::string> m_error_message;
+};
+
+} // namespace trace_intel_pt
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H
Index: lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
@@ -0,0 +1,232 @@
+//===-- IntelPTDecoder.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 "IntelPTDecoder.h"
+
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadTrace.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::trace_intel_pt;
+using namespace llvm;
+
+/// Move the decoder forward to the next synchronization point (i.e. next PSB
+/// packet).
+///
+/// Once the decoder is at that sync. point, it can start decoding instructions.
+///
+/// \return
+///   A negative number with the libipt error if we couldn't synchronize.
+///   Otherwise, a positive number with the synchronization status will be
+///   returned.
+int FindNextSynchronizationPoint(pt_insn_decoder &decoder) {
+  // Try to sync the decoder. If it fails, then get
+  // the decoder_offset and try to sync again from
+  // the next synchronization point. If the
+  // new_decoder_offset is same as decoder_offset
+  // then we can't move to the next synchronization
+  // point. Otherwise, keep resyncing until either
+  // end of trace stream (eos) is reached or
+  // pt_insn_sync_forward() passes.
+  int errcode = pt_insn_sync_forward(&decoder);
+
+  if (errcode != -pte_eos && errcode < 0) {
+    uint64_t decoder_offset = 0;
+    int errcode_off = pt_insn_get_offset(&decoder, &decoder_offset);
+    if (errcode_off >= 0) { // we could get the offset
+      while (true) {
+        errcode = pt_insn_sync_forward(&decoder);
+        if (errcode >= 0 || errcode == -pte_eos)
+          break;
+
+        uint64_t new_decoder_offset = 0;
+        errcode_off = pt_insn_get_offset(&decoder, &new_decoder_offset);
+        if (errcode_off < 0)
+          break; // We can't further synchronize.
+        else if (new_decoder_offset <= decoder_offset) {
+          // We tried resyncing the decoder and
+          // decoder didn't make any progress because
+          // the offset didn't change. We will not
+          // make any progress further. Hence,
+          // stopping in this situation.
+          break;
+        }
+        // We'll try again starting from a new offset.
+        decoder_offset = new_decoder_offset;
+      }
+    }
+  }
+
+  return errcode;
+}
+
+/// Before querying instructions, we need to query the events associated that
+/// instruction e.g. timing events like ptev_tick, or paging events like
+/// ptev_paging.
+///
+/// \return
+///   0 if there were no errors processing the events, or a negative libipt
+///   error code in case of errors.
+int ProcessPTEvents(pt_insn_decoder &decoder, int errcode) {
+  while (errcode & pts_event_pending) {
+    pt_event event;
+    errcode = pt_insn_event(&decoder, &event, sizeof(event));
+    if (errcode < 0)
+      return errcode;
+  }
+  return 0;
+};
+
+/// Decode all the instructions from a configured decoder.
+/// The decoding flow is based on
+/// https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#the-instruction-flow-decode-loop
+/// but with some relaxation to allow for gaps in the trace.
+///
+/// Error codes returned by libipt while decoding are:
+/// - negative: actual errors
+/// - positive or zero: not an error, but a list of bits signaling the status of
+/// the decoder
+///
+/// \param[in] decoder
+///   A configured libipt \a pt_insn_decoder.
+///
+/// \return
+///   The decoded instructions.
+static std::vector<IntelPTInstruction>
+DecodeInstructions(pt_insn_decoder &decoder) {
+  std::vector<IntelPTInstruction> instructions;
+
+  while (true) {
+    int errcode = FindNextSynchronizationPoint(decoder);
+    if (errcode == -pte_eos)
+      break;
+
+    if (errcode < 0) {
+      instructions.emplace_back(errcode);
+      break;
+    }
+
+    // We have synchronized, so we can start decoding
+    // instructions and events.
+    while (true) {
+      errcode = ProcessPTEvents(decoder, errcode);
+      if (errcode < 0) {
+        instructions.emplace_back(errcode);
+        break;
+      }
+      pt_insn insn;
+
+      errcode = pt_insn_next(&decoder, &insn, sizeof(insn));
+      if (errcode == -pte_eos)
+        break;
+
+      if (errcode < 0) {
+        instructions.emplace_back(insn, errcode);
+        break;
+      }
+
+      instructions.emplace_back(insn);
+    }
+  }
+
+  return instructions;
+}
+
+static Error CreateLibiptError(int errcode) {
+  return createStringError(std::errc::invalid_argument,
+                           "Intel PT decoding error %d: '%s'", errcode,
+                           pt_errstr(pt_errcode(errcode)));
+}
+
+/// Callback used by libipt for reading the process memory.
+///
+/// More information can be found in
+/// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md
+static int ReadProcessMemory(uint8_t *buffer, size_t size,
+                             const pt_asid * /* unused */, uint64_t pc,
+                             void *context) {
+  Process *process = reinterpret_cast<Process *>(context);
+
+  Status error;
+  int bytes_read = process->ReadMemory(pc, buffer, size, error);
+  if (error.Fail())
+    return -pte_nomap;
+  return bytes_read;
+}
+
+static Expected<std::vector<IntelPTInstruction>>
+CreateDecoderAndDecode(Process &process, const pt_cpu &pt_cpu,
+                       MemoryBuffer &trace) {
+  pt_config config;
+  pt_config_init(&config);
+  config.cpu = pt_cpu;
+
+  if (int errcode = pt_cpu_errata(&config.errata, &config.cpu))
+    return CreateLibiptError(errcode);
+
+  config.begin =
+      reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferStart()));
+  config.end =
+      reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferEnd()));
+
+  pt_insn_decoder *decoder = pt_insn_alloc_decoder(&config);
+  if (!decoder)
+    return CreateLibiptError(pte_nomem);
+
+  pt_image *image = pt_insn_get_image(decoder);
+  if (int error = pt_image_set_callback(image, ReadProcessMemory, &process))
+    return CreateLibiptError(error);
+
+  std::vector<IntelPTInstruction> instructions = DecodeInstructions(*decoder);
+  // We'll need the instructions in reverse order chronologically, so we
+  // reverse them now
+  std::reverse(instructions.begin(), instructions.end());
+
+  pt_insn_free_decoder(decoder);
+  return instructions;
+}
+
+Expected<DecodedThread>
+IntelPTDecoder::DecodeSingleThreadTraceFile(const FileSpec &trace_file) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> buffer_or_error =
+      MemoryBuffer::getFile(trace_file.GetPath());
+  if (std::error_code err = buffer_or_error.getError())
+    return errorCodeToError(err);
+
+  if (Expected<std::vector<IntelPTInstruction>> instructions =
+          CreateDecoderAndDecode(m_process, m_pt_cpu, **buffer_or_error))
+    return DecodedThread(std::move(*instructions));
+  else
+    return instructions.takeError();
+}
+
+Expected<DecodedThread &> ThreadTraceDecoder::Decode() {
+  if (!m_decoded_thread.hasValue() && !m_error_message.hasValue()) {
+    IntelPTDecoder decoder(*m_trace_thread->GetProcess(), m_pt_cpu);
+
+    if (llvm::Expected<DecodedThread> decoded_thread =
+            decoder.DecodeSingleThreadTraceFile(m_trace_thread->GetTraceFile()))
+      m_decoded_thread = *decoded_thread;
+    else
+      // We create a copy of the error message, as we'll create a new instance
+      // of llvm::Error whenever this function is invoked. We have to do this
+      // because llvm::Error is only movable, not copyable.
+      m_error_message = llvm::toString(decoded_thread.takeError());
+  }
+
+  if (m_decoded_thread.hasValue())
+    return *m_decoded_thread;
+  else
+    return llvm::createStringError(std::errc::invalid_argument,
+                                   m_error_message->c_str());
+}
Index: lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
@@ -0,0 +1,95 @@
+//===-- DecodedThread.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_DECODEDTHREAD_H
+#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
+
+#include <vector>
+
+#include "lldb/Target/Trace.h"
+
+#include "intel-pt.h"
+
+namespace lldb_private {
+namespace trace_intel_pt {
+
+/// \class IntelPTInstruction
+/// An instruction obtained from decoding a trace. It is either an actual
+/// instruction or an error indicating a gap in the trace.
+///
+/// Gaps in the trace can come in a few flavors:
+///   - tracing gaps (e.g. tracing was paused and then resumed)
+///   - tracing errors (e.g. buffer overflow)
+///   - decoding errors (e.g. some memory region couldn't be decoded)
+/// As mentioned, any gap is represented as an error in this class.
+class IntelPTInstruction {
+public:
+  IntelPTInstruction() = delete;
+
+  IntelPTInstruction(const pt_insn &pt_insn, int libipt_error_code = 0)
+      : m_pt_insn(pt_insn), m_libipt_error_code(libipt_error_code) {}
+
+  IntelPTInstruction(int libipt_error_code)
+      : m_pt_insn(), m_libipt_error_code(libipt_error_code) {}
+
+  /// Check if this object represents an error (i.e. a gap).
+  ///
+  /// \return
+  ///     Whether this object represents an error.
+  bool IsError() const;
+
+  /// Get the instruction pointer if this is not an error.
+  ///
+  /// \return
+  ///     The instruction pointer address.
+  llvm::Expected<lldb::addr_t> GetLoadAddress();
+
+  /// Return the libipt error code.
+  ///
+  /// libipt error codes are negative numbers.
+  ///
+  /// \return
+  ///     0 if it is not an error, or the error value otherwise.
+  int GetErrorCode() const;
+
+  /// Return a descriptive error message if this is an error.
+  ///
+  /// \return
+  ///    The error message.
+  llvm::StringRef GetErrorMessage();
+
+private:
+  pt_insn m_pt_insn;
+  int m_libipt_error_code;
+
+  std::string m_custom_error_message;
+};
+
+/// \class DecodedThread
+/// Class holding the instructions and function call hierarchy obtained from
+/// decoding a trace.
+class DecodedThread {
+public:
+  DecodedThread(std::vector<IntelPTInstruction> &&instructions)
+      : m_instructions(std::move(instructions)) {}
+
+  /// Get the instructions from the decoded trace. Some of them might indicate
+  /// errors (i.e. gaps) in the trace.
+  ///
+  /// \return
+  ///   The instructions of the trace.
+  std::vector<IntelPTInstruction> &GetInstructions();
+
+private:
+  std::vector<IntelPTInstruction> m_instructions;
+};
+
+} // namespace trace_intel_pt
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
Index: lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -0,0 +1,43 @@
+//===-- DecodedThread.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 "DecodedThread.h"
+
+#include <sstream>
+
+using namespace lldb_private;
+using namespace lldb_private::trace_intel_pt;
+using namespace llvm;
+
+bool IntelPTInstruction::IsError() const { return m_libipt_error_code < 0; }
+
+Expected<lldb::addr_t> IntelPTInstruction::GetLoadAddress() {
+  if (IsError())
+    return createStringError(std::errc::invalid_argument,
+                             GetErrorMessage().data());
+  return m_pt_insn.ip;
+}
+
+int IntelPTInstruction::GetErrorCode() const { return m_libipt_error_code; }
+
+llvm::StringRef IntelPTInstruction::GetErrorMessage() {
+  if (GetErrorCode() == -pte_nomap) {
+    if (m_custom_error_message.empty()) {
+      std::ostringstream os;
+      os << pt_errstr(pt_errcode(GetErrorCode())) << ": 0x" << std::hex
+         << m_pt_insn.ip;
+      m_custom_error_message = os.str();
+    }
+    return m_custom_error_message;
+  }
+  return pt_errstr(pt_errcode(GetErrorCode()));
+}
+
+std::vector<IntelPTInstruction> &DecodedThread::GetInstructions() {
+  return m_instructions;
+}
Index: lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt
+++ lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt
@@ -10,6 +10,8 @@
 find_library(LIBIPT_LIBRARY ipt PATHS ${LIBIPT_LIBRARY_PATH} REQUIRED)
 
 add_lldb_library(lldbPluginTraceIntelPT PLUGIN
+  DecodedThread.cpp
+  IntelPTDecoder.cpp
   TraceIntelPT.cpp
   TraceIntelPTSessionFileParser.cpp
 
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -35,6 +35,11 @@
 class Trace : public PluginInterface,
               public std::enable_shared_from_this<Trace> {
 public:
+  enum class TraceDirection {
+    Forwards = 0,
+    Backwards,
+  };
+
   /// Dump the trace data that this plug-in has access to.
   ///
   /// This function will dump all of the trace data for all threads in a user
@@ -117,7 +122,61 @@
   /// \param[in] start_position
   ///     The position of the first instruction to print.
   void DumpTraceInstructions(Thread &thread, Stream &s, size_t count,
-                             size_t start_position) const;
+                             size_t start_position);
+
+  /// Run the provided callback on the instructions of the trace of the given
+  /// thread.
+  ///
+  /// The instructions will be traversed starting at the \a from position
+  /// sequentially until the callback returns \b false, in which case no more
+  /// instructions are inspected.
+  ///
+  /// The purpose of this method is to allow inspecting traced instructions
+  /// without exposing the internal representation of how they are stored on
+  /// memory.
+  ///
+  /// \param[in] thread
+  ///     The thread whose trace will be traversed.
+  ///
+  /// \param[in] position
+  ///     The instruction position to start iterating on.
+  ///
+  /// \param[in] direction
+  ///     If \b TraceDirection::Forwards, then then instructions will be
+  ///     traversed forwards chronologically, i.e. with decrementing indices. If
+  ///     \b TraceDirection::Backwards, the traversal is done backwards
+  ///     chronologically, i.e. with incrementing indices.
+  ///
+  /// \param[in] callback
+  ///     The callback to execute on each instruction. If it returns \b true for
+  ///     the \a i-th instruction, then the instruction with index \a i + 1 will
+  ///     be inspected. If it returns \b false, no more instructions will be
+  ///     inspected.
+  virtual void TraverseInstructions(
+      const Thread &thread, size_t position, TraceDirection direction,
+      std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)>
+          callback) = 0;
+
+  /// Determine whether the trace plug-in supports the \a GetInstructionCount
+  /// method.
+  ///
+  /// Some trace plug-ins might prefer to provide instructions lazily on the
+  /// fly, being unable to provide the total number of instructions in a single
+  /// call.
+  ///
+  /// \return
+  ///     \b true if invoking \a GetInstructionCount will return a correct
+  ///     value, \b false otherwise.
+  virtual bool SupportsInstructionsCount() { return false; }
+
+  /// Get the number of instructions of the trace of the given thread.
+  ///
+  /// \param[in] thread
+  ///     The thread whose trace will be inspected.
+  ///
+  /// \return
+  ///     The total number of instructions of the trace.
+  virtual size_t GetInstructionCount(const Thread &thread) { return 0; }
 };
 
 } // namespace lldb_private
Index: lldb/include/lldb/Target/ProcessTrace.h
===================================================================
--- lldb/include/lldb/Target/ProcessTrace.h
+++ lldb/include/lldb/Target/ProcessTrace.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_TARGET_PROCESSTRACE_H
 #define LLDB_TARGET_PROCESSTRACE_H
 
+#include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/Status.h"
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to