persona0220 updated this revision to Diff 449823.
persona0220 marked 9 inline comments as done.
persona0220 added a comment.

Resolved comments


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

https://reviews.llvm.org/D130805

Files:
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.h
  lldb/test/API/commands/trace/TestTraceLoad.py
  lldb/test/API/commands/trace/TestTraceSave.py
  lldb/test/API/commands/trace/intelpt-kernel-trace/trace.json
  
lldb/test/API/commands/trace/intelpt-kernel-trace/trace_kernel_with_process.json
  lldb/test/API/commands/trace/intelpt-kernel-trace/trace_kernel_wo_cpus.json

Index: lldb/test/API/commands/trace/intelpt-kernel-trace/trace_kernel_wo_cpus.json
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-kernel-trace/trace_kernel_wo_cpus.json
@@ -0,0 +1,20 @@
+{
+  "cpuInfo": {
+    "family": 6,
+    "model": 85,
+    "stepping": 4,
+    "vendor": "GenuineIntel"
+  },
+  "processes": [
+  ],
+  "tscPerfZeroConversion": {
+    "timeMult": 1076264588,
+    "timeShift": 31,
+    "timeZero": 18433473881008870804
+  },
+  "kernel": {
+    "file": "../intelpt-multi-core-trace/modules/m.out",
+    "loadAddress": 4194304
+  },
+  "type": "intel-pt"
+}
Index: lldb/test/API/commands/trace/intelpt-kernel-trace/trace_kernel_with_process.json
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-kernel-trace/trace_kernel_with_process.json
@@ -0,0 +1,53 @@
+{
+  "cpus": [
+    {
+      "contextSwitchTrace": "../intelpt-multi-core-trace/cores/45.perf_context_switch_trace",
+      "id": 45,
+      "iptTrace": "../intelpt-multi-core-trace/cores/45.intelpt_trace"
+    },
+    {
+      "contextSwitchTrace": "../intelpt-multi-core-trace/cores/51.perf_context_switch_trace",
+      "id": 51,
+      "iptTrace": "../intelpt-multi-core-trace/cores/51.intelpt_trace"
+    }
+  ],
+  "cpuInfo": {
+    "family": 6,
+    "model": 85,
+    "stepping": 4,
+    "vendor": "GenuineIntel"
+  },
+  "processes": [
+    {
+      "modules": [
+        {
+          "file": "../intelpt-multi-core-trace/modules/m.out",
+          "systemPath": "/tmp/m.out",
+          "loadAddress": 4194304,
+          "uuid": "AEFB0D59-233F-80FF-6D3C-4DED498534CF-11017B3B"
+        }
+      ],
+      "pid": 3497234,
+      "threads": [
+        {
+          "tid": 3497234
+        },
+        {
+          "tid": 3497496
+        },
+        {
+          "tid": 3497497
+        }
+      ]
+    }
+  ],
+  "tscPerfZeroConversion": {
+    "timeMult": 1076264588,
+    "timeShift": 31,
+    "timeZero": 18433473881008870804
+  },
+  "type": "intel-pt",
+  "kernel": {
+    "file": "../intelpt-multi-core-trace/modules/m.out"
+  }
+}
Index: lldb/test/API/commands/trace/intelpt-kernel-trace/trace.json
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-kernel-trace/trace.json
@@ -0,0 +1,29 @@
+{
+  "cpus": [
+    {
+      "contextSwitchTrace": "../intelpt-multi-core-trace/cores/45.perf_context_switch_trace",
+      "id": 45,
+      "iptTrace": "../intelpt-multi-core-trace/cores/45.intelpt_trace"
+    },
+    {
+      "contextSwitchTrace": "../intelpt-multi-core-trace/cores/51.perf_context_switch_trace",
+      "id": 51,
+      "iptTrace": "../intelpt-multi-core-trace/cores/51.intelpt_trace"
+    }
+  ],
+  "cpuInfo": {
+    "family": 6,
+    "model": 85,
+    "stepping": 4,
+    "vendor": "GenuineIntel"
+  },
+  "tscPerfZeroConversion": {
+    "timeMult": 1076264588,
+    "timeShift": 31,
+    "timeZero": 18433473881008870804
+  },
+  "kernel": {
+    "file": "../intelpt-multi-core-trace/modules/m.out"
+  },
+  "type": "intel-pt"
+}
Index: lldb/test/API/commands/trace/TestTraceSave.py
===================================================================
--- lldb/test/API/commands/trace/TestTraceSave.py
+++ lldb/test/API/commands/trace/TestTraceSave.py
@@ -169,3 +169,22 @@
         ci.HandleCommand("thread trace dump instructions -c 10", res)
         self.assertEqual(res.Succeeded(), True)
         self.assertEqual(res.GetOutput(), last_ten_instructions)
