wallace created this revision. wallace added reviewers: clayborg, labath. Herald added subscribers: lldb-commits, mgorny. Herald added a reviewer: JDevlieghere. Herald added a project: LLDB. wallace requested review of this revision.
With the feedback I was getting in different diffs, I realized that splitting the parsing logic into two classes was not easy to deal with. I do see value in doing that, but I'd rather leave that as a refactor after most of the intel-pt logic is in place. Thus, I'm merging the common parser into the intel pt one, having thus only one that is fully aware of Intel PT during parsing and object creation. Besides, based on the feedback in https://reviews.llvm.org/D88769, I'm creating a ThreadIntelPT class that will be able to orchestrate decoding of its own trace and can handle the stop events correctly. This leaves the TraceIntelPT class as an initialization class that glues together different components. Right now it can initialize a trace session from a json file, and in the future will be able to initialize a trace session from a live process. Besides, I'm renaming SettingsParser to SessionParser, which I think is a better name, as the json object represents a trace session of possibly many processes. With the current set of targets, we have the following - Trace: main interface for dealing with trace sessions - TraceIntelPT: plugin Trace for dealing with intel pt sessions - TraceIntelPTSessionParser: a parser of a json trace session file that can create a corresponding TraceIntelPT instance along with Targets, ProcessTraces (to be created in https://reviews.llvm.org/D88769), and ThreadIntelPT threads. - ProcessTrace: (to be created in https://reviews.llvm.org/D88769) can handle the correct state of the traces as the user traverses the trace. I don't think there'll be a need an intel-pt specific implementation of this class. - ThreadIntelPT: a thread implementation that can handle the decoding of its own trace file, along with keeping track of the current position the user is looking at when doing reverse debugging. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D88841 Files: lldb/include/lldb/Target/Trace.h lldb/include/lldb/Target/TraceSettingsParser.h lldb/include/lldb/lldb-forward.h lldb/include/lldb/lldb-private-interfaces.h lldb/source/Commands/CommandObjectTrace.cpp lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt lldb/source/Plugins/Trace/intel-pt/ThreadIntelPT.cpp lldb/source/Plugins/Trace/intel-pt/ThreadIntelPT.h lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionParser.cpp lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionParser.h lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSettingsParser.cpp lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSettingsParser.h lldb/source/Target/CMakeLists.txt lldb/source/Target/Trace.cpp lldb/source/Target/TraceSettingsParser.cpp lldb/test/API/commands/trace/TestTraceLoad.py
Index: lldb/test/API/commands/trace/TestTraceLoad.py =================================================================== --- lldb/test/API/commands/trace/TestTraceLoad.py +++ lldb/test/API/commands/trace/TestTraceLoad.py @@ -40,7 +40,7 @@ src_dir = self.getSourceDir() # We test first an invalid type self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad.json"), error=True, - substrs=['''error: expected object at settings.processes[0] + substrs=['''error: expected object at traceSession.processes[0] Context: { @@ -53,7 +53,7 @@ Schema: { - "trace": { + "trace": { "type": "intel-pt", "pt_cpu": { "vendor": "intel" | "unknown", @@ -63,32 +63,35 @@ } },''']) - # Now we test a missing field in the global settings + # Now we test a missing field in the global session file self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad2.json"), error=True, - substrs=['error: missing value at settings.processes[1].triple', "Context", "Schema"]) + substrs=['error: missing value at traceSession.processes[1].triple', "Context", "Schema"]) # Now we test a missing field in the intel-pt settings self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad4.json"), error=True, - substrs=['''error: missing value at settings.trace.pt_cpu.family + substrs=['''error: missing value at traceSession.trace.pt_cpu.family Context: { - "pt_cpu": /* error: missing value */ { - "model": 79, - "stepping": 1, - "vendor": "intel" - }, - "type": "intel-pt" + "processes": [], + "trace": { + "pt_cpu": /* error: missing value */ { + "model": 79, + "stepping": 1, + "vendor": "intel" + }, + "type": "intel-pt" + } }''', "Schema"]) # Now we test an incorrect load address in the intel-pt settings self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad5.json"), error=True, - substrs=['error: expected numeric string at settings.processes[0].modules[0].loadAddress', + substrs=['error: expected numeric string at traceSession.processes[0].modules[0].loadAddress', '"loadAddress": /* error: expected numeric string */ 400000,', "Schema"]) # The following wrong schema will have a valid target and an invalid one. In the case of failure, # no targets should be created. self.assertEqual(self.dbg.GetNumTargets(), 0) self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad3.json"), error=True, - substrs=['error: missing value at settings.processes[1].pid']) + substrs=['error: missing value at traceSession.processes[1].pid']) self.assertEqual(self.dbg.GetNumTargets(), 0) Index: lldb/source/Target/TraceSettingsParser.cpp =================================================================== --- lldb/source/Target/TraceSettingsParser.cpp +++ /dev/null @@ -1,175 +0,0 @@ -//===-- TraceSettingParser.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 "lldb/Target/TraceSettingsParser.h" - -#include <sstream> - -#include "Plugins/Process/Utility/HistoryThread.h" -#include "lldb/Core/Debugger.h" -#include "lldb/Target/Process.h" - -using namespace lldb; -using namespace lldb_private; -using namespace llvm; - -StringRef TraceSettingsParser::GetSchema() { - static std::string schema; - if (schema.empty()) { - std::ostringstream schema_builder; - schema_builder << "{\n \"trace\": "; - schema_builder << GetPluginSchema().str() << ",\n"; - schema_builder << R"( "processes": [ - { - "pid": integer, - "triple": string, // llvm-triple - "threads": [ - { - "tid": integer, - "traceFile": string - } - ], - "modules": [ - { - "systemPath": string, // original path of the module at runtime - "file"?: string, // copy of the file if not available at "systemPath" - "loadAddress": string, // string address in hex or decimal form - "uuid"?: string, - } - ] - } - ] -} -// Notes: -// All paths are either absolute or relative to the settings file.)"; - schema = schema_builder.str(); - } - return schema; -} - -void TraceSettingsParser::NormalizePath(FileSpec &file_spec) { - if (file_spec.IsRelative()) - file_spec.PrependPathComponent(m_settings_dir); -} - -void TraceSettingsParser::ParseThread(ProcessSP &process_sp, - const JSONThread &thread) { - lldb::tid_t tid = static_cast<lldb::tid_t>(thread.tid); - - FileSpec spec(thread.trace_file); - NormalizePath(spec); - m_thread_to_trace_file_map[process_sp->GetID()][tid] = spec; - - ThreadSP thread_sp(new HistoryThread(*process_sp, tid, /*callstack*/ {})); - process_sp->GetThreadList().AddThread(thread_sp); -} - -llvm::Error TraceSettingsParser::ParseModule(TargetSP &target_sp, - const JSONModule &module) { - FileSpec system_file_spec(module.system_path); - NormalizePath(system_file_spec); - - FileSpec local_file_spec(module.file.hasValue() ? *module.file - : module.system_path); - NormalizePath(local_file_spec); - - ModuleSpec module_spec; - module_spec.GetFileSpec() = local_file_spec; - module_spec.GetPlatformFileSpec() = system_file_spec; - module_spec.SetObjectOffset(module.load_address.value); - - if (module.uuid.hasValue()) - module_spec.GetUUID().SetFromStringRef(*module.uuid); - - Status error; - ModuleSP module_sp = - target_sp->GetOrCreateModule(module_spec, /*notify*/ false, &error); - return error.ToError(); -} - -llvm::Error TraceSettingsParser::ParseProcess(Debugger &debugger, - const JSONProcess &process) { - TargetSP target_sp; - Status error = debugger.GetTargetList().CreateTarget( - debugger, /*user_exe_path*/ llvm::StringRef(), process.triple, - eLoadDependentsNo, - /*platform_options*/ nullptr, target_sp); - - if (!target_sp) - return error.ToError(); - - m_targets.push_back(target_sp); - debugger.GetTargetList().SetSelectedTarget(target_sp.get()); - - ProcessSP process_sp(target_sp->CreateProcess( - /*listener*/ nullptr, /*plugin_name*/ llvm::StringRef(), - /*crash_file*/ nullptr)); - process_sp->SetID(static_cast<lldb::pid_t>(process.pid)); - - for (const JSONThread &thread : process.threads) - ParseThread(process_sp, thread); - - for (const JSONModule &module : process.modules) { - if (llvm::Error err = ParseModule(target_sp, module)) - return err; - } - return llvm::Error::success(); -} - -llvm::Error -TraceSettingsParser::CreateJSONError(json::Path::Root &root, - const llvm::json::Value &value) { - std::string err; - raw_string_ostream os(err); - root.printErrorContext(value, os); - return createStringError(std::errc::invalid_argument, - "%s\n\nContext:\n%s\n\nSchema:\n%s", - llvm::toString(root.getError()).c_str(), - os.str().c_str(), GetSchema().data()); -} - -llvm::Error -TraceSettingsParser::ParseSettingsImpl(Debugger &debugger, - const llvm::json::Value &raw_settings) { - json::Path::Root root("settings"); - JSONTraceSettings settings; - if (!json::fromJSON(raw_settings, settings, root)) - return CreateJSONError(root, raw_settings); - - for (const JSONProcess &process : settings.processes) { - if (llvm::Error err = ParseProcess(debugger, process)) - return err; - } - - json::Object plugin_obj = *raw_settings.getAsObject()->getObject("trace"); - json::Value plugin_settings(std::move(plugin_obj)); - return ParsePluginSettings(plugin_settings); -} - -llvm::Error -TraceSettingsParser::ParseSettings(Debugger &debugger, - const llvm::json::Value &raw_settings, - llvm::StringRef settings_dir) { - m_settings_dir = settings_dir.str(); - - if (llvm::Error err = ParseSettingsImpl(debugger, raw_settings)) { - // We clean all the targets that were created internally, which should leave - // the debugger unchanged - for (auto target_sp : m_targets) - debugger.GetTargetList().DeleteTarget(target_sp); - - return err; - } - - m_trace.m_settings = *raw_settings.getAsObject(); - m_trace.m_settings_dir = m_settings_dir; - m_trace.m_thread_to_trace_file_map = m_thread_to_trace_file_map; - m_trace.m_targets = m_targets; - - return llvm::Error::success(); -} Index: lldb/source/Target/Trace.cpp =================================================================== --- lldb/source/Target/Trace.cpp +++ lldb/source/Target/Trace.cpp @@ -18,14 +18,14 @@ using namespace lldb_private; using namespace llvm; -// Helper structs used to extract the type of a trace settings json without +// Helper structs used to extract the type of a trace session json without // having to parse the entire object. struct JSONSimplePluginSettings { std::string type; }; -struct JSONSimpleTraceSettings { +struct JSONSimpleTraceSession { JSONSimplePluginSettings trace; }; @@ -38,29 +38,31 @@ return o && o.map("type", plugin_settings.type); } -bool fromJSON(const json::Value &value, JSONSimpleTraceSettings &settings, +bool fromJSON(const json::Value &value, JSONSimpleTraceSession &session, json::Path path) { json::ObjectMapper o(value, path); - return o && o.map("trace", settings.trace); + return o && o.map("trace", session.trace); } } // namespace json } // namespace llvm -llvm::Expected<lldb::TraceSP> Trace::FindPlugin(Debugger &debugger, - const json::Value &settings, - StringRef info_dir) { - JSONSimpleTraceSettings json_settings; - json::Path::Root root("settings"); - if (!json::fromJSON(settings, json_settings, root)) +llvm::Expected<lldb::TraceSP> +Trace::FindPlugin(Debugger &debugger, const json::Value &trace_session_file, + StringRef session_file_dir) { + JSONSimpleTraceSession json_session; + json::Path::Root root("traceSession"); + if (!json::fromJSON(trace_session_file, json_session, root)) return root.getError(); - ConstString plugin_name(json_settings.trace.type); + ConstString plugin_name(json_session.trace.type); auto create_callback = PluginManager::GetTraceCreateCallback(plugin_name); if (create_callback) { - TraceSP instance = create_callback(); - if (llvm::Error err = instance->ParseSettings(debugger, settings, info_dir)) - return std::move(err); + Status error; + TraceSP instance = create_callback(&trace_session_file, &session_file_dir, + &debugger, error); + if (error.Fail()) + return error.ToError(); return instance; } @@ -73,23 +75,18 @@ llvm::Expected<lldb::TraceSP> Trace::FindPlugin(StringRef name) { ConstString plugin_name(name); auto create_callback = PluginManager::GetTraceCreateCallback(plugin_name); - if (create_callback) - return create_callback(); + if (create_callback) { + Status error; + TraceSP instance = create_callback(/*trace_session_file*/ nullptr, + /*session_file_dir*/ nullptr, + /*debugger*/ nullptr, error); + if (error.Fail()) + return error.ToError(); + return instance; + } return createStringError( std::errc::invalid_argument, "no trace plug-in matches the specified type: \"%s\"", plugin_name.AsCString()); } - -llvm::Error Trace::ParseSettings(Debugger &debugger, - const llvm::json::Value &settings, - llvm::StringRef settings_dir) { - if (llvm::Error err = - CreateParser()->ParseSettings(debugger, settings, settings_dir)) - return err; - - return llvm::Error::success(); -} - -llvm::StringRef Trace::GetSchema() { return CreateParser()->GetSchema(); } Index: lldb/source/Target/CMakeLists.txt =================================================================== --- lldb/source/Target/CMakeLists.txt +++ lldb/source/Target/CMakeLists.txt @@ -66,7 +66,6 @@ ThreadPlanStack.cpp ThreadSpec.cpp Trace.cpp - TraceSettingsParser.cpp UnixSignals.cpp UnwindAssembly.cpp UnwindLLDB.cpp Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSettingsParser.h =================================================================== --- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSettingsParser.h +++ /dev/null @@ -1,73 +0,0 @@ -//===-- TraceIntelPTSettingsParser.h ----------------------------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_TraceIntelPTSettingsParser_h_ -#define liblldb_TraceIntelPTSettingsParser_h_ - -#include "intel-pt.h" - -#include "TraceIntelPT.h" -#include "lldb/Target/TraceSettingsParser.h" -#include "lldb/Utility/StructuredData.h" - -class TraceIntelPT; - -class TraceIntelPTSettingsParser : public lldb_private::TraceSettingsParser { -public: - struct JSONPTCPU { - std::string vendor; - int64_t family; - int64_t model; - int64_t stepping; - }; - - struct JSONIntelPTSettings { - JSONPTCPU pt_cpu; - }; - - TraceIntelPTSettingsParser(TraceIntelPT &trace) - : lldb_private::TraceSettingsParser((lldb_private::Trace &)trace), - m_trace(trace) {} - -protected: - llvm::StringRef GetPluginSchema() override; - - llvm::Error - ParsePluginSettings(const llvm::json::Value &plugin_settings) override; - -private: - void ParsePTCPU(const JSONPTCPU &pt_cpu); - - TraceIntelPT &m_trace; - pt_cpu m_pt_cpu; -}; - -namespace llvm { -namespace json { - -inline bool fromJSON(const llvm::json::Value &value, - TraceIntelPTSettingsParser::JSONPTCPU &pt_cpu, - llvm::json::Path path) { - llvm::json::ObjectMapper o(value, path); - return o && o.map("vendor", pt_cpu.vendor) && - o.map("family", pt_cpu.family) && o.map("model", pt_cpu.model) && - o.map("stepping", pt_cpu.stepping); -} - -inline bool -fromJSON(const llvm::json::Value &value, - TraceIntelPTSettingsParser::JSONIntelPTSettings &intel_pt_settings, - llvm::json::Path path) { - llvm::json::ObjectMapper o(value, path); - return o && o.map("pt_cpu", intel_pt_settings.pt_cpu); -} - -} // namespace json -} // namespace llvm - -#endif // liblldb_TraceIntelPTSettingsParser_h_ Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSettingsParser.cpp =================================================================== --- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSettingsParser.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//===-- TraceIntelPTSettingsParser.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 "TraceIntelPTSettingsParser.h" - -using namespace lldb; -using namespace lldb_private; -using namespace llvm; - -StringRef TraceIntelPTSettingsParser::GetPluginSchema() { - return R"({ - "type": "intel-pt", - "pt_cpu": { - "vendor": "intel" | "unknown", - "family": integer, - "model": integer, - "stepping": integer - } - })"; -} - -void TraceIntelPTSettingsParser::ParsePTCPU(const JSONPTCPU &pt_cpu) { - m_pt_cpu = {pt_cpu.vendor.compare("intel") == 0 ? pcv_intel : pcv_unknown, - static_cast<uint16_t>(pt_cpu.family), - static_cast<uint8_t>(pt_cpu.model), - static_cast<uint8_t>(pt_cpu.stepping)}; -} - -llvm::Error TraceIntelPTSettingsParser::ParsePluginSettings( - const llvm::json::Value &plugin_settings) { - json::Path::Root root("settings.trace"); - JSONIntelPTSettings settings; - if (!json::fromJSON(plugin_settings, settings, root)) - return CreateJSONError(root, plugin_settings); - - ParsePTCPU(settings.pt_cpu); - - m_trace.m_pt_cpu = m_pt_cpu; - return llvm::Error::success(); -} Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionParser.h =================================================================== --- /dev/null +++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionParser.h @@ -0,0 +1,187 @@ +//===-- TraceIntelPTSessionParser.h ----------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_TraceIntelPTSessionParser_h_ +#define liblldb_TraceIntelPTSessionParser_h_ + +#include "intel-pt.h" + +#include "TraceIntelPT.h" +#include "lldb/Utility/StructuredData.h" + +class TraceIntelPT; + +class TraceIntelPTSessionParser { +public: + struct JSONAddress { + lldb::addr_t value; + }; + + struct JSONModule { + std::string system_path; + llvm::Optional<std::string> file; + JSONAddress load_address; + llvm::Optional<std::string> uuid; + }; + + struct JSONThread { + int64_t tid; + std::string trace_file; + }; + + struct JSONProcess { + int64_t pid; + std::string triple; + std::vector<JSONThread> threads; + std::vector<JSONModule> modules; + }; + + struct JSONPTCPU { + std::string vendor; + int64_t family; + int64_t model; + int64_t stepping; + }; + + struct JSONTracePluginSettings { + std::string type; + JSONPTCPU pt_cpu; + }; + + struct JSONTraceSession { + std::vector<JSONProcess> processes; + JSONTracePluginSettings trace; + }; + + /// See \a TraceSessionParser::TraceSessionParser for the description of these + /// fields. + TraceIntelPTSessionParser(lldb_private::Debugger &debugger, + const llvm::json::Value &trace_session_file, + llvm::StringRef session_dir) + : m_debugger(debugger), m_trace_session_file(trace_session_file), + m_session_dir(session_dir) {} + + /// \return + /// The JSON schema for the session data. + static llvm::StringRef GetSchema(); + + /// Parse the structured data trace session and create the corresponding \a + /// Target objects. In case of an error, no targets are created. + /// + /// \return + /// A \a lldb::TraceSP instance with the trace session data. In case of + /// errors, return a null pointer. + llvm::Expected<lldb::TraceSP> Parse(); + +private: + llvm::Error ParseImpl(); + + /// Create a user-friendly error message upon a JSON-parsing failure using the + /// \a json::ObjectMapper functionality. + /// + /// \param[in] root + /// The \a llvm::json::Path::Root used to parse the JSON \a value. + /// + /// \param[in] value + /// The json value that failed to parse. + /// + /// \return + /// An \a llvm::Error containing the user-friendly error message. + llvm::Error CreateJSONError(llvm::json::Path::Root &root, + const llvm::json::Value &value); + + /// Resolve non-absolute paths relative to the session file folder + void NormalizePath(lldb_private::FileSpec &file_spec); + + llvm::Error ParseProcess(const JSONProcess &process); + + void ParseThread(lldb::ProcessSP &process_sp, const JSONThread &thread); + + llvm::Error ParseModule(lldb::TargetSP &target_sp, const JSONModule &module); + void ParsePTCPU(const JSONPTCPU &pt_cpu); + + lldb_private::Debugger &m_debugger; + const llvm::json::Value &m_trace_session_file; + std::string m_session_dir; + + /// Objects created as product of the parsing + /// \{ + pt_cpu m_pt_cpu; + std::vector<lldb::TargetSP> m_targets; + /// \} +}; + +namespace llvm { +namespace json { + +inline bool fromJSON(const llvm::json::Value &value, + TraceIntelPTSessionParser::JSONAddress &address, + llvm::json::Path path) { + llvm::Optional<llvm::StringRef> s = value.getAsString(); + if (s.hasValue() && !s->getAsInteger(0, address.value)) + return true; + + path.report("expected numeric string"); + return false; +} + +inline bool fromJSON(const llvm::json::Value &value, + TraceIntelPTSessionParser::JSONModule &module, + llvm::json::Path path) { + llvm::json::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); +} + +inline bool fromJSON(const llvm::json::Value &value, + TraceIntelPTSessionParser::JSONThread &thread, + llvm::json::Path path) { + llvm::json::ObjectMapper o(value, path); + return o && o.map("tid", thread.tid) && o.map("traceFile", thread.trace_file); +} + +inline bool fromJSON(const llvm::json::Value &value, + TraceIntelPTSessionParser::JSONProcess &process, + llvm::json::Path path) { + llvm::json::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); +} + +inline bool fromJSON(const llvm::json::Value &value, + TraceIntelPTSessionParser::JSONPTCPU &pt_cpu, + llvm::json::Path path) { + llvm::json::ObjectMapper o(value, path); + return o && o.map("vendor", pt_cpu.vendor) && + o.map("family", pt_cpu.family) && o.map("model", pt_cpu.model) && + o.map("stepping", pt_cpu.stepping); +} + +inline bool +fromJSON(const llvm::json::Value &value, + TraceIntelPTSessionParser::JSONTracePluginSettings &plugin_settings, + llvm::json::Path path) { + llvm::json::ObjectMapper o(value, path); + return o && o.map("type", plugin_settings.type) && + o.map("pt_cpu", plugin_settings.pt_cpu); +} + +inline bool fromJSON(const llvm::json::Value &value, + TraceIntelPTSessionParser::JSONTraceSession &session, + llvm::json::Path path) { + llvm::json::ObjectMapper o(value, path); + return o && o.map("trace", session.trace) && + o.map("processes", session.processes); +} + +} // namespace json +} // namespace llvm + +#endif // liblldb_TraceIntelPTSessionParser_h_ Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionParser.cpp =================================================================== --- /dev/null +++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionParser.cpp @@ -0,0 +1,168 @@ +//===-- TraceIntelPTSessionParser.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 "TraceIntelPTSessionParser.h" + +#include "ThreadIntelPT.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +StringRef TraceIntelPTSessionParser::GetSchema() { + return R"({ + "trace": { + "type": "intel-pt", + "pt_cpu": { + "vendor": "intel" | "unknown", + "family": integer, + "model": integer, + "stepping": integer + } + }, + "processes": [ + { + "pid": integer, + "triple": string, // llvm-triple + "threads": [ + { + "tid": integer, + "traceFile": string + } + ], + "modules": [ + { + "systemPath": string, // original path of the module at runtime + "file"?: string, // copy of the file if not available at "systemPath" + "loadAddress": string, // string address in hex or decimal form + "uuid"?: string, + } + ] + } + ] +} +// Notes: +// All paths are either absolute or relative to the session file.)"; +} + +void TraceIntelPTSessionParser::NormalizePath(FileSpec &file_spec) { + if (file_spec.IsRelative()) + file_spec.PrependPathComponent(m_session_dir); +} + +void TraceIntelPTSessionParser::ParseThread(ProcessSP &process_sp, + const JSONThread &thread) { + lldb::tid_t tid = static_cast<lldb::tid_t>(thread.tid); + + FileSpec trace_file(thread.trace_file); + NormalizePath(trace_file); + + ThreadSP thread_sp(new ThreadIntelPT(*process_sp, tid, trace_file, m_pt_cpu)); + process_sp->GetThreadList().AddThread(thread_sp); +} + +llvm::Error TraceIntelPTSessionParser::ParseModule(TargetSP &target_sp, + const JSONModule &module) { + FileSpec system_file_spec(module.system_path); + NormalizePath(system_file_spec); + + FileSpec local_file_spec(module.file.hasValue() ? *module.file + : module.system_path); + NormalizePath(local_file_spec); + + ModuleSpec module_spec; + module_spec.GetFileSpec() = local_file_spec; + module_spec.GetPlatformFileSpec() = system_file_spec; + module_spec.SetObjectOffset(module.load_address.value); + + if (module.uuid.hasValue()) + module_spec.GetUUID().SetFromStringRef(*module.uuid); + + Status error; + ModuleSP module_sp = + target_sp->GetOrCreateModule(module_spec, /*notify*/ false, &error); + return error.ToError(); +} + +llvm::Error +TraceIntelPTSessionParser::ParseProcess(const JSONProcess &process) { + TargetSP target_sp; + Status error = m_debugger.GetTargetList().CreateTarget( + m_debugger, /*user_exe_path*/ llvm::StringRef(), process.triple, + eLoadDependentsNo, + /*platform_options*/ nullptr, target_sp); + + if (!target_sp) + return error.ToError(); + + m_targets.push_back(target_sp); + m_debugger.GetTargetList().SetSelectedTarget(target_sp.get()); + + ProcessSP process_sp(target_sp->CreateProcess( + /*listener*/ nullptr, /*plugin_name*/ llvm::StringRef(), + /*crash_file*/ nullptr)); + process_sp->SetID(static_cast<lldb::pid_t>(process.pid)); + + for (const JSONThread &thread : process.threads) + ParseThread(process_sp, thread); + + for (const JSONModule &module : process.modules) { + if (llvm::Error err = ParseModule(target_sp, module)) + return err; + } + return llvm::Error::success(); +} + +void TraceIntelPTSessionParser::ParsePTCPU(const JSONPTCPU &pt_cpu) { + m_pt_cpu = {pt_cpu.vendor.compare("intel") == 0 ? pcv_intel : pcv_unknown, + static_cast<uint16_t>(pt_cpu.family), + static_cast<uint8_t>(pt_cpu.model), + static_cast<uint8_t>(pt_cpu.stepping)}; +} + +llvm::Error +TraceIntelPTSessionParser::CreateJSONError(json::Path::Root &root, + const llvm::json::Value &value) { + std::string err; + raw_string_ostream os(err); + root.printErrorContext(value, os); + return createStringError(std::errc::invalid_argument, + "%s\n\nContext:\n%s\n\nSchema:\n%s", + llvm::toString(root.getError()).c_str(), + os.str().c_str(), GetSchema().data()); +} + +llvm::Error TraceIntelPTSessionParser::ParseImpl() { + json::Path::Root root("traceSession"); + JSONTraceSession session; + if (!json::fromJSON(m_trace_session_file, session, root)) { + return CreateJSONError(root, m_trace_session_file); + } + + ParsePTCPU(session.trace.pt_cpu); + for (const JSONProcess &process : session.processes) { + if (llvm::Error err = ParseProcess(process)) + return err; + } + return llvm::Error::success(); +} + +llvm::Expected<TraceSP> TraceIntelPTSessionParser::Parse() { + if (llvm::Error err = ParseImpl()) { + // Delete all targets that were created + for (auto target_sp : m_targets) + m_debugger.GetTargetList().DeleteTarget(target_sp); + m_targets.clear(); + return std::move(err); + } + + return TraceSP(new TraceIntelPT(m_pt_cpu, m_targets)); +} Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h =================================================================== --- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h +++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -12,7 +12,7 @@ #include "intel-pt.h" #include "llvm/ADT/Optional.h" -#include "TraceIntelPTSettingsParser.h" +#include "TraceIntelPTSessionParser.h" #include "lldb/Target/Trace.h" #include "lldb/lldb-private.h" @@ -30,21 +30,55 @@ static void Terminate(); - static lldb::TraceSP CreateInstance(); + /// Create an instance of this class. + /// + /// If \a trace_session_file, \a session_file_dir and \a debugger are all + /// null, an empty Trace class will be created. If, instead, these three + /// variables are not null, then a Trace class will be created based on the + /// session file information. + /// + /// \param[in] trace_session_file + /// The contents of the trace session file. See \a Trace::FindPlugin. + /// + /// \param[in] session_file_dir + /// The path to the directory that contains the session file. It's used to + /// resolved relative paths in the session file. + /// + /// \param[in] debugger + /// The debugger instance where new Targets will be created as part of the + /// JSON data parsing. + /// + /// \param[in] error + /// A \a Status instance where errors will be stored if the Trace instance + /// could not be created. + /// + /// \return + /// A trace instance or a null pointer if there were errors. + static lldb::TraceSP + CreateInstance(const llvm::json::Value *trace_session_file, + llvm::StringRef *session_file_dir, + lldb_private::Debugger *debugger, lldb_private::Status &error); static lldb_private::ConstString GetPluginNameStatic(); uint32_t GetPluginVersion() override; /// \} -protected: + llvm::StringRef GetSchema() override; + +private: + friend class TraceIntelPTSessionParser; + TraceIntelPT() : Trace() {} - std::unique_ptr<lldb_private::TraceSettingsParser> CreateParser() override; + TraceIntelPT(const pt_cpu &pt_cpu, const std::vector<lldb::TargetSP> &targets) + : Trace(), m_pt_cpu(pt_cpu) { + for (auto target_sp : targets) + m_targets.push_back(target_sp); + } -private: - friend class TraceIntelPTSettingsParser; pt_cpu m_pt_cpu; + std::vector<std::weak_ptr<lldb_private::Target>> m_targets; }; #endif // liblldb_TraceIntelPT_h_ Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp =================================================================== --- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp +++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -8,7 +8,7 @@ #include "TraceIntelPT.h" -#include "TraceIntelPTSettingsParser.h" +#include "TraceIntelPTSessionParser.h" #include "lldb/Core/PluginManager.h" using namespace lldb; @@ -31,11 +31,6 @@ return g_name; } -std::unique_ptr<lldb_private::TraceSettingsParser> -TraceIntelPT::CreateParser() { - return std::make_unique<TraceIntelPTSettingsParser>(*this); -} - //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -46,6 +41,25 @@ void TraceIntelPT::Dump(lldb_private::Stream *s) const {} -lldb::TraceSP TraceIntelPT::CreateInstance() { +lldb::TraceSP +TraceIntelPT::CreateInstance(const llvm::json::Value *trace_session_file, + llvm::StringRef *session_file_dir, + Debugger *debugger, Status &error) { + if (trace_session_file != nullptr) { + assert(session_file_dir != nullptr && debugger != nullptr); + if (llvm::Expected<lldb::TraceSP> instance = + TraceIntelPTSessionParser(*debugger, *trace_session_file, + *session_file_dir) + .Parse()) + return *instance; + else { + error = Status(instance.takeError()); + return lldb::TraceSP(); + } + } return lldb::TraceSP(new TraceIntelPT()); } + +llvm::StringRef TraceIntelPT::GetSchema() { + return TraceIntelPTSessionParser::GetSchema(); +} Index: lldb/source/Plugins/Trace/intel-pt/ThreadIntelPT.h =================================================================== --- /dev/null +++ lldb/source/Plugins/Trace/intel-pt/ThreadIntelPT.h @@ -0,0 +1,54 @@ +//===-- ThreadIntelPT.h -----------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ThreadIntelPT_H +#define liblldb_ThreadIntelPT_H + +#include "lldb/Target/Thread.h" + +#include "intel-pt.h" + +class ThreadIntelPT : public lldb_private::Thread { +public: + /// Create an Intel PT-traced thread. + /// + /// \param[in] process + /// The process that owns this thread. + /// + /// \param[in] tid + /// The thread id of this thread. + /// + /// \param[in] trace_file + /// The trace file for this thread. + /// + /// \param[in] pt_cpu + /// The Intel CPU information required to decode the \a trace_file. + ThreadIntelPT(lldb_private::Process &process, lldb::tid_t tid, + const lldb_private::FileSpec &trace_file, const pt_cpu &pt_cpu) + : Thread(process, tid), m_trace_file(trace_file), m_pt_cpu(pt_cpu) {} + + ~ThreadIntelPT() override; + + void RefreshStateAfterStop() override; + + lldb::RegisterContextSP GetRegisterContext() override; + + lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + +protected: + bool CalculateStopInfo() override; + + lldb::RegisterContextSP m_thread_reg_ctx_sp; + +private: + lldb_private::FileSpec m_trace_file; + pt_cpu m_pt_cpu; +}; + +#endif // liblldb_ThreadIntelPT_H Index: lldb/source/Plugins/Trace/intel-pt/ThreadIntelPT.cpp =================================================================== --- /dev/null +++ lldb/source/Plugins/Trace/intel-pt/ThreadIntelPT.cpp @@ -0,0 +1,39 @@ +//===-- ThreadIntelPT.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 "ThreadIntelPT.h" + +#include <memory> + +#include "Plugins/Process/Utility/RegisterContextHistory.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" + +using namespace lldb; +using namespace lldb_private; + +ThreadIntelPT::~ThreadIntelPT() {} + +void ThreadIntelPT::RefreshStateAfterStop() {} + +RegisterContextSP ThreadIntelPT::GetRegisterContext() { + if (!m_reg_context_sp) { + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); + } + return m_reg_context_sp; +} + +RegisterContextSP +ThreadIntelPT::CreateRegisterContextForFrame(StackFrame *frame) { + // Eventually this will calculate the register context based on the current + // trace position. + return std::make_shared<RegisterContextHistory>( + *this, 0, GetProcess()->GetAddressByteSize(), LLDB_INVALID_ADDRESS); +} + +bool ThreadIntelPT::CalculateStopInfo() { return false; } Index: lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt =================================================================== --- lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt +++ lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt @@ -11,7 +11,8 @@ add_lldb_library(lldbPluginTraceIntelPT PLUGIN TraceIntelPT.cpp - TraceIntelPTSettingsParser.cpp + TraceIntelPTSessionParser.cpp + ThreadIntelPT.cpp LINK_LIBS lldbCore Index: lldb/source/Commands/CommandObjectTrace.cpp =================================================================== --- lldb/source/Commands/CommandObjectTrace.cpp +++ lldb/source/Commands/CommandObjectTrace.cpp @@ -71,7 +71,7 @@ CommandObjectTraceLoad(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "trace load", - "Load processor trace data from a JSON file.", + "Load processor trace session from a JSON file.", "trace load"), m_options() {} @@ -82,8 +82,9 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { if (command.size() != 1) { - result.AppendError("a single path to a JSON file containing trace " - "information is required"); + result.AppendError( + "a single path to a JSON file containing a trace session" + "is required"); result.SetStatus(eReturnStatusFailed); return false; } @@ -105,13 +106,14 @@ buffer_or_error.getError().message().c_str())); } - llvm::Expected<json::Value> settings = + llvm::Expected<json::Value> session_file = json::parse(buffer_or_error.get()->getBuffer().str()); - if (!settings) - return end_with_failure(settings.takeError()); + if (!session_file) + return end_with_failure(session_file.takeError()); - if (Expected<lldb::TraceSP> traceOrErr = Trace::FindPlugin( - GetDebugger(), *settings, json_file.GetDirectory().AsCString())) { + if (Expected<lldb::TraceSP> traceOrErr = + Trace::FindPlugin(GetDebugger(), *session_file, + json_file.GetDirectory().AsCString())) { lldb::TraceSP trace_sp = traceOrErr.get(); if (m_options.m_verbose) result.AppendMessageWithFormat("loading trace with plugin %s\n", Index: lldb/include/lldb/lldb-private-interfaces.h =================================================================== --- lldb/include/lldb/lldb-private-interfaces.h +++ lldb/include/lldb/lldb-private-interfaces.h @@ -21,6 +21,7 @@ namespace llvm { namespace json { class Object; +class Value; } } // namespace llvm @@ -110,7 +111,10 @@ const char *repl_options); typedef int (*ComparisonFunction)(const void *, const void *); typedef void (*DebuggerInitializeCallback)(Debugger &debugger); -typedef lldb::TraceSP (*TraceCreateInstance)(); +typedef lldb::TraceSP (*TraceCreateInstance)( + const llvm::json::Value *trace_session_file, + llvm::StringRef *session_file_dir, lldb_private::Debugger *debugger, + lldb_private::Status &status); } // namespace lldb_private Index: lldb/include/lldb/lldb-forward.h =================================================================== --- lldb/include/lldb/lldb-forward.h +++ lldb/include/lldb/lldb-forward.h @@ -227,7 +227,6 @@ class ThreadPlanTracer; class ThreadSpec; class Trace; -class TraceSettingsParser; class TraceOptions; class Type; class TypeAndOrName; Index: lldb/include/lldb/Target/TraceSettingsParser.h =================================================================== --- lldb/include/lldb/Target/TraceSettingsParser.h +++ /dev/null @@ -1,200 +0,0 @@ -//===-- TraceSettingsParser.h -----------------------------------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TARGET_TRACE_SETTINGS_PARSER_H -#define LLDB_TARGET_TRACE_SETTINGS_PARSER_H - -#include "llvm/ADT/Optional.h" - -#include "lldb/Target/Trace.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { - -/// \class TraceSettingsParser TraceSettingsParser.h -/// A plug-in interface definition class for parsing \a Trace settings. -/// -/// As \a Trace plug-ins support plug-in specific settings, this class should be -/// overriden and implement the plug-in specific parsing logic. -class TraceSettingsParser { -public: - struct JSONAddress { - lldb::addr_t value; - }; - - struct JSONModule { - std::string system_path; - llvm::Optional<std::string> file; - JSONAddress load_address; - llvm::Optional<std::string> uuid; - }; - - struct JSONThread { - int64_t tid; - std::string trace_file; - }; - - struct JSONProcess { - int64_t pid; - std::string triple; - std::vector<JSONThread> threads; - std::vector<JSONModule> modules; - }; - - struct JSONTracePluginSettings { - std::string type; - }; - - struct JSONTraceSettings { - std::vector<JSONProcess> processes; - JSONTracePluginSettings trace; - }; - - TraceSettingsParser(Trace &trace) : m_trace(trace) {} - - virtual ~TraceSettingsParser() = default; - - /// Get the JSON schema of the settings for the trace plug-in. - llvm::StringRef GetSchema(); - - /// Parse the structured data settings and create the corresponding \a Target - /// objects. In case of and error, no targets are created. - /// - /// \param[in] debugger - /// The debugger instance where the targets are created. - /// - /// \param[in] settings - /// The settings to parse. - /// - /// \param[in] settings_dir - /// The directory that contains the settings file used to resolve relative - /// paths. - /// - /// \return - /// An error object containing the reason if there is a failure. - llvm::Error ParseSettings(Debugger &debugger, - const llvm::json::Value &settings, - llvm::StringRef settings_dir); - -protected: - /// Method that should be overriden by implementations of this class to - /// provide the specific plug-in schema inside the "trace" section of the - /// global schema. - virtual llvm::StringRef GetPluginSchema() = 0; - - /// Method that should be overriden to parse the plug-in specific settings. - /// - /// \param[in] plugin_settings - /// The settings to parse specific to the plugin. - /// - /// \return - /// An error object containing the reason if there is a failure. - virtual llvm::Error - ParsePluginSettings(const llvm::json::Value &plugin_settings) = 0; - - /// Create a user-friendly error message upon a JSON-parsing failure using the - /// \a json::ObjectMapper functionality. - /// - /// \param[in] root - /// The \a llvm::json::Path::Root used to parse the JSON \a value. - /// - /// \param[in] value - /// The json value that failed to parse. - /// - /// \return - /// An \a llvm::Error containing the user-friendly error message. - llvm::Error CreateJSONError(llvm::json::Path::Root &root, - const llvm::json::Value &value); - -private: - /// Resolve non-absolute paths relativeto the settings folder - void NormalizePath(lldb_private::FileSpec &file_spec); - - llvm::Error ParseProcess(lldb_private::Debugger &debugger, - const JSONProcess &process); - void ParseThread(lldb::ProcessSP &process_sp, const JSONThread &thread); - llvm::Error ParseModule(lldb::TargetSP &target_sp, const JSONModule &module); - llvm::Error ParseSettingsImpl(lldb_private::Debugger &debugger, - const llvm::json::Value &settings); - - Trace &m_trace; - -protected: - /// Objects created as product of the parsing - /// \{ - /// The directory that contains the settings file. - std::string m_settings_dir; - - std::map<lldb::pid_t, std::map<lldb::tid_t, lldb_private::FileSpec>> - m_thread_to_trace_file_map; - std::vector<lldb::TargetSP> m_targets; - /// \} -}; - -} // namespace lldb_private - -namespace llvm { -namespace json { - -inline bool fromJSON(const llvm::json::Value &value, - lldb_private::TraceSettingsParser::JSONAddress &address, - llvm::json::Path path) { - llvm::Optional<llvm::StringRef> s = value.getAsString(); - if (s.hasValue() && !s->getAsInteger(0, address.value)) - return true; - - path.report("expected numeric string"); - return false; -} - -inline bool fromJSON(const llvm::json::Value &value, - lldb_private::TraceSettingsParser::JSONModule &module, - llvm::json::Path path) { - llvm::json::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); -} - -inline bool fromJSON(const llvm::json::Value &value, - lldb_private::TraceSettingsParser::JSONThread &thread, - llvm::json::Path path) { - llvm::json::ObjectMapper o(value, path); - return o && o.map("tid", thread.tid) && o.map("traceFile", thread.trace_file); -} - -inline bool fromJSON(const llvm::json::Value &value, - lldb_private::TraceSettingsParser::JSONProcess &process, - llvm::json::Path path) { - llvm::json::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); -} - -inline bool fromJSON( - const llvm::json::Value &value, - lldb_private::TraceSettingsParser::JSONTracePluginSettings &plugin_settings, - llvm::json::Path path) { - llvm::json::ObjectMapper o(value, path); - return o && o.map("type", plugin_settings.type); -} - -inline bool -fromJSON(const llvm::json::Value &value, - lldb_private::TraceSettingsParser::JSONTraceSettings &settings, - llvm::json::Path path) { - llvm::json::ObjectMapper o(value, path); - return o && o.map("trace", settings.trace) && - o.map("processes", settings.processes); -} - -} // namespace json -} // namespace llvm - -#endif // LLDB_TARGET_TRACE_SETTINGS_PARSER_H Index: lldb/include/lldb/Target/Trace.h =================================================================== --- lldb/include/lldb/Target/Trace.h +++ lldb/include/lldb/Target/Trace.h @@ -12,7 +12,6 @@ #include "llvm/Support/JSON.h" #include "lldb/Core/PluginInterface.h" -#include "lldb/Target/TraceSettingsParser.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/lldb-private.h" @@ -72,19 +71,18 @@ /// correctly. /// /// \param[in] debugger - /// The debugger instance were new Target will be created as part of the + /// The debugger instance where new Targets will be created as part of the /// JSON data parsing. /// - /// \param[in] settings - /// JSON object describing a trace. + /// \param[in] trace_session_file + /// The contents of the trace session file describing the trace session. /// - /// \param[in] settings_dir - /// Path to a directory used to resolve relative paths in the JSON data. - /// If the JSON data is defined in a file, this should be the - /// folder containing it. + /// \param[in] session_file_dir + /// The path to the directory that contains the session file. It's used to + /// resolved relative paths in the session file. static llvm::Expected<lldb::TraceSP> - FindPlugin(Debugger &debugger, const llvm::json::Value &settings, - llvm::StringRef settings_dir); + FindPlugin(Debugger &debugger, const llvm::json::Value &trace_session_file, + llvm::StringRef session_file_dir); /// Create an instance of trace plug-in by name. /// @@ -92,50 +90,26 @@ /// Name of the trace plugin. static llvm::Expected<lldb::TraceSP> FindPlugin(llvm::StringRef plugin_name); - /// Parse the JSON settings and create the corresponding \a Target - /// objects. In case of an error, no targets are created. + /// Get the JSON trace session schema for this plug-in. /// - /// \param[in] debugger - /// The debugger instance where the targets are created. - /// - /// \param[in] settings - /// JSON object describing a trace. + /// It should include at least these basic fields /// - /// \param[in] settings_dir - /// Path to a directory used to resolve relative paths in the JSON data. - /// If the JSON data is defined in a file, this should be the - /// folder containing it. + /// { + /// "trace": { + /// "type": "<plugin_name>" + /// } + /// } /// - /// \return - /// An error object containing the reason if there is a failure. - llvm::Error ParseSettings(Debugger &debugger, - const llvm::json::Value &settings, - llvm::StringRef settings_dir); - - /// Get the JSON schema of the settings for the trace plug-in. - llvm::StringRef GetSchema(); + /// See \a FindPlugin for more information regarding which fields to include + /// in the schema. + virtual llvm::StringRef GetSchema() = 0; protected: Trace() {} - /// The actual plug-in should define its own implementation of \a - /// TraceSettingsParser for doing any custom parsing. - virtual std::unique_ptr<lldb_private::TraceSettingsParser> CreateParser() = 0; - private: Trace(const Trace &) = delete; const Trace &operator=(const Trace &) = delete; - -protected: - friend class TraceSettingsParser; - /// JSON object that holds all settings for this trace session. - llvm::json::Object m_settings; - /// The directory that contains the settings file. - std::string m_settings_dir; - - std::map<lldb::pid_t, std::map<lldb::tid_t, lldb_private::FileSpec>> - m_thread_to_trace_file_map; - std::vector<lldb::TargetSP> m_targets; }; } // namespace lldb_private
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits