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"
|
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"
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
#include "lldb/Target/ExecutionContext.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/Target/Process.h"
|
|
|
|
|
#include "lldb/Target/SectionLoadList.h"
|
2020-10-02 14:32:22 -07:00
|
|
|
#include "lldb/Target/Thread.h"
|
2020-11-09 13:36:26 -08:00
|
|
|
#include "lldb/Target/ThreadPostMortemTrace.h"
|
2020-10-02 14:32:22 -07:00
|
|
|
#include "lldb/Utility/Stream.h"
|
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
|
2020-09-24 13:39:21 -07:00
|
|
|
// 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 {
|
2020-09-24 13:39:21 -07:00
|
|
|
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) {
|
2020-09-24 13:39:21 -07:00
|
|
|
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) {
|
2020-09-24 13:39:21 -07:00
|
|
|
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);
|
2020-09-24 13:39:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // 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) {
|
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());
|
2020-08-17 17:21:52 -07:00
|
|
|
}
|
|
|
|
|
|
2020-11-09 13:36:26 -08: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();
|
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);
|
2020-08-17 17:21:52 -07:00
|
|
|
}
|
|
|
|
|
|
2020-11-09 13:36:26 -08: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;
|
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);
|
2020-08-17 17:21:52 -07:00
|
|
|
}
|
2020-10-02 14:32:22 -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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \return
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
/// \b true if the provided line entries match line, column and source file.
|
|
|
|
|
/// This function assumes that the line entries are valid.
|
|
|
|
|
static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b) {
|
|
|
|
|
if (a.line != b.line)
|
|
|
|
|
return false;
|
|
|
|
|
if (a.column != b.column)
|
|
|
|
|
return false;
|
|
|
|
|
return a.file == b.file;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This custom LineEntry validator is neded because some line_entries have
|
|
|
|
|
// 0 as line, which is meaningless. Notice that LineEntry::IsValid only
|
|
|
|
|
// checks that line is not LLDB_INVALID_LINE_NUMBER, i.e. UINT32_MAX.
|
|
|
|
|
static bool IsLineEntryValid(const LineEntry &line_entry) {
|
|
|
|
|
return line_entry.IsValid() && line_entry.line > 0;
|
|
|
|
|
}
|
[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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
/// Helper structure for \a TraverseInstructionsWithSymbolInfo.
|
|
|
|
|
struct InstructionSymbolInfo {
|
[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
|
|
|
SymbolContext sc;
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
Address address;
|
|
|
|
|
lldb::addr_t load_address;
|
|
|
|
|
lldb::DisassemblerSP disassembler;
|
|
|
|
|
lldb::InstructionSP instruction;
|
|
|
|
|
lldb_private::ExecutionContext exe_ctx;
|
|
|
|
|
};
|
[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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
/// InstructionSymbolInfo object with symbol information for the given
|
|
|
|
|
/// instruction, calculated efficiently.
|
|
|
|
|
///
|
|
|
|
|
/// \param[in] symbol_scope
|
|
|
|
|
/// If not \b 0, then the \a InstructionSymbolInfo will have its
|
|
|
|
|
/// SymbolContext calculated up to that level.
|
|
|
|
|
///
|
|
|
|
|
/// \param[in] include_disassembler
|
|
|
|
|
/// If \b true, then the \a InstructionSymbolInfo will have the
|
|
|
|
|
/// \a disassembler and \a instruction objects calculated.
|
|
|
|
|
static void TraverseInstructionsWithSymbolInfo(
|
|
|
|
|
Trace &trace, Thread &thread, size_t position,
|
|
|
|
|
Trace::TraceDirection direction, SymbolContextItem symbol_scope,
|
|
|
|
|
bool include_disassembler,
|
|
|
|
|
std::function<bool(size_t index, Expected<InstructionSymbolInfo> insn)>
|
|
|
|
|
callback) {
|
|
|
|
|
InstructionSymbolInfo prev_insn;
|
|
|
|
|
|
|
|
|
|
Target &target = thread.GetProcess()->GetTarget();
|
|
|
|
|
ExecutionContext exe_ctx;
|
|
|
|
|
target.CalculateExecutionContext(exe_ctx);
|
|
|
|
|
const ArchSpec &arch = target.GetArchitecture();
|
|
|
|
|
|
|
|
|
|
// Find the symbol context for the given address reusing the previous
|
|
|
|
|
// instruction's symbol context when possible.
|
|
|
|
|
auto calculate_symbol_context = [&](const Address &address) {
|
|
|
|
|
AddressRange range;
|
|
|
|
|
if (prev_insn.sc.GetAddressRange(symbol_scope, 0,
|
|
|
|
|
/*inline_block_range*/ false, range) &&
|
|
|
|
|
range.Contains(address))
|
|
|
|
|
return prev_insn.sc;
|
|
|
|
|
|
|
|
|
|
SymbolContext sc;
|
|
|
|
|
address.CalculateSymbolContext(&sc, symbol_scope);
|
[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
|
|
|
return sc;
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
// Find the disassembler for the given address reusing the previous
|
|
|
|
|
// instruction's disassembler when possible.
|
|
|
|
|
auto calculate_disass = [&](const Address &address, const SymbolContext &sc) {
|
|
|
|
|
if (prev_insn.disassembler) {
|
|
|
|
|
if (InstructionSP instruction =
|
|
|
|
|
prev_insn.disassembler->GetInstructionList()
|
|
|
|
|
.GetInstructionAtAddress(address))
|
|
|
|
|
return std::make_tuple(prev_insn.disassembler, instruction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sc.function) {
|
|
|
|
|
if (DisassemblerSP disassembler =
|
|
|
|
|
sc.function->GetInstructions(exe_ctx, nullptr)) {
|
|
|
|
|
if (InstructionSP instruction =
|
|
|
|
|
disassembler->GetInstructionList().GetInstructionAtAddress(
|
|
|
|
|
address))
|
|
|
|
|
return std::make_tuple(disassembler, instruction);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// We fallback to a single instruction disassembler
|
|
|
|
|
AddressRange range(address, arch.GetMaximumOpcodeByteSize());
|
|
|
|
|
DisassemblerSP disassembler =
|
|
|
|
|
Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr,
|
|
|
|
|
/*flavor*/ nullptr, target, range);
|
|
|
|
|
return std::make_tuple(disassembler,
|
|
|
|
|
disassembler ? disassembler->GetInstructionList()
|
|
|
|
|
.GetInstructionAtAddress(address)
|
|
|
|
|
: InstructionSP());
|
|
|
|
|
};
|
[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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
trace.TraverseInstructions(
|
|
|
|
|
thread, position, direction,
|
|
|
|
|
[&](size_t index, Expected<lldb::addr_t> load_address) -> bool {
|
|
|
|
|
if (!load_address)
|
|
|
|
|
return callback(index, load_address.takeError());
|
|
|
|
|
|
|
|
|
|
InstructionSymbolInfo insn;
|
|
|
|
|
insn.load_address = *load_address;
|
|
|
|
|
insn.exe_ctx = exe_ctx;
|
|
|
|
|
insn.address.SetLoadAddress(*load_address, &target);
|
|
|
|
|
if (symbol_scope != 0)
|
|
|
|
|
insn.sc = calculate_symbol_context(insn.address);
|
|
|
|
|
if (include_disassembler)
|
|
|
|
|
std::tie(insn.disassembler, insn.instruction) =
|
|
|
|
|
calculate_disass(insn.address, insn.sc);
|
|
|
|
|
prev_insn = insn;
|
|
|
|
|
return callback(index, insn);
|
|
|
|
|
});
|
[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
|
|
|
}
|
|
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
/// Compare the symbol contexts of the provided \a InstructionSymbolInfo
|
|
|
|
|
/// objects.
|
[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
|
|
|
///
|
|
|
|
|
/// \return
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
/// \a true if both instructions belong to the same scope level analized
|
|
|
|
|
/// in the following order:
|
|
|
|
|
/// - module
|
|
|
|
|
/// - symbol
|
|
|
|
|
/// - function
|
|
|
|
|
/// - line
|
|
|
|
|
static bool
|
|
|
|
|
IsSameInstructionSymbolContext(const InstructionSymbolInfo &prev_insn,
|
|
|
|
|
const InstructionSymbolInfo &insn) {
|
|
|
|
|
// module checks
|
|
|
|
|
if (insn.sc.module_sp != prev_insn.sc.module_sp)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// symbol checks
|
|
|
|
|
if (insn.sc.symbol != prev_insn.sc.symbol)
|
[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
|
|
|
return false;
|
|
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
// function checks
|
|
|
|
|
if (!insn.sc.function && !prev_insn.sc.function)
|
[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
|
|
|
return true;
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
else if (insn.sc.function != prev_insn.sc.function)
|
|
|
|
|
return false;
|
[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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
// line entry checks
|
|
|
|
|
const bool curr_line_valid = IsLineEntryValid(insn.sc.line_entry);
|
|
|
|
|
const bool prev_line_valid = IsLineEntryValid(prev_insn.sc.line_entry);
|
|
|
|
|
if (curr_line_valid && prev_line_valid)
|
|
|
|
|
return FileLineAndColumnMatches(insn.sc.line_entry,
|
|
|
|
|
prev_insn.sc.line_entry);
|
|
|
|
|
return curr_line_valid == prev_line_valid;
|
[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
|
|
|
}
|
|
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
/// Dump the symbol context of the given instruction address if it's different
|
|
|
|
|
/// from the symbol context of the previous instruction in the trace.
|
[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
|
|
|
///
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
/// \param[in] prev_sc
|
|
|
|
|
/// The symbol context of the previous instruction in the trace.
|
[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
|
|
|
///
|
|
|
|
|
/// \param[in] address
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
/// The address whose symbol information will be dumped.
|
[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
|
|
|
///
|
|
|
|
|
/// \return
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
/// The symbol context of the current address, which might differ from the
|
|
|
|
|
/// previous one.
|
|
|
|
|
static void
|
|
|
|
|
DumpInstructionSymbolContext(Stream &s,
|
|
|
|
|
Optional<InstructionSymbolInfo> prev_insn,
|
|
|
|
|
InstructionSymbolInfo &insn) {
|
|
|
|
|
if (prev_insn && IsSameInstructionSymbolContext(*prev_insn, insn))
|
|
|
|
|
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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
s.Printf(" ");
|
|
|
|
|
|
|
|
|
|
if (!insn.sc.module_sp)
|
|
|
|
|
s.Printf("(none)");
|
|
|
|
|
else if (!insn.sc.function && !insn.sc.symbol)
|
|
|
|
|
s.Printf("%s`(none)",
|
|
|
|
|
insn.sc.module_sp->GetFileSpec().GetFilename().AsCString());
|
|
|
|
|
else
|
|
|
|
|
insn.sc.DumpStopContext(&s, insn.exe_ctx.GetTargetPtr(), insn.address,
|
|
|
|
|
/*show_fullpath*/ false,
|
|
|
|
|
/*show_module*/ true, /*show_inlined_frames*/ false,
|
|
|
|
|
/*show_function_arguments*/ true,
|
|
|
|
|
/*show_function_name*/ true);
|
|
|
|
|
s.Printf("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DumpInstructionDisassembly(Stream &s, InstructionSymbolInfo &insn) {
|
|
|
|
|
if (!insn.instruction)
|
|
|
|
|
return;
|
2021-06-02 14:05:33 -07:00
|
|
|
s.Printf(" ");
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
insn.instruction->Dump(&s, /*show_address*/ false, /*show_bytes*/ false,
|
|
|
|
|
/*max_opcode_byte_size*/ 0, &insn.exe_ctx, &insn.sc,
|
|
|
|
|
/*prev_sym_ctx*/ nullptr,
|
|
|
|
|
/*disassembly_addr_format*/ nullptr,
|
|
|
|
|
/*max_address_text_size*/ 0);
|
[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
|
|
|
}
|
|
|
|
|
|
2020-10-02 14:32:22 -07:00
|
|
|
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) {
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
Optional<size_t> instructions_count = GetInstructionCount(thread);
|
|
|
|
|
if (!instructions_count) {
|
2020-11-09 13:36:26 -08:00
|
|
|
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
|
|
|
s.Printf("thread #%u: tid = %" PRIu64 ", total instructions = %zu\n",
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
thread.GetIndexID(), thread.GetID(), *instructions_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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
if (count == 0 || end_position >= *instructions_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
|
|
|
return;
|
|
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
int digits_count = GetNumberOfDigits(end_position);
|
[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 start_position =
|
|
|
|
|
end_position + 1 < count ? 0 : end_position + 1 - count;
|
|
|
|
|
auto printInstructionIndex = [&](size_t index) {
|
|
|
|
|
s.Printf(" [%*zu] ", digits_count, index);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool was_prev_instruction_an_error = false;
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
Optional<InstructionSymbolInfo> prev_insn;
|
[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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
TraverseInstructionsWithSymbolInfo(
|
|
|
|
|
*this, thread, start_position, TraceDirection::Forwards,
|
|
|
|
|
eSymbolContextEverything, /*disassembler*/ true,
|
|
|
|
|
[&](size_t index, Expected<InstructionSymbolInfo> insn) -> bool {
|
|
|
|
|
if (!insn) {
|
|
|
|
|
printInstructionIndex(index);
|
|
|
|
|
s << toString(insn.takeError());
|
[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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
prev_insn = None;
|
|
|
|
|
was_prev_instruction_an_error = true;
|
|
|
|
|
} else {
|
[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 (was_prev_instruction_an_error)
|
|
|
|
|
s.Printf(" ...missing instructions\n");
|
|
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
if (!raw)
|
|
|
|
|
DumpInstructionSymbolContext(s, prev_insn, *insn);
|
[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
|
|
|
|
|
|
|
|
printInstructionIndex(index);
|
2021-06-02 14:05:33 -07:00
|
|
|
s.Printf("0x%016" PRIx64, insn->load_address);
|
[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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
if (!raw)
|
|
|
|
|
DumpInstructionDisassembly(s, *insn);
|
[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
|
|
|
|
[trace] Dedup different source lines when dumping instructions + refactor
When dumping the traced instructions in a for loop, like this one
4: for (int a = 0; a < n; a++)
5: do something;
there might be multiple LineEntry objects for line 4, but with different address ranges. This was causing the dump command to dump something like this:
```
a.out`main + 11 at main.cpp:4
[1] 0x0000000000400518 movl $0x0, -0x8(%rbp)
[2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4
a.out`main + 28 at main.cpp:4
[3] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)
[4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5
```
which is confusing, as main.cpp:4 appears twice consecutively.
This diff fixes that issue by making the line entry comparison strictly about the line, column and file name. Before it was also comparing the address ranges, which we don't need because our output is strictly about what the user sees in the source.
Besides, I've noticed that the logic that traverses instructions and calculates symbols and disassemblies had too much coupling, and made my changes harder to implement, so I decided to decouple it. Now there are two methods for iterating over the instruction of a trace. The existing one does it on raw load addresses, but the one provides a SymbolContext and an InstructionSP, and does the calculations efficiently (not as efficient as possible for now though), so the caller doesn't need to care about these details. I think I'll be using that iterator to reconstruct the call stacks.
I was able to fix a test with this change.
Differential Revision: https://reviews.llvm.org/D100740
2021-05-03 07:55:35 -07:00
|
|
|
prev_insn = *insn;
|
[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
|
|
|
was_prev_instruction_an_error = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s.Printf("\n");
|
|
|
|
|
return index < end_position;
|
|
|
|
|
});
|
2020-10-02 14:32:22 -07:00
|
|
|
}
|
2020-11-09 13:36:26 -08:00
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
}
|