forked from OSchip/llvm-project
Checking in files accidentally missed in later diffs of revision r310261
-- 2 files were missing in this commit which should have been there. These files were submitted initially for review and were reviewed. However, while updating the revision with newer diffs, I accidentally forgot to include them in newer diffs. So commiting now. llvm-svn: 310341
This commit is contained in:
parent
8ff723dcf1
commit
95bd95c075
|
@ -0,0 +1,583 @@
|
||||||
|
//===-- cli-wrapper-pt.cpp -------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
// CLI Wrapper of PTDecoder Tool to enable it to be used through LLDB's CLI. The
|
||||||
|
// wrapper provides a new command called processor-trace with 4 child
|
||||||
|
// subcommands as follows:
|
||||||
|
// processor-trace start
|
||||||
|
// processor-trace stop
|
||||||
|
// processor-trace show-trace-options
|
||||||
|
// processor-trace show-instr-log
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "PTDecoder.h"
|
||||||
|
#include "cli-wrapper-pt.h"
|
||||||
|
#include "lldb/API/SBCommandInterpreter.h"
|
||||||
|
#include "lldb/API/SBCommandReturnObject.h"
|
||||||
|
#include "lldb/API/SBDebugger.h"
|
||||||
|
#include "lldb/API/SBProcess.h"
|
||||||
|
#include "lldb/API/SBStream.h"
|
||||||
|
#include "lldb/API/SBStructuredData.h"
|
||||||
|
#include "lldb/API/SBTarget.h"
|
||||||
|
#include "lldb/API/SBThread.h"
|
||||||
|
|
||||||
|
static bool GetProcess(lldb::SBDebugger &debugger,
|
||||||
|
lldb::SBCommandReturnObject &result,
|
||||||
|
lldb::SBProcess &process) {
|
||||||
|
if (!debugger.IsValid()) {
|
||||||
|
result.Printf("error: invalid debugger\n");
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lldb::SBTarget target = debugger.GetSelectedTarget();
|
||||||
|
if (!target.IsValid()) {
|
||||||
|
result.Printf("error: invalid target inside debugger\n");
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
process = target.GetProcess();
|
||||||
|
if (!process.IsValid() ||
|
||||||
|
(process.GetState() == lldb::StateType::eStateDetached) ||
|
||||||
|
(process.GetState() == lldb::StateType::eStateExited) ||
|
||||||
|
(process.GetState() == lldb::StateType::eStateInvalid)) {
|
||||||
|
result.Printf("error: invalid process inside debugger's target\n");
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseCommandOption(char **command,
|
||||||
|
lldb::SBCommandReturnObject &result,
|
||||||
|
uint32_t &index, const std::string &arg,
|
||||||
|
uint32_t &parsed_result) {
|
||||||
|
char *endptr;
|
||||||
|
if (!command[++index]) {
|
||||||
|
result.Printf("error: option \"%s\" requires an argument\n", arg.c_str());
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
unsigned long output = strtoul(command[index], &endptr, 0);
|
||||||
|
if ((errno != 0) || (*endptr != '\0')) {
|
||||||
|
result.Printf("error: invalid value \"%s\" provided for option \"%s\"\n",
|
||||||
|
command[index], arg.c_str());
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (output > UINT32_MAX) {
|
||||||
|
result.Printf("error: value \"%s\" for option \"%s\" exceeds UINT32_MAX\n",
|
||||||
|
command[index], arg.c_str());
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
parsed_result = (uint32_t)output;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseCommandArgThread(char **command,
|
||||||
|
lldb::SBCommandReturnObject &result,
|
||||||
|
lldb::SBProcess &process, uint32_t &index,
|
||||||
|
lldb::tid_t &thread_id) {
|
||||||
|
char *endptr;
|
||||||
|
if (!strcmp(command[index], "all"))
|
||||||
|
thread_id = LLDB_INVALID_THREAD_ID;
|
||||||
|
else {
|
||||||
|
uint32_t thread_index_id;
|
||||||
|
errno = 0;
|
||||||
|
unsigned long output = strtoul(command[index], &endptr, 0);
|
||||||
|
if ((errno != 0) || (*endptr != '\0') || (output > UINT32_MAX)) {
|
||||||
|
result.Printf("error: invalid thread specification: \"%s\"\n",
|
||||||
|
command[index]);
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
thread_index_id = (uint32_t)output;
|
||||||
|
|
||||||
|
lldb::SBThread thread = process.GetThreadByIndexID(thread_index_id);
|
||||||
|
if (!thread.IsValid()) {
|
||||||
|
result.Printf(
|
||||||
|
"error: process has no thread with thread specification: \"%s\"\n",
|
||||||
|
command[index]);
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
thread_id = thread.GetThreadID();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProcessorTraceStart : public lldb::SBCommandPluginInterface {
|
||||||
|
public:
|
||||||
|
ProcessorTraceStart(std::shared_ptr<ptdecoder::PTDecoder> &pt_decoder)
|
||||||
|
: SBCommandPluginInterface(), pt_decoder_sp(pt_decoder) {}
|
||||||
|
|
||||||
|
~ProcessorTraceStart() {}
|
||||||
|
|
||||||
|
virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
|
||||||
|
lldb::SBCommandReturnObject &result) {
|
||||||
|
lldb::SBProcess process;
|
||||||
|
lldb::SBThread thread;
|
||||||
|
if (!GetProcess(debugger, result, process))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Default initialize API's arguments
|
||||||
|
lldb::SBTraceOptions lldb_SBTraceOptions;
|
||||||
|
uint32_t trace_buffer_size = m_default_trace_buff_size;
|
||||||
|
lldb::tid_t thread_id;
|
||||||
|
|
||||||
|
// Parse Command line options
|
||||||
|
bool thread_argument_provided = false;
|
||||||
|
if (command) {
|
||||||
|
for (uint32_t i = 0; command[i]; i++) {
|
||||||
|
if (!strcmp(command[i], "-b")) {
|
||||||
|
if (!ParseCommandOption(command, result, i, "-b", trace_buffer_size))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
thread_argument_provided = true;
|
||||||
|
if (!ParseCommandArgThread(command, result, process, i, thread_id))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thread_argument_provided) {
|
||||||
|
thread = process.GetSelectedThread();
|
||||||
|
if (!thread.IsValid()) {
|
||||||
|
result.Printf("error: invalid current selected thread\n");
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
thread_id = thread.GetThreadID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trace_buffer_size > m_max_trace_buff_size)
|
||||||
|
trace_buffer_size = m_max_trace_buff_size;
|
||||||
|
|
||||||
|
// Set API's arguments with parsed values
|
||||||
|
lldb_SBTraceOptions.setType(lldb::TraceType::eTraceTypeProcessorTrace);
|
||||||
|
lldb_SBTraceOptions.setTraceBufferSize(trace_buffer_size);
|
||||||
|
lldb_SBTraceOptions.setMetaDataBufferSize(0);
|
||||||
|
lldb_SBTraceOptions.setThreadID(thread_id);
|
||||||
|
lldb::SBStream sb_stream;
|
||||||
|
sb_stream.Printf("{\"trace-tech\":\"intel-pt\"}");
|
||||||
|
lldb::SBStructuredData custom_params;
|
||||||
|
lldb::SBError error = custom_params.SetFromJSON(sb_stream);
|
||||||
|
if (!error.Success()) {
|
||||||
|
result.Printf("error: %s\n", error.GetCString());
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lldb_SBTraceOptions.setTraceParams(custom_params);
|
||||||
|
|
||||||
|
// Start trace
|
||||||
|
pt_decoder_sp->StartProcessorTrace(process, lldb_SBTraceOptions, error);
|
||||||
|
if (!error.Success()) {
|
||||||
|
result.Printf("error: %s\n", error.GetCString());
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<ptdecoder::PTDecoder> pt_decoder_sp;
|
||||||
|
const uint32_t m_max_trace_buff_size = 0x3fff;
|
||||||
|
const uint32_t m_default_trace_buff_size = 4096;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProcessorTraceInfo : public lldb::SBCommandPluginInterface {
|
||||||
|
public:
|
||||||
|
ProcessorTraceInfo(std::shared_ptr<ptdecoder::PTDecoder> &pt_decoder)
|
||||||
|
: SBCommandPluginInterface(), pt_decoder_sp(pt_decoder) {}
|
||||||
|
|
||||||
|
~ProcessorTraceInfo() {}
|
||||||
|
|
||||||
|
virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
|
||||||
|
lldb::SBCommandReturnObject &result) {
|
||||||
|
lldb::SBProcess process;
|
||||||
|
lldb::SBThread thread;
|
||||||
|
if (!GetProcess(debugger, result, process))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lldb::tid_t thread_id;
|
||||||
|
|
||||||
|
// Parse command line options
|
||||||
|
bool thread_argument_provided = false;
|
||||||
|
if (command) {
|
||||||
|
for (uint32_t i = 0; command[i]; i++) {
|
||||||
|
thread_argument_provided = true;
|
||||||
|
if (!ParseCommandArgThread(command, result, process, i, thread_id))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thread_argument_provided) {
|
||||||
|
thread = process.GetSelectedThread();
|
||||||
|
if (!thread.IsValid()) {
|
||||||
|
result.Printf("error: invalid current selected thread\n");
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
thread_id = thread.GetThreadID();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t loop_count = 1;
|
||||||
|
bool entire_process_tracing = false;
|
||||||
|
if (thread_id == LLDB_INVALID_THREAD_ID) {
|
||||||
|
entire_process_tracing = true;
|
||||||
|
loop_count = process.GetNumThreads();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get trace information
|
||||||
|
lldb::SBError error;
|
||||||
|
lldb::SBCommandReturnObject res;
|
||||||
|
for (size_t i = 0; i < loop_count; i++) {
|
||||||
|
error.Clear();
|
||||||
|
res.Clear();
|
||||||
|
|
||||||
|
if (entire_process_tracing)
|
||||||
|
thread = process.GetThreadAtIndex(i);
|
||||||
|
else
|
||||||
|
thread = process.GetThreadByID(thread_id);
|
||||||
|
thread_id = thread.GetThreadID();
|
||||||
|
|
||||||
|
ptdecoder::PTTraceOptions options;
|
||||||
|
pt_decoder_sp->GetProcessorTraceInfo(process, thread_id, options, error);
|
||||||
|
if (!error.Success()) {
|
||||||
|
res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 ", error: %s",
|
||||||
|
thread.GetIndexID(), thread_id, error.GetCString());
|
||||||
|
result.AppendMessage(res.GetOutput());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lldb::SBStructuredData data = options.GetTraceParams(error);
|
||||||
|
if (!error.Success()) {
|
||||||
|
res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 ", error: %s",
|
||||||
|
thread.GetIndexID(), thread_id, error.GetCString());
|
||||||
|
result.AppendMessage(res.GetOutput());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lldb::SBStream s;
|
||||||
|
error = data.GetAsJSON(s);
|
||||||
|
if (!error.Success()) {
|
||||||
|
res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 ", error: %s",
|
||||||
|
thread.GetIndexID(), thread_id, error.GetCString());
|
||||||
|
result.AppendMessage(res.GetOutput());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Printf("thread #%" PRIu32 ": tid=%" PRIu64
|
||||||
|
", trace buffer size=%" PRIu64 ", meta buffer size=%" PRIu64
|
||||||
|
", trace type=%" PRIu32 ", custom trace params=%s",
|
||||||
|
thread.GetIndexID(), thread_id, options.GetTraceBufferSize(),
|
||||||
|
options.GetMetaDataBufferSize(), options.GetType(),
|
||||||
|
s.GetData());
|
||||||
|
result.AppendMessage(res.GetOutput());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<ptdecoder::PTDecoder> pt_decoder_sp;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProcessorTraceShowInstrLog : public lldb::SBCommandPluginInterface {
|
||||||
|
public:
|
||||||
|
ProcessorTraceShowInstrLog(std::shared_ptr<ptdecoder::PTDecoder> &pt_decoder)
|
||||||
|
: SBCommandPluginInterface(), pt_decoder_sp(pt_decoder) {}
|
||||||
|
|
||||||
|
~ProcessorTraceShowInstrLog() {}
|
||||||
|
|
||||||
|
virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
|
||||||
|
lldb::SBCommandReturnObject &result) {
|
||||||
|
lldb::SBProcess process;
|
||||||
|
lldb::SBThread thread;
|
||||||
|
if (!GetProcess(debugger, result, process))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Default initialize API's arguments
|
||||||
|
uint32_t offset;
|
||||||
|
bool offset_provided = false;
|
||||||
|
uint32_t count = m_default_count;
|
||||||
|
lldb::tid_t thread_id;
|
||||||
|
|
||||||
|
// Parse command line options
|
||||||
|
bool thread_argument_provided = false;
|
||||||
|
if (command) {
|
||||||
|
for (uint32_t i = 0; command[i]; i++) {
|
||||||
|
if (!strcmp(command[i], "-o")) {
|
||||||
|
if (!ParseCommandOption(command, result, i, "-o", offset))
|
||||||
|
return false;
|
||||||
|
offset_provided = true;
|
||||||
|
} else if (!strcmp(command[i], "-c")) {
|
||||||
|
if (!ParseCommandOption(command, result, i, "-c", count))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
thread_argument_provided = true;
|
||||||
|
if (!ParseCommandArgThread(command, result, process, i, thread_id))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thread_argument_provided) {
|
||||||
|
thread = process.GetSelectedThread();
|
||||||
|
if (!thread.IsValid()) {
|
||||||
|
result.Printf("error: invalid current selected thread\n");
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
thread_id = thread.GetThreadID();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t loop_count = 1;
|
||||||
|
bool entire_process_tracing = false;
|
||||||
|
if (thread_id == LLDB_INVALID_THREAD_ID) {
|
||||||
|
entire_process_tracing = true;
|
||||||
|
loop_count = process.GetNumThreads();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get instruction log and disassemble it
|
||||||
|
lldb::SBError error;
|
||||||
|
lldb::SBCommandReturnObject res;
|
||||||
|
for (size_t i = 0; i < loop_count; i++) {
|
||||||
|
error.Clear();
|
||||||
|
res.Clear();
|
||||||
|
|
||||||
|
if (entire_process_tracing)
|
||||||
|
thread = process.GetThreadAtIndex(i);
|
||||||
|
else
|
||||||
|
thread = process.GetThreadByID(thread_id);
|
||||||
|
thread_id = thread.GetThreadID();
|
||||||
|
|
||||||
|
// If offset is not provided then calculate a default offset (to display
|
||||||
|
// last 'count' number of instructions)
|
||||||
|
if (!offset_provided)
|
||||||
|
offset = count - 1;
|
||||||
|
|
||||||
|
// Get the instruction log
|
||||||
|
ptdecoder::PTInstructionList insn_list;
|
||||||
|
pt_decoder_sp->GetInstructionLogAtOffset(process, thread_id, offset,
|
||||||
|
count, insn_list, error);
|
||||||
|
if (!error.Success()) {
|
||||||
|
res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 ", error: %s",
|
||||||
|
thread.GetIndexID(), thread_id, error.GetCString());
|
||||||
|
result.AppendMessage(res.GetOutput());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disassemble the instruction log
|
||||||
|
std::string disassembler_command("dis -c 1 -s ");
|
||||||
|
res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 "\n", thread.GetIndexID(),
|
||||||
|
thread_id);
|
||||||
|
lldb::SBCommandInterpreter sb_cmnd_interpreter(
|
||||||
|
debugger.GetCommandInterpreter());
|
||||||
|
lldb::SBCommandReturnObject result_obj;
|
||||||
|
for (size_t i = 0; i < insn_list.GetSize(); i++) {
|
||||||
|
ptdecoder::PTInstruction insn = insn_list.GetInstructionAtIndex(i);
|
||||||
|
uint64_t addr = insn.GetInsnAddress();
|
||||||
|
std::string error = insn.GetError();
|
||||||
|
if (!error.empty()) {
|
||||||
|
res.AppendMessage(error.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result_obj.Clear();
|
||||||
|
std::string complete_disassembler_command =
|
||||||
|
disassembler_command + std::to_string(addr);
|
||||||
|
sb_cmnd_interpreter.HandleCommand(complete_disassembler_command.c_str(),
|
||||||
|
result_obj, false);
|
||||||
|
std::string result_str(result_obj.GetOutput());
|
||||||
|
if (result_str.empty()) {
|
||||||
|
lldb::SBCommandReturnObject output;
|
||||||
|
output.Printf(" Disassembly not found for address: %" PRIu64, addr);
|
||||||
|
res.AppendMessage(output.GetOutput());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LLDB's disassemble command displays assembly instructions along with
|
||||||
|
// the names of the functions they belong to. Parse this result to
|
||||||
|
// display only the assembly instructions and not the function names
|
||||||
|
// in an instruction log
|
||||||
|
std::size_t first_new_line_index = result_str.find_first_of('\n');
|
||||||
|
std::size_t last_new_line_index = result_str.find_last_of('\n');
|
||||||
|
if (first_new_line_index != last_new_line_index)
|
||||||
|
res.AppendMessage((result_str.substr(first_new_line_index + 1,
|
||||||
|
last_new_line_index -
|
||||||
|
first_new_line_index - 1))
|
||||||
|
.c_str());
|
||||||
|
else
|
||||||
|
res.AppendMessage(
|
||||||
|
(result_str.substr(0, result_str.length() - 1)).c_str());
|
||||||
|
}
|
||||||
|
result.AppendMessage(res.GetOutput());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<ptdecoder::PTDecoder> pt_decoder_sp;
|
||||||
|
const uint32_t m_default_count = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProcessorTraceStop : public lldb::SBCommandPluginInterface {
|
||||||
|
public:
|
||||||
|
ProcessorTraceStop(std::shared_ptr<ptdecoder::PTDecoder> &pt_decoder)
|
||||||
|
: SBCommandPluginInterface(), pt_decoder_sp(pt_decoder) {}
|
||||||
|
|
||||||
|
~ProcessorTraceStop() {}
|
||||||
|
|
||||||
|
virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
|
||||||
|
lldb::SBCommandReturnObject &result) {
|
||||||
|
lldb::SBProcess process;
|
||||||
|
lldb::SBThread thread;
|
||||||
|
if (!GetProcess(debugger, result, process))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lldb::tid_t thread_id;
|
||||||
|
|
||||||
|
// Parse command line options
|
||||||
|
bool thread_argument_provided = false;
|
||||||
|
if (command) {
|
||||||
|
for (uint32_t i = 0; command[i]; i++) {
|
||||||
|
thread_argument_provided = true;
|
||||||
|
if (!ParseCommandArgThread(command, result, process, i, thread_id))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thread_argument_provided) {
|
||||||
|
thread = process.GetSelectedThread();
|
||||||
|
if (!thread.IsValid()) {
|
||||||
|
result.Printf("error: invalid current selected thread\n");
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
thread_id = thread.GetThreadID();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop trace
|
||||||
|
lldb::SBError error;
|
||||||
|
pt_decoder_sp->StopProcessorTrace(process, error, thread_id);
|
||||||
|
if (!error.Success()) {
|
||||||
|
result.Printf("error: %s\n", error.GetCString());
|
||||||
|
result.SetStatus(lldb::eReturnStatusFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<ptdecoder::PTDecoder> pt_decoder_sp;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool PTPluginInitialize(lldb::SBDebugger &debugger) {
|
||||||
|
lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
|
||||||
|
lldb::SBCommand proc_trace = interpreter.AddMultiwordCommand(
|
||||||
|
"processor-trace", "Intel(R) Processor Trace for thread/process");
|
||||||
|
|
||||||
|
std::shared_ptr<ptdecoder::PTDecoder> PTDecoderSP(
|
||||||
|
new ptdecoder::PTDecoder(debugger));
|
||||||
|
|
||||||
|
lldb::SBCommandPluginInterface *proc_trace_start =
|
||||||
|
new ProcessorTraceStart(PTDecoderSP);
|
||||||
|
const char *help_proc_trace_start = "start Intel(R) Processor Trace on a "
|
||||||
|
"specific thread or on the whole process";
|
||||||
|
const char *syntax_proc_trace_start =
|
||||||
|
"processor-trace start <cmd-options>\n\n"
|
||||||
|
"\rcmd-options Usage:\n"
|
||||||
|
"\r processor-trace start [-b <buffer-size>] [<thread-index>]\n\n"
|
||||||
|
"\t\b-b <buffer-size>\n"
|
||||||
|
"\t size of the trace buffer to store the trace data. If not "
|
||||||
|
"specified then a default value will be taken\n\n"
|
||||||
|
"\t\b<thread-index>\n"
|
||||||
|
"\t thread index of the thread. If no threads are specified, "
|
||||||
|
"currently selected thread is taken.\n"
|
||||||
|
"\t Use the thread-index 'all' to start tracing the whole process\n";
|
||||||
|
proc_trace.AddCommand("start", proc_trace_start, help_proc_trace_start,
|
||||||
|
syntax_proc_trace_start);
|
||||||
|
|
||||||
|
lldb::SBCommandPluginInterface *proc_trace_stop =
|
||||||
|
new ProcessorTraceStop(PTDecoderSP);
|
||||||
|
const char *help_proc_trace_stop =
|
||||||
|
"stop Intel(R) Processor Trace on a specific thread or on whole process";
|
||||||
|
const char *syntax_proc_trace_stop =
|
||||||
|
"processor-trace stop <cmd-options>\n\n"
|
||||||
|
"\rcmd-options Usage:\n"
|
||||||
|
"\r processor-trace stop [<thread-index>]\n\n"
|
||||||
|
"\t\b<thread-index>\n"
|
||||||
|
"\t thread index of the thread. If no threads are specified, "
|
||||||
|
"currently selected thread is taken.\n"
|
||||||
|
"\t Use the thread-index 'all' to stop tracing the whole process\n";
|
||||||
|
proc_trace.AddCommand("stop", proc_trace_stop, help_proc_trace_stop,
|
||||||
|
syntax_proc_trace_stop);
|
||||||
|
|
||||||
|
lldb::SBCommandPluginInterface *proc_trace_show_instr_log =
|
||||||
|
new ProcessorTraceShowInstrLog(PTDecoderSP);
|
||||||
|
const char *help_proc_trace_show_instr_log =
|
||||||
|
"display a log of assembly instructions executed for a specific thread "
|
||||||
|
"or for the whole process.\n"
|
||||||
|
"The length of the log to be displayed and the offset in the whole "
|
||||||
|
"instruction log from where the log needs to be displayed can also be "
|
||||||
|
"provided. The offset is counted from the end of this whole "
|
||||||
|
"instruction log which means the last executed instruction is at offset "
|
||||||
|
"0 (zero)";
|
||||||
|
const char *syntax_proc_trace_show_instr_log =
|
||||||
|
"processor-trace show-instr-log <cmd-options>\n\n"
|
||||||
|
"\rcmd-options Usage:\n"
|
||||||
|
"\r processor-trace show-instr-log [-o <offset>] [-c <count>] "
|
||||||
|
"[<thread-index>]\n\n"
|
||||||
|
"\t\b-o <offset>\n"
|
||||||
|
"\t offset in the whole instruction log from where the log will be "
|
||||||
|
"displayed. If not specified then a default value will be taken\n\n"
|
||||||
|
"\t\b-c <count>\n"
|
||||||
|
"\t number of instructions to be displayed. If not specified then a "
|
||||||
|
"default value will be taken\n\n"
|
||||||
|
"\t\b<thread-index>\n"
|
||||||
|
"\t thread index of the thread. If no threads are specified, "
|
||||||
|
"currently selected thread is taken.\n"
|
||||||
|
"\t Use the thread-index 'all' to show instruction log for all the "
|
||||||
|
"threads of the process\n";
|
||||||
|
proc_trace.AddCommand("show-instr-log", proc_trace_show_instr_log,
|
||||||
|
help_proc_trace_show_instr_log,
|
||||||
|
syntax_proc_trace_show_instr_log);
|
||||||
|
|
||||||
|
lldb::SBCommandPluginInterface *proc_trace_options =
|
||||||
|
new ProcessorTraceInfo(PTDecoderSP);
|
||||||
|
const char *help_proc_trace_show_options =
|
||||||
|
"display all the information regarding Intel(R) Processor Trace for a "
|
||||||
|
"specific thread or for the whole process.\n"
|
||||||
|
"The information contains trace buffer size and configuration options"
|
||||||
|
" of Intel(R) Processor Trace.";
|
||||||
|
const char *syntax_proc_trace_show_options =
|
||||||
|
"processor-trace show-options <cmd-options>\n\n"
|
||||||
|
"\rcmd-options Usage:\n"
|
||||||
|
"\r processor-trace show-options [<thread-index>]\n\n"
|
||||||
|
"\t\b<thread-index>\n"
|
||||||
|
"\t thread index of the thread. If no threads are specified, "
|
||||||
|
"currently selected thread is taken.\n"
|
||||||
|
"\t Use the thread-index 'all' to display information for all threads "
|
||||||
|
"of the process\n";
|
||||||
|
proc_trace.AddCommand("show-trace-options", proc_trace_options,
|
||||||
|
help_proc_trace_show_options,
|
||||||
|
syntax_proc_trace_show_options);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
//===-- cli-wrapper-pt.h----------------------------------*- C++ -*-==========//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
// CLI Wrapper of PTDecoder Tool to enable it to be used through LLDB's CLI.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "lldb/API/SBDebugger.h"
|
||||||
|
|
||||||
|
bool PTPluginInitialize(lldb::SBDebugger &debugger);
|
Loading…
Reference in New Issue