Files
llvm/lldb/source/Target/Trace.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

408 lines
14 KiB
C++
Raw Normal View History

Add a "Trace" plug-in to LLDB to add process trace support in stages. This is the first in a series of patches that will adds a new processor trace plug-in to LLDB. The idea for this first patch to to add the plug-in interface with simple commands for the trace files that can "load" and "dump" the trace information. We can test the functionality and ensure people are happy with the way things are done and how things are organized before moving on to adding more functionality. Processor trace information can be view in a few different ways: - post mortem where a trace is saved off that can be viewed later in the debugger - gathered while a process is running and allow the user to step back in time (with no variables, memory or registers) to see how each thread arrived at where it is currently stopped. This patch attempts to start with the first solution of loading a trace file after the fact. The idea is that we will use a JSON file to load the trace information. JSON allows us to specify information about the trace like: - plug-in name in LLDB - path to trace file - shared library load information so we can re-create a target and symbolicate the information in the trace - any other info that the trace plug-in will need to be able to successfully parse the trace information - cpu type - version info - ??? A new "trace" command was added at the top level of the LLDB commmands: - "trace load" - "trace dump" I did this because if we load trace information we don't need to have a process and we might end up creating a new target for the trace information that will become active. If anyone has any input on where this would be better suited, please let me know. Walter Erquinigo will end up filling in the Intel PT specific plug-in so that it works and is tested once we can agree that the direction of this patch is the correct one, so please feel free to chime in with ideas on comments! Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D85705
2020-08-17 17:21:52 -07:00
//===-- Trace.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/Trace.h"
#include "llvm/Support/Format.h"
[trace][intel-pt] Implement the basic decoding functionality Depends on D89408. This diff finally implements trace decoding! The current interface is $ trace load /path/to/trace/session/file.json $ thread trace dump instructions thread #1: tid = 3842849, total instructions = 22 [ 0] 0x40052d [ 1] 0x40052d ... [19] 0x400521 $ # simply enter, which is a repeat command [20] 0x40052d [21] 0x400529 ... This doesn't do any disassembly, which will be done in the next diff. Changes: - Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding. - Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step. - Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces. - Added basic APIs for accessing the trace in Trace.h: - GetInstructionCount, which counts the number of instructions traced for a given thread - IsTraceFailed, which returns an Error if decoding a thread failed - ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do. - DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible. - Tests included Differential Revision: https://reviews.llvm.org/D89283
2020-10-14 10:26:10 -07:00
#include "lldb/Core/Module.h"
Add a "Trace" plug-in to LLDB to add process trace support in stages. This is the first in a series of patches that will adds a new processor trace plug-in to LLDB. The idea for this first patch to to add the plug-in interface with simple commands for the trace files that can "load" and "dump" the trace information. We can test the functionality and ensure people are happy with the way things are done and how things are organized before moving on to adding more functionality. Processor trace information can be view in a few different ways: - post mortem where a trace is saved off that can be viewed later in the debugger - gathered while a process is running and allow the user to step back in time (with no variables, memory or registers) to see how each thread arrived at where it is currently stopped. This patch attempts to start with the first solution of loading a trace file after the fact. The idea is that we will use a JSON file to load the trace information. JSON allows us to specify information about the trace like: - plug-in name in LLDB - path to trace file - shared library load information so we can re-create a target and symbolicate the information in the trace - any other info that the trace plug-in will need to be able to successfully parse the trace information - cpu type - version info - ??? A new "trace" command was added at the top level of the LLDB commmands: - "trace load" - "trace dump" I did this because if we load trace information we don't need to have a process and we might end up creating a new target for the trace information that will become active. If anyone has any input on where this would be better suited, please let me know. Walter Erquinigo will end up filling in the Intel PT specific plug-in so that it works and is tested once we can agree that the direction of this patch is the correct one, so please feel free to chime in with ideas on comments! Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D85705
2020-08-17 17:21:52 -07:00
#include "lldb/Core/PluginManager.h"
[trace][intel-pt] Implement the basic decoding functionality Depends on D89408. This diff finally implements trace decoding! The current interface is $ trace load /path/to/trace/session/file.json $ thread trace dump instructions thread #1: tid = 3842849, total instructions = 22 [ 0] 0x40052d [ 1] 0x40052d ... [19] 0x400521 $ # simply enter, which is a repeat command [20] 0x40052d [21] 0x400529 ... This doesn't do any disassembly, which will be done in the next diff. Changes: - Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding. - Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step. - Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces. - Added basic APIs for accessing the trace in Trace.h: - GetInstructionCount, which counts the number of instructions traced for a given thread - IsTraceFailed, which returns an Error if decoding a thread failed - ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do. - DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible. - Tests included Differential Revision: https://reviews.llvm.org/D89283
2020-10-14 10:26:10 -07:00
#include "lldb/Symbol/Function.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPostMortemTrace.h"
#include "lldb/Utility/Stream.h"
Add a "Trace" plug-in to LLDB to add process trace support in stages. This is the first in a series of patches that will adds a new processor trace plug-in to LLDB. The idea for this first patch to to add the plug-in interface with simple commands for the trace files that can "load" and "dump" the trace information. We can test the functionality and ensure people are happy with the way things are done and how things are organized before moving on to adding more functionality. Processor trace information can be view in a few different ways: - post mortem where a trace is saved off that can be viewed later in the debugger - gathered while a process is running and allow the user to step back in time (with no variables, memory or registers) to see how each thread arrived at where it is currently stopped. This patch attempts to start with the first solution of loading a trace file after the fact. The idea is that we will use a JSON file to load the trace information. JSON allows us to specify information about the trace like: - plug-in name in LLDB - path to trace file - shared library load information so we can re-create a target and symbolicate the information in the trace - any other info that the trace plug-in will need to be able to successfully parse the trace information - cpu type - version info - ??? A new "trace" command was added at the top level of the LLDB commmands: - "trace load" - "trace dump" I did this because if we load trace information we don't need to have a process and we might end up creating a new target for the trace information that will become active. If anyone has any input on where this would be better suited, please let me know. Walter Erquinigo will end up filling in the Intel PT specific plug-in so that it works and is tested once we can agree that the direction of this patch is the correct one, so please feel free to chime in with ideas on comments! Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D85705
2020-08-17 17:21:52 -07:00
using namespace lldb;
using namespace lldb_private;
using namespace llvm;
[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-03 12:23:12 -07:00
// Helper structs used to extract the type of a trace session json without
// having to parse the entire object.
struct JSONSimplePluginSettings {
std::string type;
};
[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-03 12:23:12 -07:00
struct JSONSimpleTraceSession {
JSONSimplePluginSettings trace;
};
namespace llvm {
namespace json {
[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-03 12:23:12 -07:00
bool fromJSON(const Value &value, JSONSimplePluginSettings &plugin_settings,
Path path) {
json::ObjectMapper o(value, path);
return o && o.map("type", plugin_settings.type);
}
[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-03 12:23:12 -07:00
bool fromJSON(const Value &value, JSONSimpleTraceSession &session, Path path) {
json::ObjectMapper o(value, path);
[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-03 12:23:12 -07:00
return o && o.map("trace", session.trace);
}
} // namespace json
} // namespace llvm
[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-03 12:23:12 -07:00
static Error createInvalidPlugInError(StringRef plugin_name) {
Add a "Trace" plug-in to LLDB to add process trace support in stages. This is the first in a series of patches that will adds a new processor trace plug-in to LLDB. The idea for this first patch to to add the plug-in interface with simple commands for the trace files that can "load" and "dump" the trace information. We can test the functionality and ensure people are happy with the way things are done and how things are organized before moving on to adding more functionality. Processor trace information can be view in a few different ways: - post mortem where a trace is saved off that can be viewed later in the debugger - gathered while a process is running and allow the user to step back in time (with no variables, memory or registers) to see how each thread arrived at where it is currently stopped. This patch attempts to start with the first solution of loading a trace file after the fact. The idea is that we will use a JSON file to load the trace information. JSON allows us to specify information about the trace like: - plug-in name in LLDB - path to trace file - shared library load information so we can re-create a target and symbolicate the information in the trace - any other info that the trace plug-in will need to be able to successfully parse the trace information - cpu type - version info - ??? A new "trace" command was added at the top level of the LLDB commmands: - "trace load" - "trace dump" I did this because if we load trace information we don't need to have a process and we might end up creating a new target for the trace information that will become active. If anyone has any input on where this would be better suited, please let me know. Walter Erquinigo will end up filling in the Intel PT specific plug-in so that it works and is tested once we can agree that the direction of this patch is the correct one, so please feel free to chime in with ideas on comments! Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D85705
2020-08-17 17:21:52 -07:00
return createStringError(
std::errc::invalid_argument,
"no trace plug-in matches the specified type: \"%s\"",
[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-03 12:23:12 -07:00
plugin_name.data());
Add a "Trace" plug-in to LLDB to add process trace support in stages. This is the first in a series of patches that will adds a new processor trace plug-in to LLDB. The idea for this first patch to to add the plug-in interface with simple commands for the trace files that can "load" and "dump" the trace information. We can test the functionality and ensure people are happy with the way things are done and how things are organized before moving on to adding more functionality. Processor trace information can be view in a few different ways: - post mortem where a trace is saved off that can be viewed later in the debugger - gathered while a process is running and allow the user to step back in time (with no variables, memory or registers) to see how each thread arrived at where it is currently stopped. This patch attempts to start with the first solution of loading a trace file after the fact. The idea is that we will use a JSON file to load the trace information. JSON allows us to specify information about the trace like: - plug-in name in LLDB - path to trace file - shared library load information so we can re-create a target and symbolicate the information in the trace - any other info that the trace plug-in will need to be able to successfully parse the trace information - cpu type - version info - ??? A new "trace" command was added at the top level of the LLDB commmands: - "trace load" - "trace dump" I did this because if we load trace information we don't need to have a process and we might end up creating a new target for the trace information that will become active. If anyone has any input on where this would be better suited, please let me know. Walter Erquinigo will end up filling in the Intel PT specific plug-in so that it works and is tested once we can agree that the direction of this patch is the correct one, so please feel free to chime in with ideas on comments! Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D85705
2020-08-17 17:21:52 -07:00
}
Expected<lldb::TraceSP>
Trace::FindPluginForPostMortemProcess(Debugger &debugger,
const json::Value &trace_session_file,
StringRef session_file_dir) {
[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-03 12:23:12 -07:00
JSONSimpleTraceSession json_session;
json::Path::Root root("traceSession");
if (!json::fromJSON(trace_session_file, json_session, root))
return root.getError();
Add a "Trace" plug-in to LLDB to add process trace support in stages. This is the first in a series of patches that will adds a new processor trace plug-in to LLDB. The idea for this first patch to to add the plug-in interface with simple commands for the trace files that can "load" and "dump" the trace information. We can test the functionality and ensure people are happy with the way things are done and how things are organized before moving on to adding more functionality. Processor trace information can be view in a few different ways: - post mortem where a trace is saved off that can be viewed later in the debugger - gathered while a process is running and allow the user to step back in time (with no variables, memory or registers) to see how each thread arrived at where it is currently stopped. This patch attempts to start with the first solution of loading a trace file after the fact. The idea is that we will use a JSON file to load the trace information. JSON allows us to specify information about the trace like: - plug-in name in LLDB - path to trace file - shared library load information so we can re-create a target and symbolicate the information in the trace - any other info that the trace plug-in will need to be able to successfully parse the trace information - cpu type - version info - ??? A new "trace" command was added at the top level of the LLDB commmands: - "trace load" - "trace dump" I did this because if we load trace information we don't need to have a process and we might end up creating a new target for the trace information that will become active. If anyone has any input on where this would be better suited, please let me know. Walter Erquinigo will end up filling in the Intel PT specific plug-in so that it works and is tested once we can agree that the direction of this patch is the correct one, so please feel free to chime in with ideas on comments! Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D85705
2020-08-17 17:21:52 -07:00
[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-03 12:23:12 -07:00
ConstString plugin_name(json_session.trace.type);
if (auto create_callback = PluginManager::GetTraceCreateCallback(plugin_name))
return create_callback(trace_session_file, session_file_dir, debugger);
return createInvalidPlugInError(json_session.trace.type);
Add a "Trace" plug-in to LLDB to add process trace support in stages. This is the first in a series of patches that will adds a new processor trace plug-in to LLDB. The idea for this first patch to to add the plug-in interface with simple commands for the trace files that can "load" and "dump" the trace information. We can test the functionality and ensure people are happy with the way things are done and how things are organized before moving on to adding more functionality. Processor trace information can be view in a few different ways: - post mortem where a trace is saved off that can be viewed later in the debugger - gathered while a process is running and allow the user to step back in time (with no variables, memory or registers) to see how each thread arrived at where it is currently stopped. This patch attempts to start with the first solution of loading a trace file after the fact. The idea is that we will use a JSON file to load the trace information. JSON allows us to specify information about the trace like: - plug-in name in LLDB - path to trace file - shared library load information so we can re-create a target and symbolicate the information in the trace - any other info that the trace plug-in will need to be able to successfully parse the trace information - cpu type - version info - ??? A new "trace" command was added at the top level of the LLDB commmands: - "trace load" - "trace dump" I did this because if we load trace information we don't need to have a process and we might end up creating a new target for the trace information that will become active. If anyone has any input on where this would be better suited, please let me know. Walter Erquinigo will end up filling in the Intel PT specific plug-in so that it works and is tested once we can agree that the direction of this patch is the correct one, so please feel free to chime in with ideas on comments! Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D85705
2020-08-17 17:21:52 -07:00
}
Expected<lldb::TraceSP>
Trace::FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process) {
if (!process.IsLiveDebugSession())
return createStringError(inconvertibleErrorCode(),
"Can't trace non-live processes");
ConstString name(plugin_name);
if (auto create_callback =
PluginManager::GetTraceCreateCallbackForLiveProcess(name))
return create_callback(process);
return createInvalidPlugInError(plugin_name);
}
[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-03 12:23:12 -07:00
Expected<StringRef> Trace::FindPluginSchema(StringRef name) {
ConstString plugin_name(name);
StringRef schema = PluginManager::GetTraceSchema(plugin_name);
if (!schema.empty())
return schema;
Add a "Trace" plug-in to LLDB to add process trace support in stages. This is the first in a series of patches that will adds a new processor trace plug-in to LLDB. The idea for this first patch to to add the plug-in interface with simple commands for the trace files that can "load" and "dump" the trace information. We can test the functionality and ensure people are happy with the way things are done and how things are organized before moving on to adding more functionality. Processor trace information can be view in a few different ways: - post mortem where a trace is saved off that can be viewed later in the debugger - gathered while a process is running and allow the user to step back in time (with no variables, memory or registers) to see how each thread arrived at where it is currently stopped. This patch attempts to start with the first solution of loading a trace file after the fact. The idea is that we will use a JSON file to load the trace information. JSON allows us to specify information about the trace like: - plug-in name in LLDB - path to trace file - shared library load information so we can re-create a target and symbolicate the information in the trace - any other info that the trace plug-in will need to be able to successfully parse the trace information - cpu type - version info - ??? A new "trace" command was added at the top level of the LLDB commmands: - "trace load" - "trace dump" I did this because if we load trace information we don't need to have a process and we might end up creating a new target for the trace information that will become active. If anyone has any input on where this would be better suited, please let me know. Walter Erquinigo will end up filling in the Intel PT specific plug-in so that it works and is tested once we can agree that the direction of this patch is the correct one, so please feel free to chime in with ideas on comments! Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D85705
2020-08-17 17:21:52 -07:00
[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-03 12:23:12 -07:00
return createInvalidPlugInError(name);
Add a "Trace" plug-in to LLDB to add process trace support in stages. This is the first in a series of patches that will adds a new processor trace plug-in to LLDB. The idea for this first patch to to add the plug-in interface with simple commands for the trace files that can "load" and "dump" the trace information. We can test the functionality and ensure people are happy with the way things are done and how things are organized before moving on to adding more functionality. Processor trace information can be view in a few different ways: - post mortem where a trace is saved off that can be viewed later in the debugger - gathered while a process is running and allow the user to step back in time (with no variables, memory or registers) to see how each thread arrived at where it is currently stopped. This patch attempts to start with the first solution of loading a trace file after the fact. The idea is that we will use a JSON file to load the trace information. JSON allows us to specify information about the trace like: - plug-in name in LLDB - path to trace file - shared library load information so we can re-create a target and symbolicate the information in the trace - any other info that the trace plug-in will need to be able to successfully parse the trace information - cpu type - version info - ??? A new "trace" command was added at the top level of the LLDB commmands: - "trace load" - "trace dump" I did this because if we load trace information we don't need to have a process and we might end up creating a new target for the trace information that will become active. If anyone has any input on where this would be better suited, please let me know. Walter Erquinigo will end up filling in the Intel PT specific plug-in so that it works and is tested once we can agree that the direction of this patch is the correct one, so please feel free to chime in with ideas on comments! Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D85705
2020-08-17 17:21:52 -07:00
}
[trace][intel-pt] Implement the basic decoding functionality Depends on D89408. This diff finally implements trace decoding! The current interface is $ trace load /path/to/trace/session/file.json $ thread trace dump instructions thread #1: tid = 3842849, total instructions = 22 [ 0] 0x40052d [ 1] 0x40052d ... [19] 0x400521 $ # simply enter, which is a repeat command [20] 0x40052d [21] 0x400529 ... This doesn't do any disassembly, which will be done in the next diff. Changes: - Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding. - Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step. - Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces. - Added basic APIs for accessing the trace in Trace.h: - GetInstructionCount, which counts the number of instructions traced for a given thread - IsTraceFailed, which returns an Error if decoding a thread failed - ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do. - DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible. - Tests included Differential Revision: https://reviews.llvm.org/D89283
2020-10-14 10:26:10 -07:00
static int GetNumberOfDigits(size_t num) {
return num == 0 ? 1 : static_cast<int>(log10(num)) + 1;
}
/// Dump the symbol context of the given instruction address if it's different
/// from the symbol context of the previous instruction in the trace.
///
/// \param[in] prev_sc
/// The symbol context of the previous instruction in the trace.
///
/// \param[in] address
/// The address whose symbol information will be dumped.
///
/// \return
/// The symbol context of the current address, which might differ from the
/// previous one.
static SymbolContext DumpSymbolContext(Stream &s, const SymbolContext &prev_sc,
Target &target, const Address &address) {
AddressRange range;
if (prev_sc.GetAddressRange(eSymbolContextEverything, 0,
/*inline_block_range*/ false, range) &&
range.ContainsFileAddress(address))
return prev_sc;
SymbolContext sc;
address.CalculateSymbolContext(&sc, eSymbolContextEverything);
if (!prev_sc.module_sp && !sc.module_sp)
return sc;
if (prev_sc.module_sp == sc.module_sp && !sc.function && !sc.symbol &&
!prev_sc.function && !prev_sc.symbol)
return sc;
s.Printf(" ");
if (!sc.module_sp)
s.Printf("(none)");
else if (!sc.function && !sc.symbol)
s.Printf("%s`(none)",
sc.module_sp->GetFileSpec().GetFilename().AsCString());
else
sc.DumpStopContext(&s, &target, address, /*show_fullpath*/ false,
/*show_module*/ true, /*show_inlined_frames*/ false,
/*show_function_arguments*/ true,
/*show_function_name*/ true);
[trace][intel-pt] Implement the basic decoding functionality Depends on D89408. This diff finally implements trace decoding! The current interface is $ trace load /path/to/trace/session/file.json $ thread trace dump instructions thread #1: tid = 3842849, total instructions = 22 [ 0] 0x40052d [ 1] 0x40052d ... [19] 0x400521 $ # simply enter, which is a repeat command [20] 0x40052d [21] 0x400529 ... This doesn't do any disassembly, which will be done in the next diff. Changes: - Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding. - Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step. - Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces. - Added basic APIs for accessing the trace in Trace.h: - GetInstructionCount, which counts the number of instructions traced for a given thread - IsTraceFailed, which returns an Error if decoding a thread failed - ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do. - DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible. - Tests included Differential Revision: https://reviews.llvm.org/D89283
2020-10-14 10:26:10 -07:00
s.Printf("\n");
return sc;
}
/// Dump an instruction given by its address using a given disassembler, unless
/// the instruction is not present in the disassembler.
///
/// \param[in] disassembler
/// A disassembler containing a certain instruction list.
///
/// \param[in] address
/// The address of the instruction to dump.
///
/// \return
/// \b true if the information could be dumped, \b false otherwise.
static bool TryDumpInstructionInfo(Stream &s,
const DisassemblerSP &disassembler,
const ExecutionContext &exe_ctx,
const Address &address) {
if (!disassembler)
return false;
if (InstructionSP instruction =
disassembler->GetInstructionList().GetInstructionAtAddress(address)) {
instruction->Dump(&s, /*show_address*/ false, /*show_bytes*/ false,
/*max_opcode_byte_size*/ 0, &exe_ctx,
/*sym_ctx*/ nullptr, /*prev_sym_ctx*/ nullptr,
/*disassembly_addr_format*/ nullptr,
/*max_address_text_size*/ 0);
return true;
}
return false;
}
/// Dump an instruction instruction given by its address.
///
/// \param[in] prev_disassembler
/// The disassembler that was used to dump the previous instruction in the
/// trace. It is useful to avoid recomputations.
///
/// \param[in] address
/// The address of the instruction to dump.
///
/// \return
/// A disassembler that contains the given instruction, which might differ
/// from the previous disassembler.
static DisassemblerSP
DumpInstructionInfo(Stream &s, const SymbolContext &sc,
const DisassemblerSP &prev_disassembler,
ExecutionContext &exe_ctx, const Address &address) {
// We first try to use the previous disassembler
if (TryDumpInstructionInfo(s, prev_disassembler, exe_ctx, address))
return prev_disassembler;
// Now we try using the current function's disassembler
if (sc.function) {
DisassemblerSP disassembler =
sc.function->GetInstructions(exe_ctx, nullptr);
[trace][intel-pt] Implement the basic decoding functionality Depends on D89408. This diff finally implements trace decoding! The current interface is $ trace load /path/to/trace/session/file.json $ thread trace dump instructions thread #1: tid = 3842849, total instructions = 22 [ 0] 0x40052d [ 1] 0x40052d ... [19] 0x400521 $ # simply enter, which is a repeat command [20] 0x40052d [21] 0x400529 ... This doesn't do any disassembly, which will be done in the next diff. Changes: - Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding. - Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step. - Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces. - Added basic APIs for accessing the trace in Trace.h: - GetInstructionCount, which counts the number of instructions traced for a given thread - IsTraceFailed, which returns an Error if decoding a thread failed - ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do. - DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible. - Tests included Differential Revision: https://reviews.llvm.org/D89283
2020-10-14 10:26:10 -07:00
if (TryDumpInstructionInfo(s, disassembler, exe_ctx, address))
return disassembler;
}
// We fallback to disassembly one instruction
Target &target = exe_ctx.GetTargetRef();
const ArchSpec &arch = target.GetArchitecture();
AddressRange range(address, arch.GetMaximumOpcodeByteSize() * 1);
DisassemblerSP disassembler =
Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr,
/*flavor*/ nullptr, target, range);
[trace][intel-pt] Implement the basic decoding functionality Depends on D89408. This diff finally implements trace decoding! The current interface is $ trace load /path/to/trace/session/file.json $ thread trace dump instructions thread #1: tid = 3842849, total instructions = 22 [ 0] 0x40052d [ 1] 0x40052d ... [19] 0x400521 $ # simply enter, which is a repeat command [20] 0x40052d [21] 0x400529 ... This doesn't do any disassembly, which will be done in the next diff. Changes: - Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding. - Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step. - Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces. - Added basic APIs for accessing the trace in Trace.h: - GetInstructionCount, which counts the number of instructions traced for a given thread - IsTraceFailed, which returns an Error if decoding a thread failed - ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do. - DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible. - Tests included Differential Revision: https://reviews.llvm.org/D89283
2020-10-14 10:26:10 -07:00
if (TryDumpInstructionInfo(s, disassembler, exe_ctx, address))
return disassembler;
return nullptr;
}
void Trace::DumpTraceInstructions(Thread &thread, Stream &s, size_t count,
[trace][intel-pt] Implement the basic decoding functionality Depends on D89408. This diff finally implements trace decoding! The current interface is $ trace load /path/to/trace/session/file.json $ thread trace dump instructions thread #1: tid = 3842849, total instructions = 22 [ 0] 0x40052d [ 1] 0x40052d ... [19] 0x400521 $ # simply enter, which is a repeat command [20] 0x40052d [21] 0x400529 ... This doesn't do any disassembly, which will be done in the next diff. Changes: - Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding. - Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step. - Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces. - Added basic APIs for accessing the trace in Trace.h: - GetInstructionCount, which counts the number of instructions traced for a given thread - IsTraceFailed, which returns an Error if decoding a thread failed - ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do. - DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible. - Tests included Differential Revision: https://reviews.llvm.org/D89283
2020-10-14 10:26:10 -07:00
size_t end_position, bool raw) {
if (!IsTraced(thread)) {
s.Printf("thread #%u: tid = %" PRIu64 ", not traced\n", thread.GetIndexID(),
thread.GetID());
return;
}
[trace][intel-pt] Implement the basic decoding functionality Depends on D89408. This diff finally implements trace decoding! The current interface is $ trace load /path/to/trace/session/file.json $ thread trace dump instructions thread #1: tid = 3842849, total instructions = 22 [ 0] 0x40052d [ 1] 0x40052d ... [19] 0x400521 $ # simply enter, which is a repeat command [20] 0x40052d [21] 0x400529 ... This doesn't do any disassembly, which will be done in the next diff. Changes: - Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding. - Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step. - Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces. - Added basic APIs for accessing the trace in Trace.h: - GetInstructionCount, which counts the number of instructions traced for a given thread - IsTraceFailed, which returns an Error if decoding a thread failed - ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do. - DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible. - Tests included Differential Revision: https://reviews.llvm.org/D89283
2020-10-14 10:26:10 -07:00
size_t instructions_count = GetInstructionCount(thread);
s.Printf("thread #%u: tid = %" PRIu64 ", total instructions = %zu\n",
thread.GetIndexID(), thread.GetID(), instructions_count);
if (count == 0 || end_position >= instructions_count)
return;
size_t start_position =
end_position + 1 < count ? 0 : end_position + 1 - count;
int digits_count = GetNumberOfDigits(end_position);
auto printInstructionIndex = [&](size_t index) {
s.Printf(" [%*zu] ", digits_count, index);
};
bool was_prev_instruction_an_error = false;
Target &target = thread.GetProcess()->GetTarget();
SymbolContext sc;
DisassemblerSP disassembler;
ExecutionContext exe_ctx;
target.CalculateExecutionContext(exe_ctx);
TraverseInstructions(
thread, start_position, TraceDirection::Forwards,
[&](size_t index, Expected<lldb::addr_t> load_address) -> bool {
if (load_address) {
// We print an empty line after a sequence of errors to show more
// clearly that there's a gap in the trace
if (was_prev_instruction_an_error)
s.Printf(" ...missing instructions\n");
Address address;
if (!raw) {
target.GetSectionLoadList().ResolveLoadAddress(*load_address,
address);
sc = DumpSymbolContext(s, sc, target, address);
}
printInstructionIndex(index);
s.Printf("0x%016" PRIx64 " ", *load_address);
if (!raw) {
disassembler =
DumpInstructionInfo(s, sc, disassembler, exe_ctx, address);
}
was_prev_instruction_an_error = false;
} else {
printInstructionIndex(index);
s << toString(load_address.takeError());
was_prev_instruction_an_error = true;
if (!raw)
sc = SymbolContext();
}
s.Printf("\n");
return index < end_position;
});
}
Error Trace::Start(const llvm::json::Value &request) {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),
"Tracing requires a live process.");
return m_live_process->TraceStart(request);
}
Error Trace::StopProcess() {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),
"Tracing requires a live process.");
return m_live_process->TraceStop(
TraceStopRequest(GetPluginName().AsCString()));
}
Error Trace::StopThreads(const std::vector<lldb::tid_t> &tids) {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),
"Tracing requires a live process.");
return m_live_process->TraceStop(
TraceStopRequest(GetPluginName().AsCString(), tids));
}
Expected<std::string> Trace::GetLiveProcessState() {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),
"Tracing requires a live process.");
return m_live_process->TraceGetState(GetPluginName().AsCString());
}
Optional<size_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid,
llvm::StringRef kind) {
auto it = m_live_thread_data.find(tid);
if (it == m_live_thread_data.end())
return None;
std::unordered_map<std::string, size_t> &single_thread_data = it->second;
auto single_thread_data_it = single_thread_data.find(kind.str());
if (single_thread_data_it == single_thread_data.end())
return None;
return single_thread_data_it->second;
}
Optional<size_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
auto data_it = m_live_process_data.find(kind.str());
if (data_it == m_live_process_data.end())
return None;
return data_it->second;
}
Expected<std::vector<uint8_t>>
Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),
"Tracing requires a live process.");
llvm::Optional<size_t> size = GetLiveThreadBinaryDataSize(tid, kind);
if (!size)
return createStringError(
inconvertibleErrorCode(),
"Tracing data \"%s\" is not available for thread %" PRIu64 ".",
kind.data(), tid);
TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(),
static_cast<int64_t>(tid), 0,
static_cast<int64_t>(*size)};
return m_live_process->TraceGetBinaryData(request);
}
Expected<std::vector<uint8_t>>
Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),
"Tracing requires a live process.");
llvm::Optional<size_t> size = GetLiveProcessBinaryDataSize(kind);
if (!size)
return createStringError(
inconvertibleErrorCode(),
"Tracing data \"%s\" is not available for the process.", kind.data());
TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(),
None, 0, static_cast<int64_t>(*size)};
return m_live_process->TraceGetBinaryData(request);
}
void Trace::RefreshLiveProcessState() {
if (!m_live_process)
return;
uint32_t new_stop_id = m_live_process->GetStopID();
if (new_stop_id == m_stop_id)
return;
m_stop_id = new_stop_id;
m_live_thread_data.clear();
Expected<std::string> json_string = GetLiveProcessState();
if (!json_string) {
DoRefreshLiveProcessState(json_string.takeError());
return;
}
Expected<TraceGetStateResponse> live_process_state =
json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse");
if (!live_process_state) {
DoRefreshLiveProcessState(live_process_state.takeError());
return;
}
for (const TraceThreadState &thread_state :
live_process_state->tracedThreads) {
for (const TraceBinaryData &item : thread_state.binaryData)
m_live_thread_data[thread_state.tid][item.kind] = item.size;
}
for (const TraceBinaryData &item : live_process_state->processBinaryData)
m_live_process_data[item.kind] = item.size;
DoRefreshLiveProcessState(std::move(live_process_state));
}