mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
[lldb][trace] Add a basic function call dumpdump [1] - Add the command scaffolding
The command is thread trace dump function-calls and as minimum will require printing to a file in json and non-json format I added a test Differential Revision: https://reviews.llvm.org/D135521
This commit is contained in:
@@ -2090,6 +2090,113 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static ThreadSP GetSingleThreadFromArgs(ExecutionContext &exe_ctx, Args &args,
|
||||
CommandReturnObject &result) {
|
||||
if (args.GetArgumentCount() == 0)
|
||||
return exe_ctx.GetThreadSP();
|
||||
|
||||
const char *arg = args.GetArgumentAtIndex(0);
|
||||
uint32_t thread_idx;
|
||||
|
||||
if (!llvm::to_integer(arg, thread_idx)) {
|
||||
result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", arg);
|
||||
return nullptr;
|
||||
}
|
||||
ThreadSP thread_sp =
|
||||
exe_ctx.GetProcessRef().GetThreadList().FindThreadByIndexID(thread_idx);
|
||||
if (!thread_sp)
|
||||
result.AppendErrorWithFormat("no thread with index: \"%s\"\n", arg);
|
||||
return thread_sp;
|
||||
}
|
||||
|
||||
// CommandObjectTraceDumpFunctionCalls
|
||||
#define LLDB_OPTIONS_thread_trace_dump_function_calls
|
||||
#include "CommandOptions.inc"
|
||||
|
||||
class CommandObjectTraceDumpFunctionCalls : public CommandObjectParsed {
|
||||
public:
|
||||
class CommandOptions : public Options {
|
||||
public:
|
||||
CommandOptions() { OptionParsingStarting(nullptr); }
|
||||
|
||||
~CommandOptions() override = default;
|
||||
|
||||
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
||||
ExecutionContext *execution_context) override {
|
||||
Status error;
|
||||
const int short_option = m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option) {
|
||||
case 'j': {
|
||||
m_json = true;
|
||||
break;
|
||||
}
|
||||
case 'J': {
|
||||
m_pretty_json = true;
|
||||
break;
|
||||
}
|
||||
case 'F': {
|
||||
m_output_file.emplace(option_arg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Unimplemented option");
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_json = false;
|
||||
m_pretty_json = false;
|
||||
m_output_file = llvm::None;
|
||||
}
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
return llvm::makeArrayRef(g_thread_trace_dump_function_calls_options);
|
||||
}
|
||||
|
||||
static const size_t kDefaultCount = 20;
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
bool m_json;
|
||||
bool m_pretty_json;
|
||||
llvm::Optional<FileSpec> m_output_file;
|
||||
};
|
||||
|
||||
CommandObjectTraceDumpFunctionCalls(CommandInterpreter &interpreter)
|
||||
: CommandObjectParsed(
|
||||
interpreter, "thread trace dump function-calls",
|
||||
"Dump the traced function-calls for one thread. If no "
|
||||
"thread is specified, the current thread is used.",
|
||||
nullptr,
|
||||
eCommandRequiresProcess | eCommandRequiresThread |
|
||||
eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
|
||||
eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {
|
||||
CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatOptional};
|
||||
m_arguments.push_back({thread_arg});
|
||||
}
|
||||
|
||||
~CommandObjectTraceDumpFunctionCalls() override = default;
|
||||
|
||||
Options *GetOptions() override { return &m_options; }
|
||||
|
||||
protected:
|
||||
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
||||
ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
|
||||
if (!thread_sp) {
|
||||
result.AppendError("invalid thread\n");
|
||||
return false;
|
||||
}
|
||||
result.AppendMessageWithFormatv(
|
||||
"json = {0}, pretty_json = {1}, file = {2}, thread = {3}",
|
||||
m_options.m_json, m_options.m_pretty_json, !!m_options.m_output_file,
|
||||
thread_sp->GetID());
|
||||
return true;
|
||||
}
|
||||
|
||||
CommandOptions m_options;
|
||||
};
|
||||
|
||||
// CommandObjectTraceDumpInstructions
|
||||
#define LLDB_OPTIONS_thread_trace_dump_instructions
|
||||
#include "CommandOptions.inc"
|
||||
@@ -2238,28 +2345,8 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
ThreadSP GetThread(Args &args, CommandReturnObject &result) {
|
||||
if (args.GetArgumentCount() == 0)
|
||||
return m_exe_ctx.GetThreadSP();
|
||||
|
||||
const char *arg = args.GetArgumentAtIndex(0);
|
||||
uint32_t thread_idx;
|
||||
|
||||
if (!llvm::to_integer(arg, thread_idx)) {
|
||||
result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
|
||||
arg);
|
||||
return nullptr;
|
||||
}
|
||||
ThreadSP thread_sp =
|
||||
m_exe_ctx.GetProcessRef().GetThreadList().FindThreadByIndexID(
|
||||
thread_idx);
|
||||
if (!thread_sp)
|
||||
result.AppendErrorWithFormat("no thread with index: \"%s\"\n", arg);
|
||||
return thread_sp;
|
||||
}
|
||||
|
||||
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
||||
ThreadSP thread_sp = GetThread(args, result);
|
||||
ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
|
||||
if (!thread_sp) {
|
||||
result.AppendError("invalid thread\n");
|
||||
return false;
|
||||
@@ -2401,6 +2488,9 @@ public:
|
||||
LoadSubCommand(
|
||||
"instructions",
|
||||
CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter)));
|
||||
LoadSubCommand(
|
||||
"function-calls",
|
||||
CommandObjectSP(new CommandObjectTraceDumpFunctionCalls(interpreter)));
|
||||
LoadSubCommand(
|
||||
"info", CommandObjectSP(new CommandObjectTraceDumpInfo(interpreter)));
|
||||
}
|
||||
|
||||
@@ -1093,6 +1093,19 @@ let Command = "thread plan list" in {
|
||||
Desc<"Display thread plans for unreported threads">;
|
||||
}
|
||||
|
||||
let Command = "thread trace dump function calls" in {
|
||||
def thread_trace_dump_function_calls_file : Option<"file", "F">, Group<1>,
|
||||
Arg<"Filename">,
|
||||
Desc<"Dump the function calls to a file instead of the standard output.">;
|
||||
def thread_trace_dump_function_calls_json: Option<"json", "j">,
|
||||
Group<1>,
|
||||
Desc<"Dump in simple JSON format.">;
|
||||
def thread_trace_dump_function_calls_pretty_json: Option<"pretty-json", "J">,
|
||||
Group<1>,
|
||||
Desc<"Dump in JSON format but pretty printing the output for easier "
|
||||
"readability.">;
|
||||
}
|
||||
|
||||
let Command = "thread trace dump instructions" in {
|
||||
def thread_trace_dump_instructions_forwards: Option<"forwards", "f">,
|
||||
Group<1>,
|
||||
|
||||
17
lldb/test/API/commands/trace/TestTraceDumpFunctionCalls.py
Normal file
17
lldb/test/API/commands/trace/TestTraceDumpFunctionCalls.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from intelpt_testcase import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test.decorators import *
|
||||
|
||||
class TestTraceDumpInfo(TraceIntelPTTestCaseBase):
|
||||
def testDumpFunctionCalls(self):
|
||||
self.expect("trace load -v " +
|
||||
os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"))
|
||||
|
||||
self.expect("thread trace dump function-calls 2",
|
||||
error=True, substrs=['error: no thread with index: "2"'])
|
||||
|
||||
self.expect("thread trace dump function-calls 1 -j",
|
||||
substrs=['json = true, pretty_json = false, file = false, thread = 3842849'])
|
||||
|
||||
self.expect("thread trace dump function-calls 1 -F /tmp -J",
|
||||
substrs=['false, pretty_json = true, file = true, thread = 3842849'])
|
||||
Reference in New Issue
Block a user