+
+    def testSaveKernelTrace(self):
+        original_trace_file = os.path.join(self.getSourceDir(), "intelpt-kernel-trace",
+                "trace.json")
+        copied_trace_dir = os.path.join(self.getBuildDir(), "intelpt-kernel-trace")
+        copied_trace_file = os.path.join(copied_trace_dir, "trace.json")
+
+        self.expect("trace load -v " + original_trace_file, substrs=["intel-pt"])
+        self.expect("trace save " + copied_trace_dir)
+
+        # We finally check that the new json has the same information as the original one
+        with open(original_trace_file) as original_file:
+            original_file = json.load(original_file)
+            with open(copied_trace_file) as copy_file:
+                copy_file = json.load(copy_file)
+                self.assertTrue("kernel" in copy_file)
+
+                self.assertEqual(os.path.basename(original_file["kernel"]["file"]),
+                        os.path.basename(copy_file["kernel"]["file"]))
Index: lldb/test/API/commands/trace/TestTraceLoad.py
===================================================================
--- lldb/test/API/commands/trace/TestTraceLoad.py
+++ lldb/test/API/commands/trace/TestTraceLoad.py
@@ -263,3 +263,31 @@
         expected_substrs = ['error: missing value at traceBundle.processes[1].pid']
         self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
         self.assertEqual(self.dbg.GetNumTargets(), 0)
+
+    @testSBAPIAndCommands
+    def testLoadKernelTrace(self):
+        src_dir = self.getSourceDir()
+        trace_description_file_path = os.path.join(src_dir, "intelpt-kernel-trace", "trace.json")
+        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, substrs=["intel-pt"])
+
+        self.expect("image list", substrs=["modules/m.out"])
+        self.expect("image list", substrs=["0xffffffff81000000"])
+
+        self.expect("thread list", substrs=[
+            "Process 1 stopped",
+            "* thread #1: tid = 0x002d",
+            "  thread #2: tid = 0x0033"])
+
+    @testSBAPIAndCommands
+    def testLoadInvalidKernelTrace(self):
+        src_dir = self.getSourceDir()
+
+        # Test kernel section with non-empty processeses section.
+        trace_description_file_path = os.path.join(src_dir, "intelpt-kernel-trace", "trace_kernel_with_process.json")
+        expected_substrs = ['error: "processes" must be empty when "kernel" is provided when parsing traceBundle']
+        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
+
+        # Test kernel section without cpus section.
+        trace_description_file_path = os.path.join(src_dir, "intelpt-kernel-trace", "trace_kernel_wo_cpus.json")
+        expected_substrs = ['error: "cpus" is required when "kernel" is provided when parsing traceBundle']
+        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.h
@@ -47,12 +47,18 @@
   std::string context_switch_trace;
 };
 
+struct JSONKernel {
+  llvm::Optional<JSONUINT64> load_address;
+  std::string file;
+};
+
 struct JSONTraceBundleDescription {
   std::string type;
   pt_cpu cpu_info;
-  std::vector<JSONProcess> processes;
+  llvm::Optional<std::vector<JSONProcess>> processes;
   llvm::Optional<std::vector<JSONCpu>> cpus;
   llvm::Optional<LinuxPerfZeroTscConversion> tsc_perf_zero_conversion;
+  llvm::Optional<JSONKernel> kernel;
 
   llvm::Optional<std::vector<lldb::cpu_id_t>> GetCpuIds();
 };
