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

rebase


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/Trace.h
  lldb/include/lldb/Target/TraceProcess.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/Trace.cpp
  lldb/source/Target/TraceProcess.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
  lldb/tools/intel-features/intel-pt/Decoder.cpp

Index: lldb/tools/intel-features/intel-pt/Decoder.cpp
===================================================================
--- lldb/tools/intel-features/intel-pt/Decoder.cpp
+++ lldb/tools/intel-features/intel-pt/Decoder.cpp
@@ -248,6 +248,8 @@
   }
 }
 
+#include <fstream>
+
 void Decoder::ReadTraceDataAndImageInfo(lldb::SBProcess &sbprocess,
                                         lldb::tid_t tid, lldb::SBError &sberror,
                                         ThreadTraceInfo &threadTraceInfo) {
@@ -255,6 +257,7 @@
   // for the first time in class
   lldb::SBTrace &trace = threadTraceInfo.GetUniqueTraceInstance();
   Buffer &pt_buffer = threadTraceInfo.GetPTBuffer();
+
   lldb::SBError error;
   if (pt_buffer.size() == 0) {
     lldb::SBTraceOptions traceoptions;
@@ -295,6 +298,11 @@
   }
   std::fill(pt_buffer.begin() + bytes_written, pt_buffer.end(), 0);
 
+  std::ofstream of("/tmp/multi-file.trace", std::ios::binary | std::ios::out);
+  for (auto bait : pt_buffer)
+    of << bait;
+  of.close();
+
   // Get information of all the modules of the inferior
   lldb::SBTarget sbtarget = sbprocess.GetTarget();
   ReadExecuteSectionInfos &readExecuteSectionInfos =
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,40 @@
             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'''])
 
         # 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 +83,125 @@
         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 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
+  [1] no memory mapped at this address'''])
+
+    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
+  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
+  [ 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/TraceProcess.cpp
===================================================================
--- lldb/source/Target/TraceProcess.cpp
+++ lldb/source/Target/TraceProcess.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;
@@ -106,6 +108,33 @@
   return GetTarget().GetArchitecture();
 }
 
+const std::map<MemoryRegionInfo::RangeType, SectionSP> &
+TraceProcess::GetSectionMap() {
+  if (m_section_map)
+    return *m_section_map;
+
+  m_section_map.emplace();
+
+  ModuleList &modules = GetTarget().GetImages();
+  SectionLoadList &load_list = GetTarget().GetSectionLoadList();
+  modules.ForEach([&](const ModuleSP &module_sp) {
+    SectionList *sections = module_sp->GetSectionList();
+    for (size_t i = 0; i < sections->GetSize(); i++) {
+      SectionSP section_sp = sections->GetSectionAtIndex(i);
+
+      addr_t load_addr = load_list.GetSectionLoadAddress(section_sp);
+      if (load_addr == LLDB_INVALID_ADDRESS)
+        continue;
+      MemoryRegionInfo::RangeType section_range(load_addr,
+                                                section_sp->GetByteSize());
+      m_section_map->insert(std::make_pair(section_range, section_sp));
+    }
+    return true;
+  });
+
+  return *m_section_map;
+}
+
 bool TraceProcess::GetProcessInfo(ProcessInstanceInfo &info) {
   info.Clear();
   info.SetProcessID(GetID());
@@ -121,5 +150,25 @@
 
 size_t TraceProcess::DoReadMemory(addr_t addr, void *buf, size_t size,
                                   Status &error) {
+  const std::map<MemoryRegionInfo::RangeType, SectionSP> &section_map =
+      GetSectionMap();
+
+  MemoryRegionInfo::RangeType address_range(addr, size);
+  // Doing (upper_bound - 1) gives us the maximum range whose base address is <=
+  // addr
+  auto it = section_map.upper_bound(address_range);
+  if (it != section_map.begin()) {
+    --it;
+    const SectionSP &section = it->second;
+    const MemoryRegionInfo::RangeType &section_range = it->first;
+
+    if (section_range.Contains(address_range) && section->GetObjectFile()) {
+      section->GetObjectFile()->CopyData(addr - section_range.GetRangeBase(),
+                                         size, buf);
+      return size;
+    }
+  }
+
+  error.SetErrorString("could not parse memory info");
   return 0;
 }
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,41 @@
   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) {
+  size_t instruction_count = GetInstructionCount(thread);
+  s.Printf("thread #%u: tid = %" PRIu64 ", total instructions = %zu\n",
+           thread.GetIndexID(), thread.GetID(), instruction_count);
+
+  int digits_count =
+      GetNumberOfDigits(std::min(instruction_count, start_position + count));
+
+  if (Error err = GetTraceErrorStatus(thread))
+    s.Printf("  %s\n", llvm::toString(std::move(err)).c_str());
+
+  ForEachInstruction(
+      thread,
+      [&](size_t index, Expected<lldb::addr_t> &load_address) -> bool {
+        if (index >= start_position + count)
+          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;
+      },
+      start_position);
 }
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,16 @@
 
   llvm::StringRef GetSchema() override;
 
