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