aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Commands/CommandObjectThread.cpp
diff options
context:
space:
mode:
authorWalter Erquinigo <wallace@fb.com>2022-06-18 15:44:37 -0700
committerWalter Erquinigo <wallace@fb.com>2022-06-22 11:14:22 -0700
commitefbfde0dd0f92d89767df53cbfb883ecf93ffa83 (patch)
treeb26140b16f9c2561fd6e3bd81ded057aa65f73b8 /lldb/source/Commands/CommandObjectThread.cpp
parent89a1d03e2b379e325daa5249411e414bbd995b5e (diff)
downloadllvm-efbfde0dd0f92d89767df53cbfb883ecf93ffa83.zip
llvm-efbfde0dd0f92d89767df53cbfb883ecf93ffa83.tar.gz
llvm-efbfde0dd0f92d89767df53cbfb883ecf93ffa83.tar.bz2
[trace] Add an option to dump instructions in json and to a file
In order to provide simple scripting support on top of instruction traces, a simple solution is to enhance the `dump instructions` command and allow printing in json and directly to a file. The format is verbose and not space efficient, but it's not supposed to be used for really large traces, in which case the TraceCursor API is the way to go. - add a -j option for printing the dump in json - add a -J option for pretty printing the json output - add a -F option for specifying an output file - add a -a option for dumping all the instructions available starting at the initial point configured with the other flags - add tests for all cases - refactored the instruction dumper and abstracted the actual "printing" logic. There are two writer implementations: CLI and JSON. This made the dumper itself much more readable and maintanable sample output: ``` (lldb) thread trace dump instructions -t -a --id 100 -J [ { "id": 100, "tsc": "43591204528448966" "loadAddress": "0x407a91", "module": "a.out", "symbol": "void std::deque<Foo, std::allocator<Foo>>::_M_push_back_aux<Foo>(Foo&&)", "mnemonic": "movq", "source": "/usr/include/c++/8/bits/deque.tcc", "line": 492, "column": 30 }, ... ``` Differential Revision: https://reviews.llvm.org/D128316
Diffstat (limited to 'lldb/source/Commands/CommandObjectThread.cpp')
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp62
1 files changed, 49 insertions, 13 deletions
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index 11affe8..037bbaf 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -2128,6 +2128,10 @@ public:
m_count = count;
break;
}
+ case 'a': {
+ m_count = std::numeric_limits<decltype(m_count)>::max();
+ break;
+ }
case 's': {
int32_t skip;
if (option_arg.empty() || option_arg.getAsInteger(0, skip) || skip < 0)
@@ -2148,6 +2152,10 @@ public:
m_dumper_options.id = id;
break;
}
+ case 'F': {
+ m_output_file.emplace(option_arg);
+ break;
+ }
case 'r': {
m_dumper_options.raw = true;
break;
@@ -2164,6 +2172,15 @@ public:
m_dumper_options.show_events = true;
break;
}
+ case 'j': {
+ m_dumper_options.json = true;
+ break;
+ }
+ case 'J': {
+ m_dumper_options.pretty_print_json = true;
+ m_dumper_options.json = true;
+ break;
+ }
case 'C': {
m_continue = true;
break;
@@ -2177,6 +2194,7 @@ public:
void OptionParsingStarting(ExecutionContext *execution_context) override {
m_count = kDefaultCount;
m_continue = false;
+ m_output_file = llvm::None;
m_dumper_options = {};
}
@@ -2189,6 +2207,7 @@ public:
// Instance variables to hold the values for command options.
size_t m_count;
size_t m_continue;
+ llvm::Optional<FileSpec> m_output_file;
TraceInstructionDumperOptions m_dumper_options;
};
@@ -2238,27 +2257,44 @@ protected:
bool DoExecute(Args &args, CommandReturnObject &result) override {
ThreadSP thread_sp = GetThread(args, result);
- if (!thread_sp)
+ if (!thread_sp) {
+ result.AppendError("invalid thread\n");
return false;
+ }
- Stream &s = result.GetOutputStream();
- s.Printf("thread #%u: tid = %" PRIu64 "\n", thread_sp->GetIndexID(),
- thread_sp->GetID());
-
- if (m_options.m_continue) {
- if (!m_last_id) {
- result.AppendMessage(" no more data\n");
- return true;
- }
+ if (m_options.m_continue && m_last_id) {
// We set up the options to continue one instruction past where
// the previous iteration stopped.
m_options.m_dumper_options.skip = 1;
m_options.m_dumper_options.id = m_last_id;
}
- const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace();
- TraceInstructionDumper dumper(trace_sp->GetCursor(*thread_sp), s,
- m_options.m_dumper_options);
+ TraceCursorUP cursor_up =
+ m_exe_ctx.GetTargetSP()->GetTrace()->GetCursor(*thread_sp);
+
+ if (m_options.m_dumper_options.id &&
+ !cursor_up->HasId(*m_options.m_dumper_options.id)) {
+ result.AppendError("invalid instruction id\n");
+ return false;
+ }
+
+ llvm::Optional<StreamFile> out_file;
+ if (m_options.m_output_file) {
+ out_file.emplace(m_options.m_output_file->GetPath().c_str(),
+ File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate,
+ lldb::eFilePermissionsFileDefault);
+ }
+
+ TraceInstructionDumper dumper(
+ std::move(cursor_up), out_file ? *out_file : result.GetOutputStream(),
+ m_options.m_dumper_options);
+
+ if (m_options.m_continue && !m_last_id) {
+ // We need to tell the dumper to stop processing data when
+ // we already ran out of instructions in a previous command
+ dumper.SetNoMoreData();
+ }
+
m_last_id = dumper.DumpInstructions(m_options.m_count);
return true;
}