+  void ForEachInstruction(
+      const Thread &thread,
+      std::function<bool(size_t index, llvm::Expected<lldb::addr_t> &load_addr)>
+          callback,
+      size_t from = 0) override;
+
+  size_t GetInstructionCount(const Thread &thread) override;
+
+  llvm::Error GetTraceErrorStatus(const Thread &thread) override;
+
 private:
   friend class TraceIntelPTSessionFileParser;
 
@@ -68,8 +74,21 @@
   TraceIntelPT(const pt_cpu &pt_cpu,
                const std::vector<std::shared_ptr<TraceThread>> &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 TraceThread, 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<const DecodedThread &> Decode(const Thread &thread);
+
   pt_cpu m_pt_cpu;
-  std::map<std::pair<lldb::pid_t, lldb::tid_t>, std::shared_ptr<TraceThread>>
+  std::map<std::pair<lldb::pid_t, lldb::tid_t>, TraceThreadDecoder>
       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,54 @@
     : m_pt_cpu(pt_cpu) {
   for (const std::shared_ptr<TraceThread> &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<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())
+    return createStringError(std::errc::invalid_argument,
+                             "The thread %" PRIu64 " is not traced.",
+                             thread.GetID());
+
+  return it->second.Decode();
+}
+
+void TraceIntelPT::ForEachInstruction(
+    const Thread &thread,
+    std::function<bool(size_t index, Expected<lldb::addr_t> &load_addr)>
+        callback,
+    size_t from) {
+  Expected<const DecodedThread &> decoded_thread = Decode(thread);
+  if (!decoded_thread)
+    return;
+
+  const std::vector<IntelPTInstruction> &instructions =
+      decoded_thread->GetInstructions();
+  for (size_t i = from; i < instructions.size(); i++) {
+    Expected<lldb::addr_t> load_addr = instructions[i].GetLoadAddress();
+    // We check the expected here to avoid forcing the callback check it.
+    (void)(bool) load_addr;
+
+    if (!callback(i, load_addr))
+      break;
+  }
+}
+
+size_t TraceIntelPT::GetInstructionCount(const Thread &thread) {
+  if (Expected<const DecodedThread &> decoded_thread = Decode(thread))
+    return decoded_thread->GetInstructions().size();
+  else
+    return 0;
+}
+
+Error TraceIntelPT::GetTraceErrorStatus(const Thread &thread) {
+  if (Expected<const DecodedThread &> decoded_thread = Decode(thread))
+    return Error::success();
+  else
+    return decoded_thread.takeError();
 }
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::TraceThread decoder that stores the output from decoding,
+/// avoiding recomputations, as decoding is expensive.
+class TraceThreadDecoder {
+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.
+  TraceThreadDecoder(const std::shared_ptr<TraceThread> &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<const DecodedThread &> Decode();
+
+private:
+  TraceThreadDecoder(const TraceThreadDecoder &other) = delete;
+
+  std::shared_ptr<TraceThread> 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/TraceThread.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(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<const DecodedThread &> TraceThreadDecoder::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,93 @@
+//===-- 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)
+      : m_pt_insn(pt_insn), m_libipt_error_code(0) {}
+
+  IntelPTInstruction(int libipt_error_code)
+      : 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() const;
+
+  /// 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() const;
+
+private:
+  pt_insn m_pt_insn;
+  int m_libipt_error_code;
+};
+
+/// \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.
+  llvm::ArrayRef<IntelPTInstruction> GetInstructions() const;
+
+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,32 @@
+//===-- 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"
+
+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() const {
+  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() const {
+  return pt_errstr(pt_errcode(GetErrorCode()));
+}
+
+ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const {
+  return makeArrayRef(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/TraceProcess.h
===================================================================
--- lldb/include/lldb/Target/TraceProcess.h
+++ lldb/include/lldb/Target/TraceProcess.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_TARGET_TRACEPROCESS_H
 #define LLDB_TARGET_TRACEPROCESS_H
 
+#include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/Status.h"
@@ -78,6 +79,12 @@
   static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
                                         lldb::ListenerSP listener_sp,
                                         const FileSpec *crash_file_path);
+
+  /// Create a map from virtual memory ranges to the sections that contain them.
+  const std::map<MemoryRegionInfo::RangeType, lldb::SectionSP> &GetSectionMap();
+
+  llvm::Optional<std::map<MemoryRegionInfo::RangeType, lldb::SectionSP>>
+      m_section_map;
 };
 
 } // namespace lldb_private
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -117,7 +117,58 @@
   /// \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] 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.
+  ///
+  /// \param[in] from
+  ///     The first index to execute the callback on.
+  virtual void ForEachInstruction(
+      const Thread &thread,
+      std::function<bool(size_t index, llvm::Expected<lldb::addr_t> &load_addr)>
+          callback,
+      size_t from = 0) = 0;
+
+  /// 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) = 0;
+
+  /// Get any errors in case the trace of the given thread can't be
+  /// reconstructed.
+  ///
+  /// If this returns an actual error, then no instructions are available in the
+  /// trace.
+  ///
+  /// \param[in] thread
+  ///     The thread whose trace will be inspected.
+  ///
+  /// \return
+  ///     An \a llvm::Error::success instance if the trace can be reconstructed,
+  ///     or an actual Error in case of failures.
+  virtual llvm::Error GetTraceErrorStatus(const Thread &thread) = 0;
 };
 
 } // namespace lldb_private
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to