1 //===-- TraceIntelPTJSONStructs.cpp ---------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "TraceIntelPTJSONStructs.h" 10 #include "llvm/Support/JSON.h" 11 #include <optional> 12 #include <string> 13 14 using namespace lldb; 15 using namespace lldb_private; 16 using namespace lldb_private::trace_intel_pt; 17 using namespace llvm; 18 using namespace llvm::json; 19 20 namespace lldb_private { 21 namespace trace_intel_pt { 22 23 std::optional<std::vector<lldb::cpu_id_t>> 24 JSONTraceBundleDescription::GetCpuIds() { 25 if (!cpus) 26 return std::nullopt; 27 std::vector<lldb::cpu_id_t> cpu_ids; 28 for (const JSONCpu &cpu : *cpus) 29 cpu_ids.push_back(cpu.id); 30 return cpu_ids; 31 } 32 33 json::Value toJSON(const JSONModule &module) { 34 json::Object json_module; 35 json_module["systemPath"] = module.system_path; 36 if (module.file) 37 json_module["file"] = *module.file; 38 json_module["loadAddress"] = toJSON(module.load_address, true); 39 if (module.uuid) 40 json_module["uuid"] = *module.uuid; 41 return std::move(json_module); 42 } 43 44 bool fromJSON(const json::Value &value, JSONModule &module, Path path) { 45 ObjectMapper o(value, path); 46 return o && o.map("systemPath", module.system_path) && 47 o.map("file", module.file) && 48 o.map("loadAddress", module.load_address) && 49 o.map("uuid", module.uuid); 50 } 51 52 json::Value toJSON(const JSONThread &thread) { 53 json::Object obj{{"tid", thread.tid}}; 54 if (thread.ipt_trace) 55 obj["iptTrace"] = *thread.ipt_trace; 56 return obj; 57 } 58 59 bool fromJSON(const json::Value &value, JSONThread &thread, Path path) { 60 ObjectMapper o(value, path); 61 return o && o.map("tid", thread.tid) && o.map("iptTrace", thread.ipt_trace); 62 } 63 64 json::Value toJSON(const JSONProcess &process) { 65 return Object{ 66 {"pid", process.pid}, 67 {"triple", process.triple}, 68 {"threads", process.threads}, 69 {"modules", process.modules}, 70 }; 71 } 72 73 bool fromJSON(const json::Value &value, JSONProcess &process, Path path) { 74 ObjectMapper o(value, path); 75 return o && o.map("pid", process.pid) && o.map("triple", process.triple) && 76 o.map("threads", process.threads) && o.map("modules", process.modules); 77 } 78 79 json::Value toJSON(const JSONCpu &cpu) { 80 return Object{ 81 {"id", cpu.id}, 82 {"iptTrace", cpu.ipt_trace}, 83 {"contextSwitchTrace", cpu.context_switch_trace}, 84 }; 85 } 86 87 bool fromJSON(const json::Value &value, JSONCpu &cpu, Path path) { 88 ObjectMapper o(value, path); 89 uint64_t cpu_id; 90 if (!(o && o.map("id", cpu_id) && o.map("iptTrace", cpu.ipt_trace) && 91 o.map("contextSwitchTrace", cpu.context_switch_trace))) 92 return false; 93 cpu.id = cpu_id; 94 return true; 95 } 96 97 json::Value toJSON(const pt_cpu &cpu_info) { 98 return Object{ 99 {"vendor", cpu_info.vendor == pcv_intel ? "GenuineIntel" : "Unknown"}, 100 {"family", cpu_info.family}, 101 {"model", cpu_info.model}, 102 {"stepping", cpu_info.stepping}, 103 }; 104 } 105 106 bool fromJSON(const json::Value &value, pt_cpu &cpu_info, Path path) { 107 ObjectMapper o(value, path); 108 std::string vendor; 109 uint64_t family, model, stepping; 110 if (!(o && o.map("vendor", vendor) && o.map("family", family) && 111 o.map("model", model) && o.map("stepping", stepping))) 112 return false; 113 cpu_info.vendor = vendor == "GenuineIntel" ? pcv_intel : pcv_unknown; 114 cpu_info.family = family; 115 cpu_info.model = model; 116 cpu_info.stepping = stepping; 117 return true; 118 } 119 120 json::Value toJSON(const JSONKernel &kernel) { 121 json::Object json_module; 122 if (kernel.load_address) 123 json_module["loadAddress"] = toJSON(*kernel.load_address, true); 124 json_module["file"] = kernel.file; 125 return std::move(json_module); 126 } 127 128 bool fromJSON(const json::Value &value, JSONKernel &kernel, Path path) { 129 ObjectMapper o(value, path); 130 return o && o.map("loadAddress", kernel.load_address) && 131 o.map("file", kernel.file); 132 } 133 134 json::Value toJSON(const JSONTraceBundleDescription &bundle_description) { 135 return Object{ 136 {"type", bundle_description.type}, 137 {"processes", bundle_description.processes}, 138 // We have to do this because the compiler fails at doing it 139 // automatically because pt_cpu is not in a namespace 140 {"cpuInfo", toJSON(bundle_description.cpu_info)}, 141 {"cpus", bundle_description.cpus}, 142 {"tscPerfZeroConversion", bundle_description.tsc_perf_zero_conversion}, 143 {"kernel", bundle_description.kernel}}; 144 } 145 146 bool fromJSON(const json::Value &value, 147 JSONTraceBundleDescription &bundle_description, Path path) { 148 ObjectMapper o(value, path); 149 if (!(o && o.map("processes", bundle_description.processes) && 150 o.map("type", bundle_description.type) && 151 o.map("cpus", bundle_description.cpus) && 152 o.map("tscPerfZeroConversion", 153 bundle_description.tsc_perf_zero_conversion) && 154 o.map("kernel", bundle_description.kernel))) 155 return false; 156 if (bundle_description.cpus && !bundle_description.tsc_perf_zero_conversion) { 157 path.report( 158 "\"tscPerfZeroConversion\" is required when \"cpus\" is provided"); 159 return false; 160 } 161 // We have to do this because the compiler fails at doing it automatically 162 // because pt_cpu is not in a namespace 163 if (!fromJSON(*value.getAsObject()->get("cpuInfo"), 164 bundle_description.cpu_info, path.field("cpuInfo"))) 165 return false; 166 167 // When kernel section is present, this is kernel-only tracing. Thus, throw an 168 // error if the "processes" section is non-empty or the "cpus" section is not 169 // present. 170 if (bundle_description.kernel) { 171 if (bundle_description.processes && 172 !bundle_description.processes->empty()) { 173 path.report("\"processes\" must be empty when \"kernel\" is provided"); 174 return false; 175 } 176 if (!bundle_description.cpus) { 177 path.report("\"cpus\" is required when \"kernel\" is provided"); 178 return false; 179 } 180 } else if (!bundle_description.processes) { 181 // Usermode tracing requires processes section. 182 path.report("\"processes\" is required when \"kernel\" is not provided"); 183 return false; 184 } 185 return true; 186 } 187 188 } // namespace trace_intel_pt 189 } // namespace lldb_private 190