diff options
author | Walter Erquinigo <wallace@fb.com> | 2022-06-18 15:44:37 -0700 |
---|---|---|
committer | Walter Erquinigo <wallace@fb.com> | 2022-06-22 11:14:22 -0700 |
commit | efbfde0dd0f92d89767df53cbfb883ecf93ffa83 (patch) | |
tree | b26140b16f9c2561fd6e3bd81ded057aa65f73b8 /lldb/source/Commands/CommandObjectThread.cpp | |
parent | 89a1d03e2b379e325daa5249411e414bbd995b5e (diff) | |
download | llvm-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.cpp | 62 |
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; } |