188 lines
6.2 KiB
C++
188 lines
6.2 KiB
C++
//===-- TraceIntelPTJSONStructs.cpp ---------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TraceIntelPTJSONStructs.h"
|
|
#include "llvm/Support/JSON.h"
|
|
#include <string>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::trace_intel_pt;
|
|
using namespace llvm;
|
|
using namespace llvm::json;
|
|
|
|
namespace lldb_private {
|
|
namespace trace_intel_pt {
|
|
|
|
Optional<std::vector<lldb::cpu_id_t>> JSONTraceBundleDescription::GetCpuIds() {
|
|
if (!cpus)
|
|
return None;
|
|
std::vector<lldb::cpu_id_t> cpu_ids;
|
|
for (const JSONCpu &cpu : *cpus)
|
|
cpu_ids.push_back(cpu.id);
|
|
return cpu_ids;
|
|
}
|
|
|
|
json::Value toJSON(const JSONModule &module) {
|
|
json::Object json_module;
|
|
json_module["systemPath"] = module.system_path;
|
|
if (module.file)
|
|
json_module["file"] = *module.file;
|
|
json_module["loadAddress"] = toJSON(module.load_address, true);
|
|
if (module.uuid)
|
|
json_module["uuid"] = *module.uuid;
|
|
return std::move(json_module);
|
|
}
|
|
|
|
bool fromJSON(const json::Value &value, JSONModule &module, Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.map("systemPath", module.system_path) &&
|
|
o.map("file", module.file) &&
|
|
o.map("loadAddress", module.load_address) &&
|
|
o.map("uuid", module.uuid);
|
|
}
|
|
|
|
json::Value toJSON(const JSONThread &thread) {
|
|
json::Object obj{{"tid", thread.tid}};
|
|
if (thread.ipt_trace)
|
|
obj["iptTrace"] = *thread.ipt_trace;
|
|
return obj;
|
|
}
|
|
|
|
bool fromJSON(const json::Value &value, JSONThread &thread, Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.map("tid", thread.tid) && o.map("iptTrace", thread.ipt_trace);
|
|
}
|
|
|
|
json::Value toJSON(const JSONProcess &process) {
|
|
return Object{
|
|
{"pid", process.pid},
|
|
{"triple", process.triple},
|
|
{"threads", process.threads},
|
|
{"modules", process.modules},
|
|
};
|
|
}
|
|
|
|
bool fromJSON(const json::Value &value, JSONProcess &process, Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.map("pid", process.pid) && o.map("triple", process.triple) &&
|
|
o.map("threads", process.threads) && o.map("modules", process.modules);
|
|
}
|
|
|
|
json::Value toJSON(const JSONCpu &cpu) {
|
|
return Object{
|
|
{"id", cpu.id},
|
|
{"iptTrace", cpu.ipt_trace},
|
|
{"contextSwitchTrace", cpu.context_switch_trace},
|
|
};
|
|
}
|
|
|
|
bool fromJSON(const json::Value &value, JSONCpu &cpu, Path path) {
|
|
ObjectMapper o(value, path);
|
|
uint64_t cpu_id;
|
|
if (!(o && o.map("id", cpu_id) && o.map("iptTrace", cpu.ipt_trace) &&
|
|
o.map("contextSwitchTrace", cpu.context_switch_trace)))
|
|
return false;
|
|
cpu.id = cpu_id;
|
|
return true;
|
|
}
|
|
|
|
json::Value toJSON(const pt_cpu &cpu_info) {
|
|
return Object{
|
|
{"vendor", cpu_info.vendor == pcv_intel ? "GenuineIntel" : "Unknown"},
|
|
{"family", cpu_info.family},
|
|
{"model", cpu_info.model},
|
|
{"stepping", cpu_info.stepping},
|
|
};
|
|
}
|
|
|
|
bool fromJSON(const json::Value &value, pt_cpu &cpu_info, Path path) {
|
|
ObjectMapper o(value, path);
|
|
std::string vendor;
|
|
uint64_t family, model, stepping;
|
|
if (!(o && o.map("vendor", vendor) && o.map("family", family) &&
|
|
o.map("model", model) && o.map("stepping", stepping)))
|
|
return false;
|
|
cpu_info.vendor = vendor == "GenuineIntel" ? pcv_intel : pcv_unknown;
|
|
cpu_info.family = family;
|
|
cpu_info.model = model;
|
|
cpu_info.stepping = stepping;
|
|
return true;
|
|
}
|
|
|
|
json::Value toJSON(const JSONKernel &kernel) {
|
|
json::Object json_module;
|
|
if (kernel.load_address)
|
|
json_module["loadAddress"] = toJSON(*kernel.load_address, true);
|
|
json_module["file"] = kernel.file;
|
|
return std::move(json_module);
|
|
}
|
|
|
|
bool fromJSON(const json::Value &value, JSONKernel &kernel, Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.map("loadAddress", kernel.load_address) &&
|
|
o.map("file", kernel.file);
|
|
}
|
|
|
|
json::Value toJSON(const JSONTraceBundleDescription &bundle_description) {
|
|
return Object{
|
|
{"type", bundle_description.type},
|
|
{"processes", bundle_description.processes},
|
|
// We have to do this because the compiler fails at doing it
|
|
// automatically because pt_cpu is not in a namespace
|
|
{"cpuInfo", toJSON(bundle_description.cpu_info)},
|
|
{"cpus", bundle_description.cpus},
|
|
{"tscPerfZeroConversion", bundle_description.tsc_perf_zero_conversion},
|
|
{"kernel", bundle_description.kernel}};
|
|
}
|
|
|
|
bool fromJSON(const json::Value &value,
|
|
JSONTraceBundleDescription &bundle_description, Path path) {
|
|
ObjectMapper o(value, path);
|
|
if (!(o && o.map("processes", bundle_description.processes) &&
|
|
o.map("type", bundle_description.type) &&
|
|
o.map("cpus", bundle_description.cpus) &&
|
|
o.map("tscPerfZeroConversion",
|
|
bundle_description.tsc_perf_zero_conversion) &&
|
|
o.map("kernel", bundle_description.kernel)))
|
|
return false;
|
|
if (bundle_description.cpus && !bundle_description.tsc_perf_zero_conversion) {
|
|
path.report(
|
|
"\"tscPerfZeroConversion\" is required when \"cpus\" is provided");
|
|
return false;
|
|
}
|
|
// We have to do this because the compiler fails at doing it automatically
|
|
// because pt_cpu is not in a namespace
|
|
if (!fromJSON(*value.getAsObject()->get("cpuInfo"),
|
|
bundle_description.cpu_info, path.field("cpuInfo")))
|
|
return false;
|
|
|
|
// When kernel section is present, this is kernel-only tracing. Thus, throw an
|
|
// error if the "processes" section is non-empty or the "cpus" section is not
|
|
// present.
|
|
if (bundle_description.kernel) {
|
|
if (bundle_description.processes &&
|
|
!bundle_description.processes->empty()) {
|
|
path.report("\"processes\" must be empty when \"kernel\" is provided");
|
|
return false;
|
|
}
|
|
if (!bundle_description.cpus) {
|
|
path.report("\"cpus\" is required when \"kernel\" is provided");
|
|
return false;
|
|
}
|
|
} else if (!bundle_description.processes) {
|
|
// Usermode tracing requires processes section.
|
|
path.report("\"processes\" is required when \"kernel\" is not provided");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace trace_intel_pt
|
|
} // namespace lldb_private
|