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"
13bdd1243dSDimitry 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"
18*297eecfbSDimitry Andric #include "lldb/Target/ProcessTrace.h"
1981ad6265SDimitry Andric #include "lldb/Target/Target.h"
20bdd1243dSDimitry Andric #include <optional>
2181ad6265SDimitry Andric
2281ad6265SDimitry Andric using namespace lldb;
2381ad6265SDimitry Andric using namespace lldb_private;
2481ad6265SDimitry Andric using namespace lldb_private::trace_intel_pt;
2581ad6265SDimitry Andric using namespace llvm;
2681ad6265SDimitry Andric
NormalizePath(const std::string & path)2781ad6265SDimitry Andric FileSpec TraceIntelPTBundleLoader::NormalizePath(const std::string &path) {
2881ad6265SDimitry Andric FileSpec file_spec(path);
2981ad6265SDimitry Andric if (file_spec.IsRelative())
3081ad6265SDimitry Andric file_spec.PrependPathComponent(m_bundle_dir);
3181ad6265SDimitry Andric return file_spec;
3281ad6265SDimitry Andric }
3381ad6265SDimitry Andric
ParseModule(Target & target,const JSONModule & module)3481ad6265SDimitry Andric Error TraceIntelPTBundleLoader::ParseModule(Target &target,
3581ad6265SDimitry Andric const JSONModule &module) {
3681ad6265SDimitry Andric auto do_parse = [&]() -> Error {
3781ad6265SDimitry Andric FileSpec system_file_spec(module.system_path);
3881ad6265SDimitry Andric
39bdd1243dSDimitry Andric FileSpec local_file_spec(module.file.has_value() ? *module.file
4081ad6265SDimitry Andric : module.system_path);
4181ad6265SDimitry Andric
4281ad6265SDimitry Andric ModuleSpec module_spec;
4381ad6265SDimitry Andric module_spec.GetFileSpec() = local_file_spec;
4481ad6265SDimitry Andric module_spec.GetPlatformFileSpec() = system_file_spec;
4581ad6265SDimitry Andric
46bdd1243dSDimitry Andric if (module.uuid.has_value())
4781ad6265SDimitry Andric module_spec.GetUUID().SetFromStringRef(*module.uuid);
4881ad6265SDimitry Andric
4981ad6265SDimitry Andric Status error;
5081ad6265SDimitry Andric ModuleSP module_sp =
5181ad6265SDimitry Andric target.GetOrCreateModule(module_spec, /*notify*/ false, &error);
5281ad6265SDimitry Andric
5381ad6265SDimitry Andric if (error.Fail())
5481ad6265SDimitry Andric return error.ToError();
5581ad6265SDimitry Andric
5681ad6265SDimitry Andric bool load_addr_changed = false;
5781ad6265SDimitry Andric module_sp->SetLoadAddress(target, module.load_address.value, false,
5881ad6265SDimitry Andric load_addr_changed);
5981ad6265SDimitry Andric return Error::success();
6081ad6265SDimitry Andric };
6181ad6265SDimitry Andric if (Error err = do_parse())
6281ad6265SDimitry Andric return createStringError(
6381ad6265SDimitry Andric inconvertibleErrorCode(), "Error when parsing module %s. %s",
6481ad6265SDimitry Andric module.system_path.c_str(), toString(std::move(err)).c_str());
6581ad6265SDimitry Andric return Error::success();
6681ad6265SDimitry Andric }
6781ad6265SDimitry Andric
CreateJSONError(json::Path::Root & root,const json::Value & value)6881ad6265SDimitry Andric Error TraceIntelPTBundleLoader::CreateJSONError(json::Path::Root &root,
6981ad6265SDimitry Andric const json::Value &value) {
7081ad6265SDimitry Andric std::string err;
7181ad6265SDimitry Andric raw_string_ostream os(err);
7281ad6265SDimitry Andric root.printErrorContext(value, os);
7381ad6265SDimitry Andric return createStringError(
7481ad6265SDimitry Andric std::errc::invalid_argument, "%s\n\nContext:\n%s\n\nSchema:\n%s",
7581ad6265SDimitry Andric toString(root.getError()).c_str(), os.str().c_str(), GetSchema().data());
7681ad6265SDimitry Andric }
7781ad6265SDimitry Andric
7881ad6265SDimitry Andric ThreadPostMortemTraceSP
ParseThread(Process & process,const JSONThread & thread)7981ad6265SDimitry Andric TraceIntelPTBundleLoader::ParseThread(Process &process,
8081ad6265SDimitry Andric const JSONThread &thread) {
8181ad6265SDimitry Andric lldb::tid_t tid = static_cast<lldb::tid_t>(thread.tid);
8281ad6265SDimitry Andric
83bdd1243dSDimitry Andric std::optional<FileSpec> trace_file;
8481ad6265SDimitry Andric if (thread.ipt_trace)
8581ad6265SDimitry Andric trace_file = FileSpec(*thread.ipt_trace);
8681ad6265SDimitry Andric
8781ad6265SDimitry Andric ThreadPostMortemTraceSP thread_sp =
8881ad6265SDimitry Andric std::make_shared<ThreadPostMortemTrace>(process, tid, trace_file);
8981ad6265SDimitry Andric process.GetThreadList().AddThread(thread_sp);
9081ad6265SDimitry Andric return thread_sp;
9181ad6265SDimitry Andric }
9281ad6265SDimitry Andric
9381ad6265SDimitry Andric Expected<TraceIntelPTBundleLoader::ParsedProcess>
CreateEmptyProcess(lldb::pid_t pid,llvm::StringRef triple)94bdd1243dSDimitry Andric TraceIntelPTBundleLoader::CreateEmptyProcess(lldb::pid_t pid,
95bdd1243dSDimitry Andric llvm::StringRef triple) {
9681ad6265SDimitry Andric TargetSP target_sp;
9781ad6265SDimitry Andric Status error = m_debugger.GetTargetList().CreateTarget(
98bdd1243dSDimitry Andric m_debugger, /*user_exe_path*/ StringRef(), triple, eLoadDependentsNo,
9981ad6265SDimitry Andric /*platform_options*/ nullptr, target_sp);
10081ad6265SDimitry Andric
10181ad6265SDimitry Andric if (!target_sp)
10281ad6265SDimitry Andric return error.ToError();
10381ad6265SDimitry Andric
10481ad6265SDimitry Andric ParsedProcess parsed_process;
10581ad6265SDimitry Andric parsed_process.target_sp = target_sp;
10681ad6265SDimitry Andric
107*297eecfbSDimitry Andric ProcessTrace::Initialize();
108*297eecfbSDimitry Andric ProcessSP process_sp = target_sp->CreateProcess(
109*297eecfbSDimitry Andric /*listener*/ nullptr, "trace",
110*297eecfbSDimitry Andric /*crash_file*/ nullptr,
111*297eecfbSDimitry Andric /*can_connect*/ false);
11281ad6265SDimitry Andric
113bdd1243dSDimitry Andric process_sp->SetID(static_cast<lldb::pid_t>(pid));
114bdd1243dSDimitry Andric
115bdd1243dSDimitry Andric return parsed_process;
116bdd1243dSDimitry Andric }
117bdd1243dSDimitry Andric
118bdd1243dSDimitry Andric Expected<TraceIntelPTBundleLoader::ParsedProcess>
ParseProcess(const JSONProcess & process)119bdd1243dSDimitry Andric TraceIntelPTBundleLoader::ParseProcess(const JSONProcess &process) {
120bdd1243dSDimitry Andric Expected<ParsedProcess> parsed_process =
121bdd1243dSDimitry Andric CreateEmptyProcess(process.pid, process.triple.value_or(""));
122bdd1243dSDimitry Andric
123bdd1243dSDimitry Andric if (!parsed_process)
124bdd1243dSDimitry Andric return parsed_process.takeError();
125bdd1243dSDimitry Andric
126bdd1243dSDimitry Andric ProcessSP process_sp = parsed_process->target_sp->GetProcessSP();
12781ad6265SDimitry Andric
12881ad6265SDimitry Andric for (const JSONThread &thread : process.threads)
129bdd1243dSDimitry Andric parsed_process->threads.push_back(ParseThread(*process_sp, thread));
13081ad6265SDimitry Andric
13181ad6265SDimitry Andric for (const JSONModule &module : process.modules)
132bdd1243dSDimitry Andric if (Error err = ParseModule(*parsed_process->target_sp, module))
13381ad6265SDimitry Andric return std::move(err);
13481ad6265SDimitry Andric
13581ad6265SDimitry Andric if (!process.threads.empty())
13681ad6265SDimitry Andric process_sp->GetThreadList().SetSelectedThreadByIndexID(0);
13781ad6265SDimitry Andric
13881ad6265SDimitry Andric // We invoke DidAttach to create a correct stopped state for the process and
13981ad6265SDimitry Andric // its threads.
14081ad6265SDimitry Andric ArchSpec process_arch;
14181ad6265SDimitry Andric process_sp->DidAttach(process_arch);
14281ad6265SDimitry Andric
14381ad6265SDimitry Andric return parsed_process;
14481ad6265SDimitry Andric }
14581ad6265SDimitry Andric
146bdd1243dSDimitry Andric Expected<TraceIntelPTBundleLoader::ParsedProcess>
ParseKernel(const JSONTraceBundleDescription & bundle_description)147bdd1243dSDimitry Andric TraceIntelPTBundleLoader::ParseKernel(
148bdd1243dSDimitry Andric const JSONTraceBundleDescription &bundle_description) {
149bdd1243dSDimitry Andric Expected<ParsedProcess> parsed_process =
150bdd1243dSDimitry Andric CreateEmptyProcess(kDefaultKernelProcessID, "");
151bdd1243dSDimitry Andric
152bdd1243dSDimitry Andric if (!parsed_process)
153bdd1243dSDimitry Andric return parsed_process.takeError();
154bdd1243dSDimitry Andric
155bdd1243dSDimitry Andric ProcessSP process_sp = parsed_process->target_sp->GetProcessSP();
156bdd1243dSDimitry Andric
157bdd1243dSDimitry Andric // Add cpus as fake threads
158bdd1243dSDimitry Andric for (const JSONCpu &cpu : *bundle_description.cpus) {
159bdd1243dSDimitry Andric ThreadPostMortemTraceSP thread_sp = std::make_shared<ThreadPostMortemTrace>(
160bdd1243dSDimitry Andric *process_sp, static_cast<lldb::tid_t>(cpu.id), FileSpec(cpu.ipt_trace));
161bdd1243dSDimitry Andric thread_sp->SetName(formatv("kernel_cpu_{0}", cpu.id).str().c_str());
162bdd1243dSDimitry Andric process_sp->GetThreadList().AddThread(thread_sp);
163bdd1243dSDimitry Andric parsed_process->threads.push_back(thread_sp);
164bdd1243dSDimitry Andric }
165bdd1243dSDimitry Andric
166bdd1243dSDimitry Andric // Add kernel image
167bdd1243dSDimitry Andric FileSpec file_spec(bundle_description.kernel->file);
168bdd1243dSDimitry Andric ModuleSpec module_spec;
169bdd1243dSDimitry Andric module_spec.GetFileSpec() = file_spec;
170bdd1243dSDimitry Andric
171bdd1243dSDimitry Andric Status error;
172bdd1243dSDimitry Andric ModuleSP module_sp =
173bdd1243dSDimitry Andric parsed_process->target_sp->GetOrCreateModule(module_spec, false, &error);
174bdd1243dSDimitry Andric
175bdd1243dSDimitry Andric if (error.Fail())
176bdd1243dSDimitry Andric return error.ToError();
177bdd1243dSDimitry Andric
178bdd1243dSDimitry Andric lldb::addr_t load_address =
179bdd1243dSDimitry Andric bundle_description.kernel->load_address
180bdd1243dSDimitry Andric ? bundle_description.kernel->load_address->value
181bdd1243dSDimitry Andric : kDefaultKernelLoadAddress;
182bdd1243dSDimitry Andric
183bdd1243dSDimitry Andric bool load_addr_changed = false;
184bdd1243dSDimitry Andric module_sp->SetLoadAddress(*parsed_process->target_sp, load_address, false,
185bdd1243dSDimitry Andric load_addr_changed);
186bdd1243dSDimitry Andric
187bdd1243dSDimitry Andric process_sp->GetThreadList().SetSelectedThreadByIndexID(0);
188bdd1243dSDimitry Andric
189bdd1243dSDimitry Andric // We invoke DidAttach to create a correct stopped state for the process and
190bdd1243dSDimitry Andric // its threads.
191bdd1243dSDimitry Andric ArchSpec process_arch;
192bdd1243dSDimitry Andric process_sp->DidAttach(process_arch);
193bdd1243dSDimitry Andric
194bdd1243dSDimitry Andric return parsed_process;
195bdd1243dSDimitry Andric }
196bdd1243dSDimitry Andric
19781ad6265SDimitry Andric Expected<std::vector<TraceIntelPTBundleLoader::ParsedProcess>>
LoadBundle(const JSONTraceBundleDescription & bundle_description)19881ad6265SDimitry Andric TraceIntelPTBundleLoader::LoadBundle(
19981ad6265SDimitry Andric const JSONTraceBundleDescription &bundle_description) {
20081ad6265SDimitry Andric std::vector<ParsedProcess> parsed_processes;
20181ad6265SDimitry Andric
20281ad6265SDimitry Andric auto HandleError = [&](Error &&err) {
20381ad6265SDimitry Andric // Delete all targets that were created so far in case of failures
20481ad6265SDimitry Andric for (ParsedProcess &parsed_process : parsed_processes)
20581ad6265SDimitry Andric m_debugger.GetTargetList().DeleteTarget(parsed_process.target_sp);
20681ad6265SDimitry Andric return std::move(err);
20781ad6265SDimitry Andric };
20881ad6265SDimitry Andric
209bdd1243dSDimitry Andric if (bundle_description.processes) {
210bdd1243dSDimitry Andric for (const JSONProcess &process : *bundle_description.processes) {
21181ad6265SDimitry Andric if (Expected<ParsedProcess> parsed_process = ParseProcess(process))
21281ad6265SDimitry Andric parsed_processes.push_back(std::move(*parsed_process));
21381ad6265SDimitry Andric else
21481ad6265SDimitry Andric return HandleError(parsed_process.takeError());
21581ad6265SDimitry Andric }
216bdd1243dSDimitry Andric }
217bdd1243dSDimitry Andric
218bdd1243dSDimitry Andric if (bundle_description.kernel) {
219bdd1243dSDimitry Andric if (Expected<ParsedProcess> kernel_process =
220bdd1243dSDimitry Andric ParseKernel(bundle_description))
221bdd1243dSDimitry Andric parsed_processes.push_back(std::move(*kernel_process));
222bdd1243dSDimitry Andric else
223bdd1243dSDimitry Andric return HandleError(kernel_process.takeError());
224bdd1243dSDimitry Andric }
22581ad6265SDimitry Andric
22681ad6265SDimitry Andric return parsed_processes;
22781ad6265SDimitry Andric }
22881ad6265SDimitry Andric
GetSchema()22981ad6265SDimitry Andric StringRef TraceIntelPTBundleLoader::GetSchema() {
23081ad6265SDimitry Andric static std::string schema;
23181ad6265SDimitry Andric if (schema.empty()) {
23281ad6265SDimitry Andric schema = R"({
23381ad6265SDimitry Andric "type": "intel-pt",
23481ad6265SDimitry Andric "cpuInfo": {
23581ad6265SDimitry Andric // CPU information gotten from, for example, /proc/cpuinfo.
23681ad6265SDimitry Andric
23781ad6265SDimitry Andric "vendor": "GenuineIntel" | "unknown",
23881ad6265SDimitry Andric "family": integer,
23981ad6265SDimitry Andric "model": integer,
24081ad6265SDimitry Andric "stepping": integer
24181ad6265SDimitry Andric },
242bdd1243dSDimitry Andric "processes?": [
24381ad6265SDimitry Andric {
24481ad6265SDimitry Andric "pid": integer,
24581ad6265SDimitry Andric "triple"?: string,
24681ad6265SDimitry Andric // Optional clang/llvm target triple.
247bdd1243dSDimitry Andric // This must be provided if the trace will be created not using the
248bdd1243dSDimitry Andric // CLI or on a machine other than where the target was traced.
24981ad6265SDimitry Andric "threads": [
25081ad6265SDimitry Andric // A list of known threads for the given process. When context switch
25181ad6265SDimitry Andric // data is provided, LLDB will automatically create threads for the
25281ad6265SDimitry Andric // this process whenever it finds new threads when traversing the
25381ad6265SDimitry Andric // context switches, so passing values to this list in this case is
25481ad6265SDimitry Andric // optional.
25581ad6265SDimitry Andric {
25681ad6265SDimitry Andric "tid": integer,
25781ad6265SDimitry Andric "iptTrace"?: string
25881ad6265SDimitry Andric // Path to the raw Intel PT buffer file for this thread.
25981ad6265SDimitry Andric }
26081ad6265SDimitry Andric ],
26181ad6265SDimitry Andric "modules": [
26281ad6265SDimitry Andric {
26381ad6265SDimitry Andric "systemPath": string,
26481ad6265SDimitry Andric // Original path of the module at runtime.
26581ad6265SDimitry Andric "file"?: string,
26681ad6265SDimitry Andric // Path to a copy of the file if not available at "systemPath".
26781ad6265SDimitry Andric "loadAddress": integer | string decimal | hex string,
26881ad6265SDimitry Andric // Lowest address of the sections of the module loaded on memory.
26981ad6265SDimitry Andric "uuid"?: string,
27081ad6265SDimitry Andric // Build UUID for the file for sanity checks.
27181ad6265SDimitry Andric }
27281ad6265SDimitry Andric ]
27381ad6265SDimitry Andric }
27481ad6265SDimitry Andric ],
27581ad6265SDimitry Andric "cpus"?: [
27681ad6265SDimitry Andric {
27781ad6265SDimitry Andric "id": integer,
27881ad6265SDimitry Andric // Id of this CPU core.
27981ad6265SDimitry Andric "iptTrace": string,
28081ad6265SDimitry Andric // Path to the raw Intel PT buffer for this cpu core.
28181ad6265SDimitry Andric "contextSwitchTrace": string,
28281ad6265SDimitry Andric // Path to the raw perf_event_open context switch trace file for this cpu core.
28381ad6265SDimitry Andric // The perf_event must have been configured with PERF_SAMPLE_TID and
28481ad6265SDimitry Andric // PERF_SAMPLE_TIME, as well as sample_id_all = 1.
28581ad6265SDimitry Andric }
28681ad6265SDimitry Andric ],
28781ad6265SDimitry Andric "tscPerfZeroConversion"?: {
28881ad6265SDimitry Andric // Values used to convert between TSCs and nanoseconds. See the time_zero
28981ad6265SDimitry Andric // section in https://man7.org/linux/man-pages/man2/perf_event_open.2.html
2905f757f3fSDimitry Andric // for information.
29181ad6265SDimitry Andric
29281ad6265SDimitry Andric "timeMult": integer,
29381ad6265SDimitry Andric "timeShift": integer,
29481ad6265SDimitry Andric "timeZero": integer | string decimal | hex string,
295bdd1243dSDimitry Andric },
296bdd1243dSDimitry Andric "kernel"?: {
297bdd1243dSDimitry Andric "loadAddress"?: integer | string decimal | hex string,
298bdd1243dSDimitry Andric // Kernel's image load address. Defaults to 0xffffffff81000000, which
299bdd1243dSDimitry Andric // is a load address of x86 architecture if KASLR is not enabled.
300bdd1243dSDimitry Andric "file": string,
301bdd1243dSDimitry Andric // Path to the kernel image.
30281ad6265SDimitry Andric }
30381ad6265SDimitry Andric }
30481ad6265SDimitry Andric
30581ad6265SDimitry Andric Notes:
30681ad6265SDimitry Andric
307bdd1243dSDimitry Andric - All paths are either absolute or relative to folder containing the bundle
308bdd1243dSDimitry Andric description file.
30981ad6265SDimitry Andric - "cpus" is provided if and only if processes[].threads[].iptTrace is not provided.
31081ad6265SDimitry Andric - "tscPerfZeroConversion" must be provided if "cpus" is provided.
311bdd1243dSDimitry Andric - If "kernel" is provided, then the "processes" section must be empty or not
312bdd1243dSDimitry Andric passed at all, and the "cpus" section must be provided. This configuration
313bdd1243dSDimitry Andric indicates that the kernel was traced and user processes weren't. Besides
314bdd1243dSDimitry Andric that, the kernel is treated as a single process with one thread per CPU
315bdd1243dSDimitry Andric core. This doesn't handle actual kernel threads, but instead treats
316bdd1243dSDimitry Andric all the instructions executed by the kernel on each core as an
317bdd1243dSDimitry Andric individual thread.})";
31881ad6265SDimitry Andric }
31981ad6265SDimitry Andric return schema;
32081ad6265SDimitry Andric }
32181ad6265SDimitry Andric
AugmentThreadsFromContextSwitches(JSONTraceBundleDescription & bundle_description)32281ad6265SDimitry Andric Error TraceIntelPTBundleLoader::AugmentThreadsFromContextSwitches(
32381ad6265SDimitry Andric JSONTraceBundleDescription &bundle_description) {
324bdd1243dSDimitry Andric if (!bundle_description.cpus || !bundle_description.processes)
32581ad6265SDimitry Andric return Error::success();
32681ad6265SDimitry Andric
32781ad6265SDimitry Andric if (!bundle_description.tsc_perf_zero_conversion)
32881ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(),
32981ad6265SDimitry Andric "TSC to nanos conversion values are needed when "
33081ad6265SDimitry Andric "context switch information is provided.");
33181ad6265SDimitry Andric
33281ad6265SDimitry Andric DenseMap<lldb::pid_t, JSONProcess *> indexed_processes;
33381ad6265SDimitry Andric DenseMap<JSONProcess *, DenseSet<tid_t>> indexed_threads;
33481ad6265SDimitry Andric
335bdd1243dSDimitry Andric for (JSONProcess &process : *bundle_description.processes) {
33681ad6265SDimitry Andric indexed_processes[process.pid] = &process;
33781ad6265SDimitry Andric for (JSONThread &thread : process.threads)
33881ad6265SDimitry Andric indexed_threads[&process].insert(thread.tid);
33981ad6265SDimitry Andric }
34081ad6265SDimitry Andric
34181ad6265SDimitry Andric auto on_thread_seen = [&](lldb::pid_t pid, tid_t tid) {
34281ad6265SDimitry Andric auto proc = indexed_processes.find(pid);
34381ad6265SDimitry Andric if (proc == indexed_processes.end())
34481ad6265SDimitry Andric return;
34581ad6265SDimitry Andric if (indexed_threads[proc->second].count(tid))
34681ad6265SDimitry Andric return;
34781ad6265SDimitry Andric indexed_threads[proc->second].insert(tid);
348*297eecfbSDimitry Andric proc->second->threads.push_back({tid, /*ipt_trace=*/std::nullopt});
34981ad6265SDimitry Andric };
35081ad6265SDimitry Andric
35181ad6265SDimitry Andric for (const JSONCpu &cpu : *bundle_description.cpus) {
35281ad6265SDimitry Andric Error err = Trace::OnDataFileRead(
35381ad6265SDimitry Andric FileSpec(cpu.context_switch_trace),
35481ad6265SDimitry Andric [&](ArrayRef<uint8_t> data) -> Error {
35581ad6265SDimitry Andric Expected<std::vector<ThreadContinuousExecution>> executions =
356bdd1243dSDimitry Andric DecodePerfContextSwitchTrace(
357bdd1243dSDimitry Andric data, cpu.id, *bundle_description.tsc_perf_zero_conversion);
35881ad6265SDimitry Andric if (!executions)
35981ad6265SDimitry Andric return executions.takeError();
36081ad6265SDimitry Andric for (const ThreadContinuousExecution &execution : *executions)
36181ad6265SDimitry Andric on_thread_seen(execution.pid, execution.tid);
36281ad6265SDimitry Andric return Error::success();
36381ad6265SDimitry Andric });
36481ad6265SDimitry Andric if (err)
36581ad6265SDimitry Andric return err;
36681ad6265SDimitry Andric }
36781ad6265SDimitry Andric return Error::success();
36881ad6265SDimitry Andric }
36981ad6265SDimitry Andric
CreateTraceIntelPTInstance(JSONTraceBundleDescription & bundle_description,std::vector<ParsedProcess> & parsed_processes)37081ad6265SDimitry Andric Expected<TraceSP> TraceIntelPTBundleLoader::CreateTraceIntelPTInstance(
371bdd1243dSDimitry Andric JSONTraceBundleDescription &bundle_description,
372bdd1243dSDimitry Andric std::vector<ParsedProcess> &parsed_processes) {
37381ad6265SDimitry Andric std::vector<ThreadPostMortemTraceSP> threads;
37481ad6265SDimitry Andric std::vector<ProcessSP> processes;
37581ad6265SDimitry Andric for (const ParsedProcess &parsed_process : parsed_processes) {
37681ad6265SDimitry Andric processes.push_back(parsed_process.target_sp->GetProcessSP());
37781ad6265SDimitry Andric threads.insert(threads.end(), parsed_process.threads.begin(),
37881ad6265SDimitry Andric parsed_process.threads.end());
37981ad6265SDimitry Andric }
38081ad6265SDimitry Andric
381bdd1243dSDimitry Andric TraceIntelPT::TraceMode trace_mode = bundle_description.kernel
382bdd1243dSDimitry Andric ? TraceIntelPT::TraceMode::KernelMode
383bdd1243dSDimitry Andric : TraceIntelPT::TraceMode::UserMode;
384bdd1243dSDimitry Andric
38581ad6265SDimitry Andric TraceSP trace_instance = TraceIntelPT::CreateInstanceForPostmortemTrace(
386bdd1243dSDimitry Andric bundle_description, processes, threads, trace_mode);
38781ad6265SDimitry Andric for (const ParsedProcess &parsed_process : parsed_processes)
38881ad6265SDimitry Andric parsed_process.target_sp->SetTrace(trace_instance);
38981ad6265SDimitry Andric
39081ad6265SDimitry Andric return trace_instance;
39181ad6265SDimitry Andric }
39281ad6265SDimitry Andric
NormalizeAllPaths(JSONTraceBundleDescription & bundle_description)39381ad6265SDimitry Andric void TraceIntelPTBundleLoader::NormalizeAllPaths(
39481ad6265SDimitry Andric JSONTraceBundleDescription &bundle_description) {
395bdd1243dSDimitry Andric if (bundle_description.processes) {
396bdd1243dSDimitry Andric for (JSONProcess &process : *bundle_description.processes) {
39781ad6265SDimitry Andric for (JSONModule &module : process.modules) {
39881ad6265SDimitry Andric module.system_path = NormalizePath(module.system_path).GetPath();
39981ad6265SDimitry Andric if (module.file)
40081ad6265SDimitry Andric module.file = NormalizePath(*module.file).GetPath();
40181ad6265SDimitry Andric }
40281ad6265SDimitry Andric for (JSONThread &thread : process.threads) {
40381ad6265SDimitry Andric if (thread.ipt_trace)
40481ad6265SDimitry Andric thread.ipt_trace = NormalizePath(*thread.ipt_trace).GetPath();
40581ad6265SDimitry Andric }
40681ad6265SDimitry Andric }
407bdd1243dSDimitry Andric }
40881ad6265SDimitry Andric if (bundle_description.cpus) {
40981ad6265SDimitry Andric for (JSONCpu &cpu : *bundle_description.cpus) {
41081ad6265SDimitry Andric cpu.context_switch_trace =
41181ad6265SDimitry Andric NormalizePath(cpu.context_switch_trace).GetPath();
41281ad6265SDimitry Andric cpu.ipt_trace = NormalizePath(cpu.ipt_trace).GetPath();
41381ad6265SDimitry Andric }
41481ad6265SDimitry Andric }
415bdd1243dSDimitry Andric if (bundle_description.kernel) {
416bdd1243dSDimitry Andric bundle_description.kernel->file =
417bdd1243dSDimitry Andric NormalizePath(bundle_description.kernel->file).GetPath();
418bdd1243dSDimitry Andric }
41981ad6265SDimitry Andric }
42081ad6265SDimitry Andric
Load()42181ad6265SDimitry Andric Expected<TraceSP> TraceIntelPTBundleLoader::Load() {
42281ad6265SDimitry Andric json::Path::Root root("traceBundle");
42381ad6265SDimitry Andric JSONTraceBundleDescription bundle_description;
42481ad6265SDimitry Andric if (!fromJSON(m_bundle_description, bundle_description, root))
42581ad6265SDimitry Andric return CreateJSONError(root, m_bundle_description);
42681ad6265SDimitry Andric
42781ad6265SDimitry Andric NormalizeAllPaths(bundle_description);
42881ad6265SDimitry Andric
42981ad6265SDimitry Andric if (Error err = AugmentThreadsFromContextSwitches(bundle_description))
43081ad6265SDimitry Andric return std::move(err);
43181ad6265SDimitry Andric
43281ad6265SDimitry Andric if (Expected<std::vector<ParsedProcess>> parsed_processes =
43381ad6265SDimitry Andric LoadBundle(bundle_description))
43481ad6265SDimitry Andric return CreateTraceIntelPTInstance(bundle_description, *parsed_processes);
43581ad6265SDimitry Andric else
43681ad6265SDimitry Andric return parsed_processes.takeError();
43781ad6265SDimitry Andric }
438