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