1602497d6SWalter Erquinigo //===-- TraceIntelPTJSONStructs.cpp ---------------------------------------===//
2602497d6SWalter Erquinigo //
3602497d6SWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4602497d6SWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
5602497d6SWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6602497d6SWalter Erquinigo //
7602497d6SWalter Erquinigo //===----------------------------------------------------------------------===//
8602497d6SWalter Erquinigo
9602497d6SWalter Erquinigo #include "TraceIntelPTJSONStructs.h"
10602497d6SWalter Erquinigo #include "llvm/Support/JSON.h"
11f190ce62SKazu Hirata #include <optional>
12602497d6SWalter Erquinigo #include <string>
13602497d6SWalter Erquinigo
14602497d6SWalter Erquinigo using namespace lldb;
15602497d6SWalter Erquinigo using namespace lldb_private;
16602497d6SWalter Erquinigo using namespace lldb_private::trace_intel_pt;
17602497d6SWalter Erquinigo using namespace llvm;
18fc5ef57cSWalter Erquinigo using namespace llvm::json;
19602497d6SWalter Erquinigo
20fc5ef57cSWalter Erquinigo namespace lldb_private {
21fc5ef57cSWalter Erquinigo namespace trace_intel_pt {
22602497d6SWalter Erquinigo
23*2fe83274SKazu Hirata std::optional<std::vector<lldb::cpu_id_t>>
GetCpuIds()24*2fe83274SKazu Hirata JSONTraceBundleDescription::GetCpuIds() {
256a5355e8SWalter Erquinigo if (!cpus)
26d920ab4aSKazu Hirata return std::nullopt;
276a5355e8SWalter Erquinigo std::vector<lldb::cpu_id_t> cpu_ids;
286a5355e8SWalter Erquinigo for (const JSONCpu &cpu : *cpus)
296a5355e8SWalter Erquinigo cpu_ids.push_back(cpu.id);
306a5355e8SWalter Erquinigo return cpu_ids;
31602497d6SWalter Erquinigo }
32602497d6SWalter Erquinigo
toJSON(const JSONModule & module)33fc5ef57cSWalter Erquinigo json::Value toJSON(const JSONModule &module) {
34fc5ef57cSWalter Erquinigo json::Object json_module;
35fc5ef57cSWalter Erquinigo json_module["systemPath"] = module.system_path;
36fc5ef57cSWalter Erquinigo if (module.file)
37fc5ef57cSWalter Erquinigo json_module["file"] = *module.file;
389f45f23dSWalter Erquinigo json_module["loadAddress"] = toJSON(module.load_address, true);
39fc5ef57cSWalter Erquinigo if (module.uuid)
40fc5ef57cSWalter Erquinigo json_module["uuid"] = *module.uuid;
41fc5ef57cSWalter Erquinigo return std::move(json_module);
42602497d6SWalter Erquinigo }
43602497d6SWalter Erquinigo
fromJSON(const json::Value & value,JSONModule & module,Path path)44fc5ef57cSWalter Erquinigo bool fromJSON(const json::Value &value, JSONModule &module, Path path) {
45fc5ef57cSWalter Erquinigo ObjectMapper o(value, path);
46fc5ef57cSWalter Erquinigo return o && o.map("systemPath", module.system_path) &&
47fc5ef57cSWalter Erquinigo o.map("file", module.file) &&
48fc5ef57cSWalter Erquinigo o.map("loadAddress", module.load_address) &&
49fc5ef57cSWalter Erquinigo o.map("uuid", module.uuid);
50fc5ef57cSWalter Erquinigo }
51fc5ef57cSWalter Erquinigo
toJSON(const JSONThread & thread)52fc5ef57cSWalter Erquinigo json::Value toJSON(const JSONThread &thread) {
53a19fcc2bSWalter Erquinigo json::Object obj{{"tid", thread.tid}};
546a5355e8SWalter Erquinigo if (thread.ipt_trace)
556a5355e8SWalter Erquinigo obj["iptTrace"] = *thread.ipt_trace;
56a19fcc2bSWalter Erquinigo return obj;
57fc5ef57cSWalter Erquinigo }
58fc5ef57cSWalter Erquinigo
fromJSON(const json::Value & value,JSONThread & thread,Path path)59fc5ef57cSWalter Erquinigo bool fromJSON(const json::Value &value, JSONThread &thread, Path path) {
60fc5ef57cSWalter Erquinigo ObjectMapper o(value, path);
616a5355e8SWalter Erquinigo return o && o.map("tid", thread.tid) && o.map("iptTrace", thread.ipt_trace);
62fc5ef57cSWalter Erquinigo }
63fc5ef57cSWalter Erquinigo
toJSON(const JSONProcess & process)64fc5ef57cSWalter Erquinigo json::Value toJSON(const JSONProcess &process) {
65fc5ef57cSWalter Erquinigo return Object{
66fc5ef57cSWalter Erquinigo {"pid", process.pid},
67fc5ef57cSWalter Erquinigo {"triple", process.triple},
68fc5ef57cSWalter Erquinigo {"threads", process.threads},
69fc5ef57cSWalter Erquinigo {"modules", process.modules},
70fc5ef57cSWalter Erquinigo };
71fc5ef57cSWalter Erquinigo }
72fc5ef57cSWalter Erquinigo
fromJSON(const json::Value & value,JSONProcess & process,Path path)73fc5ef57cSWalter Erquinigo bool fromJSON(const json::Value &value, JSONProcess &process, Path path) {
74fc5ef57cSWalter Erquinigo ObjectMapper o(value, path);
75fc5ef57cSWalter Erquinigo return o && o.map("pid", process.pid) && o.map("triple", process.triple) &&
76fc5ef57cSWalter Erquinigo o.map("threads", process.threads) && o.map("modules", process.modules);
77fc5ef57cSWalter Erquinigo }
78fc5ef57cSWalter Erquinigo
toJSON(const JSONCpu & cpu)796a5355e8SWalter Erquinigo json::Value toJSON(const JSONCpu &cpu) {
80fc5ef57cSWalter Erquinigo return Object{
816a5355e8SWalter Erquinigo {"id", cpu.id},
826a5355e8SWalter Erquinigo {"iptTrace", cpu.ipt_trace},
836a5355e8SWalter Erquinigo {"contextSwitchTrace", cpu.context_switch_trace},
84fc5ef57cSWalter Erquinigo };
85fc5ef57cSWalter Erquinigo }
86fc5ef57cSWalter Erquinigo
fromJSON(const json::Value & value,JSONCpu & cpu,Path path)876a5355e8SWalter Erquinigo bool fromJSON(const json::Value &value, JSONCpu &cpu, Path path) {
88fc5ef57cSWalter Erquinigo ObjectMapper o(value, path);
896a5355e8SWalter Erquinigo uint64_t cpu_id;
906a5355e8SWalter Erquinigo if (!(o && o.map("id", cpu_id) && o.map("iptTrace", cpu.ipt_trace) &&
916a5355e8SWalter Erquinigo o.map("contextSwitchTrace", cpu.context_switch_trace)))
92fc5ef57cSWalter Erquinigo return false;
936a5355e8SWalter Erquinigo cpu.id = cpu_id;
94fc5ef57cSWalter Erquinigo return true;
95fc5ef57cSWalter Erquinigo }
96fc5ef57cSWalter Erquinigo
toJSON(const pt_cpu & cpu_info)97fc5ef57cSWalter Erquinigo json::Value toJSON(const pt_cpu &cpu_info) {
98fc5ef57cSWalter Erquinigo return Object{
99fc5ef57cSWalter Erquinigo {"vendor", cpu_info.vendor == pcv_intel ? "GenuineIntel" : "Unknown"},
100fc5ef57cSWalter Erquinigo {"family", cpu_info.family},
101602497d6SWalter Erquinigo {"model", cpu_info.model},
102602497d6SWalter Erquinigo {"stepping", cpu_info.stepping},
103fc5ef57cSWalter Erquinigo };
104602497d6SWalter Erquinigo }
105602497d6SWalter Erquinigo
fromJSON(const json::Value & value,pt_cpu & cpu_info,Path path)106fc5ef57cSWalter Erquinigo bool fromJSON(const json::Value &value, pt_cpu &cpu_info, Path path) {
107fc5ef57cSWalter Erquinigo ObjectMapper o(value, path);
108fc5ef57cSWalter Erquinigo std::string vendor;
109fc5ef57cSWalter Erquinigo uint64_t family, model, stepping;
110561a61fbSWalter Erquinigo if (!(o && o.map("vendor", vendor) && o.map("family", family) &&
111561a61fbSWalter Erquinigo o.map("model", model) && o.map("stepping", stepping)))
112fc5ef57cSWalter Erquinigo return false;
113fc5ef57cSWalter Erquinigo cpu_info.vendor = vendor == "GenuineIntel" ? pcv_intel : pcv_unknown;
114fc5ef57cSWalter Erquinigo cpu_info.family = family;
115fc5ef57cSWalter Erquinigo cpu_info.model = model;
116fc5ef57cSWalter Erquinigo cpu_info.stepping = stepping;
117fc5ef57cSWalter Erquinigo return true;
118602497d6SWalter Erquinigo }
119602497d6SWalter Erquinigo
toJSON(const JSONKernel & kernel)1206fb744beSWalter Erquinigo json::Value toJSON(const JSONKernel &kernel) {
1216fb744beSWalter Erquinigo json::Object json_module;
1226fb744beSWalter Erquinigo if (kernel.load_address)
1236fb744beSWalter Erquinigo json_module["loadAddress"] = toJSON(*kernel.load_address, true);
1246fb744beSWalter Erquinigo json_module["file"] = kernel.file;
1256fb744beSWalter Erquinigo return std::move(json_module);
1266fb744beSWalter Erquinigo }
1276fb744beSWalter Erquinigo
fromJSON(const json::Value & value,JSONKernel & kernel,Path path)1286fb744beSWalter Erquinigo bool fromJSON(const json::Value &value, JSONKernel &kernel, Path path) {
1296fb744beSWalter Erquinigo ObjectMapper o(value, path);
1306fb744beSWalter Erquinigo return o && o.map("loadAddress", kernel.load_address) &&
1316fb744beSWalter Erquinigo o.map("file", kernel.file);
1326fb744beSWalter Erquinigo }
1336fb744beSWalter Erquinigo
toJSON(const JSONTraceBundleDescription & bundle_description)134b8dcd0baSWalter Erquinigo json::Value toJSON(const JSONTraceBundleDescription &bundle_description) {
135d179ea12SWalter Erquinigo return Object{
136d179ea12SWalter Erquinigo {"type", bundle_description.type},
137b8dcd0baSWalter Erquinigo {"processes", bundle_description.processes},
138fc5ef57cSWalter Erquinigo // We have to do this because the compiler fails at doing it
139fc5ef57cSWalter Erquinigo // automatically because pt_cpu is not in a namespace
140b8dcd0baSWalter Erquinigo {"cpuInfo", toJSON(bundle_description.cpu_info)},
141b8dcd0baSWalter Erquinigo {"cpus", bundle_description.cpus},
1426fb744beSWalter Erquinigo {"tscPerfZeroConversion", bundle_description.tsc_perf_zero_conversion},
1436fb744beSWalter Erquinigo {"kernel", bundle_description.kernel}};
144602497d6SWalter Erquinigo }
145602497d6SWalter Erquinigo
fromJSON(const json::Value & value,JSONTraceBundleDescription & bundle_description,Path path)146d179ea12SWalter Erquinigo bool fromJSON(const json::Value &value,
147d179ea12SWalter Erquinigo JSONTraceBundleDescription &bundle_description, Path path) {
148fc5ef57cSWalter Erquinigo ObjectMapper o(value, path);
149b8dcd0baSWalter Erquinigo if (!(o && o.map("processes", bundle_description.processes) &&
150d179ea12SWalter Erquinigo o.map("type", bundle_description.type) &&
151d179ea12SWalter Erquinigo o.map("cpus", bundle_description.cpus) &&
152d179ea12SWalter Erquinigo o.map("tscPerfZeroConversion",
1536fb744beSWalter Erquinigo bundle_description.tsc_perf_zero_conversion) &&
1546fb744beSWalter Erquinigo o.map("kernel", bundle_description.kernel)))
155fc5ef57cSWalter Erquinigo return false;
156b8dcd0baSWalter Erquinigo if (bundle_description.cpus && !bundle_description.tsc_perf_zero_conversion) {
1571a3f9969SWalter Erquinigo path.report(
1586a5355e8SWalter Erquinigo "\"tscPerfZeroConversion\" is required when \"cpus\" is provided");
1591a3f9969SWalter Erquinigo return false;
1601a3f9969SWalter Erquinigo }
161fc5ef57cSWalter Erquinigo // We have to do this because the compiler fails at doing it automatically
162fc5ef57cSWalter Erquinigo // because pt_cpu is not in a namespace
163d179ea12SWalter Erquinigo if (!fromJSON(*value.getAsObject()->get("cpuInfo"),
164d179ea12SWalter Erquinigo bundle_description.cpu_info, path.field("cpuInfo")))
165fc5ef57cSWalter Erquinigo return false;
1666fb744beSWalter Erquinigo
1676fb744beSWalter Erquinigo // When kernel section is present, this is kernel-only tracing. Thus, throw an
1686fb744beSWalter Erquinigo // error if the "processes" section is non-empty or the "cpus" section is not
1696fb744beSWalter Erquinigo // present.
1706fb744beSWalter Erquinigo if (bundle_description.kernel) {
1716fb744beSWalter Erquinigo if (bundle_description.processes &&
1726fb744beSWalter Erquinigo !bundle_description.processes->empty()) {
1736fb744beSWalter Erquinigo path.report("\"processes\" must be empty when \"kernel\" is provided");
1746fb744beSWalter Erquinigo return false;
1756fb744beSWalter Erquinigo }
1766fb744beSWalter Erquinigo if (!bundle_description.cpus) {
1776fb744beSWalter Erquinigo path.report("\"cpus\" is required when \"kernel\" is provided");
1786fb744beSWalter Erquinigo return false;
1796fb744beSWalter Erquinigo }
1806fb744beSWalter Erquinigo } else if (!bundle_description.processes) {
1816fb744beSWalter Erquinigo // Usermode tracing requires processes section.
1826fb744beSWalter Erquinigo path.report("\"processes\" is required when \"kernel\" is not provided");
1836fb744beSWalter Erquinigo return false;
1846fb744beSWalter Erquinigo }
185fc5ef57cSWalter Erquinigo return true;
186fc5ef57cSWalter Erquinigo }
187fc5ef57cSWalter Erquinigo
188fc5ef57cSWalter Erquinigo } // namespace trace_intel_pt
189fc5ef57cSWalter Erquinigo } // namespace lldb_private
190