@@ -67,6 +73,8 @@
 
 llvm::json::Value toJSON(const pt_cpu &cpu_info);
 
+llvm::json::Value toJSON(const JSONKernel &kernel);
+
 llvm::json::Value toJSON(const JSONTraceBundleDescription &bundle_description);
 
 bool fromJSON(const llvm::json::Value &value, JSONModule &module,
@@ -84,6 +92,9 @@
 bool fromJSON(const llvm::json::Value &value, pt_cpu &cpu_info,
               llvm::json::Path path);
 
+bool fromJSON(const llvm::json::Value &value, JSONModule &kernel,
+              llvm::json::Path path);
+
 bool fromJSON(const llvm::json::Value &value, JSONTraceBundleDescription &bundle_description,
               llvm::json::Path path);
 } // namespace trace_intel_pt
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.cpp
@@ -116,21 +116,40 @@
   return true;
 }
 
+json::Value toJSON(const JSONKernel &kernel) {
+  json::Object json_module;
+  if (kernel.load_address)
+    json_module["loadAddress"] = toJSON(*kernel.load_address, true);
+  json_module["file"] = kernel.file;
+  return std::move(json_module);
+}
+
+bool fromJSON(const json::Value &value, JSONKernel &kernel, Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("loadAddress", kernel.load_address) &&
+         o.map("file", kernel.file);
+}
+
 json::Value toJSON(const JSONTraceBundleDescription &bundle_description) {
-  return Object{{"type", bundle_description.type},
-                {"processes", bundle_description.processes},
-                // We have to do this because the compiler fails at doing it
-                // automatically because pt_cpu is not in a namespace
-                {"cpuInfo", toJSON(bundle_description.cpu_info)},
-                {"cpus", bundle_description.cpus},
-                {"tscPerfZeroConversion", bundle_description.tsc_perf_zero_conversion}};
+  return Object{
+      {"type", bundle_description.type},
+      {"processes", bundle_description.processes},
+      // We have to do this because the compiler fails at doing it
+      // automatically because pt_cpu is not in a namespace
+      {"cpuInfo", toJSON(bundle_description.cpu_info)},
+      {"cpus", bundle_description.cpus},
+      {"tscPerfZeroConversion", bundle_description.tsc_perf_zero_conversion},
+      {"kernel", bundle_description.kernel}};
 }
 
 bool fromJSON(const json::Value &value, JSONTraceBundleDescription &bundle_description, Path path) {
   ObjectMapper o(value, path);
   if (!(o && o.map("processes", bundle_description.processes) &&
-        o.map("type", bundle_description.type) && o.map("cpus", bundle_description.cpus) &&
-        o.map("tscPerfZeroConversion", bundle_description.tsc_perf_zero_conversion)))
+        o.map("type", bundle_description.type) &&
+        o.map("cpus", bundle_description.cpus) &&
+        o.map("tscPerfZeroConversion",
+              bundle_description.tsc_perf_zero_conversion) &&
+        o.map("kernel", bundle_description.kernel)))
     return false;
   if (bundle_description.cpus && !bundle_description.tsc_perf_zero_conversion) {
     path.report(
@@ -142,6 +161,25 @@
   if (!fromJSON(*value.getAsObject()->get("cpuInfo"), bundle_description.cpu_info,
                 path.field("cpuInfo")))
     return false;
+
+  // When kernel section is present, this is kernel-only tracing. Thus, throw an
+  // error if the "processes" section is non-empty or the "cpus" section is not
+  // present.
+  if (bundle_description.kernel) {
+    if (bundle_description.processes &&
+        !bundle_description.processes->empty()) {
+      path.report("\"processes\" must be empty when \"kernel\" is provided");
+      return false;
+    }
+    if (!bundle_description.cpus) {
+      path.report("\"cpus\" is required when \"kernel\" is provided");
+      return false;
+    }
+  } else if (!bundle_description.processes) {
+    // Usermode tracing requires processes section.
+    path.report("\"processes\" is required when \"kernel\" is not provided");
+    return false;
+  }
   return true;
 }
 
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
@@ -23,6 +23,13 @@
 const bool kDefaultPerCpuTracing = false;
 const bool kDefaultDisableCgroupFiltering = false;
 
+// Physical address where the kernel is loaded in x86 architecture. Refer to
+// https://github.com/torvalds/linux/blob/master/Documentation/x86/x86_64/mm.rst
+// for the start address of kernel text section.
+// The kernel entry point is 0x1000000 by default when KASLR is disabled.
+const lldb::addr_t kDefaultKernelLoadAddress = 0xffffffff81000000;
+const lldb::pid_t kDefaultKernelProcessID = 1;
+
 } // namespace trace_intel_pt
 } // namespace lldb_private
 
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
@@ -10,6 +10,7 @@
 
 #include "PerfContextSwitchDecoder.h"
 #include "TraceIntelPT.h"
