xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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>>
GetCpuIds()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 
toJSON(const JSONModule & module)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 
fromJSON(const json::Value & value,JSONModule & module,Path path)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 
toJSON(const JSONThread & thread)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 
fromJSON(const json::Value & value,JSONThread & thread,Path path)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 
toJSON(const JSONProcess & process)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 
fromJSON(const json::Value & value,JSONProcess & process,Path path)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 
toJSON(const JSONCpu & cpu)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 
fromJSON(const json::Value & value,JSONCpu & cpu,Path path)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 
toJSON(const pt_cpu & cpu_info)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 
fromJSON(const json::Value & value,pt_cpu & cpu_info,Path path)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 
toJSON(const JSONKernel & kernel)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 
fromJSON(const json::Value & value,JSONKernel & kernel,Path path)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 
toJSON(const JSONTraceBundleDescription & bundle_description)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 
fromJSON(const json::Value & value,JSONTraceBundleDescription & bundle_description,Path path)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