diff --git a/lldb/tools/intel-features/CMakeLists.txt b/lldb/tools/intel-features/CMakeLists.txt --- a/lldb/tools/intel-features/CMakeLists.txt +++ b/lldb/tools/intel-features/CMakeLists.txt @@ -1,9 +1,8 @@ # Flags to control each individual feature option(LLDB_BUILD_INTEL_MPX "Enable Building of Intel(R) Memory Protection Extensions" ON) -option(LLDB_BUILD_INTEL_PT "Enable Building of Intel(R) Processor Trace Tool" OFF) # Return if all features are OFF -if (NOT LLDB_BUILD_INTEL_MPX AND NOT LLDB_BUILD_INTEL_PT) +if (NOT LLDB_BUILD_INTEL_MPX) return() endif() @@ -16,34 +15,6 @@ SET (CLI_WRAPPER_PREPROCESSORS "${CLI_WRAPPER_PREPROCESSORS} -DBUILD_INTEL_MPX") endif() -if (LLDB_BUILD_INTEL_PT) - add_subdirectory(intel-pt) - LIST (APPEND FEATURE_LIBS ${FEATURE_LIBS} lldbIntelPT) - SET (CLI_WRAPPER_PREPROCESSORS "${CLI_WRAPPER_PREPROCESSORS} -DBUILD_INTEL_PT") -endif() - -# Add python wrapper if python not disabled -if (LLDB_ENABLE_PYTHON AND LLDB_BUILD_INTEL_PT) - list(APPEND FEATURE_LIBS ${FEATURE_LIBS} ${Python3_LIBRARIES}) - set(LLDB_INTEL_FEATURES_PYTHON_WRAP - ${LLDB_BINARY_DIR}/tools/intel-features/scripts/IntelFeaturesPythonWrap.cpp) - set_source_files_properties(${LLDB_INTEL_FEATURES_PYTHON_WRAP} - PROPERTIES GENERATED 1) - - if (CLANG_CL) - set_source_files_properties(${LLDB_INTEL_FEATURES_PYTHON_WRAP} - PROPERTIES COMPILE_FLAGS -Wno-unused-function) - endif() - - if (LLVM_COMPILER_IS_GCC_COMPATIBLE AND - NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") - set_property(SOURCE ${LLDB_INTEL_FEATURES_PYTHON_WRAP} - APPEND_STRING PROPERTY COMPILE_FLAGS - " -Wno-sequence-point -Wno-cast-qual") - endif () - add_subdirectory(scripts) -endif() - if (NOT CLI_WRAPPER_PREPROCESSORS) return() endif() @@ -53,16 +24,10 @@ add_lldb_library(lldbIntelFeatures SHARED cli-wrapper.cpp - ${LLDB_INTEL_FEATURES_PYTHON_WRAP} LINK_LIBS ${FEATURE_LIBS} ) -# Add link dependencies for python wrapper -if (LLDB_ENABLE_PYTHON AND LLDB_BUILD_INTEL_PT) - add_dependencies(lldbIntelFeatures intel-features-swig_wrapper) -endif() - install(TARGETS lldbIntelFeatures LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}) diff --git a/lldb/tools/intel-features/README.txt b/lldb/tools/intel-features/README.txt --- a/lldb/tools/intel-features/README.txt +++ b/lldb/tools/intel-features/README.txt @@ -25,8 +25,8 @@ commands. For each hardware feature, separate cli commands have been developed that are -provided by wrappers (cli-wrapper-pt.cpp and cli-wrapper-mpxtable.cpp) residing -in feature specific folders ("intel-pt" and "intel-mpx" respectively). +provided by wrappers (e.g. cli-wrapper-mpxtable.cpp) residing +in feature specific folders. For details regarding cli commands of each feature, please refer to these feature specific wrappers. @@ -44,11 +44,6 @@ feature while building lldbIntelFeatures library. This is done by flags described below: - - LLDB_BUILD_INTEL_PT - The flag enables building of Intel(R) Processor Trace - feature (inside intel-pt folder). This flag defaults to "OFF" meaning the - feature is excluded while building lldbIntelFeatures library. Set it to "ON" - in order to include it. - - LLDB_BUILD_INTEL_MPX - Enables building Intel(R) Memory Protection Extensions feature (inside intel-mpx folder). This flag defaults to "ON" meaning the feature is excluded while building lldbIntelFeatures library. diff --git a/lldb/tools/intel-features/cli-wrapper.cpp b/lldb/tools/intel-features/cli-wrapper.cpp --- a/lldb/tools/intel-features/cli-wrapper.cpp +++ b/lldb/tools/intel-features/cli-wrapper.cpp @@ -18,10 +18,6 @@ #include "intel-mpx/cli-wrapper-mpxtable.h" #endif -#ifdef BUILD_INTEL_PT -#include "intel-pt/cli-wrapper-pt.h" -#endif - #include "lldb/API/SBDebugger.h" namespace lldb { @@ -30,10 +26,6 @@ bool lldb::PluginInitialize(lldb::SBDebugger debugger) { -#ifdef BUILD_INTEL_PT - PTPluginInitialize(debugger); -#endif - #ifdef BUILD_INTEL_MPX MPXPluginInitialize(debugger); #endif diff --git a/lldb/tools/intel-features/intel-pt/CMakeLists.txt b/lldb/tools/intel-features/intel-pt/CMakeLists.txt deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -if (NOT LIBIPT_INCLUDE_PATH) - message (FATAL_ERROR "libipt include path not provided") -endif() - -if (NOT EXISTS "${LIBIPT_INCLUDE_PATH}") - message (FATAL_ERROR "invalid libipt include path provided") -endif() -include_directories(${LIBIPT_INCLUDE_PATH}) - -if (NOT LIBIPT_LIBRARY_PATH) - find_library(LIBIPT_LIBRARY ipt) -else() - if (NOT EXISTS "${LIBIPT_LIBRARY_PATH}") - message (FATAL_ERROR "invalid libipt library path provided") - endif() - find_library(LIBIPT_LIBRARY ipt PATHS ${LIBIPT_LIBRARY_PATH}) -endif() - -if (NOT LIBIPT_LIBRARY) - message (FATAL_ERROR "libipt library not found") -endif() - -add_lldb_library(lldbIntelPT - PTDecoder.cpp - Decoder.cpp - cli-wrapper-pt.cpp - - LINK_LIBS - ${LIBIPT_LIBRARY} - liblldb - ) diff --git a/lldb/tools/intel-features/intel-pt/Decoder.h b/lldb/tools/intel-features/intel-pt/Decoder.h deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/Decoder.h +++ /dev/null @@ -1,325 +0,0 @@ -//===-- Decoder.h -----------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef Decoder_h_ -#define Decoder_h_ - -// C/C++ Includes -#include -#include -#include -#include - -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBProcess.h" -#include "lldb/API/SBStream.h" -#include "lldb/API/SBStructuredData.h" -#include "lldb/API/SBTarget.h" -#include "lldb/API/SBTrace.h" -#include "lldb/API/SBTraceOptions.h" -#include "lldb/lldb-enumerations.h" -#include "lldb/lldb-types.h" - -#include "intel-pt.h" - -namespace ptdecoder_private { -/// \class Instruction -/// Represents an assembly instruction containing raw -/// instruction bytes, instruction address along with information -/// regarding execution flow context and Intel(R) Processor Trace -/// context. -class Instruction { -public: - Instruction() : ip(0), data(), error(), iclass(ptic_error), speculative(0) {} - - Instruction(const Instruction &insn) = default; - - Instruction(const struct pt_insn &insn) - : ip(insn.ip), data(), error(insn.size == 0 ? "invalid instruction" : ""), - iclass(insn.iclass), speculative(insn.speculative) { - if (insn.size != 0) - data.assign(insn.raw, insn.raw + insn.size); - } - - Instruction(const char *err) - : ip(0), data(), error(err ? err : "unknown error"), iclass(ptic_error), - speculative(0) {} - - ~Instruction() {} - - uint64_t GetInsnAddress() const { return ip; } - - size_t GetRawBytes(void *buf, size_t size) const { - if ((buf == nullptr) || (size == 0)) - return data.size(); - - size_t bytes_to_read = ((size <= data.size()) ? size : data.size()); - ::memcpy(buf, data.data(), bytes_to_read); - return bytes_to_read; - } - - const std::string &GetError() const { return error; } - - bool GetSpeculative() const { return speculative; } - -private: - uint64_t ip; // instruction address in inferior's memory image - std::vector data; // raw bytes - std::string error; // Error string if instruction is invalid - enum pt_insn_class iclass; // classification of the instruction - // A collection of flags giving additional information about instruction - uint32_t speculative : 1; // Instruction was executed speculatively or not -}; - -/// \class InstructionList -/// Represents a list of assembly instructions. Each instruction is of -/// type Instruction. -class InstructionList { -public: - InstructionList() : m_insn_vec() {} - - InstructionList(const InstructionList &insn_list) - : m_insn_vec(insn_list.m_insn_vec) {} - - ~InstructionList() {} - - // Get number of instructions in the list - size_t GetSize() const { return m_insn_vec.size(); } - - // Get instruction at index - Instruction GetInstructionAtIndex(uint32_t idx) { - return (idx < m_insn_vec.size() ? m_insn_vec[idx] - : Instruction("invalid instruction")); - } - - // Append intruction at the end of the list - void AppendInstruction(Instruction inst) { m_insn_vec.push_back(inst); } - -private: - std::vector m_insn_vec; -}; - -/// \class TraceOptions -/// Provides Intel(R) Processor Trace specific configuration options and -/// other information obtained by decoding and post-processing the trace -/// data. Currently, this information comprises of the total number of -/// assembly instructions executed for an inferior. -class TraceOptions : public lldb::SBTraceOptions { -public: - TraceOptions() : lldb::SBTraceOptions(), m_insn_log_size(0) {} - - ~TraceOptions() {} - - /// Get total number of assembly instructions obtained after decoding the - /// complete Intel(R) Processor Trace data obtained from LLDB. - /// - /// \return - /// Total number of instructions. - uint32_t getInstructionLogSize() const { return m_insn_log_size; } - - /// Set total number of assembly instructions. - /// - /// \param[in] size - /// Value to be set. - void setInstructionLogSize(uint32_t size) { m_insn_log_size = size; } - -private: - uint32_t m_insn_log_size; -}; - -/// \class Decoder -/// This class makes use of Intel(R) Processor Trace hardware feature -/// (implememted inside LLDB) to gather trace data for an inferior (being -/// debugged with LLDB) to provide meaningful information out of it. -/// -/// Currently the meaningful information comprises of the execution flow -/// of the inferior (in terms of assembly instructions executed). The class -/// enables user to: -/// - start the trace with configuration options for a thread/process, -/// - stop the trace for a thread/process, -/// - get the execution flow (assembly instructions) for a thread and -/// - get trace specific information for a thread -class Decoder { -public: - typedef std::vector Instructions; - - Decoder(lldb::SBDebugger &sbdebugger) - : m_mapProcessUID_mapThreadID_TraceInfo_mutex(), - m_mapProcessUID_mapThreadID_TraceInfo(), - m_debugger_user_id(sbdebugger.GetID()) {} - - ~Decoder() {} - - void StartProcessorTrace(lldb::SBProcess &sbprocess, - lldb::SBTraceOptions &sbtraceoptions, - lldb::SBError &sberror); - - void StopProcessorTrace(lldb::SBProcess &sbprocess, lldb::SBError &sberror, - lldb::tid_t tid = LLDB_INVALID_THREAD_ID); - - void GetInstructionLogAtOffset(lldb::SBProcess &sbprocess, lldb::tid_t tid, - uint32_t offset, uint32_t count, - InstructionList &result_list, - lldb::SBError &sberror); - - void GetProcessorTraceInfo(lldb::SBProcess &sbprocess, lldb::tid_t tid, - TraceOptions &traceinfo, lldb::SBError &sberror); - -private: - class ThreadTraceInfo; - typedef std::vector Buffer; - - // internal class to manage inferior's read-execute section information - class ReadExecuteSectionInfo { - public: - uint64_t load_address; - uint64_t file_offset; - uint64_t size; - std::string image_path; - - ReadExecuteSectionInfo(const uint64_t addr, const uint64_t offset, - const uint64_t sz, const std::string &path) - : load_address(addr), file_offset(offset), size(sz), image_path(path) {} - - ReadExecuteSectionInfo(const ReadExecuteSectionInfo &rxsection) = default; - }; - - typedef struct pt_cpu CPUInfo; - typedef std::vector ReadExecuteSectionInfos; - - // Check whether the provided SBProcess belongs to the same SBDebugger with - // which Decoder class instance was constructed. - void CheckDebuggerID(lldb::SBProcess &sbprocess, lldb::SBError &sberror); - - // Function to remove entries of finished processes/threads in the class - void RemoveDeadProcessesAndThreads(lldb::SBProcess &sbprocess); - - // Parse cpu information from trace configuration received from LLDB - void ParseCPUInfo(CPUInfo &pt_cpu, lldb::SBStructuredData &s, - lldb::SBError &sberror); - - /// Function performs following tasks for a given process and thread: - /// - Checks if the given thread is registered in the class or not. If not - /// then tries to register it if trace was ever started on the entire - /// process. Else returns error. - /// - fetches trace and other necessary information from LLDB (using - /// ReadTraceDataAndImageInfo()) and decodes the trace (using - /// DecodeProcessorTrace()) - void FetchAndDecode(lldb::SBProcess &sbprocess, lldb::tid_t tid, - lldb::SBError &sberror, - ThreadTraceInfo **threadTraceInfo); - - // Helper function of FetchAndDecode() to get raw trace data and memory image - // info of inferior from LLDB - void ReadTraceDataAndImageInfo(lldb::SBProcess &sbprocess, lldb::tid_t tid, - lldb::SBError &sberror, - ThreadTraceInfo &threadTraceInfo); - - // Helper function of FetchAndDecode() to initialize raw trace decoder and - // start trace decoding - void DecodeProcessorTrace(lldb::SBProcess &sbprocess, lldb::tid_t tid, - lldb::SBError &sberror, - ThreadTraceInfo &threadTraceInfo); - - // Helper function of ReadTraceDataAndImageInfo() function for gathering - // inferior's memory image info along with all dynamic libraries linked with - // it - void GetTargetModulesInfo(lldb::SBTarget &sbtarget, - ReadExecuteSectionInfos &readExecuteSectionInfos, - lldb::SBError &sberror); - - /// Helper functions of DecodeProcessorTrace() function for: - /// - initializing raw trace decoder (provided by Intel(R) Processor Trace - /// Decoding library) - /// - start trace decoding - void InitializePTInstDecoder( - struct pt_insn_decoder **decoder, struct pt_config *config, - const CPUInfo &pt_cpu, Buffer &pt_buffer, - const ReadExecuteSectionInfos &readExecuteSectionInfos, - lldb::SBError &sberror) const; - void DecodeTrace(struct pt_insn_decoder *decoder, - Instructions &instruction_list, lldb::SBError &sberror); - int HandlePTInstructionEvents(pt_insn_decoder *decoder, int errcode, - Instructions &instruction_list, - lldb::SBError &sberror); - - int AppendErrorToInstructionList(int errcode, pt_insn_decoder *decoder, - Instructions &instruction_list, - lldb::SBError &sberror); - - void AppendErrorWithOffsetToInstructionList(int errcode, - uint64_t decoder_offset, - Instructions &instruction_list, - lldb::SBError &sberror); - - void AppendErrorWithoutOffsetToInstructionList(int errcode, - Instructions &instruction_list, - lldb::SBError &sberror); - - // Function to diagnose and indicate errors during raw trace decoding - void Diagnose(struct pt_insn_decoder *decoder, int errcode, - lldb::SBError &sberror, const struct pt_insn *insn = nullptr); - - class ThreadTraceInfo { - public: - ThreadTraceInfo() - : m_pt_buffer(), m_readExecuteSectionInfos(), m_thread_stop_id(0), - m_trace(), m_pt_cpu(), m_instruction_log() {} - - ThreadTraceInfo(const ThreadTraceInfo &trace_info) = default; - - ~ThreadTraceInfo() {} - - Buffer &GetPTBuffer() { return m_pt_buffer; } - - void AllocatePTBuffer(uint64_t size) { m_pt_buffer.assign(size, 0); } - - ReadExecuteSectionInfos &GetReadExecuteSectionInfos() { - return m_readExecuteSectionInfos; - } - - CPUInfo &GetCPUInfo() { return m_pt_cpu; } - - Instructions &GetInstructionLog() { return m_instruction_log; } - - uint32_t GetStopID() const { return m_thread_stop_id; } - - void SetStopID(uint32_t stop_id) { m_thread_stop_id = stop_id; } - - lldb::SBTrace &GetUniqueTraceInstance() { return m_trace; } - - void SetUniqueTraceInstance(lldb::SBTrace &trace) { m_trace = trace; } - - friend class Decoder; - - private: - Buffer m_pt_buffer; // raw trace buffer - ReadExecuteSectionInfos - m_readExecuteSectionInfos; // inferior's memory image info - uint32_t m_thread_stop_id; // stop id for thread - lldb::SBTrace m_trace; // unique tracing instance of a thread/process - CPUInfo m_pt_cpu; // cpu info of the target on which inferior is running - Instructions m_instruction_log; // complete instruction log - }; - - typedef std::map MapThreadID_TraceInfo; - typedef std::map - MapProcessUID_MapThreadID_TraceInfo; - - std::mutex m_mapProcessUID_mapThreadID_TraceInfo_mutex; - MapProcessUID_MapThreadID_TraceInfo - m_mapProcessUID_mapThreadID_TraceInfo; // to store trace information for - // each process and its associated - // threads - lldb::user_id_t m_debugger_user_id; // SBDebugger instance which is associated - // to this Decoder instance -}; - -} // namespace ptdecoder_private -#endif // Decoder_h_ diff --git a/lldb/tools/intel-features/intel-pt/Decoder.cpp b/lldb/tools/intel-features/intel-pt/Decoder.cpp deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/Decoder.cpp +++ /dev/null @@ -1,960 +0,0 @@ -//===-- Decoder.cpp ---------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Decoder.h" - -// C/C++ Includes -#include -#include - -#include "lldb/API/SBModule.h" -#include "lldb/API/SBProcess.h" -#include "lldb/API/SBThread.h" - -using namespace ptdecoder_private; - -// This function removes entries of all the processes/threads which were once -// registered in the class but are not alive anymore because they died or -// finished executing. -void Decoder::RemoveDeadProcessesAndThreads(lldb::SBProcess &sbprocess) { - lldb::SBTarget sbtarget = sbprocess.GetTarget(); - lldb::SBDebugger sbdebugger = sbtarget.GetDebugger(); - uint32_t num_targets = sbdebugger.GetNumTargets(); - - auto itr_process = m_mapProcessUID_mapThreadID_TraceInfo.begin(); - while (itr_process != m_mapProcessUID_mapThreadID_TraceInfo.end()) { - bool process_found = false; - lldb::SBTarget target; - lldb::SBProcess process; - for (uint32_t i = 0; i < num_targets; i++) { - target = sbdebugger.GetTargetAtIndex(i); - process = target.GetProcess(); - if (process.GetUniqueID() == itr_process->first) { - process_found = true; - break; - } - } - - // Remove the process's entry if it was not found in SBDebugger - if (!process_found) { - itr_process = m_mapProcessUID_mapThreadID_TraceInfo.erase(itr_process); - continue; - } - - // If the state of the process is exited or detached then remove process's - // entry. If not then remove entry for all those registered threads of this - // process that are not alive anymore. - lldb::StateType state = process.GetState(); - if ((state == lldb::StateType::eStateDetached) || - (state == lldb::StateType::eStateExited)) - itr_process = m_mapProcessUID_mapThreadID_TraceInfo.erase(itr_process); - else { - auto itr_thread = itr_process->second.begin(); - while (itr_thread != itr_process->second.end()) { - if (itr_thread->first == LLDB_INVALID_THREAD_ID) { - ++itr_thread; - continue; - } - - lldb::SBThread thread = process.GetThreadByID(itr_thread->first); - if (!thread.IsValid()) - itr_thread = itr_process->second.erase(itr_thread); - else - ++itr_thread; - } - ++itr_process; - } - } -} - -void Decoder::StartProcessorTrace(lldb::SBProcess &sbprocess, - lldb::SBTraceOptions &sbtraceoptions, - lldb::SBError &sberror) { - sberror.Clear(); - CheckDebuggerID(sbprocess, sberror); - if (!sberror.Success()) - return; - - std::lock_guard guard( - m_mapProcessUID_mapThreadID_TraceInfo_mutex); - RemoveDeadProcessesAndThreads(sbprocess); - - if (sbtraceoptions.getType() != lldb::TraceType::eTraceTypeProcessorTrace) { - sberror.SetErrorStringWithFormat("SBTraceOptions::TraceType not set to " - "eTraceTypeProcessorTrace; ProcessID = " - "%" PRIu64, - sbprocess.GetProcessID()); - return; - } - lldb::SBStructuredData sbstructdata = sbtraceoptions.getTraceParams(sberror); - if (!sberror.Success()) - return; - - const char *trace_tech_key = "trace-tech"; - std::string trace_tech_value("intel-pt"); - lldb::SBStructuredData value = sbstructdata.GetValueForKey(trace_tech_key); - if (!value.IsValid()) { - sberror.SetErrorStringWithFormat( - "key \"%s\" not set in custom trace parameters", trace_tech_key); - return; - } - - char string_value[9]; - size_t bytes_written = value.GetStringValue( - string_value, sizeof(string_value) / sizeof(*string_value)); - if (!bytes_written || - (bytes_written > (sizeof(string_value) / sizeof(*string_value)))) { - sberror.SetErrorStringWithFormat( - "key \"%s\" not set in custom trace parameters", trace_tech_key); - return; - } - - std::size_t pos = - trace_tech_value.find((const char *)string_value, 0, bytes_written); - if ((pos == std::string::npos)) { - sberror.SetErrorStringWithFormat( - "key \"%s\" not set to \"%s\" in custom trace parameters", - trace_tech_key, trace_tech_value.c_str()); - return; - } - - // Start Tracing - lldb::SBError error; - uint32_t unique_id = sbprocess.GetUniqueID(); - lldb::tid_t tid = sbtraceoptions.getThreadID(); - lldb::SBTrace trace = sbprocess.StartTrace(sbtraceoptions, error); - if (!error.Success()) { - if (tid == LLDB_INVALID_THREAD_ID) - sberror.SetErrorStringWithFormat("%s; ProcessID = %" PRIu64, - error.GetCString(), - sbprocess.GetProcessID()); - else - sberror.SetErrorStringWithFormat( - "%s; thread_id = %" PRIu64 ", ProcessID = %" PRIu64, - error.GetCString(), tid, sbprocess.GetProcessID()); - return; - } - - MapThreadID_TraceInfo &mapThreadID_TraceInfo = - m_mapProcessUID_mapThreadID_TraceInfo[unique_id]; - ThreadTraceInfo &trace_info = mapThreadID_TraceInfo[tid]; - trace_info.SetUniqueTraceInstance(trace); - trace_info.SetStopID(sbprocess.GetStopID()); -} - -void Decoder::StopProcessorTrace(lldb::SBProcess &sbprocess, - lldb::SBError &sberror, lldb::tid_t tid) { - sberror.Clear(); - CheckDebuggerID(sbprocess, sberror); - if (!sberror.Success()) { - return; - } - - std::lock_guard guard( - m_mapProcessUID_mapThreadID_TraceInfo_mutex); - RemoveDeadProcessesAndThreads(sbprocess); - - uint32_t unique_id = sbprocess.GetUniqueID(); - auto itr_process = m_mapProcessUID_mapThreadID_TraceInfo.find(unique_id); - if (itr_process == m_mapProcessUID_mapThreadID_TraceInfo.end()) { - sberror.SetErrorStringWithFormat( - "tracing not active for this process; ProcessID = %" PRIu64, - sbprocess.GetProcessID()); - return; - } - - lldb::SBError error; - if (tid == LLDB_INVALID_THREAD_ID) { - // This implies to stop tracing on the whole process - lldb::user_id_t id_to_be_ignored = LLDB_INVALID_UID; - auto itr_thread = itr_process->second.begin(); - while (itr_thread != itr_process->second.end()) { - // In the case when user started trace on the entire process and then - // registered newly spawned threads of this process in the class later, - // these newly spawned threads will have same trace id. If we stopped - // trace on the entire process then tracing stops automatically for these - // newly spawned registered threads. Stopping trace on them again will - // return error and therefore we need to skip stopping trace on them - // again. - lldb::SBTrace &trace = itr_thread->second.GetUniqueTraceInstance(); - lldb::user_id_t lldb_pt_user_id = trace.GetTraceUID(); - if (lldb_pt_user_id != id_to_be_ignored) { - trace.StopTrace(error, itr_thread->first); - if (!error.Success()) { - std::string error_string(error.GetCString()); - if ((error_string.find("tracing not active for this process") == - std::string::npos) && - (error_string.find("tracing not active for this thread") == - std::string::npos)) { - sberror.SetErrorStringWithFormat( - "%s; thread id=%" PRIu64 ", ProcessID = %" PRIu64, - error_string.c_str(), itr_thread->first, - sbprocess.GetProcessID()); - return; - } - } - - if (itr_thread->first == LLDB_INVALID_THREAD_ID) - id_to_be_ignored = lldb_pt_user_id; - } - itr_thread = itr_process->second.erase(itr_thread); - } - m_mapProcessUID_mapThreadID_TraceInfo.erase(itr_process); - } else { - // This implies to stop tracing on a single thread. - // if 'tid' is registered in the class then get the trace id and stop trace - // on it. If it is not then check if tracing was ever started on the entire - // process (because there is a possibility that trace is still running for - // 'tid' but it was not registered in the class because user had started - // trace on the whole process and 'tid' spawned later). In that case, get - // the trace id of the process trace instance and stop trace on this thread. - // If tracing was never started on the entire process then return error - // because there is no way tracing is active on 'tid'. - MapThreadID_TraceInfo &mapThreadID_TraceInfo = itr_process->second; - lldb::SBTrace trace; - auto itr = mapThreadID_TraceInfo.find(tid); - if (itr != mapThreadID_TraceInfo.end()) { - trace = itr->second.GetUniqueTraceInstance(); - } else { - auto itr = mapThreadID_TraceInfo.find(LLDB_INVALID_THREAD_ID); - if (itr != mapThreadID_TraceInfo.end()) { - trace = itr->second.GetUniqueTraceInstance(); - } else { - sberror.SetErrorStringWithFormat( - "tracing not active for this thread; thread id=%" PRIu64 - ", ProcessID = %" PRIu64, - tid, sbprocess.GetProcessID()); - return; - } - } - - // Stop Tracing - trace.StopTrace(error, tid); - if (!error.Success()) { - std::string error_string(error.GetCString()); - sberror.SetErrorStringWithFormat( - "%s; thread id=%" PRIu64 ", ProcessID = %" PRIu64, - error_string.c_str(), tid, sbprocess.GetProcessID()); - if (error_string.find("tracing not active") == std::string::npos) - return; - } - // Delete the entry of 'tid' from this class (if any) - mapThreadID_TraceInfo.erase(tid); - } -} - -void Decoder::ReadTraceDataAndImageInfo(lldb::SBProcess &sbprocess, - lldb::tid_t tid, lldb::SBError &sberror, - ThreadTraceInfo &threadTraceInfo) { - // Allocate trace data buffer and parse cpu info for 'tid' if it is registered - // for the first time in class - lldb::SBTrace &trace = threadTraceInfo.GetUniqueTraceInstance(); - Buffer &pt_buffer = threadTraceInfo.GetPTBuffer(); - lldb::SBError error; - if (pt_buffer.size() == 0) { - lldb::SBTraceOptions traceoptions; - traceoptions.setThreadID(tid); - trace.GetTraceConfig(traceoptions, error); - if (!error.Success()) { - sberror.SetErrorStringWithFormat("%s; ProcessID = %" PRIu64, - error.GetCString(), - sbprocess.GetProcessID()); - return; - } - if (traceoptions.getType() != lldb::TraceType::eTraceTypeProcessorTrace) { - sberror.SetErrorStringWithFormat("invalid TraceType received from LLDB " - "for this thread; thread id=%" PRIu64 - ", ProcessID = %" PRIu64, - tid, sbprocess.GetProcessID()); - return; - } - - threadTraceInfo.AllocatePTBuffer(traceoptions.getTraceBufferSize()); - lldb::SBStructuredData sbstructdata = traceoptions.getTraceParams(sberror); - if (!sberror.Success()) - return; - CPUInfo &pt_cpu = threadTraceInfo.GetCPUInfo(); - ParseCPUInfo(pt_cpu, sbstructdata, sberror); - if (!sberror.Success()) - return; - } - - // Call LLDB API to get raw trace data for this thread - size_t bytes_written = trace.GetTraceData(error, (void *)pt_buffer.data(), - pt_buffer.size(), 0, tid); - if (!error.Success()) { - sberror.SetErrorStringWithFormat( - "%s; thread_id = %" PRIu64 ", ProcessID = %" PRIu64, - error.GetCString(), tid, sbprocess.GetProcessID()); - return; - } - std::fill(pt_buffer.begin() + bytes_written, pt_buffer.end(), 0); - - // Get information of all the modules of the inferior - lldb::SBTarget sbtarget = sbprocess.GetTarget(); - ReadExecuteSectionInfos &readExecuteSectionInfos = - threadTraceInfo.GetReadExecuteSectionInfos(); - GetTargetModulesInfo(sbtarget, readExecuteSectionInfos, sberror); - if (!sberror.Success()) - return; -} - -void Decoder::DecodeProcessorTrace(lldb::SBProcess &sbprocess, lldb::tid_t tid, - lldb::SBError &sberror, - ThreadTraceInfo &threadTraceInfo) { - // Initialize instruction decoder - struct pt_insn_decoder *decoder = nullptr; - struct pt_config config; - Buffer &pt_buffer = threadTraceInfo.GetPTBuffer(); - CPUInfo &pt_cpu = threadTraceInfo.GetCPUInfo(); - ReadExecuteSectionInfos &readExecuteSectionInfos = - threadTraceInfo.GetReadExecuteSectionInfos(); - - InitializePTInstDecoder(&decoder, &config, pt_cpu, pt_buffer, - readExecuteSectionInfos, sberror); - if (!sberror.Success()) - return; - - // Start raw trace decoding - Instructions &instruction_list = threadTraceInfo.GetInstructionLog(); - instruction_list.clear(); - DecodeTrace(decoder, instruction_list, sberror); -} - -// Raw trace decoding requires information of Read & Execute sections of each -// module of the inferior. This function updates internal state of the class to -// store this information. -void Decoder::GetTargetModulesInfo( - lldb::SBTarget &sbtarget, ReadExecuteSectionInfos &readExecuteSectionInfos, - lldb::SBError &sberror) { - if (!sbtarget.IsValid()) { - sberror.SetErrorStringWithFormat("Can't get target's modules info from " - "LLDB; process has an invalid target"); - return; - } - - lldb::SBFileSpec target_file_spec = sbtarget.GetExecutable(); - if (!target_file_spec.IsValid()) { - sberror.SetErrorStringWithFormat("Target has an invalid file spec"); - return; - } - - uint32_t num_modules = sbtarget.GetNumModules(); - readExecuteSectionInfos.clear(); - - // Store information of all RX sections of each module of inferior - for (uint32_t i = 0; i < num_modules; i++) { - lldb::SBModule module = sbtarget.GetModuleAtIndex(i); - if (!module.IsValid()) { - sberror.SetErrorStringWithFormat( - "Can't get module info [ %" PRIu32 - " ] of target \"%s\" from LLDB, invalid module", - i, target_file_spec.GetFilename()); - return; - } - - lldb::SBFileSpec module_file_spec = module.GetPlatformFileSpec(); - if (!module_file_spec.IsValid()) { - sberror.SetErrorStringWithFormat( - "Can't get module info [ %" PRIu32 - " ] of target \"%s\" from LLDB, invalid file spec", - i, target_file_spec.GetFilename()); - return; - } - - const char *image(module_file_spec.GetFilename()); - lldb::SBError error; - char image_complete_path[1024]; - uint32_t path_length = module_file_spec.GetPath( - image_complete_path, sizeof(image_complete_path)); - size_t num_sections = module.GetNumSections(); - - // Store information of only RX sections - for (size_t idx = 0; idx < num_sections; idx++) { - lldb::SBSection section = module.GetSectionAtIndex(idx); - uint32_t section_permission = section.GetPermissions(); - if ((section_permission & lldb::Permissions::ePermissionsReadable) && - (section_permission & lldb::Permissions::ePermissionsExecutable)) { - lldb::SBData section_data = section.GetSectionData(); - if (!section_data.IsValid()) { - sberror.SetErrorStringWithFormat( - "Can't get module info [ %" PRIu32 " ] \"%s\" of target " - "\"%s\" from LLDB, invalid " - "data in \"%s\" section", - i, image, target_file_spec.GetFilename(), section.GetName()); - return; - } - - // In case section has no data, skip it. - if (section_data.GetByteSize() == 0) - continue; - - if (!path_length) { - sberror.SetErrorStringWithFormat( - "Can't get module info [ %" PRIu32 " ] \"%s\" of target " - "\"%s\" from LLDB, module " - "has an invalid path length", - i, image, target_file_spec.GetFilename()); - return; - } - - std::string image_path(image_complete_path, path_length); - readExecuteSectionInfos.emplace_back( - section.GetLoadAddress(sbtarget), section.GetFileOffset(), - section_data.GetByteSize(), image_path); - } - } - } -} - -// Raw trace decoding requires information of the target cpu on which inferior -// is running. This function gets the Trace Configuration from LLDB, parses it -// for cpu model, family, stepping and vendor id info and updates the internal -// state of the class to store this information. -void Decoder::ParseCPUInfo(CPUInfo &pt_cpu, lldb::SBStructuredData &s, - lldb::SBError &sberror) { - lldb::SBStructuredData custom_trace_params = s.GetValueForKey("intel-pt"); - if (!custom_trace_params.IsValid()) { - sberror.SetErrorStringWithFormat("lldb couldn't provide cpuinfo"); - return; - } - - uint64_t family = 0, model = 0, stepping = 0; - char vendor[32]; - const char *key_family = "cpu_family"; - const char *key_model = "cpu_model"; - const char *key_stepping = "cpu_stepping"; - const char *key_vendor = "cpu_vendor"; - - // parse family - lldb::SBStructuredData struct_family = - custom_trace_params.GetValueForKey(key_family); - if (!struct_family.IsValid()) { - sberror.SetErrorStringWithFormat( - "%s info missing in custom trace parameters", key_family); - return; - } - family = struct_family.GetIntegerValue(0x10000); - if (family > UINT16_MAX) { - sberror.SetErrorStringWithFormat( - "invalid CPU family value extracted from custom trace parameters"); - return; - } - pt_cpu.family = (uint16_t)family; - - // parse model - lldb::SBStructuredData struct_model = - custom_trace_params.GetValueForKey(key_model); - if (!struct_model.IsValid()) { - sberror.SetErrorStringWithFormat( - "%s info missing in custom trace parameters; family=%" PRIu16, - key_model, pt_cpu.family); - return; - } - model = struct_model.GetIntegerValue(0x100); - if (model > UINT8_MAX) { - sberror.SetErrorStringWithFormat("invalid CPU model value extracted from " - "custom trace parameters; family=%" PRIu16, - pt_cpu.family); - return; - } - pt_cpu.model = (uint8_t)model; - - // parse stepping - lldb::SBStructuredData struct_stepping = - custom_trace_params.GetValueForKey(key_stepping); - if (!struct_stepping.IsValid()) { - sberror.SetErrorStringWithFormat( - "%s info missing in custom trace parameters; family=%" PRIu16 - ", model=%" PRIu8, - key_stepping, pt_cpu.family, pt_cpu.model); - return; - } - stepping = struct_stepping.GetIntegerValue(0x100); - if (stepping > UINT8_MAX) { - sberror.SetErrorStringWithFormat("invalid CPU stepping value extracted " - "from custom trace parameters; " - "family=%" PRIu16 ", model=%" PRIu8, - pt_cpu.family, pt_cpu.model); - return; - } - pt_cpu.stepping = (uint8_t)stepping; - - // parse vendor info - pt_cpu.vendor = pcv_unknown; - lldb::SBStructuredData struct_vendor = - custom_trace_params.GetValueForKey(key_vendor); - if (!struct_vendor.IsValid()) { - sberror.SetErrorStringWithFormat( - "%s info missing in custom trace parameters; family=%" PRIu16 - ", model=%" PRIu8 ", stepping=%" PRIu8, - key_vendor, pt_cpu.family, pt_cpu.model, pt_cpu.stepping); - return; - } - auto length = struct_vendor.GetStringValue(vendor, sizeof(vendor)); - if (length && strstr(vendor, "GenuineIntel")) - pt_cpu.vendor = pcv_intel; -} - -// Initialize trace decoder with pt_config structure and populate its image -// structure with inferior's memory image information. pt_config structure is -// initialized with trace buffer and cpu info of the inferior before storing it -// in trace decoder. -void Decoder::InitializePTInstDecoder( - struct pt_insn_decoder **decoder, struct pt_config *config, - const CPUInfo &pt_cpu, Buffer &pt_buffer, - const ReadExecuteSectionInfos &readExecuteSectionInfos, - lldb::SBError &sberror) const { - if (!decoder || !config) { - sberror.SetErrorStringWithFormat("internal error"); - return; - } - - // Load cpu info of inferior's target in pt_config struct - pt_config_init(config); - config->cpu = pt_cpu; - int errcode = pt_cpu_errata(&(config->errata), &(config->cpu)); - if (errcode < 0) { - sberror.SetErrorStringWithFormat("processor trace decoding library: " - "pt_cpu_errata() failed with error: " - "\"%s\"", - pt_errstr(pt_errcode(errcode))); - return; - } - - // Load trace buffer's starting and end address in pt_config struct - config->begin = pt_buffer.data(); - config->end = pt_buffer.data() + pt_buffer.size(); - - // Fill trace decoder with pt_config struct - *decoder = pt_insn_alloc_decoder(config); - if (*decoder == nullptr) { - sberror.SetErrorStringWithFormat("processor trace decoding library: " - "pt_insn_alloc_decoder() returned null " - "pointer"); - return; - } - - // Fill trace decoder's image with inferior's memory image information - struct pt_image *image = pt_insn_get_image(*decoder); - if (!image) { - sberror.SetErrorStringWithFormat("processor trace decoding library: " - "pt_insn_get_image() returned null " - "pointer"); - pt_insn_free_decoder(*decoder); - return; - } - - for (auto &itr : readExecuteSectionInfos) { - errcode = pt_image_add_file(image, itr.image_path.c_str(), itr.file_offset, - itr.size, nullptr, itr.load_address); - if (errcode < 0) { - sberror.SetErrorStringWithFormat("processor trace decoding library: " - "pt_image_add_file() failed with error: " - "\"%s\"", - pt_errstr(pt_errcode(errcode))); - pt_insn_free_decoder(*decoder); - return; - } - } -} - -void Decoder::AppendErrorWithOffsetToInstructionList( - int errcode, uint64_t decoder_offset, Instructions &instruction_list, - lldb::SBError &sberror) { - sberror.SetErrorStringWithFormat( - "processor trace decoding library: \"%s\" [decoder_offset] => " - "[0x%" PRIu64 "]", - pt_errstr(pt_errcode(errcode)), decoder_offset); - instruction_list.emplace_back(sberror.GetCString()); -} - -void Decoder::AppendErrorWithoutOffsetToInstructionList( - int errcode, Instructions &instruction_list, lldb::SBError &sberror) { - sberror.SetErrorStringWithFormat("processor trace decoding library: \"%s\"", - pt_errstr(pt_errcode(errcode))); - instruction_list.emplace_back(sberror.GetCString()); -} - -int Decoder::AppendErrorToInstructionList(int errcode, pt_insn_decoder *decoder, - Instructions &instruction_list, - lldb::SBError &sberror) { - uint64_t decoder_offset = 0; - int errcode_off = pt_insn_get_offset(decoder, &decoder_offset); - if (errcode_off < 0) { - AppendErrorWithoutOffsetToInstructionList(errcode, instruction_list, - sberror); - return errcode_off; - } - AppendErrorWithOffsetToInstructionList(errcode, decoder_offset, - instruction_list, sberror); - return 0; -} - -int Decoder::HandlePTInstructionEvents(pt_insn_decoder *decoder, int errcode, - Instructions &instruction_list, - lldb::SBError &sberror) { - while (errcode & pts_event_pending) { - pt_event event; - errcode = pt_insn_event(decoder, &event, sizeof(event)); - if (errcode < 0) - return errcode; - - // The list of events are in - // https://github.com/intel/libipt/blob/master/doc/man/pt_qry_event.3.md - if (event.type == ptev_overflow) { - int append_errcode = AppendErrorToInstructionList( - errcode, decoder, instruction_list, sberror); - if (append_errcode < 0) - return append_errcode; - } - // Other events don't signal stream errors - } - - return 0; -} - -// Start actual decoding of raw trace -void Decoder::DecodeTrace(struct pt_insn_decoder *decoder, - Instructions &instruction_list, - lldb::SBError &sberror) { - uint64_t decoder_offset = 0; - - while (1) { - struct pt_insn insn; - - // Try to sync the decoder. If it fails then get the decoder_offset and try - // to sync again. If the new_decoder_offset is same as decoder_offset then - // we will not succeed in syncing for any number of pt_insn_sync_forward() - // operations. Return in that case. Else keep resyncing until either end of - // trace stream is reached or pt_insn_sync_forward() passes. - int errcode = pt_insn_sync_forward(decoder); - if (errcode < 0) { - if (errcode == -pte_eos) - return; - - int errcode_off = pt_insn_get_offset(decoder, &decoder_offset); - if (errcode_off < 0) { - AppendErrorWithoutOffsetToInstructionList(errcode, instruction_list, - sberror); - return; - } - - sberror.SetErrorStringWithFormat( - "processor trace decoding library: \"%s\" [decoder_offset] => " - "[0x%" PRIu64 "]", - pt_errstr(pt_errcode(errcode)), decoder_offset); - instruction_list.emplace_back(sberror.GetCString()); - while (1) { - errcode = pt_insn_sync_forward(decoder); - if (errcode >= 0) - break; - - if (errcode == -pte_eos) - return; - - uint64_t new_decoder_offset = 0; - errcode_off = pt_insn_get_offset(decoder, &new_decoder_offset); - if (errcode_off < 0) { - sberror.SetErrorStringWithFormat( - "processor trace decoding library: \"%s\"", - pt_errstr(pt_errcode(errcode))); - instruction_list.emplace_back(sberror.GetCString()); - return; - } else if (new_decoder_offset <= decoder_offset) { - // We tried resyncing the decoder and decoder didn't make any - // progress because the offset didn't change. We will not make any - // progress further. Hence, returning in this situation. - return; - } - AppendErrorWithOffsetToInstructionList(errcode, new_decoder_offset, - instruction_list, sberror); - decoder_offset = new_decoder_offset; - } - } - - while (1) { - errcode = HandlePTInstructionEvents(decoder, errcode, instruction_list, - sberror); - if (errcode < 0) { - int append_errcode = AppendErrorToInstructionList( - errcode, decoder, instruction_list, sberror); - if (append_errcode < 0) - return; - break; - } - errcode = pt_insn_next(decoder, &insn, sizeof(insn)); - if (errcode < 0) { - if (insn.iclass == ptic_error) - break; - - instruction_list.emplace_back(insn); - - if (errcode == -pte_eos) - return; - - Diagnose(decoder, errcode, sberror, &insn); - instruction_list.emplace_back(sberror.GetCString()); - break; - } - instruction_list.emplace_back(insn); - if (errcode & pts_eos) - return; - } - } -} - -// Function to diagnose and indicate errors during raw trace decoding -void Decoder::Diagnose(struct pt_insn_decoder *decoder, int decode_error, - lldb::SBError &sberror, const struct pt_insn *insn) { - int errcode; - uint64_t offset; - - errcode = pt_insn_get_offset(decoder, &offset); - if (insn) { - if (errcode < 0) - sberror.SetErrorStringWithFormat( - "processor trace decoding library: \"%s\" [decoder_offset, " - "last_successful_decoded_ip] => [?, 0x%" PRIu64 "]", - pt_errstr(pt_errcode(decode_error)), insn->ip); - else - sberror.SetErrorStringWithFormat( - "processor trace decoding library: \"%s\" [decoder_offset, " - "last_successful_decoded_ip] => [0x%" PRIu64 ", 0x%" PRIu64 "]", - pt_errstr(pt_errcode(decode_error)), offset, insn->ip); - } else { - if (errcode < 0) - sberror.SetErrorStringWithFormat( - "processor trace decoding library: \"%s\"", - pt_errstr(pt_errcode(decode_error))); - else - sberror.SetErrorStringWithFormat( - "processor trace decoding library: \"%s\" [decoder_offset] => " - "[0x%" PRIu64 "]", - pt_errstr(pt_errcode(decode_error)), offset); - } -} - -void Decoder::GetInstructionLogAtOffset(lldb::SBProcess &sbprocess, - lldb::tid_t tid, uint32_t offset, - uint32_t count, - InstructionList &result_list, - lldb::SBError &sberror) { - sberror.Clear(); - CheckDebuggerID(sbprocess, sberror); - if (!sberror.Success()) { - return; - } - - std::lock_guard guard( - m_mapProcessUID_mapThreadID_TraceInfo_mutex); - RemoveDeadProcessesAndThreads(sbprocess); - - ThreadTraceInfo *threadTraceInfo = nullptr; - FetchAndDecode(sbprocess, tid, sberror, &threadTraceInfo); - if (!sberror.Success()) { - return; - } - if (threadTraceInfo == nullptr) { - sberror.SetErrorStringWithFormat("internal error"); - return; - } - - // Return instruction log by populating 'result_list' - Instructions &insn_list = threadTraceInfo->GetInstructionLog(); - uint64_t sum = (uint64_t)offset + 1; - if (((insn_list.size() <= offset) && (count <= sum) && - ((sum - count) >= insn_list.size())) || - (count < 1)) { - sberror.SetErrorStringWithFormat( - "Instruction Log not available for offset=%" PRIu32 - " and count=%" PRIu32 ", ProcessID = %" PRIu64, - offset, count, sbprocess.GetProcessID()); - return; - } - - Instructions::iterator itr_first = - (insn_list.size() <= offset) ? insn_list.begin() - : insn_list.begin() + insn_list.size() - sum; - Instructions::iterator itr_last = - (count <= sum) ? insn_list.begin() + insn_list.size() - (sum - count) - : insn_list.end(); - Instructions::iterator itr = itr_first; - while (itr != itr_last) { - result_list.AppendInstruction(*itr); - ++itr; - } -} - -void Decoder::GetProcessorTraceInfo(lldb::SBProcess &sbprocess, lldb::tid_t tid, - TraceOptions &options, - lldb::SBError &sberror) { - sberror.Clear(); - CheckDebuggerID(sbprocess, sberror); - if (!sberror.Success()) { - return; - } - - std::lock_guard guard( - m_mapProcessUID_mapThreadID_TraceInfo_mutex); - RemoveDeadProcessesAndThreads(sbprocess); - - ThreadTraceInfo *threadTraceInfo = nullptr; - FetchAndDecode(sbprocess, tid, sberror, &threadTraceInfo); - if (!sberror.Success()) { - return; - } - if (threadTraceInfo == nullptr) { - sberror.SetErrorStringWithFormat("internal error"); - return; - } - - // Get SBTraceOptions from LLDB for 'tid', populate 'traceoptions' with it - lldb::SBTrace &trace = threadTraceInfo->GetUniqueTraceInstance(); - lldb::SBTraceOptions traceoptions; - lldb::SBError error; - traceoptions.setThreadID(tid); - trace.GetTraceConfig(traceoptions, error); - if (!error.Success()) { - std::string error_string(error.GetCString()); - if (error_string.find("tracing not active") != std::string::npos) { - uint32_t unique_id = sbprocess.GetUniqueID(); - auto itr_process = m_mapProcessUID_mapThreadID_TraceInfo.find(unique_id); - if (itr_process == m_mapProcessUID_mapThreadID_TraceInfo.end()) - return; - itr_process->second.erase(tid); - } - sberror.SetErrorStringWithFormat("%s; ProcessID = %" PRIu64, - error_string.c_str(), - sbprocess.GetProcessID()); - return; - } - if (traceoptions.getType() != lldb::TraceType::eTraceTypeProcessorTrace) { - sberror.SetErrorStringWithFormat("invalid TraceType received from LLDB " - "for this thread; thread id=%" PRIu64 - ", ProcessID = %" PRIu64, - tid, sbprocess.GetProcessID()); - return; - } - options.setType(traceoptions.getType()); - options.setTraceBufferSize(traceoptions.getTraceBufferSize()); - options.setMetaDataBufferSize(traceoptions.getMetaDataBufferSize()); - lldb::SBStructuredData sbstructdata = traceoptions.getTraceParams(sberror); - if (!sberror.Success()) - return; - options.setTraceParams(sbstructdata); - options.setInstructionLogSize(threadTraceInfo->GetInstructionLog().size()); -} - -void Decoder::FetchAndDecode(lldb::SBProcess &sbprocess, lldb::tid_t tid, - lldb::SBError &sberror, - ThreadTraceInfo **threadTraceInfo) { - // Return with error if 'sbprocess' is not registered in the class - uint32_t unique_id = sbprocess.GetUniqueID(); - auto itr_process = m_mapProcessUID_mapThreadID_TraceInfo.find(unique_id); - if (itr_process == m_mapProcessUID_mapThreadID_TraceInfo.end()) { - sberror.SetErrorStringWithFormat( - "tracing not active for this process; ProcessID = %" PRIu64, - sbprocess.GetProcessID()); - return; - } - - if (tid == LLDB_INVALID_THREAD_ID) { - sberror.SetErrorStringWithFormat( - "invalid thread id provided; thread_id = %" PRIu64 - ", ProcessID = %" PRIu64, - tid, sbprocess.GetProcessID()); - return; - } - - // Check whether 'tid' thread is registered in the class. If it is then in - // case StopID didn't change then return without doing anything (no need to - // read and decode trace data then). Otherwise, save new StopID and proceed - // with reading and decoding trace. - if (threadTraceInfo == nullptr) { - sberror.SetErrorStringWithFormat("internal error"); - return; - } - - MapThreadID_TraceInfo &mapThreadID_TraceInfo = itr_process->second; - auto itr_thread = mapThreadID_TraceInfo.find(tid); - if (itr_thread != mapThreadID_TraceInfo.end()) { - if (itr_thread->second.GetStopID() == sbprocess.GetStopID()) { - *threadTraceInfo = &(itr_thread->second); - return; - } - itr_thread->second.SetStopID(sbprocess.GetStopID()); - } else { - // Implies 'tid' is not registered in the class. If tracing was never - // started on the entire process then return an error. Else try to register - // this thread and proceed with reading and decoding trace. - lldb::SBError error; - itr_thread = mapThreadID_TraceInfo.find(LLDB_INVALID_THREAD_ID); - if (itr_thread == mapThreadID_TraceInfo.end()) { - sberror.SetErrorStringWithFormat( - "tracing not active for this thread; ProcessID = %" PRIu64, - sbprocess.GetProcessID()); - return; - } - - lldb::SBTrace &trace = itr_thread->second.GetUniqueTraceInstance(); - ThreadTraceInfo &trace_info = mapThreadID_TraceInfo[tid]; - trace_info.SetUniqueTraceInstance(trace); - trace_info.SetStopID(sbprocess.GetStopID()); - itr_thread = mapThreadID_TraceInfo.find(tid); - } - - // Get raw trace data and inferior image from LLDB for the registered thread - ReadTraceDataAndImageInfo(sbprocess, tid, sberror, itr_thread->second); - if (!sberror.Success()) { - std::string error_string(sberror.GetCString()); - if (error_string.find("tracing not active") != std::string::npos) - mapThreadID_TraceInfo.erase(itr_thread); - return; - } - // Decode raw trace data - DecodeProcessorTrace(sbprocess, tid, sberror, itr_thread->second); - if (!sberror.Success()) { - return; - } - *threadTraceInfo = &(itr_thread->second); -} - -// This function checks whether the provided SBProcess instance belongs to same -// SBDebugger with which this tool instance is associated. -void Decoder::CheckDebuggerID(lldb::SBProcess &sbprocess, - lldb::SBError &sberror) { - if (!sbprocess.IsValid()) { - sberror.SetErrorStringWithFormat("invalid process instance"); - return; - } - - lldb::SBTarget sbtarget = sbprocess.GetTarget(); - if (!sbtarget.IsValid()) { - sberror.SetErrorStringWithFormat( - "process contains an invalid target; ProcessID = %" PRIu64, - sbprocess.GetProcessID()); - return; - } - - lldb::SBDebugger sbdebugger = sbtarget.GetDebugger(); - if (!sbdebugger.IsValid()) { - sberror.SetErrorStringWithFormat("process's target contains an invalid " - "debugger instance; ProcessID = %" PRIu64, - sbprocess.GetProcessID()); - return; - } - - if (sbdebugger.GetID() != m_debugger_user_id) { - sberror.SetErrorStringWithFormat( - "process belongs to a different SBDebugger instance than the one for " - "which the tool is instantiated; ProcessID = %" PRIu64, - sbprocess.GetProcessID()); - return; - } -} diff --git a/lldb/tools/intel-features/intel-pt/PTDecoder.h b/lldb/tools/intel-features/intel-pt/PTDecoder.h deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/PTDecoder.h +++ /dev/null @@ -1,270 +0,0 @@ -//===-- PTDecoder.h ---------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef PTDecoder_h_ -#define PTDecoder_h_ - -// C/C++ Includes -#include - -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBProcess.h" -#include "lldb/API/SBStructuredData.h" -#include "lldb/API/SBTraceOptions.h" -#include "lldb/lldb-enumerations.h" -#include "lldb/lldb-types.h" - -namespace ptdecoder_private { -class Instruction; -class InstructionList; -class TraceOptions; -class Decoder; -} // namespace ptdecoder_private - -namespace ptdecoder { - -/// \class PTInstruction -/// Represents an assembly instruction containing raw -/// instruction bytes, instruction address along with information -/// regarding execution flow context and Intel(R) Processor Trace -/// context. -class PTInstruction { -public: - PTInstruction() = default; - - PTInstruction(const std::shared_ptr &ptr); - - ~PTInstruction(); - - // Get instruction address in inferior's memory image - uint64_t GetInsnAddress() const; - - /// Get raw bytes of the instruction in the buffer. - /// - /// \param[out] buf - /// The buffer where the raw bytes will be written. This buffer should be - /// allocated by the caller of this API. Providing an unallocated buffer - /// is an error. In case of errors, the content of the buffer is not - /// valid. - /// - /// \param[in] size - /// Number of raw bytes to be written to @buf. Atleast @size bytes of - /// memory should be allocated to @buf otherwise the behaviour of the API - /// is undefined. Providing 0 for this argument is an error. - /// - /// \return - /// Number of bytes of the instruction actually written to @buf if API - /// succeeds. In case of errors, total number of raw bytes of the - /// instruction is returned. - size_t GetRawBytes(void *buf, size_t size) const; - - // Get error string if it represents an invalid instruction. For a valid - // instruction, an empty string is returned - std::string GetError() const; - - // Instruction was executed speculatively or not - bool GetSpeculative() const; - -private: - std::shared_ptr m_opaque_sp; -}; - -/// \class PTInstructionList -/// Represents a list of assembly instructions. Each instruction is of -/// type PTInstruction. -class PTInstructionList { -public: - // Get number of instructions in the list - size_t GetSize() const; - - // Get instruction at index - PTInstruction GetInstructionAtIndex(uint32_t idx); - - void Clear(); - -private: - friend class PTDecoder; - - void SetSP(const std::shared_ptr &ptr); - - std::shared_ptr m_opaque_sp; -}; - -/// \class PTTraceOptions -/// Provides configuration options like trace type, trace buffer size, -/// meta data buffer size along with other Intel(R) Processor Trace -/// specific options. -class PTTraceOptions { -public: - lldb::TraceType GetType() const; - - uint64_t GetTraceBufferSize() const; - - uint64_t GetMetaDataBufferSize() const; - - /// Get Intel(R) Processor Trace specific configuration options (apart from - /// trace buffer size, meta data buffer size and TraceType) formatted as - /// json text i.e. {"Name":Value,"Name":Value} pairs, where "Value" is a - /// 64-bit unsigned integer in hex format. For "Name", please refer to - /// SBProcess::StartTrace API description for setting SBTraceOptions. - /// - /// \return - /// A string formatted as json text {"Name":Value,"Name":Value} - lldb::SBStructuredData GetTraceParams(lldb::SBError &error); - -private: - friend class PTDecoder; - - void SetSP(const std::shared_ptr &ptr); - - std::shared_ptr m_opaque_sp; -}; - -/// \class PTDecoder -/// This class makes use of Intel(R) Processor Trace hardware feature -/// (implememted inside LLDB) to gather trace data for an inferior (being -/// debugged with LLDB) to provide meaningful information out of it. -/// -/// Currently the meaningful information comprises of the execution flow -/// of the inferior (in terms of assembly instructions executed). The class -/// enables user to: -/// - start the trace with configuration options for a thread/process, -/// - stop the trace for a thread/process, -/// - get the execution flow (assembly instructions) for a thread and -/// - get trace specific information for a thread -class PTDecoder { -public: - PTDecoder(lldb::SBDebugger &sbdebugger); - - /// Start Intel(R) Processor Trace on a thread or complete process with - /// Intel(R) Processor Trace specific configuration options - /// - /// \param[in] sbprocess - /// A valid process on which this operation will be performed. An error is - /// returned in case of an invalid process. - /// - /// \param[in] sbtraceoptions - /// Contains thread id information and configuration options: - /// - /// For tracing a single thread, provide a valid thread id. If sbprocess - /// doesn't contain this thread id, error will be returned. For tracing - /// complete process, set it to lldb::LLDB_INVALID_THREAD_ID - /// Configuration options comprises of: - /// a) trace buffer size, meta data buffer size, TraceType and - /// b) All other possible Intel(R) Processor Trace specific configuration - /// options (hereafter collectively referred as CUSTOM_OPTIONS), formatted - /// as json text i.e. {"Name":Value,"Name":Value,..} inside - /// sbtraceoptions, where "Value" should be a 64-bit unsigned integer in - /// hex format. For information regarding what all configuration options - /// are currently supported by LLDB and detailed information about - /// CUSTOM_OPTIONS usage, please refer to SBProcess::StartTrace() API - /// description. To know about all possible configuration options of - /// Intel(R) Processor Trace, please refer to Intel(R) 64 and IA-32 - /// Architectures Software Developer's Manual. - /// - /// TraceType should be set to lldb::TraceType::eTraceTypeProcessorTrace, - /// else error is returned. To find out any other requirement to start - /// tracing successfully, please refer to SBProcess::StartTrace() API - /// description. LLDB's current implementation of Intel(R) Processor Trace - /// feature may round off invalid values for configuration options. - /// Therefore, the configuration options with which the trace was actually - /// started, might be different to the ones with which trace was asked to - /// be started by user. The actual used configuration options can be - /// obtained from GetProcessorTraceInfo() API. - /// - /// \param[out] sberror - /// An error with the failure reason if API fails. Else success. - void StartProcessorTrace(lldb::SBProcess &sbprocess, - lldb::SBTraceOptions &sbtraceoptions, - lldb::SBError &sberror); - - /// Stop Intel(R) Processor Trace on a thread or complete process. - /// - /// \param[in] sbprocess - /// A valid process on which this operation will be performed. An error is - /// returned in case of an invalid process. - /// - /// \param[in] tid - /// Case 1: To stop tracing a single thread, provide a valid thread id. If - /// sbprocess doesn't contain the thread tid, error will be returned. - /// Case 2: To stop tracing complete process, use - /// lldb::LLDB_INVALID_THREAD_ID. - /// - /// \param[out] sberror - /// An error with the failure reason if API fails. Else success. - void StopProcessorTrace(lldb::SBProcess &sbprocess, lldb::SBError &sberror, - lldb::tid_t tid = LLDB_INVALID_THREAD_ID); - - /// Get instruction log containing the execution flow for a thread of a - /// process in terms of assembly instructions executed. - /// - /// \param[in] sbprocess - /// A valid process on which this operation will be performed. An error is - /// returned in case of an invalid process. - /// - /// \param[in] tid - /// A valid thread id of the thread for which instruction log is desired. - /// If sbprocess doesn't contain the thread tid, error will be returned. - /// - /// \param[in] count - /// The number of instructions requested by the user to be returned from - /// the complete instruction log. Complete instruction log refers to all - /// the assembly instructions obtained after decoding the complete raw - /// trace data obtained from LLDB. The length of the complete instruction - /// log is dependent on the trace buffer size with which processor tracing - /// was started for this thread. - /// The number of instructions actually returned are dependent on 'count' - /// and 'offset' parameters of this API. - /// - /// \param[in] offset - /// The offset in the complete instruction log from where 'count' number - /// of instructions are requested by the user. offset is counted from the - /// end of of this complete instruction log (which means the last executed - /// instruction is at offset 0 (zero)). - /// - /// \param[out] result_list - /// Depending upon 'count' and 'offset' values, list will be overwritten - /// with the new instructions. - /// - /// \param[out] sberror - /// An error with the failure reason if API fails. Else success. - void GetInstructionLogAtOffset(lldb::SBProcess &sbprocess, lldb::tid_t tid, - uint32_t offset, uint32_t count, - PTInstructionList &result_list, - lldb::SBError &sberror); - - /// Get Intel(R) Processor Trace specific information for a thread of a - /// process. The information contains the actual configuration options with - /// which the trace was started for this thread. - /// - /// \param[in] sbprocess - /// A valid process on which this operation will be performed. An error is - /// returned in case of an invalid process. - /// - /// \param[in] tid - /// A valid thread id of the thread for which the trace specific - /// information is required. If sbprocess doesn't contain the thread tid, - /// an error will be returned. - /// - /// \param[out] options - /// Contains actual configuration options (they may be different to the - /// ones with which tracing was asked to be started for this thread during - /// StartProcessorTrace() API call). - /// - /// \param[out] sberror - /// An error with the failure reason if API fails. Else success. - void GetProcessorTraceInfo(lldb::SBProcess &sbprocess, lldb::tid_t tid, - PTTraceOptions &options, lldb::SBError &sberror); - -private: - std::shared_ptr m_opaque_sp; -}; - -} // namespace ptdecoder -#endif // PTDecoder_h_ diff --git a/lldb/tools/intel-features/intel-pt/PTDecoder.cpp b/lldb/tools/intel-features/intel-pt/PTDecoder.cpp deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/PTDecoder.cpp +++ /dev/null @@ -1,149 +0,0 @@ -//===-- PTDecoder.cpp -------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "PTDecoder.h" -#include "Decoder.h" - -using namespace ptdecoder; -using namespace ptdecoder_private; - -// PTInstruction class member functions definitions -PTInstruction::PTInstruction( - const std::shared_ptr &ptr) - : m_opaque_sp(ptr) {} - -PTInstruction::~PTInstruction() {} - -uint64_t PTInstruction::GetInsnAddress() const { - return (m_opaque_sp ? m_opaque_sp->GetInsnAddress() : 0); -} - -size_t PTInstruction::GetRawBytes(void *buf, size_t size) const { - return (m_opaque_sp ? m_opaque_sp->GetRawBytes(buf, size) : 0); -} - -std::string PTInstruction::GetError() const { - return (m_opaque_sp ? m_opaque_sp->GetError() : "null pointer"); -} - -bool PTInstruction::GetSpeculative() const { - return (m_opaque_sp ? m_opaque_sp->GetSpeculative() : 0); -} - -// PTInstructionList class member functions definitions -size_t PTInstructionList::GetSize() const { - return (m_opaque_sp ? m_opaque_sp->GetSize() : 0); -} - -PTInstruction PTInstructionList::GetInstructionAtIndex(uint32_t idx) { - if (m_opaque_sp) - return PTInstruction(std::shared_ptr( - new Instruction(m_opaque_sp->GetInstructionAtIndex(idx)))); - - return PTInstruction(std::shared_ptr( - new Instruction("invalid instruction"))); -} - -void PTInstructionList::SetSP( - const std::shared_ptr &ptr) { - m_opaque_sp = ptr; -} -void PTInstructionList::Clear() { - if (!m_opaque_sp) - return; - m_opaque_sp.reset(); -} - -// PTTraceOptions class member functions definitions -lldb::TraceType PTTraceOptions::GetType() const { - return (m_opaque_sp ? m_opaque_sp->getType() - : lldb::TraceType::eTraceTypeNone); -} - -uint64_t PTTraceOptions::GetTraceBufferSize() const { - return (m_opaque_sp ? m_opaque_sp->getTraceBufferSize() : 0); -} - -uint64_t PTTraceOptions::GetMetaDataBufferSize() const { - return (m_opaque_sp ? m_opaque_sp->getMetaDataBufferSize() : 0); -} - -lldb::SBStructuredData PTTraceOptions::GetTraceParams(lldb::SBError &error) { - if (!m_opaque_sp) - error.SetErrorString("null pointer"); - return (m_opaque_sp ? m_opaque_sp->getTraceParams(error) - : lldb::SBStructuredData()); -} - -void PTTraceOptions::SetSP( - const std::shared_ptr &ptr) { - m_opaque_sp = ptr; -} - -// PTDecoder class member functions definitions -PTDecoder::PTDecoder(lldb::SBDebugger &sbdebugger) - : m_opaque_sp(new ptdecoder_private::Decoder(sbdebugger)) {} - -void PTDecoder::StartProcessorTrace(lldb::SBProcess &sbprocess, - lldb::SBTraceOptions &sbtraceoptions, - lldb::SBError &sberror) { - if (m_opaque_sp == nullptr) { - sberror.SetErrorStringWithFormat("invalid PTDecoder instance"); - return; - } - - m_opaque_sp->StartProcessorTrace(sbprocess, sbtraceoptions, sberror); -} - -void PTDecoder::StopProcessorTrace(lldb::SBProcess &sbprocess, - lldb::SBError &sberror, lldb::tid_t tid) { - if (m_opaque_sp == nullptr) { - sberror.SetErrorStringWithFormat("invalid PTDecoder instance"); - return; - } - - m_opaque_sp->StopProcessorTrace(sbprocess, sberror, tid); -} - -void PTDecoder::GetInstructionLogAtOffset(lldb::SBProcess &sbprocess, - lldb::tid_t tid, uint32_t offset, - uint32_t count, - PTInstructionList &result_list, - lldb::SBError &sberror) { - if (m_opaque_sp == nullptr) { - sberror.SetErrorStringWithFormat("invalid PTDecoder instance"); - return; - } - - std::shared_ptr insn_list_ptr( - new InstructionList()); - m_opaque_sp->GetInstructionLogAtOffset(sbprocess, tid, offset, count, - *insn_list_ptr, sberror); - if (!sberror.Success()) - return; - - result_list.SetSP(insn_list_ptr); -} - -void PTDecoder::GetProcessorTraceInfo(lldb::SBProcess &sbprocess, - lldb::tid_t tid, PTTraceOptions &options, - lldb::SBError &sberror) { - if (m_opaque_sp == nullptr) { - sberror.SetErrorStringWithFormat("invalid PTDecoder instance"); - return; - } - - std::shared_ptr trace_options_ptr( - new TraceOptions()); - m_opaque_sp->GetProcessorTraceInfo(sbprocess, tid, *trace_options_ptr, - sberror); - if (!sberror.Success()) - return; - - options.SetSP(trace_options_ptr); -} diff --git a/lldb/tools/intel-features/intel-pt/README_CLI.txt b/lldb/tools/intel-features/intel-pt/README_CLI.txt deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/README_CLI.txt +++ /dev/null @@ -1,123 +0,0 @@ -**************************************************************************** -* README * -* * -* This file provides all the information regarding 4 new CLI commands that * -* enable using Intel(R) Processor Trace Tool from LLDB's CLI. * -**************************************************************************** - - -============ -Introduction -============ -A C++ based cli wrapper has been developed to use Intel(R) Processor Trace Tool -through LLDB's command line. This also provides an idea to all developers on how -to integrate the Tool into various IDEs providing LLDB as a debugger. - - - -============ -How to Build -============ -The wrapper cli-wrapper-pt.cpp needs to be compiled and linked with the shared -library of the Intel(R) Processor Trace Tool in order to be used through LLDB's -CLI. The procedure to build shared library of the Intel(R) Processor Trace Tool -is given in README_TOOL.txt file. - - - -============ -How to Use -============ -All these commands are available via shared library (lldbIntelFeatures) -obtained after building intel-features folder from top. Please refer to -cli-wrapper.cpp and README files of "intel-features" folder for this purpose. - - - -============ -Description -============ -4 CLI commands have been designed keeping the LLDB's existing CLI command syntax -in mind. - - 1) processor-trace start [-b ] [] - - Start Intel(R) Processor Trace on a specific thread or on the whole process - - Syntax: processor-trace start - - cmd-options Usage: - processor-trace start [-b ] [] - - -b - size of the trace buffer to store the trace data. If not specified - then a default value (=4KB) will be taken - - - thread index of the thread. If no threads are specified, currently - selected thread is taken. Use the thread-index 'all' to start - tracing the whole process - - - - 2) processor-trace stop [] - - Stop Intel(R) Processor Trace on a specific thread or on the whole process - - Syntax: processor-trace stop - - cmd-options Usage: - processor-trace stop [] - - - thread index of the thread. If no threads are specified, currently - selected thread is taken. Use the thread-index 'all' to stop - tracing the whole process - - - - 3) processor-trace show-trace-options [] - - Display all the information regarding Intel(R) Processor Trace for a specific - thread or for the whole process. The information contains trace buffer - size and configuration options of Intel(R) Processor Trace. - - Syntax: processor-trace show-trace-options - - cmd-options Usage: - processor-trace show-trace-options [] - - - thread index of the thread. If no threads are specified, currently - selected thread is taken. Use the thread-index 'all' to display - information for all threads of the process - - - - 4) processor-trace show-instr-log [-o ] [-c ] [] - - Display a log of assembly instructions executed for a specific thread or - for the whole process. 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). - - Syntax: processor-trace show-instr-log - - cmd-options Usage: - processor-trace show-instr-log [-o ] [-c ] [] - - -c - number of instructions to be displayed. If not specified then a - default value (=10) will be taken - - -o - offset in the whole instruction log from where the log will be - displayed. If not specified then default value is calculated as - offset = count -1 - - - thread index of the thread. If no threads are specified, currently - selected thread is taken. Use the thread-index 'all' to show - instruction log for all the threads of the process diff --git a/lldb/tools/intel-features/intel-pt/README_TOOL.txt b/lldb/tools/intel-features/intel-pt/README_TOOL.txt deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/README_TOOL.txt +++ /dev/null @@ -1,311 +0,0 @@ -******************************************************************************* -* README * -* * -* This file provides all the information regarding Intel(R) Processor Trace * -* Tool. It consists explanation about how Tool internally works, its hardware * -* and software dependencies, build procedure and usage of the API. * -******************************************************************************* - - - -============ -Introduction -============ -The Intel(R) Processor Trace Tool is developed on top of LLDB and provides its -its users execution trace of the debugged applications. Tool makes use of -Intel(R) Processor Trace hardware feature implementation inside LLDB for this -purpose. This hardware feature generates a set of trace packets that -encapsulates program flow information. These trace packets along with the binary -of the application can be decoded with the help of a software decoder to -construct the execution trace of the application. - -More information about Intel(R) Processor Trace feature can be obtained from -website: https://software.intel.com/en-us/blogs/2013/09/18/processor-tracing - - - - -========= -Details -========= -The functionality of the Tool consists three parts: - -1. Raw Trace Collection from LLDB - With the help of API of this Tool (given below), Intel(R) Processor Trace - can be started on the application being debugged with LLDB. The generated - trace of the application is gathered inside LLDB and is collected by the - Tool from LLDB through LLDB's public API. - -2. Raw Trace Decoding - For decoding the raw trace data, the Tool makes use of "libipt", an - Intel(R) Processor Trace Decoder Library. The library needs binary of - the application and information about the cpu on which the application is - running in order to decode the raw trace. The Tool gathers this - information from LLDB public API and provide it to "libipt". More - information about "libipt" can be found at: - https://software.intel.com/en-us/blogs/2013/09/18/processor-tracing and - https://github.com/01org/processor-trace - -3. Decoded Trace Post-processing - The decoded trace is post-processed to reconstruct the execution flow of - the application. The execution flow contains the list of assembly - instructions (called instruction log hereafter). - - - - -============= -Dependencies -============= -The Tool has following hardware and software dependencies: - - - Hardware dependency: The Tool makes use of this hardware feature to capture - raw trace of an application from LLDB. This hardware feature may not be - present in all processors. The hardware feature is supported on Broadwell - and other succeeding CPUs such as Skylake etc. In order for Tool to provide - something meaningful, the target machine on which the application is running - should have this feature. - - - Software dependency: The Tool has an indirect dependency on the Operating - System level software support for Intel(R) Processor Trace on the target - machine where the application is running and being debugged by LLDB. This - support is required to enable raw trace generation on the target machine. - Currently, the Tool works for applications running on Linux OS as till now - the Operating System level support for the feature is present only in Linux - (more specifically starting from the 4.1 kernel). In Linux, this feature is - implemented in perf_events subsystem and is usable through perf_event_open - system call. In the User space level, the Tool has a direct dependency on - "libipt" to decode the captured raw trace. This library might be - pre-installed on host systems. If not then the library can be built from - its sources (available at): https://github.com/01org/processor-trace - - - - -============ -How to Build -============ -The Tool has a cmake based build and can be built by specifying some extra flags -while building LLDB with cmake. The following cmake flags need to be provided to -build the Tool: - - - LIBIPT_INCLUDE_PATH - The flag specifies the directory where the header - file of "libipt" resides. If the library is not pre-installed on the host - system and is built directly from "libipt" project sources then this file - may either come as a part of the sources itself or will be generated in - build folder while building library. - - - LIBIPT_LIBRARY_PATH - The flag points to the location of "libipt" shared - library. - -The Tool currently works successfully with following versions of this library: - - v1.4, v1.5, v1.6 - - - -============ -How to Use -============ -The Tool's API are exposed as a C++ object oriented interface (file PTDecoder.h) -in a shared library. The main class that implements the whole functionality is -PTDecoder. This class makes use of 3 other classes, - - PTInstruction to represent an assembly instruction - - PTInstructionList to return instruction log - - PTTraceOptions to return trace specific information -The users can use these API to develop their own products. All API are also -available as python functions through a script bridging interface, allowing -them to be used directly from python either interactively or to build python -apps. - -Currently, cli wrapper has been developed on top of the Tool to use it through -LLDB's command line. Please refer to README_CLI.txt file for command line usage. - - -A brief introduction about the classes and their API are given below. - - class PTDecoder - =============== - This class makes use of Intel(R) Processor Trace hardware feature - (implemented inside LLDB) to gather trace data for an inferior (being - debugged with LLDB) to provide meaningful information out of it. Currently - the meaningful information comprises of the execution flow of the inferior - (in terms of assembly instructions executed). The class enables user to: - - - start the trace with configuration options for a thread/process, - - stop the trace for a thread/process, - - get the execution flow (assembly instructions) for a thread and - - get trace specific information for a thread - - Corresponding API are explained below: - a) void StartProcessorTrace(lldb::SBProcess &sbprocess, - lldb::SBTraceOptions &sbtraceoptions, - lldb::SBError &sberror) - ------------------------------------------------------------------------ - This API allows the user to start trace on a particular thread or on - the whole process with Intel(R) Processor Trace specific - configuration options. - - @param[in] sbprocess : A valid process on which this operation - will be performed. An error is returned in case of an invalid - process. - - @param[out] sberror : An error with the failure reason if API - fails. Else success. - - @param[in] sbtraceoptions : Contains thread id information and - configuration options: - For tracing a single thread, provide a valid thread id. If - sbprocess doesn't contain this thread id, error will be returned. - For tracing complete process, set to lldb::LLDB_INVALID_THREAD_ID - Configuration options comprises of: - - trace buffer size, meta data buffer size, TraceType and - - All other possible Intel(R) Processor Trace specific - configuration options (hereafter collectively referred as - CUSTOM_OPTIONS) - - Trace buffer, meant to store the trace data read from target - machine, inside LLDB is configured as a cyclic buffer. Hence, - depending upon the trace buffer size provided here, buffer - overwrites may happen while LLDB writes trace data into it. - CUSTOM_OPTIONS are formatted as json text i.e. {"Name":Value, - "Name":Value,...} inside sbtraceoptions, where "Value" should be - a 64-bit unsigned integer in hex format. For information - regarding what all configuration options are currently supported - by LLDB and detailed information about CUSTOM_OPTIONS usage, - please refer to SBProcess::StartTrace() API description. An - overview of some of the various CUSTOM_OPTIONS are briefly given - below. Please refer to "Intel(R) 64 and IA-32 Architectures - Software Developer's Manual" for more details about them. - - CYCEn Enable/Disable Cycle Count Packet (CYC) Packet - - OS Packet generation enabled/disabled if - Current Privilege Level (CPL)=0 - - User Packet generation enabled/disabled if CPL>0 - - CR3Filter Enable/Disable CR3 Filtering - - MTCEn Enable/disable MTC packets - - TSCEn Enable/disable TSC packets - - DisRETC Enable/disable RET Compression - - BranchEn Enable/disable COFI-based packets - - MTCFreq Defines MTC Packet Frequency - - CycThresh CYC Packet threshold - - PSBFreq Frequency of PSB Packets - - TraceType should be set to - lldb::TraceType::eTraceTypeProcessorTrace, else error is - returned. To find out any other requirement to start tracing - successfully, refer to SBProcess::StartTrace() API description. - LLDB's current implementation of Intel(R) Processor Trace - feature may round off invalid values for configuration options. - Therefore, the configuration options with which the trace was - actually started, might be different to the ones with which - trace was asked to be started by user. The actual used - configuration options can be obtained from - GetProcessorTraceInfo() API. - - - - b) void StopProcessorTrace(lldb::SBProcess &sbprocess, - lldb::SBError &sberror, - lldb::tid_t tid = LLDB_INVALID_THREAD_ID) - ------------------------------------------------------------------------ - This API allows the user to Stop trace on a particular thread or on - the whole process. - - @param[in] sbprocess : A valid process on which this operation will - be performed. An error is returned in case of an invalid process. - - @param[in] tid : To stop tracing a single thread, provide a - valid thread id. If sbprocess doesn't contain the thread tid, - error will be returned. To stop tracing complete process, use - lldb::LLDB_INVALID_THREAD_ID - - @param[out] sberror : An error with the failure reason if API fails. - Else success - - - - c) void GetInstructionLogAtOffset(lldb::SBProcess &sbprocess, lldb::tid_t tid, - uint32_t offset, uint32_t count, - PTInstructionList &result_list, - lldb::SBError &sberror) - ------------------------------------------------------------------------ - This API provides instruction log that contains the execution flow - for a thread of a process in terms of assembly instruction executed. - The API works on only 1 thread at a time. To gather this information - for whole process, this API needs to be called for each thread. - - @param[in] sbprocess : A valid process on which this operation - will be performed. An error is returned in case of an invalid - process. - - @param[in] tid : A valid thread id of the thread for which - instruction log is desired. If sbprocess doesn't contain the - thread tid, error will be returned. - - @param[in] count : Number of instructions requested by the - user to be returned from the complete instruction log. Complete - instruction log refers to all the assembly instructions obtained - after decoding the complete raw trace data obtained from LLDB. - The length of the complete instruction log is dependent on the - trace buffer size with which processor tracing was started for - this thread. - The number of instructions actually returned are dependent on - 'count' and 'offset' parameters of this API. - - @param[in] offset : The offset in the complete instruction log - from where 'count' number of instructions are requested by the - user. offset is counted from the end of of this complete - instruction log (which means the last executed instruction - is at offset 0 (zero)). - - @param[out] result_list : Depending upon 'count' and 'offset' values, - list will be overwritten with the instructions. - - @param[out] sberror : An error with the failure reason if API - fails. Else success - - - - d) void GetProcessorTraceInfo(lldb::SBProcess &sbprocess, lldb::tid_t tid, - PTTraceOptions &options, lldb::SBError &sberror) - ------------------------------------------------------------------------ - This API provides Intel(R) Processor Trace specific information for - a thread of a process. The API works on only 1 thread at a time. To - gather this information for whole process, this API needs to be - called for each thread. The information contains the actual - configuration options with which the trace was started for this - thread. - - @param[in] sbprocess : The valid process on which this operation - will be performed. An error is returned in case of an invalid - process. - - @param[in] tid : A valid thread id of the thread for which the - trace specific information is required. If sbprocess doesn't - contain the thread tid, an error will be returned. - - @param[out] options : Contains actual configuration options (they - may be different to the ones with which tracing was asked to be - started for this thread during StartProcessorTrace() API call). - - @param[out] sberror : An error with the failure reason if API - fails. Else success - - - class PTInstruction - =================== - This class represents an assembly instruction containing raw instruction - bytes, instruction address along with execution flow context and - Intel(R) Processor Trace context. For more details, please refer to - PTDecoder.h file. - - class PTInstructionList - ======================= - This class represents a list of assembly instructions. Each assembly - instruction is of type PTInstruction. - - class PTTraceOptions - ==================== - This class provides Intel(R) Processor Trace specific configuration - options like trace type, trace buffer size, meta data buffer size along - with other trace specific options. For more details, please refer to - PTDecoder.h file. diff --git a/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.h b/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.h deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.h +++ /dev/null @@ -1,12 +0,0 @@ -//===-- cli-wrapper-pt.h----------------------------------*- C++ -*-==========// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// 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); diff --git a/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.cpp b/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.cpp deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/cli-wrapper-pt.cpp +++ /dev/null @@ -1,586 +0,0 @@ -//===-- cli-wrapper-pt.cpp -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// 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; - } - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - 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()); - } - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - 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()); - } - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - 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; - } - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - 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/interface/PTDecoder.i b/lldb/tools/intel-features/intel-pt/interface/PTDecoder.i deleted file mode 100644 --- a/lldb/tools/intel-features/intel-pt/interface/PTDecoder.i +++ /dev/null @@ -1,10 +0,0 @@ -%include "stdint.i" - -%include "lldb/lldb-defines.h" -%include "lldb/lldb-enumerations.h" -%include "lldb/lldb-forward.h" -%include "lldb/lldb-types.h" - -%include "lldb/API/SBDefines.h" - -%include "../PTDecoder.h" diff --git a/lldb/tools/intel-features/scripts/CMakeLists.txt b/lldb/tools/intel-features/scripts/CMakeLists.txt deleted file mode 100644 --- a/lldb/tools/intel-features/scripts/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -file(GLOB_RECURSE SWIG_SOURCES *.swig) - -set(FLAGS - -c++ - -shadow - -python - -D__STDC_LIMIT_MACROS - -D__STDC_CONSTANT_MACROS - ) - -set(INCLUDES - -I${LLDB_SOURCE_DIR}/include - -I${LLDB_SOURCE_DIR}/tools/intel-features/intel-pt - ) - -set(OUTPUT_PYTHON_WRAPPER - ${CMAKE_CURRENT_BINARY_DIR}/IntelFeaturesPythonWrap.cpp - ) - -set(OUTPUT_PYTHON_SCRIPT_DIR - ${CMAKE_CURRENT_BINARY_DIR} - ) - -find_package(SWIG REQUIRED) -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/IntelFeaturesPythonWrap.cpp - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lldbIntelFeatures.py - DEPENDS ${SWIG_SOURCES} - COMMAND ${SWIG_EXECUTABLE} ${FLAGS} ${INCLUDES} -o ${OUTPUT_PYTHON_WRAPPER} -outdir ${OUTPUT_PYTHON_SCRIPT_DIR} ${SWIG_SOURCES} - COMMENT "Generating python wrapper for features library") - -set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/IntelFeaturesPythonWrap.cpp PROPERTIES GENERATED 1) -set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/lldbIntelFeatures.py PROPERTIES GENERATED 1) - -add_custom_target(intel-features-swig_wrapper ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/IntelFeaturesPythonWrap.cpp - ) diff --git a/lldb/tools/intel-features/scripts/lldb-intel-features.swig b/lldb/tools/intel-features/scripts/lldb-intel-features.swig deleted file mode 100644 --- a/lldb/tools/intel-features/scripts/lldb-intel-features.swig +++ /dev/null @@ -1,16 +0,0 @@ -%module lldbIntelFeatures - -%{ -#include "lldb/lldb-public.h" -#include "intel-pt/PTDecoder.h" -using namespace ptdecoder; -%} - -/* Undefine GCC keyword to make Swig happy when processing glibc's stdint.h */ -#define __extension__ - -/* Combined python typemap for all features */ -%include "python-typemaps.txt" - -/* Feature specific python interface files*/ -%include "../intel-pt/interface/PTDecoder.i" diff --git a/lldb/tools/intel-features/scripts/python-typemaps.txt b/lldb/tools/intel-features/scripts/python-typemaps.txt deleted file mode 100644 --- a/lldb/tools/intel-features/scripts/python-typemaps.txt +++ /dev/null @@ -1,31 +0,0 @@ -/* Typemap definitions to allow SWIG to properly handle some data types */ - -// typemap for an incoming buffer -%typemap(in) (void *buf, size_t size) { - if (PyInt_Check($input)) { - $2 = PyInt_AsLong($input); - } else if (PyLong_Check($input)) { - $2 = PyLong_AsLong($input); - } else { - PyErr_SetString(PyExc_ValueError, "Expecting an integer or long object"); - return NULL; - } - if ($2 <= 0) { - PyErr_SetString(PyExc_ValueError, "Positive integer expected"); - return NULL; - } - $1 = (void *) malloc($2); -} - -// Return the buffer. Discarding any previous return result -%typemap(argout) (void *buf, size_t size) { - Py_XDECREF($result); /* Blow away any previous result */ - if (result == 0) { - $result = Py_None; - Py_INCREF($result); - } else { - PyObject *py_bytes = PyBytes_FromStringAndSize(reinterpret_cast($1), result); - $result = py_bytes; - } - free($1); -}