+#include "TraceIntelPTConstants.h"
 #include "TraceIntelPTJSONStructs.h"
 
 #include "lldb/Core/Module.h"
@@ -335,6 +336,25 @@
   return processes;
 }
 
+static llvm::Expected<JSONKernel>
+BuildKernelSection(TraceIntelPT &trace_ipt, const FileSpec &directory) {
+  JSONKernel json_kernel;
+  std::vector<Process *> processes = trace_ipt.GetAllProcesses();
+  Process *kernel_process = processes[0];
+
+  assert(processes.size() == 1 && "User processeses exist in kernel mode");
+  assert(kernel_process->GetID() == kDefaultKernelProcessID &&
+         "Kernel process not exist");
+
+  Expected<std::vector<JSONModule>> json_modules =
+      BuildModulesSection(*kernel_process, directory);
+  if (!json_modules)
+    return json_modules.takeError();
+
+  JSONModule kernel_image = json_modules.get()[0];
+  return JSONKernel{kernel_image.load_address, kernel_image.system_path};
+}
+
 Expected<FileSpec> TraceIntelPTBundleSaver::SaveToDisk(TraceIntelPT &trace_ipt,
                                                        FileSpec directory,
                                                        bool compact) {
@@ -348,20 +368,38 @@
 
   FileSystem::Instance().Resolve(directory);
 
-  Expected<std::vector<JSONProcess>> json_processes =
-      BuildProcessesSection(trace_ipt, directory);
-
-  if (!json_processes)
-    return json_processes.takeError();
-
   Expected<Optional<std::vector<JSONCpu>>> json_cpus =
       BuildCpusSection(trace_ipt, directory, compact);
   if (!json_cpus)
     return json_cpus.takeError();
 
-  JSONTraceBundleDescription json_intel_pt_bundle_desc{"intel-pt", *cpu_info, *json_processes,
-                                         *json_cpus,
-                                         trace_ipt.GetPerfZeroTscConversion()};
+  Optional<std::vector<JSONProcess>> json_processes = llvm::None;
+  Optional<JSONKernel> json_kernel = llvm::None;
+
+  if (trace_ipt.GetTraceMode() == TraceIntelPT::TraceMode::KernelMode) {
+    Expected<Optional<JSONKernel>> exp_json_kernel =
+        BuildKernelSection(trace_ipt, directory);
+    if (!exp_json_kernel)
+      return exp_json_kernel.takeError();
+    else
+      json_kernel = *exp_json_kernel;
+  } else {
+    Expected<Optional<std::vector<JSONProcess>>> exp_json_processes =
+        BuildProcessesSection(trace_ipt, directory);
+    if (!exp_json_processes)
+      return exp_json_processes.takeError();
+    else
+      json_processes = *exp_json_processes;
+  }
+
+  JSONTraceBundleDescription json_intel_pt_bundle_desc{
+      "intel-pt",
+      *cpu_info,
+      json_processes,
+      *json_cpus,
+      trace_ipt.GetPerfZeroTscConversion(),
+      json_kernel};
 
-  return SaveTraceBundleDescription(toJSON(json_intel_pt_bundle_desc), directory);
+  return SaveTraceBundleDescription(toJSON(json_intel_pt_bundle_desc),
+                                    directory);
 }
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.h
@@ -66,6 +66,10 @@
   CreateTraceIntelPTInstance(JSONTraceBundleDescription &bundle_description,
                              std::vector<ParsedProcess> &parsed_processes);
 
