xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1*f6aab3d8Srobert //===-- TraceIntelPTBundleLoader.cpp --------------------------------------===//
2*f6aab3d8Srobert //
3*f6aab3d8Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*f6aab3d8Srobert // See https://llvm.org/LICENSE.txt for license information.
5*f6aab3d8Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*f6aab3d8Srobert //
7*f6aab3d8Srobert //===----------------------------------------------------------------------===//
8*f6aab3d8Srobert 
9*f6aab3d8Srobert #include "TraceIntelPTBundleLoader.h"
10*f6aab3d8Srobert 
11*f6aab3d8Srobert #include "../common/ThreadPostMortemTrace.h"
12*f6aab3d8Srobert #include "TraceIntelPT.h"
13*f6aab3d8Srobert #include "TraceIntelPTConstants.h"
14*f6aab3d8Srobert #include "TraceIntelPTJSONStructs.h"
15*f6aab3d8Srobert #include "lldb/Core/Debugger.h"
16*f6aab3d8Srobert #include "lldb/Core/Module.h"
17*f6aab3d8Srobert #include "lldb/Target/Process.h"
18*f6aab3d8Srobert #include "lldb/Target/Target.h"
19*f6aab3d8Srobert #include <optional>
20*f6aab3d8Srobert 
21*f6aab3d8Srobert using namespace lldb;
22*f6aab3d8Srobert using namespace lldb_private;
23*f6aab3d8Srobert using namespace lldb_private::trace_intel_pt;
24*f6aab3d8Srobert using namespace llvm;
25*f6aab3d8Srobert 
NormalizePath(const std::string & path)26*f6aab3d8Srobert FileSpec TraceIntelPTBundleLoader::NormalizePath(const std::string &path) {
27*f6aab3d8Srobert   FileSpec file_spec(path);
28*f6aab3d8Srobert   if (file_spec.IsRelative())
29*f6aab3d8Srobert     file_spec.PrependPathComponent(m_bundle_dir);
30*f6aab3d8Srobert   return file_spec;
31*f6aab3d8Srobert }
32*f6aab3d8Srobert 
ParseModule(Target & target,const JSONModule & module)33*f6aab3d8Srobert Error TraceIntelPTBundleLoader::ParseModule(Target &target,
34*f6aab3d8Srobert                                             const JSONModule &module) {
35*f6aab3d8Srobert   auto do_parse = [&]() -> Error {
36*f6aab3d8Srobert     FileSpec system_file_spec(module.system_path);
37*f6aab3d8Srobert 
38*f6aab3d8Srobert     FileSpec local_file_spec(module.file.has_value() ? *module.file
39*f6aab3d8Srobert                                                      : module.system_path);
40*f6aab3d8Srobert 
41*f6aab3d8Srobert     ModuleSpec module_spec;
42*f6aab3d8Srobert     module_spec.GetFileSpec() = local_file_spec;
43*f6aab3d8Srobert     module_spec.GetPlatformFileSpec() = system_file_spec;
44*f6aab3d8Srobert 
45*f6aab3d8Srobert     if (module.uuid.has_value())
46*f6aab3d8Srobert       module_spec.GetUUID().SetFromStringRef(*module.uuid);
47*f6aab3d8Srobert 
48*f6aab3d8Srobert     Status error;
49*f6aab3d8Srobert     ModuleSP module_sp =
50*f6aab3d8Srobert         target.GetOrCreateModule(module_spec, /*notify*/ false, &error);
51*f6aab3d8Srobert 
52*f6aab3d8Srobert     if (error.Fail())
53*f6aab3d8Srobert       return error.ToError();
54*f6aab3d8Srobert 
55*f6aab3d8Srobert     bool load_addr_changed = false;
56*f6aab3d8Srobert     module_sp->SetLoadAddress(target, module.load_address.value, false,
57*f6aab3d8Srobert                               load_addr_changed);
58*f6aab3d8Srobert     return Error::success();
59*f6aab3d8Srobert   };
60*f6aab3d8Srobert   if (Error err = do_parse())
61*f6aab3d8Srobert     return createStringError(
62*f6aab3d8Srobert         inconvertibleErrorCode(), "Error when parsing module %s. %s",
63*f6aab3d8Srobert         module.system_path.c_str(), toString(std::move(err)).c_str());
64*f6aab3d8Srobert   return Error::success();
65*f6aab3d8Srobert }
66*f6aab3d8Srobert 
CreateJSONError(json::Path::Root & root,const json::Value & value)67*f6aab3d8Srobert Error TraceIntelPTBundleLoader::CreateJSONError(json::Path::Root &root,
68*f6aab3d8Srobert                                                 const json::Value &value) {
69*f6aab3d8Srobert   std::string err;
70*f6aab3d8Srobert   raw_string_ostream os(err);
71*f6aab3d8Srobert   root.printErrorContext(value, os);
72*f6aab3d8Srobert   return createStringError(
73*f6aab3d8Srobert       std::errc::invalid_argument, "%s\n\nContext:\n%s\n\nSchema:\n%s",
74*f6aab3d8Srobert       toString(root.getError()).c_str(), os.str().c_str(), GetSchema().data());
75*f6aab3d8Srobert }
76*f6aab3d8Srobert 
77*f6aab3d8Srobert ThreadPostMortemTraceSP
ParseThread(Process & process,const JSONThread & thread)78*f6aab3d8Srobert TraceIntelPTBundleLoader::ParseThread(Process &process,
79*f6aab3d8Srobert                                       const JSONThread &thread) {
80*f6aab3d8Srobert   lldb::tid_t tid = static_cast<lldb::tid_t>(thread.tid);
81*f6aab3d8Srobert 
82*f6aab3d8Srobert   std::optional<FileSpec> trace_file;
83*f6aab3d8Srobert   if (thread.ipt_trace)
84*f6aab3d8Srobert     trace_file = FileSpec(*thread.ipt_trace);
85*f6aab3d8Srobert 
86*f6aab3d8Srobert   ThreadPostMortemTraceSP thread_sp =
87*f6aab3d8Srobert       std::make_shared<ThreadPostMortemTrace>(process, tid, trace_file);
88*f6aab3d8Srobert   process.GetThreadList().AddThread(thread_sp);
89*f6aab3d8Srobert   return thread_sp;
90*f6aab3d8Srobert }
91*f6aab3d8Srobert 
92*f6aab3d8Srobert Expected<TraceIntelPTBundleLoader::ParsedProcess>
CreateEmptyProcess(lldb::pid_t pid,llvm::StringRef triple)93*f6aab3d8Srobert TraceIntelPTBundleLoader::CreateEmptyProcess(lldb::pid_t pid,
94*f6aab3d8Srobert                                              llvm::StringRef triple) {
95*f6aab3d8Srobert   TargetSP target_sp;
96*f6aab3d8Srobert   Status error = m_debugger.GetTargetList().CreateTarget(
97*f6aab3d8Srobert       m_debugger, /*user_exe_path*/ StringRef(), triple, eLoadDependentsNo,
98*f6aab3d8Srobert       /*platform_options*/ nullptr, target_sp);
99*f6aab3d8Srobert 
100*f6aab3d8Srobert   if (!target_sp)
101*f6aab3d8Srobert     return error.ToError();
102*f6aab3d8Srobert 
103*f6aab3d8Srobert   ParsedProcess parsed_process;
104*f6aab3d8Srobert   parsed_process.target_sp = target_sp;
105*f6aab3d8Srobert 
106*f6aab3d8Srobert   ProcessSP process_sp = target_sp->CreateProcess(
107*f6aab3d8Srobert       /*listener*/ nullptr, "trace",
108*f6aab3d8Srobert       /*crash_file*/ nullptr,
109*f6aab3d8Srobert       /*can_connect*/ false);
110*f6aab3d8Srobert 
111*f6aab3d8Srobert   process_sp->SetID(static_cast<lldb::pid_t>(pid));
112*f6aab3d8Srobert 
113*f6aab3d8Srobert   return parsed_process;
114*f6aab3d8Srobert }
115*f6aab3d8Srobert 
116*f6aab3d8Srobert Expected<TraceIntelPTBundleLoader::ParsedProcess>
ParseProcess(const JSONProcess & process)117*f6aab3d8Srobert TraceIntelPTBundleLoader::ParseProcess(const JSONProcess &process) {
118*f6aab3d8Srobert   Expected<ParsedProcess> parsed_process =
119*f6aab3d8Srobert       CreateEmptyProcess(process.pid, process.triple.value_or(""));
120*f6aab3d8Srobert 
121*f6aab3d8Srobert   if (!parsed_process)
122*f6aab3d8Srobert     return parsed_process.takeError();
123*f6aab3d8Srobert 
124*f6aab3d8Srobert   ProcessSP process_sp = parsed_process->target_sp->GetProcessSP();
125*f6aab3d8Srobert 
126*f6aab3d8Srobert   for (const JSONThread &thread : process.threads)
127*f6aab3d8Srobert     parsed_process->threads.push_back(ParseThread(*process_sp, thread));
128*f6aab3d8Srobert 
129*f6aab3d8Srobert   for (const JSONModule &module : process.modules)
130*f6aab3d8Srobert     if (Error err = ParseModule(*parsed_process->target_sp, module))
131*f6aab3d8Srobert       return std::move(err);
132*f6aab3d8Srobert 
133*f6aab3d8Srobert   if (!process.threads.empty())
134*f6aab3d8Srobert     process_sp->GetThreadList().SetSelectedThreadByIndexID(0);
135*f6aab3d8Srobert 
136*f6aab3d8Srobert   // We invoke DidAttach to create a correct stopped state for the process and
137*f6aab3d8Srobert   // its threads.
138*f6aab3d8Srobert   ArchSpec process_arch;
139*f6aab3d8Srobert   process_sp->DidAttach(process_arch);
140*f6aab3d8Srobert 
141*f6aab3d8Srobert   return parsed_process;
142*f6aab3d8Srobert }
143*f6aab3d8Srobert 
144*f6aab3d8Srobert Expected<TraceIntelPTBundleLoader::ParsedProcess>
ParseKernel(const JSONTraceBundleDescription & bundle_description)145*f6aab3d8Srobert TraceIntelPTBundleLoader::ParseKernel(
146*f6aab3d8Srobert     const JSONTraceBundleDescription &bundle_description) {
147*f6aab3d8Srobert   Expected<ParsedProcess> parsed_process =
148*f6aab3d8Srobert       CreateEmptyProcess(kDefaultKernelProcessID, "");
149*f6aab3d8Srobert 
150*f6aab3d8Srobert   if (!parsed_process)
151*f6aab3d8Srobert     return parsed_process.takeError();
152*f6aab3d8Srobert 
153*f6aab3d8Srobert   ProcessSP process_sp = parsed_process->target_sp->GetProcessSP();
154*f6aab3d8Srobert 
155*f6aab3d8Srobert   // Add cpus as fake threads
156*f6aab3d8Srobert   for (const JSONCpu &cpu : *bundle_description.cpus) {
157*f6aab3d8Srobert     ThreadPostMortemTraceSP thread_sp = std::make_shared<ThreadPostMortemTrace>(
158*f6aab3d8Srobert         *process_sp, static_cast<lldb::tid_t>(cpu.id), FileSpec(cpu.ipt_trace));
159*f6aab3d8Srobert     thread_sp->SetName(formatv("kernel_cpu_{0}", cpu.id).str().c_str());
160*f6aab3d8Srobert     process_sp->GetThreadList().AddThread(thread_sp);
161*f6aab3d8Srobert     parsed_process->threads.push_back(thread_sp);
162*f6aab3d8Srobert   }
163*f6aab3d8Srobert 
164*f6aab3d8Srobert   // Add kernel image
165*f6aab3d8Srobert   FileSpec file_spec(bundle_description.kernel->file);
166*f6aab3d8Srobert   ModuleSpec module_spec;
167*f6aab3d8Srobert   module_spec.GetFileSpec() = file_spec;
168*f6aab3d8Srobert 
169*f6aab3d8Srobert   Status error;
170*f6aab3d8Srobert   ModuleSP module_sp =
171*f6aab3d8Srobert       parsed_process->target_sp->GetOrCreateModule(module_spec, false, &error);
172*f6aab3d8Srobert 
173*f6aab3d8Srobert   if (error.Fail())
174*f6aab3d8Srobert     return error.ToError();
175*f6aab3d8Srobert 
176*f6aab3d8Srobert   lldb::addr_t load_address =
177*f6aab3d8Srobert       bundle_description.kernel->load_address
178*f6aab3d8Srobert           ? bundle_description.kernel->load_address->value
179*f6aab3d8Srobert           : kDefaultKernelLoadAddress;
180*f6aab3d8Srobert 
181*f6aab3d8Srobert   bool load_addr_changed = false;
182*f6aab3d8Srobert   module_sp->SetLoadAddress(*parsed_process->target_sp, load_address, false,
183*f6aab3d8Srobert                             load_addr_changed);
184*f6aab3d8Srobert 
185*f6aab3d8Srobert   process_sp->GetThreadList().SetSelectedThreadByIndexID(0);
186*f6aab3d8Srobert 
187*f6aab3d8Srobert   // We invoke DidAttach to create a correct stopped state for the process and
188*f6aab3d8Srobert   // its threads.
189*f6aab3d8Srobert   ArchSpec process_arch;
190*f6aab3d8Srobert   process_sp->DidAttach(process_arch);
191*f6aab3d8Srobert 
192*f6aab3d8Srobert   return parsed_process;
193*f6aab3d8Srobert }
194*f6aab3d8Srobert 
195*f6aab3d8Srobert Expected<std::vector<TraceIntelPTBundleLoader::ParsedProcess>>
LoadBundle(const JSONTraceBundleDescription & bundle_description)196*f6aab3d8Srobert TraceIntelPTBundleLoader::LoadBundle(
197*f6aab3d8Srobert     const JSONTraceBundleDescription &bundle_description) {
198*f6aab3d8Srobert   std::vector<ParsedProcess> parsed_processes;
199*f6aab3d8Srobert 
200*f6aab3d8Srobert   auto HandleError = [&](Error &&err) {
201*f6aab3d8Srobert     // Delete all targets that were created so far in case of failures
202*f6aab3d8Srobert     for (ParsedProcess &parsed_process : parsed_processes)
203*f6aab3d8Srobert       m_debugger.GetTargetList().DeleteTarget(parsed_process.target_sp);
204*f6aab3d8Srobert     return std::move(err);
205*f6aab3d8Srobert   };
206*f6aab3d8Srobert 
207*f6aab3d8Srobert   if (bundle_description.processes) {
208*f6aab3d8Srobert     for (const JSONProcess &process : *bundle_description.processes) {
209*f6aab3d8Srobert       if (Expected<ParsedProcess> parsed_process = ParseProcess(process))
210*f6aab3d8Srobert         parsed_processes.push_back(std::move(*parsed_process));
211*f6aab3d8Srobert       else
212*f6aab3d8Srobert         return HandleError(parsed_process.takeError());
213*f6aab3d8Srobert     }
214*f6aab3d8Srobert   }
215*f6aab3d8Srobert 
216*f6aab3d8Srobert   if (bundle_description.kernel) {
217*f6aab3d8Srobert     if (Expected<ParsedProcess> kernel_process =
218*f6aab3d8Srobert             ParseKernel(bundle_description))
219*f6aab3d8Srobert       parsed_processes.push_back(std::move(*kernel_process));
220*f6aab3d8Srobert     else
221*f6aab3d8Srobert       return HandleError(kernel_process.takeError());
222*f6aab3d8Srobert   }
223*f6aab3d8Srobert 
224*f6aab3d8Srobert   return parsed_processes;
225*f6aab3d8Srobert }
226*f6aab3d8Srobert 
GetSchema()227*f6aab3d8Srobert StringRef TraceIntelPTBundleLoader::GetSchema() {
228*f6aab3d8Srobert   static std::string schema;
229*f6aab3d8Srobert   if (schema.empty()) {
230*f6aab3d8Srobert     schema = R"({
231*f6aab3d8Srobert   "type": "intel-pt",
232*f6aab3d8Srobert   "cpuInfo": {
233*f6aab3d8Srobert     // CPU information gotten from, for example, /proc/cpuinfo.
234*f6aab3d8Srobert 
235*f6aab3d8Srobert     "vendor": "GenuineIntel" | "unknown",
236*f6aab3d8Srobert     "family": integer,
237*f6aab3d8Srobert     "model": integer,
238*f6aab3d8Srobert     "stepping": integer
239*f6aab3d8Srobert   },
240*f6aab3d8Srobert   "processes?": [
241*f6aab3d8Srobert     {
242*f6aab3d8Srobert       "pid": integer,
243*f6aab3d8Srobert       "triple"?: string,
244*f6aab3d8Srobert           // Optional clang/llvm target triple.
245*f6aab3d8Srobert           // This must be provided if the trace will be created not using the
246*f6aab3d8Srobert           // CLI or on a machine other than where the target was traced.
247*f6aab3d8Srobert       "threads": [
248*f6aab3d8Srobert           // A list of known threads for the given process. When context switch
249*f6aab3d8Srobert           // data is provided, LLDB will automatically create threads for the
250*f6aab3d8Srobert           // this process whenever it finds new threads when traversing the
251*f6aab3d8Srobert           // context switches, so passing values to this list in this case is
252*f6aab3d8Srobert           // optional.
253*f6aab3d8Srobert         {
254*f6aab3d8Srobert           "tid": integer,
255*f6aab3d8Srobert           "iptTrace"?: string
256*f6aab3d8Srobert               // Path to the raw Intel PT buffer file for this thread.
257*f6aab3d8Srobert         }
258*f6aab3d8Srobert       ],
259*f6aab3d8Srobert       "modules": [
260*f6aab3d8Srobert         {
261*f6aab3d8Srobert           "systemPath": string,
262*f6aab3d8Srobert               // Original path of the module at runtime.
263*f6aab3d8Srobert           "file"?: string,
264*f6aab3d8Srobert               // Path to a copy of the file if not available at "systemPath".
265*f6aab3d8Srobert           "loadAddress": integer | string decimal | hex string,
266*f6aab3d8Srobert               // Lowest address of the sections of the module loaded on memory.
267*f6aab3d8Srobert           "uuid"?: string,
268*f6aab3d8Srobert               // Build UUID for the file for sanity checks.
269*f6aab3d8Srobert         }
270*f6aab3d8Srobert       ]
271*f6aab3d8Srobert     }
272*f6aab3d8Srobert   ],
273*f6aab3d8Srobert   "cpus"?: [
274*f6aab3d8Srobert     {
275*f6aab3d8Srobert       "id": integer,
276*f6aab3d8Srobert           // Id of this CPU core.
277*f6aab3d8Srobert       "iptTrace": string,
278*f6aab3d8Srobert           // Path to the raw Intel PT buffer for this cpu core.
279*f6aab3d8Srobert       "contextSwitchTrace": string,
280*f6aab3d8Srobert           // Path to the raw perf_event_open context switch trace file for this cpu core.
281*f6aab3d8Srobert           // The perf_event must have been configured with PERF_SAMPLE_TID and
282*f6aab3d8Srobert           // PERF_SAMPLE_TIME, as well as sample_id_all = 1.
283*f6aab3d8Srobert     }
284*f6aab3d8Srobert   ],
285*f6aab3d8Srobert   "tscPerfZeroConversion"?: {
286*f6aab3d8Srobert     // Values used to convert between TSCs and nanoseconds. See the time_zero
287*f6aab3d8Srobert     // section in https://man7.org/linux/man-pages/man2/perf_event_open.2.html
288*f6aab3d8Srobert     // for for information.
289*f6aab3d8Srobert 
290*f6aab3d8Srobert     "timeMult": integer,
291*f6aab3d8Srobert     "timeShift": integer,
292*f6aab3d8Srobert     "timeZero": integer | string decimal | hex string,
293*f6aab3d8Srobert   },
294*f6aab3d8Srobert   "kernel"?: {
295*f6aab3d8Srobert     "loadAddress"?: integer | string decimal | hex string,
296*f6aab3d8Srobert         // Kernel's image load address. Defaults to 0xffffffff81000000, which
297*f6aab3d8Srobert         // is a load address of x86 architecture if KASLR is not enabled.
298*f6aab3d8Srobert     "file": string,
299*f6aab3d8Srobert         // Path to the kernel image.
300*f6aab3d8Srobert   }
301*f6aab3d8Srobert }
302*f6aab3d8Srobert 
303*f6aab3d8Srobert Notes:
304*f6aab3d8Srobert 
305*f6aab3d8Srobert - All paths are either absolute or relative to folder containing the bundle
306*f6aab3d8Srobert   description file.
307*f6aab3d8Srobert - "cpus" is provided if and only if processes[].threads[].iptTrace is not provided.
308*f6aab3d8Srobert - "tscPerfZeroConversion" must be provided if "cpus" is provided.
309*f6aab3d8Srobert - If "kernel" is provided, then the "processes" section must be empty or not
310*f6aab3d8Srobert   passed at all, and the "cpus" section must be provided. This configuration
311*f6aab3d8Srobert   indicates that the kernel was traced and user processes weren't. Besides
312*f6aab3d8Srobert   that, the kernel is treated as a single process with one thread per CPU
313*f6aab3d8Srobert   core. This doesn't handle actual kernel threads, but instead treats
314*f6aab3d8Srobert   all the instructions executed by the kernel on each core as an
315*f6aab3d8Srobert   individual thread.})";
316*f6aab3d8Srobert   }
317*f6aab3d8Srobert   return schema;
318*f6aab3d8Srobert }
319*f6aab3d8Srobert 
AugmentThreadsFromContextSwitches(JSONTraceBundleDescription & bundle_description)320*f6aab3d8Srobert Error TraceIntelPTBundleLoader::AugmentThreadsFromContextSwitches(
321*f6aab3d8Srobert     JSONTraceBundleDescription &bundle_description) {
322*f6aab3d8Srobert   if (!bundle_description.cpus || !bundle_description.processes)
323*f6aab3d8Srobert     return Error::success();
324*f6aab3d8Srobert 
325*f6aab3d8Srobert   if (!bundle_description.tsc_perf_zero_conversion)
326*f6aab3d8Srobert     return createStringError(inconvertibleErrorCode(),
327*f6aab3d8Srobert                              "TSC to nanos conversion values are needed when "
328*f6aab3d8Srobert                              "context switch information is provided.");
329*f6aab3d8Srobert 
330*f6aab3d8Srobert   DenseMap<lldb::pid_t, JSONProcess *> indexed_processes;
331*f6aab3d8Srobert   DenseMap<JSONProcess *, DenseSet<tid_t>> indexed_threads;
332*f6aab3d8Srobert 
333*f6aab3d8Srobert   for (JSONProcess &process : *bundle_description.processes) {
334*f6aab3d8Srobert     indexed_processes[process.pid] = &process;
335*f6aab3d8Srobert     for (JSONThread &thread : process.threads)
336*f6aab3d8Srobert       indexed_threads[&process].insert(thread.tid);
337*f6aab3d8Srobert   }
338*f6aab3d8Srobert 
339*f6aab3d8Srobert   auto on_thread_seen = [&](lldb::pid_t pid, tid_t tid) {
340*f6aab3d8Srobert     auto proc = indexed_processes.find(pid);
341*f6aab3d8Srobert     if (proc == indexed_processes.end())
342*f6aab3d8Srobert       return;
343*f6aab3d8Srobert     if (indexed_threads[proc->second].count(tid))
344*f6aab3d8Srobert       return;
345*f6aab3d8Srobert     indexed_threads[proc->second].insert(tid);
346*f6aab3d8Srobert     proc->second->threads.push_back({tid, /*ipt_trace=*/None});
347*f6aab3d8Srobert   };
348*f6aab3d8Srobert 
349*f6aab3d8Srobert   for (const JSONCpu &cpu : *bundle_description.cpus) {
350*f6aab3d8Srobert     Error err = Trace::OnDataFileRead(
351*f6aab3d8Srobert         FileSpec(cpu.context_switch_trace),
352*f6aab3d8Srobert         [&](ArrayRef<uint8_t> data) -> Error {
353*f6aab3d8Srobert           Expected<std::vector<ThreadContinuousExecution>> executions =
354*f6aab3d8Srobert               DecodePerfContextSwitchTrace(
355*f6aab3d8Srobert                   data, cpu.id, *bundle_description.tsc_perf_zero_conversion);
356*f6aab3d8Srobert           if (!executions)
357*f6aab3d8Srobert             return executions.takeError();
358*f6aab3d8Srobert           for (const ThreadContinuousExecution &execution : *executions)
359*f6aab3d8Srobert             on_thread_seen(execution.pid, execution.tid);
360*f6aab3d8Srobert           return Error::success();
361*f6aab3d8Srobert         });
362*f6aab3d8Srobert     if (err)
363*f6aab3d8Srobert       return err;
364*f6aab3d8Srobert   }
365*f6aab3d8Srobert   return Error::success();
366*f6aab3d8Srobert }
367*f6aab3d8Srobert 
CreateTraceIntelPTInstance(JSONTraceBundleDescription & bundle_description,std::vector<ParsedProcess> & parsed_processes)368*f6aab3d8Srobert Expected<TraceSP> TraceIntelPTBundleLoader::CreateTraceIntelPTInstance(
369*f6aab3d8Srobert     JSONTraceBundleDescription &bundle_description,
370*f6aab3d8Srobert     std::vector<ParsedProcess> &parsed_processes) {
371*f6aab3d8Srobert   std::vector<ThreadPostMortemTraceSP> threads;
372*f6aab3d8Srobert   std::vector<ProcessSP> processes;
373*f6aab3d8Srobert   for (const ParsedProcess &parsed_process : parsed_processes) {
374*f6aab3d8Srobert     processes.push_back(parsed_process.target_sp->GetProcessSP());
375*f6aab3d8Srobert     threads.insert(threads.end(), parsed_process.threads.begin(),
376*f6aab3d8Srobert                    parsed_process.threads.end());
377*f6aab3d8Srobert   }
378*f6aab3d8Srobert 
379*f6aab3d8Srobert   TraceIntelPT::TraceMode trace_mode = bundle_description.kernel
380*f6aab3d8Srobert                                            ? TraceIntelPT::TraceMode::KernelMode
381*f6aab3d8Srobert                                            : TraceIntelPT::TraceMode::UserMode;
382*f6aab3d8Srobert 
383*f6aab3d8Srobert   TraceSP trace_instance = TraceIntelPT::CreateInstanceForPostmortemTrace(
384*f6aab3d8Srobert       bundle_description, processes, threads, trace_mode);
385*f6aab3d8Srobert   for (const ParsedProcess &parsed_process : parsed_processes)
386*f6aab3d8Srobert     parsed_process.target_sp->SetTrace(trace_instance);
387*f6aab3d8Srobert 
388*f6aab3d8Srobert   return trace_instance;
389*f6aab3d8Srobert }
390*f6aab3d8Srobert 
NormalizeAllPaths(JSONTraceBundleDescription & bundle_description)391*f6aab3d8Srobert void TraceIntelPTBundleLoader::NormalizeAllPaths(
392*f6aab3d8Srobert     JSONTraceBundleDescription &bundle_description) {
393*f6aab3d8Srobert   if (bundle_description.processes) {
394*f6aab3d8Srobert     for (JSONProcess &process : *bundle_description.processes) {
395*f6aab3d8Srobert       for (JSONModule &module : process.modules) {
396*f6aab3d8Srobert         module.system_path = NormalizePath(module.system_path).GetPath();
397*f6aab3d8Srobert         if (module.file)
398*f6aab3d8Srobert           module.file = NormalizePath(*module.file).GetPath();
399*f6aab3d8Srobert       }
400*f6aab3d8Srobert       for (JSONThread &thread : process.threads) {
401*f6aab3d8Srobert         if (thread.ipt_trace)
402*f6aab3d8Srobert           thread.ipt_trace = NormalizePath(*thread.ipt_trace).GetPath();
403*f6aab3d8Srobert       }
404*f6aab3d8Srobert     }
405*f6aab3d8Srobert   }
406*f6aab3d8Srobert   if (bundle_description.cpus) {
407*f6aab3d8Srobert     for (JSONCpu &cpu : *bundle_description.cpus) {
408*f6aab3d8Srobert       cpu.context_switch_trace =
409*f6aab3d8Srobert           NormalizePath(cpu.context_switch_trace).GetPath();
410*f6aab3d8Srobert       cpu.ipt_trace = NormalizePath(cpu.ipt_trace).GetPath();
411*f6aab3d8Srobert     }
412*f6aab3d8Srobert   }
413*f6aab3d8Srobert   if (bundle_description.kernel) {
414*f6aab3d8Srobert     bundle_description.kernel->file =
415*f6aab3d8Srobert         NormalizePath(bundle_description.kernel->file).GetPath();
416*f6aab3d8Srobert   }
417*f6aab3d8Srobert }
418*f6aab3d8Srobert 
Load()419*f6aab3d8Srobert Expected<TraceSP> TraceIntelPTBundleLoader::Load() {
420*f6aab3d8Srobert   json::Path::Root root("traceBundle");
421*f6aab3d8Srobert   JSONTraceBundleDescription bundle_description;
422*f6aab3d8Srobert   if (!fromJSON(m_bundle_description, bundle_description, root))
423*f6aab3d8Srobert     return CreateJSONError(root, m_bundle_description);
424*f6aab3d8Srobert 
425*f6aab3d8Srobert   NormalizeAllPaths(bundle_description);
426*f6aab3d8Srobert 
427*f6aab3d8Srobert   if (Error err = AugmentThreadsFromContextSwitches(bundle_description))
428*f6aab3d8Srobert     return std::move(err);
429*f6aab3d8Srobert 
430*f6aab3d8Srobert   if (Expected<std::vector<ParsedProcess>> parsed_processes =
431*f6aab3d8Srobert           LoadBundle(bundle_description))
432*f6aab3d8Srobert     return CreateTraceIntelPTInstance(bundle_description, *parsed_processes);
433*f6aab3d8Srobert   else
434*f6aab3d8Srobert     return parsed_processes.takeError();
435*f6aab3d8Srobert }
436