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