+  /// Create an empty Process object with given pid and target.
+  llvm::Expected<ParsedProcess> CreateEmptyProcess(lldb::pid_t pid,
+                                                   llvm::StringRef triple);
+
   /// Create the corresponding Threads and Process objects given the JSON
   /// process definition.
   ///
@@ -76,6 +80,10 @@
   /// Create a module associated with the given \p target using the definition from \p module.
   llvm::Error ParseModule(Target &target, const JSONModule &module);
 
+  /// Create a kernel process and cpu threads given the JSON kernel definition.
+  llvm::Expected<ParsedProcess>
+  ParseKernel(const JSONTraceBundleDescription &bundle_description);
+
   /// Create a user-friendly error message upon a JSON-parsing failure using the
   /// \a json::ObjectMapper functionality.
   ///
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp
@@ -10,6 +10,7 @@
 
 #include "../common/ThreadPostMortemTrace.h"
 #include "TraceIntelPT.h"
+#include "TraceIntelPTConstants.h"
 #include "TraceIntelPTJSONStructs.h"
 
 #include "lldb/Core/Debugger.h"
@@ -89,11 +90,11 @@
 }
 
 Expected<TraceIntelPTBundleLoader::ParsedProcess>
-TraceIntelPTBundleLoader::ParseProcess(const JSONProcess &process) {
+TraceIntelPTBundleLoader::CreateEmptyProcess(lldb::pid_t pid,
+                                             llvm::StringRef triple) {
   TargetSP target_sp;
   Status error = m_debugger.GetTargetList().CreateTarget(
-      m_debugger, /*user_exe_path*/ StringRef(), process.triple.value_or(""),
-      eLoadDependentsNo,
+      m_debugger, /*user_exe_path*/ StringRef(), triple, eLoadDependentsNo,
       /*platform_options*/ nullptr, target_sp);
 
   if (!target_sp)
@@ -107,13 +108,26 @@
       /*crash_file*/ nullptr,
       /*can_connect*/ false);
 
-  process_sp->SetID(static_cast<lldb::pid_t>(process.pid));
+  process_sp->SetID(static_cast<lldb::pid_t>(pid));
+
+  return parsed_process;
+}
+
+Expected<TraceIntelPTBundleLoader::ParsedProcess>
+TraceIntelPTBundleLoader::ParseProcess(const JSONProcess &process) {
+  Expected<ParsedProcess> parsed_process =
+      CreateEmptyProcess(process.pid, process.triple.value_or(""));
+
+  if (!parsed_process)
+    return parsed_process.takeError();
+
+  ProcessSP process_sp = parsed_process->target_sp->GetProcessSP();
 
   for (const JSONThread &thread : process.threads)
-    parsed_process.threads.push_back(ParseThread(*process_sp, thread));
+    parsed_process->threads.push_back(ParseThread(*process_sp, thread));
 
   for (const JSONModule &module : process.modules)
-    if (Error err = ParseModule(*target_sp, module))
+    if (Error err = ParseModule(*parsed_process->target_sp, module))
       return std::move(err);
 
   if (!process.threads.empty())
@@ -127,6 +141,57 @@
   return parsed_process;
 }
 
