[intel pt] Refactor parsing
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.
Differential Revision: https://reviews.llvm.org/D88841
2020-10-04 03:23:12 +08:00
|
|
|
//===-- 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 "lldb/Target/TraceSessionFileParser.h"
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
2020-10-15 01:25:39 +08:00
|
|
|
#include "lldb/Core/Debugger.h"
|
[intel pt] Refactor parsing
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.
Differential Revision: https://reviews.llvm.org/D88841
2020-10-04 03:23:12 +08:00
|
|
|
#include "lldb/Core/Module.h"
|
2020-10-15 01:25:39 +08:00
|
|
|
#include "lldb/Target/Process.h"
|
[intel pt] Refactor parsing
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.
Differential Revision: https://reviews.llvm.org/D88841
2020-10-04 03:23:12 +08:00
|
|
|
#include "lldb/Target/Target.h"
|
2020-10-15 01:25:39 +08:00
|
|
|
#include "lldb/Target/ThreadTrace.h"
|
[intel pt] Refactor parsing
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.
Differential Revision: https://reviews.llvm.org/D88841
2020-10-04 03:23:12 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2020-10-15 01:25:39 +08:00
|
|
|
ThreadTraceSP 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);
|
|
|
|
|
|
|
|
ThreadTraceSP thread_sp =
|
|
|
|
std::make_shared<ThreadTrace>(*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;
|
|
|
|
|
|
|
|
m_debugger.GetTargetList().SetSelectedTarget(target_sp.get());
|
|
|
|
|
|
|
|
ProcessSP process_sp = target_sp->CreateProcess(
|
|
|
|
/*listener*/ nullptr, "trace",
|
|
|
|
/*crash_file*/ nullptr);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
[intel pt] Refactor parsing
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.
Differential Revision: https://reviews.llvm.org/D88841
2020-10-04 03:23:12 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-10-15 01:25:39 +08:00
|
|
|
bool fromJSON(const Value &value,
|
|
|
|
TraceSessionFileParser::JSONTraceSessionBase &session,
|
|
|
|
Path path) {
|
|
|
|
ObjectMapper o(value, path);
|
|
|
|
return o && o.map("processes", session.processes);
|
|
|
|
}
|
|
|
|
|
[intel pt] Refactor parsing
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.
Differential Revision: https://reviews.llvm.org/D88841
2020-10-04 03:23:12 +08:00
|
|
|
} // namespace json
|
|
|
|
} // namespace llvm
|