diff options
author | Walter Erquinigo <wallace@fb.com> | 2022-03-22 09:18:53 -0700 |
---|---|---|
committer | Walter Erquinigo <wallace@fb.com> | 2022-04-06 12:19:36 -0700 |
commit | 05b4bf2571244da2cef438e907036b35a0e1f99a (patch) | |
tree | 312ab9fdb79f607e97379e01d4fd4a853c5a55b1 /lldb/source/Commands/CommandObjectThread.cpp | |
parent | 0d237d1f055d307439785be8a173f7b81e9aaffe (diff) | |
download | llvm-05b4bf2571244da2cef438e907036b35a0e1f99a.zip llvm-05b4bf2571244da2cef438e907036b35a0e1f99a.tar.gz llvm-05b4bf2571244da2cef438e907036b35a0e1f99a.tar.bz2 |
[trace][intelpt] Introduce instruction Ids
In order to support quick arbitrary access to instructions in the trace, we need
each instruction to have an id. It could be an index or any other value that the
trace plugin defines.
This will be useful for reverse debugging or for creating callstacks, as each
frame will need an instruction id associated with them.
I've updated the `thread trace dump instructions` command accordingly. It now
prints the instruction id instead of relative offset. I've also added a new --id
argument that allows starting the dump from an arbitrary position.
Differential Revision: https://reviews.llvm.org/D122254
Diffstat (limited to 'lldb/source/Commands/CommandObjectThread.cpp')
-rw-r--r-- | lldb/source/Commands/CommandObjectThread.cpp | 120 |
1 files changed, 64 insertions, 56 deletions
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index a87addc..78ec540 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -2099,8 +2099,7 @@ public: #define LLDB_OPTIONS_thread_trace_dump_instructions #include "CommandOptions.inc" -class CommandObjectTraceDumpInstructions - : public CommandObjectIterateOverThreads { +class CommandObjectTraceDumpInstructions : public CommandObjectParsed { public: class CommandOptions : public Options { public: @@ -2132,19 +2131,29 @@ public: "invalid integer value for option '%s'", option_arg.str().c_str()); else - m_skip = skip; + m_dumper_options.skip = skip; + break; + } + case 'i': { + uint64_t id; + if (option_arg.empty() || option_arg.getAsInteger(0, id)) + error.SetErrorStringWithFormat( + "invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_dumper_options.id = id; break; } case 'r': { - m_raw = true; + m_dumper_options.raw = true; break; } case 'f': { - m_forwards = true; + m_dumper_options.forwards = true; break; } case 't': { - m_show_tsc = true; + m_dumper_options.show_tsc = true; break; } case 'C': { @@ -2159,11 +2168,8 @@ public: void OptionParsingStarting(ExecutionContext *execution_context) override { m_count = kDefaultCount; - m_skip = 0; - m_raw = false; - m_forwards = false; - m_show_tsc = false; m_continue = false; + m_dumper_options = {}; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { @@ -2174,23 +2180,19 @@ public: // Instance variables to hold the values for command options. size_t m_count; - size_t m_skip; - bool m_raw; - bool m_forwards; - bool m_show_tsc; - bool m_continue; + size_t m_continue; + TraceInstructionDumperOptions m_dumper_options; }; CommandObjectTraceDumpInstructions(CommandInterpreter &interpreter) - : CommandObjectIterateOverThreads( + : CommandObjectParsed( interpreter, "thread trace dump instructions", - "Dump the traced instructions for one or more threads. If no " - "threads are specified, show the current thread. Use the " - "thread-index \"all\" to see all threads.", + "Dump the traced instructions for one thread. If no " + "thread is specified, show the current thread.", nullptr, - eCommandRequiresProcess | eCommandTryTargetAPILock | - eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | - eCommandProcessMustBeTraced) {} + eCommandRequiresProcess | eCommandRequiresThread | + eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {} ~CommandObjectTraceDumpInstructions() override = default; @@ -2200,57 +2202,63 @@ public: uint32_t index) override { std::string cmd; current_command_args.GetCommandString(cmd); - if (cmd.find("--continue") == std::string::npos) + if (cmd.find(" --continue") == std::string::npos) cmd += " --continue"; return cmd; } protected: - bool DoExecute(Args &args, CommandReturnObject &result) override { - if (!m_options.m_continue) - m_dumpers.clear(); + ThreadSP GetThread(Args &args, CommandReturnObject &result) { + if (args.GetArgumentCount() == 0) + return m_exe_ctx.GetThreadSP(); - return CommandObjectIterateOverThreads::DoExecute(args, result); - } - - bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { - Stream &s = result.GetOutputStream(); + const char *arg = args.GetArgumentAtIndex(0); + uint32_t thread_idx; - const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace(); + if (!llvm::to_integer(arg, thread_idx)) { + result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", + arg); + return nullptr; + } ThreadSP thread_sp = - m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); - - if (!m_dumpers.count(thread_sp->GetID())) { - lldb::TraceCursorUP cursor_up = trace_sp->GetCursor(*thread_sp); - // Set up the cursor and return the presentation index of the first - // instruction to dump after skipping instructions. - auto setUpCursor = [&]() { - cursor_up->SetForwards(m_options.m_forwards); - if (m_options.m_forwards) - return cursor_up->Seek(m_options.m_skip, TraceCursor::SeekType::Set); - return -cursor_up->Seek(-m_options.m_skip, TraceCursor::SeekType::End); - }; - - int initial_index = setUpCursor(); + m_exe_ctx.GetProcessRef().GetThreadList().FindThreadByIndexID( + thread_idx); + if (!thread_sp) + result.AppendErrorWithFormat("no thread with index: \"%s\"\n", arg); + return thread_sp; + } - auto dumper = std::make_unique<TraceInstructionDumper>( - std::move(cursor_up), initial_index, m_options.m_raw, - m_options.m_show_tsc); + bool DoExecute(Args &args, CommandReturnObject &result) override { + ThreadSP thread_sp = GetThread(args, result); + if (!thread_sp) + return false; - // This happens when the seek value was more than the number of available - // instructions. - if (std::abs(initial_index) < (int)m_options.m_skip) - dumper->SetNoMoreData(); + Stream &s = result.GetOutputStream(); + s.Printf("thread #%u: tid = %" PRIu64 "\n", thread_sp->GetIndexID(), + thread_sp->GetID()); - m_dumpers[thread_sp->GetID()] = std::move(dumper); + if (m_options.m_continue) { + if (!m_last_id) { + result.AppendMessage(" no more data\n"); + return true; + } + // 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; } - m_dumpers[thread_sp->GetID()]->DumpInstructions(s, m_options.m_count); + const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace(); + TraceInstructionDumper dumper(trace_sp->GetCursor(*thread_sp), s, + m_options.m_dumper_options); + m_last_id = dumper.DumpInstructions(m_options.m_count); return true; } CommandOptions m_options; - std::map<lldb::tid_t, std::unique_ptr<TraceInstructionDumper>> m_dumpers; + // Last traversed id used to continue a repeat command. None means + // that all the trace has been consumed. + llvm::Optional<lldb::user_id_t> m_last_id; }; // CommandObjectTraceDumpInfo |