+Expected<TraceIntelPTBundleLoader::ParsedProcess>
+TraceIntelPTBundleLoader::ParseKernel(
+    const JSONTraceBundleDescription &bundle_description) {
+  Expected<ParsedProcess> parsed_process =
+      CreateEmptyProcess(kDefaultKernelProcessID, "");
+
+  if (!parsed_process)
+    return parsed_process.takeError();
+
+  ProcessSP process_sp = parsed_process->target_sp->GetProcessSP();
+
+  // Add cpus as fake threads
+  for (const JSONCpu &cpu : *bundle_description.cpus) {
+    ThreadPostMortemTraceSP thread_sp = std::make_shared<ThreadPostMortemTrace>(
+        *process_sp, static_cast<lldb::tid_t>(cpu.id), FileSpec(cpu.ipt_trace));
+    thread_sp->SetName(formatv("kernel_cpu_{0}", cpu.id).str().c_str());
+    process_sp->GetThreadList().AddThread(thread_sp);
+    parsed_process->threads.push_back(thread_sp);
+  }
+
+  // Add kernel image
+  FileSpec file_spec(bundle_description.kernel->file);
+  ModuleSpec module_spec;
+  module_spec.GetFileSpec() = file_spec;
+
+  Status error;
+  ModuleSP module_sp =
+      parsed_process->target_sp->GetOrCreateModule(module_spec, false, &error);
+
+  if (error.Fail())
+    return error.ToError();
+
+  lldb::addr_t load_address =
+      bundle_description.kernel->load_address
+          ? bundle_description.kernel->load_address->value
+          : kDefaultKernelLoadAddress;
+
+  bool load_addr_changed = false;
+  module_sp->SetLoadAddress(*parsed_process->target_sp, load_address, false,
+                            load_addr_changed);
+
+  process_sp->GetThreadList().SetSelectedThreadByIndexID(0);
+
+  // We invoke DidAttach to create a correct stopped state for the process and
+  // its threads.
+  ArchSpec process_arch;
+  process_sp->DidAttach(process_arch);
+
+  return parsed_process;
+}
+
 Expected<std::vector<TraceIntelPTBundleLoader::ParsedProcess>>
 TraceIntelPTBundleLoader::LoadBundle(
     const JSONTraceBundleDescription &bundle_description) {
@@ -139,13 +204,22 @@
     return std::move(err);
   };
 
-  for (const JSONProcess &process : bundle_description.processes) {
-    if (Expected<ParsedProcess> parsed_process = ParseProcess(process))
-      parsed_processes.push_back(std::move(*parsed_process));
-    else
-      return HandleError(parsed_process.takeError());
+  if (bundle_description.processes) {
+    for (const JSONProcess &process : *bundle_description.processes) {
+      if (Expected<ParsedProcess> parsed_process = ParseProcess(process))
+        parsed_processes.push_back(std::move(*parsed_process));
+      else
+        return HandleError(parsed_process.takeError());
+    }
   }
 
+  if (bundle_description.kernel) {
+    if (Expected<ParsedProcess> kernel_process =
+            ParseKernel(bundle_description))
+      parsed_processes.push_back(std::move(*kernel_process));
+    else
+      return HandleError(kernel_process.takeError());
+  }
   return parsed_processes;
 }
 
@@ -162,7 +236,7 @@
     "model": integer,
     "stepping": integer
   },
-  "processes": [
+  "processes"?: [
     {
       "pid": integer,
       "triple"?: string,
@@ -213,6 +287,13 @@
     "timeMult": integer,
     "timeShift": integer,
     "timeZero": integer | string decimal | hex string,
+  },
+  "kernel"?: {
+    "loadAddress"?: integer | string decimal | hex string,
+        // Kernel's image load address. Defaults to 0xffffffff81000000, which
+        // is a load address of x86 architecture if KASLR is not enabled.
+    "file": string,
+        // Path to the kernel image.
   }
 }
 
@@ -221,6 +302,8 @@
 - All paths are either absolute or relative to folder containing the bundle description file.
 - "cpus" is provided if and only if processes[].threads[].iptTrace is not provided.
 - "tscPerfZeroConversion" must be provided if "cpus" is provided.
+- "processes" is provided if and only if "kernel" is not provided.
+- If "kernel" is provided, then the "processes" section must be empty and the "cpus" section must be provided. This configuration indicates that the kernel was traced and user processes weren't. Besides that, the kernel is treated as a single process with one thread per CPU core. This doesn't handle actual kernel threads, but instead treats all the instructions executed by the kernel on each core as an individual thread.
  })";
   }
   return schema;
@@ -228,7 +311,7 @@
 
 Error TraceIntelPTBundleLoader::AugmentThreadsFromContextSwitches(
     JSONTraceBundleDescription &bundle_description) {
-  if (!bundle_description.cpus)
+  if (!bundle_description.cpus || !bundle_description.processes)
     return Error::success();
 
   if (!bundle_description.tsc_perf_zero_conversion)
@@ -239,7 +322,7 @@
   DenseMap<lldb::pid_t, JSONProcess *> indexed_processes;
   DenseMap<JSONProcess *, DenseSet<tid_t>> indexed_threads;
 
-  for (JSONProcess &process : bundle_description.processes) {
+  for (JSONProcess &process : *bundle_description.processes) {
     indexed_processes[process.pid] = &process;
     for (JSONThread &thread : process.threads)
       indexed_threads[&process].insert(thread.tid);
@@ -284,8 +367,12 @@
                    parsed_process.threads.end());
   }
 
+  TraceIntelPT::TraceMode trace_mode = bundle_description.kernel
+                                           ? TraceIntelPT::TraceMode::KernelMode
+                                           : TraceIntelPT::TraceMode::UserMode;
+
   TraceSP trace_instance = TraceIntelPT::CreateInstanceForPostmortemTrace(
-      bundle_description, processes, threads);
+      bundle_description, processes, threads, trace_mode);
   for (const ParsedProcess &parsed_process : parsed_processes)
     parsed_process.target_sp->SetTrace(trace_instance);
 
@@ -294,15 +381,17 @@
 
 void TraceIntelPTBundleLoader::NormalizeAllPaths(
     JSONTraceBundleDescription &bundle_description) {
-  for (JSONProcess &process : bundle_description.processes) {
-    for (JSONModule &module : process.modules) {
-      module.system_path = NormalizePath(module.system_path).GetPath();
-      if (module.file)
-        module.file = NormalizePath(*module.file).GetPath();
-    }
-    for (JSONThread &thread : process.threads) {
-      if (thread.ipt_trace)
-        thread.ipt_trace = NormalizePath(*thread.ipt_trace).GetPath();
+  if (bundle_description.processes) {
+    for (JSONProcess &process : *bundle_description.processes) {
+      for (JSONModule &module : process.modules) {
+        module.system_path = NormalizePath(module.system_path).GetPath();
+        if (module.file)
+          module.file = NormalizePath(*module.file).GetPath();
+      }
+      for (JSONThread &thread : process.threads) {
+        if (thread.ipt_trace)
+          thread.ipt_trace = NormalizePath(*thread.ipt_trace).GetPath();
+      }
     }
   }
   if (bundle_description.cpus) {
@@ -312,6 +401,10 @@
       cpu.ipt_trace = NormalizePath(cpu.ipt_trace).GetPath();
     }
   }
+  if (bundle_description.kernel) {
+    bundle_description.kernel->file =
+        NormalizePath(bundle_description.kernel->file).GetPath();
+  }
 }
 
 Expected<TraceSP> TraceIntelPTBundleLoader::Load() {
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
@@ -173,6 +173,10 @@
 
   TraceIntelPTSP GetSharedPtr();
 
+  enum class TraceMode { UserMode, KernelMode };
+
+  TraceMode GetTraceMode();
+
 private:
   friend class TraceIntelPTBundleLoader;
 
@@ -184,28 +188,34 @@
   ///     The definition file for the postmortem bundle.
   ///
   /// \param[in] traced_processes
-  ///     The processes traced in the live session.
+  ///     The processes traced in the postmortem session.
   ///
   /// \param[in] trace_threads
-  ///     The threads traced in the live session. They must belong to the
+  ///     The threads traced in the postmortem session. They must belong to the
   ///     processes mentioned above.
   ///
+  /// \param[in] trace_mode
+  ///     The tracing mode of the postmortem session.
+  ///
   /// \return
   ///     A TraceIntelPT shared pointer instance.
   /// \{
   static TraceIntelPTSP CreateInstanceForPostmortemTrace(
       JSONTraceBundleDescription &bundle_description,
       llvm::ArrayRef<lldb::ProcessSP> traced_processes,
-      llvm::ArrayRef<lldb::ThreadPostMortemTraceSP> traced_threads);
+      llvm::ArrayRef<lldb::ThreadPostMortemTraceSP> traced_threads,
+      TraceMode trace_mode);
 
   /// This constructor is used by CreateInstanceForPostmortemTrace to get the
   /// instance ready before using shared pointers, which is a limitation of C++.
   TraceIntelPT(JSONTraceBundleDescription &bundle_description,
-               llvm::ArrayRef<lldb::ProcessSP> traced_processes);
+               llvm::ArrayRef<lldb::ProcessSP> traced_processes,
+               TraceMode trace_mode);
   /// \}
 
   /// Constructor for live processes
