persona0220 created this revision.
persona0220 added reviewers: wallace, jj10306.
Herald added a project: All.
persona0220 requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
Add a new "kernel" section with following schema.
"kernel": {
"loadAddress"?: decimal | hex string | string decimal
# This is optional. If it's not specified, use default address
0xffffffff81000000.
"file": string
# path to the kernel image
}
Here's more details of the diff:
- If "kernel" section exist, it means current tracing mode is //KernelMode//.
- If tracing mode is //KernelMode//, the "processes" section must be empty and
the "kernel" and "cpus" section must be provided. This is tested with
`TestTraceLoad`.
- "kernel" section is parsed and turned into a new process with a single module
which is the kernel image. The kernel process has N fake threads, one for each
cpu.
Repository:
rG LLVM Github Monorepo
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/intelpt-kernel-trace/cores/45.intelpt_trace
lldb/test/API/commands/trace/intelpt-kernel-trace/cores/45.perf_context_switch_trace
lldb/test/API/commands/trace/intelpt-kernel-trace/cores/51.intelpt_trace
lldb/test/API/commands/trace/intelpt-kernel-trace/cores/51.perf_context_switch_trace
lldb/test/API/commands/trace/intelpt-kernel-trace/modules/m.out
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": "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": "cores/45.perf_context_switch_trace",
+ "id": 45,
+ "iptTrace": "cores/45.intelpt_trace"
+ },
+ {
+ "contextSwitchTrace": "cores/51.perf_context_switch_trace",
+ "id": 51,
+ "iptTrace": "cores/51.intelpt_trace"
+ }
+ ],
+ "cpuInfo": {
+ "family": 6,
+ "model": 85,
+ "stepping": 4,
+ "vendor": "GenuineIntel"
+ },
+ "processes": [
+ {
+ "modules": [
+ {
+ "file": "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": "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,32 @@
+{
+ "cpus": [
+ {
+ "contextSwitchTrace": "cores/45.perf_context_switch_trace",
+ "id": 45,
+ "iptTrace": "cores/45.intelpt_trace"
+ },
+ {
+ "contextSwitchTrace": "cores/51.perf_context_switch_trace",
+ "id": 51,
+ "iptTrace": "cores/51.intelpt_trace"
+ }
+ ],
+ "cpuInfo": {
+ "family": 6,
+ "model": 85,
+ "stepping": 4,
+ "vendor": "GenuineIntel"
+ },
+ "processes": [
+ ],
+ "tscPerfZeroConversion": {
+ "timeMult": 1076264588,
+ "timeShift": 31,
+ "timeZero": 18433473881008870804
+ },
+ "kernel": {
+ "file": "modules/m.out",
+ "loadAddress": 4194304
+ },
+ "type": "intel-pt"
+}
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,30 @@
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("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<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,6 +116,20 @@
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},
@@ -123,14 +137,16 @@
// 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}};
+ {"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("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 +158,18 @@
if (!fromJSON(*value.getAsObject()->get("cpuInfo"), bundle_description.cpu_info,
path.field("cpuInfo")))
return false;
+ // When kernel section is present, this is kernel mode tracing. Thus, throw an
+ // error if there is any user process or cpus section is not present.
+ if (bundle_description.kernel){
+ if(!bundle_description.processes.empty()) {
+ path.report("\"processes\" must be empty when \"kernel\" is provided");
+ return false;
+ }
+ else if(!bundle_description.cpus) {
+ path.report("\"cpus\" is required when \"kernel\" is 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
@@ -22,6 +22,7 @@
const llvm::Optional<size_t> kDefaultPsbPeriod = llvm::None;
const bool kDefaultPerCpuTracing = false;
const bool kDefaultDisableCgroupFiltering = false;
+const uint64_t kDefaultKernelLoadAddress = 0xffffffff81000000;
} // 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
@@ -359,6 +359,8 @@
if (!json_cpus)
return json_cpus.takeError();
+ //TODO: Add kernel section
+
JSONTraceBundleDescription json_intel_pt_bundle_desc{"intel-pt", *cpu_info, *json_processes,
*json_cpus,
trace_ipt.GetPerfZeroTscConversion()};
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
@@ -76,6 +76,8 @@
/// Create a module associated with the given \p target using the definition from \p module.
llvm::Error ParseModule(Target &target, const JSONModule &module);
+ 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
@@ -11,6 +11,7 @@
#include "../common/ThreadPostMortemTrace.h"
#include "TraceIntelPT.h"
#include "TraceIntelPTJSONStructs.h"
+#include "TraceIntelPTConstants.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
@@ -127,6 +128,71 @@
return parsed_process;
}
+Expected<TraceIntelPTBundleLoader::ParsedProcess>
+TraceIntelPTBundleLoader::ParseKernel(const JSONTraceBundleDescription &bundle_description) {
+ TargetSP target_sp;
+ Status error = m_debugger.GetTargetList().CreateTarget(
+ m_debugger, /*user_exe_path*/ StringRef(), "",
+ eLoadDependentsNo,
+ /*platform_options*/ nullptr, target_sp);
+
+ if (!target_sp)
+ return error.ToError();
+
+ ParsedProcess kernel_process;
+ kernel_process.target_sp = target_sp;
+
+ ProcessSP process_sp = target_sp->CreateProcess(
+ /*listener*/ nullptr, "trace",
+ /*crash_file*/ nullptr,
+ /*can_connect*/ false);
+
+ // Let fake kernel process's pid to be 1.
+ process_sp->SetID(static_cast<lldb::pid_t>(1));
+
+ // Add cpus as fake threads
+ for (const JSONCpu &cpu : *bundle_description.cpus) {
+ char thread_name[20];
+ sprintf(thread_name, "kernel_cpu_%d", cpu.id);
+ lldb::tid_t tid = static_cast<lldb::tid_t>(cpu.id);
+
+ Optional<FileSpec> trace_file;
+ trace_file = FileSpec(cpu.ipt_trace);
+
+ ThreadPostMortemTraceSP thread_sp = std::make_shared<ThreadPostMortemTrace>(*process_sp, tid, trace_file);
+ thread_sp->SetName(thread_name);
+ process_sp->GetThreadList().AddThread(thread_sp);
+ kernel_process.threads.push_back(thread_sp);
+ }
+
+ // Add kernel image
+ FileSpec system_file_spec(bundle_description.kernel->file);
+ ModuleSpec module_spec;
+ module_spec.GetFileSpec() = system_file_spec;
+ module_spec.GetPlatformFileSpec() = system_file_spec;
+
+ ModuleSP module_sp = target_sp->GetOrCreateModule(module_spec, false, &error);
+
+ if (error.Fail())
+ return error.ToError();
+
+ bool load_addr_changed = false;
+ if (bundle_description.kernel->load_address)
+ module_sp->SetLoadAddress(*target_sp, bundle_description.kernel->load_address->value, false, load_addr_changed);
+ else
+ module_sp->SetLoadAddress(*target_sp, kDefaultKernelLoadAddress, 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 kernel_process;
+}
+
+
Expected<std::vector<TraceIntelPTBundleLoader::ParsedProcess>>
TraceIntelPTBundleLoader::LoadBundle(
const JSONTraceBundleDescription &bundle_description) {
@@ -146,6 +212,12 @@
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;
}
@@ -213,6 +285,12 @@
"timeMult": integer,
"timeShift": integer,
"timeZero": integer | string decimal | hex string,
+ },
+ "kernel"?: {
+ "loadAddress"?: integer | string decimal | hex string,
+ // Kernel's start address. 0xffffffff81000000 on default.
+ "file": string,
+ // Path to the kernel image.
}
}
@@ -221,6 +299,7 @@
- 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.
+- If tracing mode is "kernel", then the "processes" section must be empty and the "kernel" and "cpus" section must be provided.
})";
}
return schema;
@@ -284,8 +363,11 @@
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);
@@ -312,6 +394,8 @@
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,11 @@
TraceIntelPTSP GetSharedPtr();
+ enum TraceMode {
+ UserMode,
+ KernelMode
+ };
+
private:
friend class TraceIntelPTBundleLoader;
@@ -190,13 +195,17 @@
/// The threads traced in the live session. They must belong to the
/// processes mentioned above.
///
+ /// \param[in] trace_mode
+ /// The tracing mode in the live session. One of TraceMode enum value.
+ ///
/// \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++.
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
@@ -80,7 +80,7 @@
TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace(
JSONTraceBundleDescription &bundle_description, ArrayRef<ProcessSP> traced_processes,
- ArrayRef<ThreadPostMortemTraceSP> traced_threads) {
+ ArrayRef<ThreadPostMortemTraceSP> traced_threads, TraceMode trace_mode) {
TraceIntelPTSP trace_sp(new TraceIntelPT(bundle_description, traced_processes));
trace_sp->m_storage.tsc_conversion = bundle_description.tsc_perf_zero_conversion;
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits