xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
181ad6265SDimitry Andric //===-- TraceIntelPTBundleLoader.cpp --------------------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #include "TraceIntelPTBundleLoader.h"
1081ad6265SDimitry Andric 
1181ad6265SDimitry Andric #include "../common/ThreadPostMortemTrace.h"
1281ad6265SDimitry Andric #include "TraceIntelPT.h"
13*bdd1243dSDimitry Andric #include "TraceIntelPTConstants.h"
1481ad6265SDimitry Andric #include "TraceIntelPTJSONStructs.h"
1581ad6265SDimitry Andric #include "lldb/Core/Debugger.h"
1681ad6265SDimitry Andric #include "lldb/Core/Module.h"
1781ad6265SDimitry Andric #include "lldb/Target/Process.h"
1881ad6265SDimitry Andric #include "lldb/Target/Target.h"
19*bdd1243dSDimitry Andric #include <optional>
2081ad6265SDimitry Andric 
2181ad6265SDimitry Andric using namespace lldb;
2281ad6265SDimitry Andric using namespace lldb_private;
2381ad6265SDimitry Andric using namespace lldb_private::trace_intel_pt;
2481ad6265SDimitry Andric using namespace llvm;
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric FileSpec TraceIntelPTBundleLoader::NormalizePath(const std::string &path) {
2781ad6265SDimitry Andric   FileSpec file_spec(path);
2881ad6265SDimitry Andric   if (file_spec.IsRelative())
2981ad6265SDimitry Andric     file_spec.PrependPathComponent(m_bundle_dir);
3081ad6265SDimitry Andric   return file_spec;
3181ad6265SDimitry Andric }
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric Error TraceIntelPTBundleLoader::ParseModule(Target &target,
3481ad6265SDimitry Andric                                             const JSONModule &module) {
3581ad6265SDimitry Andric   auto do_parse = [&]() -> Error {
3681ad6265SDimitry Andric     FileSpec system_file_spec(module.system_path);
3781ad6265SDimitry Andric 
38*bdd1243dSDimitry Andric     FileSpec local_file_spec(module.file.has_value() ? *module.file
3981ad6265SDimitry Andric                                                      : module.system_path);
4081ad6265SDimitry Andric 
4181ad6265SDimitry Andric     ModuleSpec module_spec;
4281ad6265SDimitry Andric     module_spec.GetFileSpec() = local_file_spec;
4381ad6265SDimitry Andric     module_spec.GetPlatformFileSpec() = system_file_spec;
4481ad6265SDimitry Andric 
45*bdd1243dSDimitry Andric     if (module.uuid.has_value())
4681ad6265SDimitry Andric       module_spec.GetUUID().SetFromStringRef(*module.uuid);
4781ad6265SDimitry Andric 
4881ad6265SDimitry Andric     Status error;
4981ad6265SDimitry Andric     ModuleSP module_sp =
5081ad6265SDimitry Andric         target.GetOrCreateModule(module_spec, /*notify*/ false, &error);
5181ad6265SDimitry Andric 
5281ad6265SDimitry Andric     if (error.Fail())
5381ad6265SDimitry Andric       return error.ToError();
5481ad6265SDimitry Andric 
5581ad6265SDimitry Andric     bool load_addr_changed = false;
5681ad6265SDimitry Andric     module_sp->SetLoadAddress(target, module.load_address.value, false,
5781ad6265SDimitry Andric                               load_addr_changed);
5881ad6265SDimitry Andric     return Error::success();
5981ad6265SDimitry Andric   };
6081ad6265SDimitry Andric   if (Error err = do_parse())
6181ad6265SDimitry Andric     return createStringError(
6281ad6265SDimitry Andric         inconvertibleErrorCode(), "Error when parsing module %s. %s",
6381ad6265SDimitry Andric         module.system_path.c_str(), toString(std::move(err)).c_str());
6481ad6265SDimitry Andric   return Error::success();
6581ad6265SDimitry Andric }
6681ad6265SDimitry Andric 
6781ad6265SDimitry Andric Error TraceIntelPTBundleLoader::CreateJSONError(json::Path::Root &root,
6881ad6265SDimitry Andric                                                 const json::Value &value) {
6981ad6265SDimitry Andric   std::string err;
7081ad6265SDimitry Andric   raw_string_ostream os(err);
7181ad6265SDimitry Andric   root.printErrorContext(value, os);
7281ad6265SDimitry Andric   return createStringError(
7381ad6265SDimitry Andric       std::errc::invalid_argument, "%s\n\nContext:\n%s\n\nSchema:\n%s",
7481ad6265SDimitry Andric       toString(root.getError()).c_str(), os.str().c_str(), GetSchema().data());
7581ad6265SDimitry Andric }
7681ad6265SDimitry Andric 
7781ad6265SDimitry Andric ThreadPostMortemTraceSP
7881ad6265SDimitry Andric TraceIntelPTBundleLoader::ParseThread(Process &process,
7981ad6265SDimitry Andric                                       const JSONThread &thread) {
8081ad6265SDimitry Andric   lldb::tid_t tid = static_cast<lldb::tid_t>(thread.tid);
8181ad6265SDimitry Andric 
82*bdd1243dSDimitry Andric   std::optional<FileSpec> trace_file;
8381ad6265SDimitry Andric   if (thread.ipt_trace)
8481ad6265SDimitry Andric     trace_file = FileSpec(*thread.ipt_trace);
8581ad6265SDimitry Andric 
8681ad6265SDimitry Andric   ThreadPostMortemTraceSP thread_sp =
8781ad6265SDimitry Andric       std::make_shared<ThreadPostMortemTrace>(process, tid, trace_file);
8881ad6265SDimitry Andric   process.GetThreadList().AddThread(thread_sp);
8981ad6265SDimitry Andric   return thread_sp;
9081ad6265SDimitry Andric }
9181ad6265SDimitry Andric 
9281ad6265SDimitry Andric Expected<TraceIntelPTBundleLoader::ParsedProcess>
93*bdd1243dSDimitry Andric TraceIntelPTBundleLoader::CreateEmptyProcess(lldb::pid_t pid,
94*bdd1243dSDimitry Andric                                              llvm::StringRef triple) {
9581ad6265SDimitry Andric   TargetSP target_sp;
9681ad6265SDimitry Andric   Status error = m_debugger.GetTargetList().CreateTarget(
97*bdd1243dSDimitry Andric       m_debugger, /*user_exe_path*/ StringRef(), triple, eLoadDependentsNo,
9881ad6265SDimitry Andric       /*platform_options*/ nullptr, target_sp);
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric   if (!target_sp)
10181ad6265SDimitry Andric     return error.ToError();
10281ad6265SDimitry Andric 
10381ad6265SDimitry Andric   ParsedProcess parsed_process;
10481ad6265SDimitry Andric   parsed_process.target_sp = target_sp;
10581ad6265SDimitry Andric 
10681ad6265SDimitry Andric   ProcessSP process_sp = target_sp->CreateProcess(
10781ad6265SDimitry Andric       /*listener*/ nullptr, "trace",
10881ad6265SDimitry Andric       /*crash_file*/ nullptr,
10981ad6265SDimitry Andric       /*can_connect*/ false);
11081ad6265SDimitry Andric 
111*bdd1243dSDimitry Andric   process_sp->SetID(static_cast<lldb::pid_t>(pid));
112*bdd1243dSDimitry Andric 
113*bdd1243dSDimitry Andric   return parsed_process;
114*bdd1243dSDimitry Andric }
115*bdd1243dSDimitry Andric 
116*bdd1243dSDimitry Andric Expected<TraceIntelPTBundleLoader::ParsedProcess>
117*bdd1243dSDimitry Andric TraceIntelPTBundleLoader::ParseProcess(const JSONProcess &process) {
118*bdd1243dSDimitry Andric   Expected<ParsedProcess> parsed_process =
119*bdd1243dSDimitry Andric       CreateEmptyProcess(process.pid, process.triple.value_or(""));
120*bdd1243dSDimitry Andric 
121*bdd1243dSDimitry Andric   if (!parsed_process)
122*bdd1243dSDimitry Andric     return parsed_process.takeError();
123*bdd1243dSDimitry Andric 
124*bdd1243dSDimitry Andric   ProcessSP process_sp = parsed_process->target_sp->GetProcessSP();
12581ad6265SDimitry Andric 
12681ad6265SDimitry Andric   for (const JSONThread &thread : process.threads)
127*bdd1243dSDimitry Andric     parsed_process->threads.push_back(ParseThread(*process_sp, thread));
12881ad6265SDimitry Andric 
12981ad6265SDimitry Andric   for (const JSONModule &module : process.modules)
130*bdd1243dSDimitry Andric     if (Error err = ParseModule(*parsed_process->target_sp, module))
13181ad6265SDimitry Andric       return std::move(err);
13281ad6265SDimitry Andric 
13381ad6265SDimitry Andric   if (!process.threads.empty())
13481ad6265SDimitry Andric     process_sp->GetThreadList().SetSelectedThreadByIndexID(0);
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric   // We invoke DidAttach to create a correct stopped state for the process and
13781ad6265SDimitry Andric   // its threads.
13881ad6265SDimitry Andric   ArchSpec process_arch;
13981ad6265SDimitry Andric   process_sp->DidAttach(process_arch);
14081ad6265SDimitry Andric 
14181ad6265SDimitry Andric   return parsed_process;
14281ad6265SDimitry Andric }
14381ad6265SDimitry Andric 
144*bdd1243dSDimitry Andric Expected<TraceIntelPTBundleLoader::ParsedProcess>
145*bdd1243dSDimitry Andric TraceIntelPTBundleLoader::ParseKernel(
146*bdd1243dSDimitry Andric     const JSONTraceBundleDescription &bundle_description) {
147*bdd1243dSDimitry Andric   Expected<ParsedProcess> parsed_process =
148*bdd1243dSDimitry Andric       CreateEmptyProcess(kDefaultKernelProcessID, "");
149*bdd1243dSDimitry Andric 
150*bdd1243dSDimitry Andric   if (!parsed_process)
151*bdd1243dSDimitry Andric     return parsed_process.takeError();
152*bdd1243dSDimitry Andric 
153*bdd1243dSDimitry Andric   ProcessSP process_sp = parsed_process->target_sp->GetProcessSP();
154*bdd1243dSDimitry Andric 
155*bdd1243dSDimitry Andric   // Add cpus as fake threads
156*bdd1243dSDimitry Andric   for (const JSONCpu &cpu : *bundle_description.cpus) {
157*bdd1243dSDimitry Andric     ThreadPostMortemTraceSP thread_sp = std::make_shared<ThreadPostMortemTrace>(
158*bdd1243dSDimitry Andric         *process_sp, static_cast<lldb::tid_t>(cpu.id), FileSpec(cpu.ipt_trace));
159*bdd1243dSDimitry Andric     thread_sp->SetName(formatv("kernel_cpu_{0}", cpu.id).str().c_str());
160*bdd1243dSDimitry Andric     process_sp->GetThreadList().AddThread(thread_sp);
161*bdd1243dSDimitry Andric     parsed_process->threads.push_back(thread_sp);
162*bdd1243dSDimitry Andric   }
163*bdd1243dSDimitry Andric 
164*bdd1243dSDimitry Andric   // Add kernel image
165*bdd1243dSDimitry Andric   FileSpec file_spec(bundle_description.kernel->file);
166*bdd1243dSDimitry Andric   ModuleSpec module_spec;
167*bdd1243dSDimitry Andric   module_spec.GetFileSpec() = file_spec;
168*bdd1243dSDimitry Andric 
169*bdd1243dSDimitry Andric   Status error;
170*bdd1243dSDimitry Andric   ModuleSP module_sp =
171*bdd1243dSDimitry Andric       parsed_process->target_sp->GetOrCreateModule(module_spec, false, &error);
172*bdd1243dSDimitry Andric 
173*bdd1243dSDimitry Andric   if (error.Fail())
174*bdd1243dSDimitry Andric     return error.ToError();
175*bdd1243dSDimitry Andric 
176*bdd1243dSDimitry Andric   lldb::addr_t load_address =
177*bdd1243dSDimitry Andric       bundle_description.kernel->load_address
178*bdd1243dSDimitry Andric           ? bundle_description.kernel->load_address->value
179*bdd1243dSDimitry Andric           : kDefaultKernelLoadAddress;
180*bdd1243dSDimitry Andric 
181*bdd1243dSDimitry Andric   bool load_addr_changed = false;
182*bdd1243dSDimitry Andric   module_sp->SetLoadAddress(*parsed_process->target_sp, load_address, false,
183*bdd1243dSDimitry Andric                             load_addr_changed);
184*bdd1243dSDimitry Andric 
185*bdd1243dSDimitry Andric   process_sp->GetThreadList().SetSelectedThreadByIndexID(0);
186*bdd1243dSDimitry Andric 
187*bdd1243dSDimitry Andric   // We invoke DidAttach to create a correct stopped state for the process and
188*bdd1243dSDimitry Andric   // its threads.
189*bdd1243dSDimitry Andric   ArchSpec process_arch;
190*bdd1243dSDimitry Andric   process_sp->DidAttach(process_arch);
191*bdd1243dSDimitry Andric 
192*bdd1243dSDimitry Andric   return parsed_process;
193*bdd1243dSDimitry Andric }
194*bdd1243dSDimitry Andric 
19581ad6265SDimitry Andric Expected<std::vector<TraceIntelPTBundleLoader::ParsedProcess>>
19681ad6265SDimitry Andric TraceIntelPTBundleLoader::LoadBundle(
19781ad6265SDimitry Andric     const JSONTraceBundleDescription &bundle_description) {
19881ad6265SDimitry Andric   std::vector<ParsedProcess> parsed_processes;
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric   auto HandleError = [&](Error &&err) {
20181ad6265SDimitry Andric     // Delete all targets that were created so far in case of failures
20281ad6265SDimitry Andric     for (ParsedProcess &parsed_process : parsed_processes)
20381ad6265SDimitry Andric       m_debugger.GetTargetList().DeleteTarget(parsed_process.target_sp);
20481ad6265SDimitry Andric     return std::move(err);
20581ad6265SDimitry Andric   };
20681ad6265SDimitry Andric 
207*bdd1243dSDimitry Andric   if (bundle_description.processes) {
208*bdd1243dSDimitry Andric     for (const JSONProcess &process : *bundle_description.processes) {
20981ad6265SDimitry Andric       if (Expected<ParsedProcess> parsed_process = ParseProcess(process))
21081ad6265SDimitry Andric         parsed_processes.push_back(std::move(*parsed_process));
21181ad6265SDimitry Andric       else
21281ad6265SDimitry Andric         return HandleError(parsed_process.takeError());
21381ad6265SDimitry Andric     }
214*bdd1243dSDimitry Andric   }
215*bdd1243dSDimitry Andric 
216*bdd1243dSDimitry Andric   if (bundle_description.kernel) {
217*bdd1243dSDimitry Andric     if (Expected<ParsedProcess> kernel_process =
218*bdd1243dSDimitry Andric             ParseKernel(bundle_description))
219*bdd1243dSDimitry Andric       parsed_processes.push_back(std::move(*kernel_process));
220*bdd1243dSDimitry Andric     else
221*bdd1243dSDimitry Andric       return HandleError(kernel_process.takeError());
222*bdd1243dSDimitry Andric   }
22381ad6265SDimitry Andric 
22481ad6265SDimitry Andric   return parsed_processes;
22581ad6265SDimitry Andric }
22681ad6265SDimitry Andric 
22781ad6265SDimitry Andric StringRef TraceIntelPTBundleLoader::GetSchema() {
22881ad6265SDimitry Andric   static std::string schema;
22981ad6265SDimitry Andric   if (schema.empty()) {
23081ad6265SDimitry Andric     schema = R"({
23181ad6265SDimitry Andric   "type": "intel-pt",
23281ad6265SDimitry Andric   "cpuInfo": {
23381ad6265SDimitry Andric     // CPU information gotten from, for example, /proc/cpuinfo.
23481ad6265SDimitry Andric 
23581ad6265SDimitry Andric     "vendor": "GenuineIntel" | "unknown",
23681ad6265SDimitry Andric     "family": integer,
23781ad6265SDimitry Andric     "model": integer,
23881ad6265SDimitry Andric     "stepping": integer
23981ad6265SDimitry Andric   },
240*bdd1243dSDimitry Andric   "processes?": [
24181ad6265SDimitry Andric     {
24281ad6265SDimitry Andric       "pid": integer,
24381ad6265SDimitry Andric       "triple"?: string,
24481ad6265SDimitry Andric           // Optional clang/llvm target triple.
245*bdd1243dSDimitry Andric           // This must be provided if the trace will be created not using the
246*bdd1243dSDimitry Andric           // CLI or on a machine other than where the target was traced.
24781ad6265SDimitry Andric       "threads": [
24881ad6265SDimitry Andric           // A list of known threads for the given process. When context switch
24981ad6265SDimitry Andric           // data is provided, LLDB will automatically create threads for the
25081ad6265SDimitry Andric           // this process whenever it finds new threads when traversing the
25181ad6265SDimitry Andric           // context switches, so passing values to this list in this case is
25281ad6265SDimitry Andric           // optional.
25381ad6265SDimitry Andric         {
25481ad6265SDimitry Andric           "tid": integer,
25581ad6265SDimitry Andric           "iptTrace"?: string
25681ad6265SDimitry Andric               // Path to the raw Intel PT buffer file for this thread.
25781ad6265SDimitry Andric         }
25881ad6265SDimitry Andric       ],
25981ad6265SDimitry Andric       "modules": [
26081ad6265SDimitry Andric         {
26181ad6265SDimitry Andric           "systemPath": string,
26281ad6265SDimitry Andric               // Original path of the module at runtime.
26381ad6265SDimitry Andric           "file"?: string,
26481ad6265SDimitry Andric               // Path to a copy of the file if not available at "systemPath".
26581ad6265SDimitry Andric           "loadAddress": integer | string decimal | hex string,
26681ad6265SDimitry Andric               // Lowest address of the sections of the module loaded on memory.
26781ad6265SDimitry Andric           "uuid"?: string,
26881ad6265SDimitry Andric               // Build UUID for the file for sanity checks.
26981ad6265SDimitry Andric         }
27081ad6265SDimitry Andric       ]
27181ad6265SDimitry Andric     }
27281ad6265SDimitry Andric   ],
27381ad6265SDimitry Andric   "cpus"?: [
27481ad6265SDimitry Andric     {
27581ad6265SDimitry Andric       "id": integer,
27681ad6265SDimitry Andric           // Id of this CPU core.
27781ad6265SDimitry Andric       "iptTrace": string,
27881ad6265SDimitry Andric           // Path to the raw Intel PT buffer for this cpu core.
27981ad6265SDimitry Andric       "contextSwitchTrace": string,
28081ad6265SDimitry Andric           // Path to the raw perf_event_open context switch trace file for this cpu core.
28181ad6265SDimitry Andric           // The perf_event must have been configured with PERF_SAMPLE_TID and
28281ad6265SDimitry Andric           // PERF_SAMPLE_TIME, as well as sample_id_all = 1.
28381ad6265SDimitry Andric     }
28481ad6265SDimitry Andric   ],
28581ad6265SDimitry Andric   "tscPerfZeroConversion"?: {
28681ad6265SDimitry Andric     // Values used to convert between TSCs and nanoseconds. See the time_zero
28781ad6265SDimitry Andric     // section in https://man7.org/linux/man-pages/man2/perf_event_open.2.html
28881ad6265SDimitry Andric     // for for information.
28981ad6265SDimitry Andric 
29081ad6265SDimitry Andric     "timeMult": integer,
29181ad6265SDimitry Andric     "timeShift": integer,
29281ad6265SDimitry Andric     "timeZero": integer | string decimal | hex string,
293*bdd1243dSDimitry Andric   },
294*bdd1243dSDimitry Andric   "kernel"?: {
295*bdd1243dSDimitry Andric     "loadAddress"?: integer | string decimal | hex string,
296*bdd1243dSDimitry Andric         // Kernel's image load address. Defaults to 0xffffffff81000000, which
297*bdd1243dSDimitry Andric         // is a load address of x86 architecture if KASLR is not enabled.
298*bdd1243dSDimitry Andric     "file": string,
299*bdd1243dSDimitry Andric         // Path to the kernel image.
30081ad6265SDimitry Andric   }
30181ad6265SDimitry Andric }
30281ad6265SDimitry Andric 
30381ad6265SDimitry Andric Notes:
30481ad6265SDimitry Andric 
305*bdd1243dSDimitry Andric - All paths are either absolute or relative to folder containing the bundle
306*bdd1243dSDimitry Andric   description file.
30781ad6265SDimitry Andric - "cpus" is provided if and only if processes[].threads[].iptTrace is not provided.
30881ad6265SDimitry Andric - "tscPerfZeroConversion" must be provided if "cpus" is provided.
309*bdd1243dSDimitry Andric - If "kernel" is provided, then the "processes" section must be empty or not
310*bdd1243dSDimitry Andric   passed at all, and the "cpus" section must be provided. This configuration
311*bdd1243dSDimitry Andric   indicates that the kernel was traced and user processes weren't. Besides
312*bdd1243dSDimitry Andric   that, the kernel is treated as a single process with one thread per CPU
313*bdd1243dSDimitry Andric   core. This doesn't handle actual kernel threads, but instead treats
314*bdd1243dSDimitry Andric   all the instructions executed by the kernel on each core as an
315*bdd1243dSDimitry Andric   individual thread.})";
31681ad6265SDimitry Andric   }
31781ad6265SDimitry Andric   return schema;
31881ad6265SDimitry Andric }
31981ad6265SDimitry Andric 
32081ad6265SDimitry Andric Error TraceIntelPTBundleLoader::AugmentThreadsFromContextSwitches(
32181ad6265SDimitry Andric     JSONTraceBundleDescription &bundle_description) {
322*bdd1243dSDimitry Andric   if (!bundle_description.cpus || !bundle_description.processes)
32381ad6265SDimitry Andric     return Error::success();
32481ad6265SDimitry Andric 
32581ad6265SDimitry Andric   if (!bundle_description.tsc_perf_zero_conversion)
32681ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(),
32781ad6265SDimitry Andric                              "TSC to nanos conversion values are needed when "
32881ad6265SDimitry Andric                              "context switch information is provided.");
32981ad6265SDimitry Andric 
33081ad6265SDimitry Andric   DenseMap<lldb::pid_t, JSONProcess *> indexed_processes;
33181ad6265SDimitry Andric   DenseMap<JSONProcess *, DenseSet<tid_t>> indexed_threads;
33281ad6265SDimitry Andric 
333*bdd1243dSDimitry Andric   for (JSONProcess &process : *bundle_description.processes) {
33481ad6265SDimitry Andric     indexed_processes[process.pid] = &process;
33581ad6265SDimitry Andric     for (JSONThread &thread : process.threads)
33681ad6265SDimitry Andric       indexed_threads[&process].insert(thread.tid);
33781ad6265SDimitry Andric   }
33881ad6265SDimitry Andric 
33981ad6265SDimitry Andric   auto on_thread_seen = [&](lldb::pid_t pid, tid_t tid) {
34081ad6265SDimitry Andric     auto proc = indexed_processes.find(pid);
34181ad6265SDimitry Andric     if (proc == indexed_processes.end())
34281ad6265SDimitry Andric       return;
34381ad6265SDimitry Andric     if (indexed_threads[proc->second].count(tid))
34481ad6265SDimitry Andric       return;
34581ad6265SDimitry Andric     indexed_threads[proc->second].insert(tid);
34681ad6265SDimitry Andric     proc->second->threads.push_back({tid, /*ipt_trace=*/None});
34781ad6265SDimitry Andric   };
34881ad6265SDimitry Andric 
34981ad6265SDimitry Andric   for (const JSONCpu &cpu : *bundle_description.cpus) {
35081ad6265SDimitry Andric     Error err = Trace::OnDataFileRead(
35181ad6265SDimitry Andric         FileSpec(cpu.context_switch_trace),
35281ad6265SDimitry Andric         [&](ArrayRef<uint8_t> data) -> Error {
35381ad6265SDimitry Andric           Expected<std::vector<ThreadContinuousExecution>> executions =
354*bdd1243dSDimitry Andric               DecodePerfContextSwitchTrace(
355*bdd1243dSDimitry Andric                   data, cpu.id, *bundle_description.tsc_perf_zero_conversion);
35681ad6265SDimitry Andric           if (!executions)
35781ad6265SDimitry Andric             return executions.takeError();
35881ad6265SDimitry Andric           for (const ThreadContinuousExecution &execution : *executions)
35981ad6265SDimitry Andric             on_thread_seen(execution.pid, execution.tid);
36081ad6265SDimitry Andric           return Error::success();
36181ad6265SDimitry Andric         });
36281ad6265SDimitry Andric     if (err)
36381ad6265SDimitry Andric       return err;
36481ad6265SDimitry Andric   }
36581ad6265SDimitry Andric   return Error::success();
36681ad6265SDimitry Andric }
36781ad6265SDimitry Andric 
36881ad6265SDimitry Andric Expected<TraceSP> TraceIntelPTBundleLoader::CreateTraceIntelPTInstance(
369*bdd1243dSDimitry Andric     JSONTraceBundleDescription &bundle_description,
370*bdd1243dSDimitry Andric     std::vector<ParsedProcess> &parsed_processes) {
37181ad6265SDimitry Andric   std::vector<ThreadPostMortemTraceSP> threads;
37281ad6265SDimitry Andric   std::vector<ProcessSP> processes;
37381ad6265SDimitry Andric   for (const ParsedProcess &parsed_process : parsed_processes) {
37481ad6265SDimitry Andric     processes.push_back(parsed_process.target_sp->GetProcessSP());
37581ad6265SDimitry Andric     threads.insert(threads.end(), parsed_process.threads.begin(),
37681ad6265SDimitry Andric                    parsed_process.threads.end());
37781ad6265SDimitry Andric   }
37881ad6265SDimitry Andric 
379*bdd1243dSDimitry Andric   TraceIntelPT::TraceMode trace_mode = bundle_description.kernel
380*bdd1243dSDimitry Andric                                            ? TraceIntelPT::TraceMode::KernelMode
381*bdd1243dSDimitry Andric                                            : TraceIntelPT::TraceMode::UserMode;
382*bdd1243dSDimitry Andric 
38381ad6265SDimitry Andric   TraceSP trace_instance = TraceIntelPT::CreateInstanceForPostmortemTrace(
384*bdd1243dSDimitry Andric       bundle_description, processes, threads, trace_mode);
38581ad6265SDimitry Andric   for (const ParsedProcess &parsed_process : parsed_processes)
38681ad6265SDimitry Andric     parsed_process.target_sp->SetTrace(trace_instance);
38781ad6265SDimitry Andric 
38881ad6265SDimitry Andric   return trace_instance;
38981ad6265SDimitry Andric }
39081ad6265SDimitry Andric 
39181ad6265SDimitry Andric void TraceIntelPTBundleLoader::NormalizeAllPaths(
39281ad6265SDimitry Andric     JSONTraceBundleDescription &bundle_description) {
393*bdd1243dSDimitry Andric   if (bundle_description.processes) {
394*bdd1243dSDimitry Andric     for (JSONProcess &process : *bundle_description.processes) {
39581ad6265SDimitry Andric       for (JSONModule &module : process.modules) {
39681ad6265SDimitry Andric         module.system_path = NormalizePath(module.system_path).GetPath();
39781ad6265SDimitry Andric         if (module.file)
39881ad6265SDimitry Andric           module.file = NormalizePath(*module.file).GetPath();
39981ad6265SDimitry Andric       }
40081ad6265SDimitry Andric       for (JSONThread &thread : process.threads) {
40181ad6265SDimitry Andric         if (thread.ipt_trace)
40281ad6265SDimitry Andric           thread.ipt_trace = NormalizePath(*thread.ipt_trace).GetPath();
40381ad6265SDimitry Andric       }
40481ad6265SDimitry Andric     }
405*bdd1243dSDimitry Andric   }
40681ad6265SDimitry Andric   if (bundle_description.cpus) {
40781ad6265SDimitry Andric     for (JSONCpu &cpu : *bundle_description.cpus) {
40881ad6265SDimitry Andric       cpu.context_switch_trace =
40981ad6265SDimitry Andric           NormalizePath(cpu.context_switch_trace).GetPath();
41081ad6265SDimitry Andric       cpu.ipt_trace = NormalizePath(cpu.ipt_trace).GetPath();
41181ad6265SDimitry Andric     }
41281ad6265SDimitry Andric   }
413*bdd1243dSDimitry Andric   if (bundle_description.kernel) {
414*bdd1243dSDimitry Andric     bundle_description.kernel->file =
415*bdd1243dSDimitry Andric         NormalizePath(bundle_description.kernel->file).GetPath();
416*bdd1243dSDimitry Andric   }
41781ad6265SDimitry Andric }
41881ad6265SDimitry Andric 
41981ad6265SDimitry Andric Expected<TraceSP> TraceIntelPTBundleLoader::Load() {
42081ad6265SDimitry Andric   json::Path::Root root("traceBundle");
42181ad6265SDimitry Andric   JSONTraceBundleDescription bundle_description;
42281ad6265SDimitry Andric   if (!fromJSON(m_bundle_description, bundle_description, root))
42381ad6265SDimitry Andric     return CreateJSONError(root, m_bundle_description);
42481ad6265SDimitry Andric 
42581ad6265SDimitry Andric   NormalizeAllPaths(bundle_description);
42681ad6265SDimitry Andric 
42781ad6265SDimitry Andric   if (Error err = AugmentThreadsFromContextSwitches(bundle_description))
42881ad6265SDimitry Andric     return std::move(err);
42981ad6265SDimitry Andric 
43081ad6265SDimitry Andric   if (Expected<std::vector<ParsedProcess>> parsed_processes =
43181ad6265SDimitry Andric           LoadBundle(bundle_description))
43281ad6265SDimitry Andric     return CreateTraceIntelPTInstance(bundle_description, *parsed_processes);
43381ad6265SDimitry Andric   else
43481ad6265SDimitry Andric     return parsed_processes.takeError();
43581ad6265SDimitry Andric }
436