-  TraceIntelPT(Process &live_process) : Trace(live_process){};
+  TraceIntelPT(Process &live_process)
+      : Trace(live_process), trace_mode(TraceMode::UserMode){};
 
   /// Decode the trace of the given thread that, i.e. recontruct the traced
   /// instructions.
@@ -245,6 +255,9 @@
 
   /// Get the storage after refreshing the data in the case of a live process.
   Storage &GetUpdatedStorage();
+
+  /// The tracing mode of post mortem trace.
+  TraceMode trace_mode;
 };
 
 } // namespace trace_intel_pt
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
@@ -78,10 +78,14 @@
   return std::static_pointer_cast<TraceIntelPT>(shared_from_this());
 }
 
+TraceIntelPT::TraceMode TraceIntelPT::GetTraceMode() { return trace_mode; }
+
 TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace(
-    JSONTraceBundleDescription &bundle_description, ArrayRef<ProcessSP> traced_processes,
-    ArrayRef<ThreadPostMortemTraceSP> traced_threads) {
-  TraceIntelPTSP trace_sp(new TraceIntelPT(bundle_description, traced_processes));
+    JSONTraceBundleDescription &bundle_description,
+    ArrayRef<ProcessSP> traced_processes,
+    ArrayRef<ThreadPostMortemTraceSP> traced_threads, TraceMode trace_mode) {
+  TraceIntelPTSP trace_sp(
+      new TraceIntelPT(bundle_description, traced_processes, trace_mode));
   trace_sp->m_storage.tsc_conversion = bundle_description.tsc_perf_zero_conversion;
 
   if (bundle_description.cpus) {
@@ -97,11 +101,6 @@
       cpus.push_back(cpu.id);
     }
 
-    std::vector<tid_t> tids;
-    for (const JSONProcess &process : bundle_description.processes)
-      for (const JSONThread &thread : process.threads)
-        tids.push_back(thread.tid);
-
     trace_sp->m_storage.multicpu_decoder.emplace(trace_sp);
   } else {
     for (const ThreadPostMortemTraceSP &thread : traced_threads) {
@@ -120,9 +119,10 @@
 }
 
 TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription &bundle_description,
-                           ArrayRef<ProcessSP> traced_processes)
+                           ArrayRef<ProcessSP> traced_processes,
+                           TraceMode trace_mode)
     : Trace(traced_processes, bundle_description.GetCpuIds()),
-      m_cpu_info(bundle_description.cpu_info) {}
+      m_cpu_info(bundle_description.cpu_info), trace_mode(trace_mode) {}
 
 Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) {
   if (const char *error = RefreshLiveProcessState())
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to