From 95bd95c075067d904eaaad9c29a95afd16676952 Mon Sep 17 00:00:00 2001 From: Abhishek Aggarwal Date: Tue, 8 Aug 2017 09:25:50 +0000 Subject: [PATCH] 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 --- .../intel-features/intel-pt/cli-wrapper-pt.cpp | 583 +++++++++++++++++++++ .../tools/intel-features/intel-pt/cli-wrapper-pt.h | 13 + 2 files changed, 596 insertions(+) create mode 100644 lldb/tools/intel-features/intel-pt/cli-wrapper-pt.cpp create mode 100644 lldb/tools/intel-features/intel-pt/cli-wrapper-pt.h diff --git a/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.cpp b/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.cpp new file mode 100644 index 0000000..1fa236c --- /dev/null +++ b/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.cpp @@ -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 +#include +#include +#include +#include + +#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 &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 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 &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 pt_decoder_sp; +}; + +class ProcessorTraceShowInstrLog : public lldb::SBCommandPluginInterface { +public: + ProcessorTraceShowInstrLog(std::shared_ptr &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 pt_decoder_sp; + const uint32_t m_default_count = 10; +}; + +class ProcessorTraceStop : public lldb::SBCommandPluginInterface { +public: + ProcessorTraceStop(std::shared_ptr &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 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 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 \n\n" + "\rcmd-options Usage:\n" + "\r processor-trace start [-b ] []\n\n" + "\t\b-b \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\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 \n\n" + "\rcmd-options Usage:\n" + "\r processor-trace stop []\n\n" + "\t\b\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 \n\n" + "\rcmd-options Usage:\n" + "\r processor-trace show-instr-log [-o ] [-c ] " + "[]\n\n" + "\t\b-o \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 \n" + "\t number of instructions to be displayed. If not specified then a " + "default value will be taken\n\n" + "\t\b\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 \n\n" + "\rcmd-options Usage:\n" + "\r processor-trace show-options []\n\n" + "\t\b\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; +} diff --git a/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.h b/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.h new file mode 100644 index 0000000..e2a0ee4 --- /dev/null +++ b/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.h @@ -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); -- 2.7.4