aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Trace/common/TraceSessionFileParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Trace/common/TraceSessionFileParser.cpp')
-rw-r--r--lldb/source/Plugins/Trace/common/TraceSessionFileParser.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Trace/common/TraceSessionFileParser.cpp b/lldb/source/Plugins/Trace/common/TraceSessionFileParser.cpp
new file mode 100644
index 000000000000..c88ad9dc6a59
--- /dev/null
+++ b/lldb/source/Plugins/Trace/common/TraceSessionFileParser.cpp
@@ -0,0 +1,224 @@
+//===-- TraceSessionFileParser.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 "TraceSessionFileParser.h"
+#include "ThreadPostMortemTrace.h"
+
+#include <sstream>
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm;
+
+void TraceSessionFileParser::NormalizePath(lldb_private::FileSpec &file_spec) {
+ if (file_spec.IsRelative())
+ file_spec.PrependPathComponent(m_session_file_dir);
+}
+
+Error TraceSessionFileParser::ParseModule(lldb::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;
+
+ if (module.uuid.hasValue())
+ module_spec.GetUUID().SetFromStringRef(*module.uuid);
+
+ Status error;
+ ModuleSP module_sp =
+ target_sp->GetOrCreateModule(module_spec, /*notify*/ false, &error);
+
+ if (error.Fail())
+ return error.ToError();
+
+ bool load_addr_changed = false;
+ module_sp->SetLoadAddress(*target_sp, module.load_address.value, false,
+ load_addr_changed);
+ return llvm::Error::success();
+}
+
+Error TraceSessionFileParser::CreateJSONError(json::Path::Root &root,
+ const 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",
+ toString(root.getError()).c_str(), os.str().c_str(), m_schema.data());
+}
+
+std::string TraceSessionFileParser::BuildSchema(StringRef plugin_schema) {
+ std::ostringstream schema_builder;
+ schema_builder << "{\n \"trace\": ";
+ schema_builder << plugin_schema.data() << ",";
+ 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 session file.
+}
+)";
+ return schema_builder.str();
+}
+
+ThreadPostMortemTraceSP
+TraceSessionFileParser::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);
+
+ ThreadPostMortemTraceSP thread_sp =
+ std::make_shared<ThreadPostMortemTrace>(*process_sp, tid, trace_file);
+ process_sp->GetThreadList().AddThread(thread_sp);
+ return thread_sp;
+}
+
+Expected<TraceSessionFileParser::ParsedProcess>
+TraceSessionFileParser::ParseProcess(const JSONProcess &process) {
+ TargetSP target_sp;
+ Status error = m_debugger.GetTargetList().CreateTarget(
+ m_debugger, /*user_exe_path*/ StringRef(), process.triple,
+ eLoadDependentsNo,
+ /*platform_options*/ nullptr, target_sp);
+
+ if (!target_sp)
+ return error.ToError();
+
+ ParsedProcess parsed_process;
+ parsed_process.target_sp = target_sp;
+
+ ProcessSP process_sp = target_sp->CreateProcess(
+ /*listener*/ nullptr, "trace",
+ /*crash_file*/ nullptr,
+ /*can_connect*/ false);
+
+ process_sp->SetID(static_cast<lldb::pid_t>(process.pid));
+
+ for (const JSONThread &thread : process.threads)
+ parsed_process.threads.push_back(ParseThread(process_sp, thread));
+
+ for (const JSONModule &module : process.modules)
+ if (Error err = ParseModule(target_sp, module))
+ return std::move(err);
+
+ if (!process.threads.empty())
+ process_sp->GetThreadList().SetSelectedThreadByIndexID(0);
+
+ // We invoke DidAttach to create a correct stopped state for the process and
+ // its threads.
+ ArchSpec process_arch;
+ process_sp->DidAttach(process_arch);
+
+ return parsed_process;
+}
+
+Expected<std::vector<TraceSessionFileParser::ParsedProcess>>
+TraceSessionFileParser::ParseCommonSessionFile(
+ const JSONTraceSessionBase &session) {
+ std::vector<ParsedProcess> parsed_processes;
+
+ auto onError = [&]() {
+ // Delete all targets that were created so far in case of failures
+ for (ParsedProcess &parsed_process : parsed_processes)
+ m_debugger.GetTargetList().DeleteTarget(parsed_process.target_sp);
+ };
+
+ for (const JSONProcess &process : session.processes) {
+ if (Expected<ParsedProcess> parsed_process = ParseProcess(process))
+ parsed_processes.push_back(std::move(*parsed_process));
+ else {
+ onError();
+ return parsed_process.takeError();
+ }
+ }
+ return parsed_processes;
+}
+
+namespace llvm {
+namespace json {
+
+bool fromJSON(const Value &value, TraceSessionFileParser::JSONAddress &address,
+ Path path) {
+ Optional<StringRef> s = value.getAsString();
+ if (s.hasValue() && !s->getAsInteger(0, address.value))
+ return true;
+
+ path.report("expected numeric string");
+ return false;
+}
+
+bool fromJSON(const Value &value, TraceSessionFileParser::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);
+}
+
+bool fromJSON(const Value &value, TraceSessionFileParser::JSONThread &thread,
+ Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("tid", thread.tid) && o.map("traceFile", thread.trace_file);
+}
+
+bool fromJSON(const Value &value, TraceSessionFileParser::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);
+}
+
+bool fromJSON(const Value &value,
+ TraceSessionFileParser::JSONTracePluginSettings &plugin_settings,
+ Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("type", plugin_settings.type);
+}
+
+bool fromJSON(const Value &value,
+ TraceSessionFileParser::JSONTraceSessionBase &session,
+ Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("processes", session.processes);
+}
+
+} // namespace json
+} // namespace llvm