[Lldb-commits] [lldb] r310261 - Tool for using Intel(R) Processor Trace hardware feature
Abhishek Aggarwal via lldb-commits
lldb-commits at lists.llvm.org
Mon Aug 7 08:26:12 PDT 2017
Author: abhishek
Date: Mon Aug 7 08:26:11 2017
New Revision: 310261
URL: http://llvm.org/viewvc/llvm-project?rev=310261&view=rev
Log:
Tool for using Intel(R) Processor Trace hardware feature
Summary:
1. Provide single library for all Intel specific hardware features instead
of individual libraries for each feature
2. Added Intel(R) Processor Trace hardware feature in this single library.
Details about the tool implementing this feature is as follows:
Tool developed on top of LLDB to provide its users the execution
trace of the debugged inferiors. Tool's API are exposed as C++ object
oriented interface in a shared library. API are designed especially to be
easily integrable with IDEs providing LLDB as an application debugger.
Entire API is also available as Python functions through a script bridging
interface allowing development of python modules.
This patch also provides a CLI wrapper to use the Tool through LLDB's command
line. Highlights of the Tool and the wrapper are given below:
******************************
Intel(R) Processor Trace Tool:
******************************
- Provides execution trace of the debugged application
- Uses Intel(R) Processor Trace hardware feature (already implemented inside LLDB)
for this purpose
-- Collects trace packets generated by this feature from LLDB, decodes and
post-processes them
-- Constructs the execution trace of the application
-- Presents execution trace as a list of assembly instructions
- Provides 4 APIs (exposed as C++ object oriented interface)
-- start trace with configuration options for a thread/process,
-- stop trace for a thread/process,
-- get the execution flow (assembly instructions) for a thread,
-- get trace specific information for a thread
- Easily integrable into IDEs providing LLDB as application debugger
- Entire API available as Python functions through script bridging interface
-- Allows developing python apps on top of Tool
- README_TOOL.txt provides more details about the Tool, its dependencies, building
steps and API usage
- Tool ready to use through LLDB's command line
-- CLI wrapper has been developed on top of the Tool for this purpose
*********************************
CLI wrapper: cli-wrapper-pt.cpp
*********************************
- Provides 4 commands (syntax similar to LLDB's CLI commands):
-- processor-trace start
-- processor-trace stop
-- processor-trace show-trace-options
-- processor-trace show-instr-log
- README_CLI.txt provides more details about commands and their options
Signed-off-by: Abhishek Aggarwal <abhishek.a.aggarwal at intel.com>
Reviewers: clayborg, jingham, lldb-commits, labath
Reviewed By: clayborg
Subscribers: ravitheja, emaste, krytarowski, mgorny
Differential Revision: https://reviews.llvm.org/D33035
Added:
lldb/trunk/tools/intel-features/
lldb/trunk/tools/intel-features/CMakeLists.txt
lldb/trunk/tools/intel-features/README.txt
lldb/trunk/tools/intel-features/cli-wrapper.cpp
lldb/trunk/tools/intel-features/intel-mpx/
lldb/trunk/tools/intel-features/intel-mpx/CMakeLists.txt
lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp
- copied, changed from r310259, lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp
lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.h
lldb/trunk/tools/intel-features/intel-mpx/test/
lldb/trunk/tools/intel-features/intel-mpx/test/Makefile
- copied unchanged from r310259, lldb/trunk/tools/intel-mpx/test/Makefile
lldb/trunk/tools/intel-features/intel-mpx/test/README.txt
- copied, changed from r310259, lldb/trunk/tools/intel-mpx/test/README.txt
lldb/trunk/tools/intel-features/intel-mpx/test/TestMPXTable.py
- copied, changed from r310259, lldb/trunk/tools/intel-mpx/test/TestMPXTable.py
lldb/trunk/tools/intel-features/intel-mpx/test/main.cpp
- copied, changed from r310259, lldb/trunk/tools/intel-mpx/test/main.cpp
lldb/trunk/tools/intel-features/intel-pt/
lldb/trunk/tools/intel-features/intel-pt/CMakeLists.txt
lldb/trunk/tools/intel-features/intel-pt/Decoder.cpp
lldb/trunk/tools/intel-features/intel-pt/Decoder.h
lldb/trunk/tools/intel-features/intel-pt/PTDecoder.cpp
lldb/trunk/tools/intel-features/intel-pt/PTDecoder.h
lldb/trunk/tools/intel-features/intel-pt/README_CLI.txt
lldb/trunk/tools/intel-features/intel-pt/README_TOOL.txt
lldb/trunk/tools/intel-features/intel-pt/interface/
lldb/trunk/tools/intel-features/intel-pt/interface/PTDecoder.i
lldb/trunk/tools/intel-features/scripts/
lldb/trunk/tools/intel-features/scripts/CMakeLists.txt
lldb/trunk/tools/intel-features/scripts/lldb-intel-features.swig
lldb/trunk/tools/intel-features/scripts/python-typemaps.txt
Removed:
lldb/trunk/tools/intel-mpx/CMakeLists.txt
lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp
lldb/trunk/tools/intel-mpx/test/Makefile
lldb/trunk/tools/intel-mpx/test/README.txt
lldb/trunk/tools/intel-mpx/test/TestMPXTable.py
lldb/trunk/tools/intel-mpx/test/main.cpp
Modified:
lldb/trunk/tools/CMakeLists.txt
Modified: lldb/trunk/tools/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/CMakeLists.txt?rev=310261&r1=310260&r2=310261&view=diff
==============================================================================
--- lldb/trunk/tools/CMakeLists.txt (original)
+++ lldb/trunk/tools/CMakeLists.txt Mon Aug 7 08:26:11 2017
@@ -8,4 +8,4 @@ add_subdirectory(lldb-mi)
if (LLDB_CAN_USE_LLDB_SERVER)
add_subdirectory(lldb-server)
endif()
-add_subdirectory(intel-mpx)
+add_subdirectory(intel-features)
Added: lldb/trunk/tools/intel-features/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/CMakeLists.txt?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/CMakeLists.txt (added)
+++ lldb/trunk/tools/intel-features/CMakeLists.txt Mon Aug 7 08:26:11 2017
@@ -0,0 +1,66 @@
+include(${LLDB_PROJECT_ROOT}/cmake/LLDBDependencies.cmake)
+
+# 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)
+ return()
+endif()
+
+LIST (APPEND FEATURE_LIBS "")
+
+# Add feature specific subdirectories based on flags
+if (LLDB_BUILD_INTEL_MPX AND CMAKE_SYSTEM_NAME MATCHES "Linux")
+ add_subdirectory(intel-mpx)
+ LIST (APPEND FEATURE_LIBS ${FEATURE_LIBS} lldbIntelMPX)
+ 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 (NOT LLDB_DISABLE_PYTHON AND LLDB_BUILD_INTEL_PT)
+ 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()
+
+set_source_files_properties(cli-wrapper.cpp PROPERTIES
+ COMPILE_FLAGS ${CLI_WRAPPER_PREPROCESSORS})
+
+add_lldb_library(lldbIntelFeatures SHARED
+ cli-wrapper.cpp
+ ${LLDB_INTEL_FEATURES_PYTHON_WRAP}
+
+ LINK_LIBS
+ ${FEATURE_LIBS}
+ )
+
+# Add link dependencies for python wrapper
+if (NOT LLDB_DISABLE_PYTHON AND LLDB_BUILD_INTEL_PT)
+ add_dependencies(lldbIntelFeatures intel-features-swig_wrapper)
+ target_link_libraries(lldbIntelFeatures PRIVATE ${LLDB_SYSTEM_LIBS})
+endif()
+
+install(TARGETS lldbIntelFeatures
+ LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX})
Added: lldb/trunk/tools/intel-features/README.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/README.txt?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/README.txt (added)
+++ lldb/trunk/tools/intel-features/README.txt Mon Aug 7 08:26:11 2017
@@ -0,0 +1,73 @@
+****************************************************************************
+* README *
+* *
+* This file provides all the information regarding new CLI commands that *
+* enable using various hardware features of Intel(R) architecture based *
+* processors from LLDB's CLI. *
+****************************************************************************
+
+
+============
+Introduction
+============
+A shared library has been developed to use various hardware features of
+Intel(R) architecture based processors through LLDB's command line. The library
+currently comprises of hardware features namely Intel(R) Processor Trace and
+Intel(R) Memory Protection Extensions.
+
+
+============
+Details
+============
+A C++ based cli wrapper (cli-wrapper.cpp) has been developed here that
+agglomerates all cli commands for various hardware features. This wrapper is
+build to generate a shared library (lldbIntelFeatures) to provide all these
+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).
+
+For details regarding cli commands of each feature, please refer to these
+feature specific wrappers.
+
+
+
+============
+How to Build
+============
+The shared library (lldbIntelFeatures) has a cmake based build and can be built
+while building LLDB with cmake. "cli-wrapper.cpp" file is compiled along with all
+the feature specific source files (residing in feature specific folders).
+
+Furthermore, flexibility is provided to the user to include/exclude a particular
+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.
+
+Please refer to README files in feature specific folders to know about additional
+flags that need to be set in order to build that feature successfully.
+
+
+============
+How to Use
+============
+All CLI commands provided by this shared library can be used through the LLDB's
+CLI by executing "plugin load <shared_lib_name>" on LLDB CLI. shared_lib_name here
+is lldbIntelFeatures
+
+
+
+============
+Description
+============
+Please refer to README_CLI file of each feature to know about details of CLI
+commands.
Added: lldb/trunk/tools/intel-features/cli-wrapper.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/cli-wrapper.cpp?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/cli-wrapper.cpp (added)
+++ lldb/trunk/tools/intel-features/cli-wrapper.cpp Mon Aug 7 08:26:11 2017
@@ -0,0 +1,37 @@
+//===-- cli-wrapper.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// CLI Wrapper for hardware features of Intel(R) architecture based processors
+// to enable them to be used through LLDB's CLI. For details, please refer to
+// cli wrappers of each individual feature, residing in their respective
+// folders.
+//
+// Compile this into a shared lib and load by placing at appropriate locations
+// on disk or by using "plugin load" command at the LLDB command line.
+//
+//===----------------------------------------------------------------------===//
+
+#include "intel-mpx/cli-wrapper-mpxtable.h"
+#include "intel-pt/cli-wrapper-pt.h"
+#include "lldb/API/SBDebugger.h"
+
+namespace lldb {
+bool PluginInitialize(lldb::SBDebugger debugger);
+}
+
+bool lldb::PluginInitialize(lldb::SBDebugger debugger) {
+
+#ifdef BUILD_INTEL_PT
+ PTPluginInitialize(debugger);
+#endif
+
+#ifdef BUILD_INTEL_MPX
+ MPXPluginInitialize(debugger);
+#endif
+
+ return true;
+}
Added: lldb/trunk/tools/intel-features/intel-mpx/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-mpx/CMakeLists.txt?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-mpx/CMakeLists.txt (added)
+++ lldb/trunk/tools/intel-features/intel-mpx/CMakeLists.txt Mon Aug 7 08:26:11 2017
@@ -0,0 +1,9 @@
+add_lldb_library(lldbIntelMPX
+ cli-wrapper-mpxtable.cpp
+
+ LINK_LIBS
+ liblldb
+
+ LINK_COMPONENTS
+ Support
+ )
Copied: lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp (from r310259, lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp)
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp?p2=lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp&p1=lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp&r1=310259&r2=310261&rev=310261&view=diff
==============================================================================
--- lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp (original)
+++ lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp Mon Aug 7 08:26:11 2017
@@ -1,4 +1,5 @@
-//===-- IntelMPXTablePlugin.cpp----------------------------------*- C++ -*-===//
+//===-- cli-wrapper-mpxtable.cpp----------------------------------*- C++
+//-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,6 +13,7 @@
#include <string>
// Project includes
+#include "cli-wrapper-mpxtable.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/API/SBMemoryRegionInfo.h"
@@ -21,10 +23,6 @@
#include "llvm/ADT/Triple.h"
-namespace lldb {
-bool PluginInitialize(lldb::SBDebugger debugger);
-}
-
static bool GetPtr(char *cptr, uint64_t &ptr, lldb::SBFrame &frame,
lldb::SBCommandReturnObject &result) {
if (!cptr) {
@@ -285,8 +283,8 @@ static bool GetInitInfo(lldb::SBDebugger
lldb::SBValue bndcfgu_val = frame.FindRegister("bndcfgu");
if (!bndcfgu_val.IsValid()) {
- result.SetError(
- "Cannot access register BNDCFGU. Does the target support MPX?");
+ result.SetError("Cannot access register BNDCFGU. Does the target support "
+ "Intel(R) Memory Protection Extensions (Intel(R) MPX)?");
result.SetStatus(lldb::eReturnStatusFailed);
return false;
}
@@ -409,17 +407,17 @@ public:
}
};
-bool lldb::PluginInitialize(lldb::SBDebugger debugger) {
+bool MPXPluginInitialize(lldb::SBDebugger &debugger) {
lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
lldb::SBCommand mpxTable = interpreter.AddMultiwordCommand(
- "mpx-table", "A utility to access the MPX table entries.");
+ "mpx-table", "A utility to access the Intel(R) MPX table entries.");
- const char *mpx_show_help = "Show the MPX table entry of a pointer.\n"
- "mpx-table show <pointer>";
+ const char *mpx_show_help = "Show the Intel(R) MPX table entry of a pointer."
+ "\nmpx-table show <pointer>";
mpxTable.AddCommand("show", new MPXTableShow(), mpx_show_help);
const char *mpx_set_help =
- "Set the MPX table entry of a pointer.\n"
+ "Set the Intel(R) MPX table entry of a pointer.\n"
"mpx-table set <pointer> <lower bound> <upper bound>";
mpxTable.AddCommand("set", new MPXTableSet(), mpx_set_help);
Added: lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.h?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.h (added)
+++ lldb/trunk/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.h Mon Aug 7 08:26:11 2017
@@ -0,0 +1,12 @@
+//===-- cli-wrapper-mpxtable.h----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBDebugger.h"
+
+bool MPXPluginInitialize(lldb::SBDebugger &debugger);
Copied: lldb/trunk/tools/intel-features/intel-mpx/test/README.txt (from r310259, lldb/trunk/tools/intel-mpx/test/README.txt)
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-mpx/test/README.txt?p2=lldb/trunk/tools/intel-features/intel-mpx/test/README.txt&p1=lldb/trunk/tools/intel-mpx/test/README.txt&r1=310259&r2=310261&rev=310261&view=diff
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/README.txt (original)
+++ lldb/trunk/tools/intel-features/intel-mpx/test/README.txt Mon Aug 7 08:26:11 2017
@@ -2,5 +2,5 @@ In order to run this test, create the fo
packages/Python/lldbsuite/test/functionalities/plugins/commands/mpxtablecmd
-and copy into it the contents of this direcotry.
+and copy into it the contents of this directory.
Copied: lldb/trunk/tools/intel-features/intel-mpx/test/TestMPXTable.py (from r310259, lldb/trunk/tools/intel-mpx/test/TestMPXTable.py)
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-mpx/test/TestMPXTable.py?p2=lldb/trunk/tools/intel-features/intel-mpx/test/TestMPXTable.py&p1=lldb/trunk/tools/intel-mpx/test/TestMPXTable.py&r1=310259&r2=310261&rev=310261&view=diff
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/TestMPXTable.py (original)
+++ lldb/trunk/tools/intel-features/intel-mpx/test/TestMPXTable.py Mon Aug 7 08:26:11 2017
@@ -24,16 +24,17 @@ class TestMPXTable(TestBase):
@skipIf(compiler="clang")
@skipIf(oslist=no_match(['linux']))
@skipIf(archs=no_match(['i386', 'x86_64']))
- @skipIf(compiler="gcc", compiler_version=["<", "5"]) #GCC version >= 5 supports Intel(R) MPX.
+ @skipIf(compiler="gcc", compiler_version=["<", "5"]) #GCC version >= 5 supports
+ #Intel(R) Memory Protection Extensions (Intel(R) MPX).
def test_show_command(self):
"""Test 'mpx-table show' command"""
self.build()
lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"]
lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib")
- plugin_file = os.path.join(lldb_lib_dir, "liblldb-intel-mpxtable.so")
+ plugin_file = os.path.join(lldb_lib_dir, "liblldbIntelFeatures.so")
if not os.path.isfile(plugin_file):
- self.skipTest("Intel(R) mpx-table plugin missing.")
+ self.skipTest("features plugin missing.")
plugin_command = " "
seq = ("plugin", "load", plugin_file)
plugin_command = plugin_command.join(seq)
@@ -123,9 +124,9 @@ class TestMPXTable(TestBase):
lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"]
lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib")
- plugin_file = os.path.join(lldb_lib_dir, "liblldb-intel-mpxtable.so")
+ plugin_file = os.path.join(lldb_lib_dir, "liblldbIntelFeatures.so")
if not os.path.isfile(plugin_file):
- self.skipTest("Intel(R) mpx-table plugin missing.")
+ self.skipTest("features plugin missing.")
plugin_command = " "
seq = ("plugin", "load", plugin_file)
plugin_command = plugin_command.join(seq)
Copied: lldb/trunk/tools/intel-features/intel-mpx/test/main.cpp (from r310259, lldb/trunk/tools/intel-mpx/test/main.cpp)
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-mpx/test/main.cpp?p2=lldb/trunk/tools/intel-features/intel-mpx/test/main.cpp&p1=lldb/trunk/tools/intel-mpx/test/main.cpp&r1=310259&r2=310261&rev=310261&view=diff
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/main.cpp (original)
+++ lldb/trunk/tools/intel-features/intel-mpx/test/main.cpp Mon Aug 7 08:26:11 2017
@@ -32,7 +32,8 @@ void func(int *ptr) {
int
main(int argc, char const *argv[])
{
- // This call returns 0 only if the CPU and the kernel support Intel(R) MPX.
+ // This call returns 0 only if the CPU and the kernel support
+ // Intel(R) Memory Protection Extensions (Intel(R) MPX).
if (prctl(PR_MPX_ENABLE_MANAGEMENT, 0, 0, 0, 0) != 0)
return -1;
Added: lldb/trunk/tools/intel-features/intel-pt/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-pt/CMakeLists.txt?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-pt/CMakeLists.txt (added)
+++ lldb/trunk/tools/intel-features/intel-pt/CMakeLists.txt Mon Aug 7 08:26:11 2017
@@ -0,0 +1,31 @@
+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
+ )
Added: lldb/trunk/tools/intel-features/intel-pt/Decoder.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-pt/Decoder.cpp?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-pt/Decoder.cpp (added)
+++ lldb/trunk/tools/intel-features/intel-pt/Decoder.cpp Mon Aug 7 08:26:11 2017
@@ -0,0 +1,904 @@
+//===-- Decoder.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Project includes
+#include "Decoder.h"
+
+// C/C++ Includes
+#include <cinttypes>
+#include <cstring>
+
+// Other libraries and framework includes
+#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<std::mutex> 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<std::mutex> 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;
+ }
+ }
+}
+
+// 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) {
+ sberror.SetErrorStringWithFormat(
+ "processor trace decoding library: \"%s\"",
+ pt_errstr(pt_errcode(errcode)));
+ instruction_list.emplace_back(sberror.GetCString());
+ 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;
+ }
+ sberror.SetErrorStringWithFormat(
+ "processor trace decoding library: \"%s\" [decoder_offset] => "
+ "[0x%" PRIu64 "]",
+ pt_errstr(pt_errcode(errcode)), new_decoder_offset);
+ instruction_list.emplace_back(sberror.GetCString());
+ decoder_offset = new_decoder_offset;
+ }
+ }
+
+ while (1) {
+ 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<std::mutex> 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<std::mutex> 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;
+ }
+}
Added: lldb/trunk/tools/intel-features/intel-pt/Decoder.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-pt/Decoder.h?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-pt/Decoder.h (added)
+++ lldb/trunk/tools/intel-features/intel-pt/Decoder.h Mon Aug 7 08:26:11 2017
@@ -0,0 +1,327 @@
+//===-- Decoder.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef Decoder_h_
+#define Decoder_h_
+
+// C/C++ Includes
+#include <map>
+#include <mutex>
+#include <string>
+#include <vector>
+
+// Project includes, Other libraries and framework includes
+#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
+/// @brief 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<uint8_t> 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
+/// @brief 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<Instruction> m_insn_vec;
+};
+
+//----------------------------------------------------------------------
+/// @class TraceOptions
+/// @brief 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
+/// @brief 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<Instruction> 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<uint8_t> 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<ReadExecuteSectionInfo> 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);
+
+ // 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<lldb::user_id_t, ThreadTraceInfo> MapThreadID_TraceInfo;
+ typedef std::map<uint32_t, MapThreadID_TraceInfo>
+ 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_
Added: lldb/trunk/tools/intel-features/intel-pt/PTDecoder.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-pt/PTDecoder.cpp?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-pt/PTDecoder.cpp (added)
+++ lldb/trunk/tools/intel-features/intel-pt/PTDecoder.cpp Mon Aug 7 08:26:11 2017
@@ -0,0 +1,175 @@
+//===-- PTDecoder.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Project includes
+#include "PTDecoder.h"
+#include "Decoder.h"
+
+using namespace ptdecoder;
+using namespace ptdecoder_private;
+
+// PTInstruction class member functions definitions
+PTInstruction::PTInstruction() : m_opaque_sp() {}
+
+PTInstruction::PTInstruction(const PTInstruction &insn)
+ : m_opaque_sp(insn.m_opaque_sp) {}
+
+PTInstruction::PTInstruction(
+ const std::shared_ptr<ptdecoder_private::Instruction> &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
+PTInstructionList::PTInstructionList() : m_opaque_sp() {}
+
+PTInstructionList::PTInstructionList(const PTInstructionList &insn_list)
+ : m_opaque_sp(insn_list.m_opaque_sp) {}
+
+PTInstructionList::~PTInstructionList() {}
+
+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<ptdecoder_private::Instruction>(
+ new Instruction(m_opaque_sp->GetInstructionAtIndex(idx))));
+
+ return PTInstruction(std::shared_ptr<ptdecoder_private::Instruction>(
+ new Instruction("invalid instruction")));
+}
+
+void PTInstructionList::SetSP(
+ const std::shared_ptr<ptdecoder_private::InstructionList> &ptr) {
+ m_opaque_sp = ptr;
+}
+void PTInstructionList::Clear() {
+ if (!m_opaque_sp)
+ return;
+ m_opaque_sp.reset();
+}
+
+// PTTraceOptions class member functions definitions
+PTTraceOptions::PTTraceOptions() : m_opaque_sp() {}
+
+PTTraceOptions::PTTraceOptions(const PTTraceOptions &options)
+ : m_opaque_sp(options.m_opaque_sp) {}
+
+PTTraceOptions::~PTTraceOptions() {}
+
+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<ptdecoder_private::TraceOptions> &ptr) {
+ m_opaque_sp = ptr;
+}
+
+// PTDecoder class member functions definitions
+PTDecoder::PTDecoder(lldb::SBDebugger &sbdebugger)
+ : m_opaque_sp(new ptdecoder_private::Decoder(sbdebugger)) {}
+
+PTDecoder::PTDecoder(const PTDecoder &ptdecoder)
+ : m_opaque_sp(ptdecoder.m_opaque_sp) {}
+
+PTDecoder::~PTDecoder() {}
+
+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<ptdecoder_private::InstructionList> 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<ptdecoder_private::TraceOptions> trace_options_ptr(
+ new TraceOptions());
+ m_opaque_sp->GetProcessorTraceInfo(sbprocess, tid, *trace_options_ptr,
+ sberror);
+ if (!sberror.Success())
+ return;
+
+ options.SetSP(trace_options_ptr);
+}
Added: lldb/trunk/tools/intel-features/intel-pt/PTDecoder.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-pt/PTDecoder.h?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-pt/PTDecoder.h (added)
+++ lldb/trunk/tools/intel-features/intel-pt/PTDecoder.h Mon Aug 7 08:26:11 2017
@@ -0,0 +1,310 @@
+//===-- PTDecoder.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef PTDecoder_h_
+#define PTDecoder_h_
+
+// C/C++ Includes
+#include <vector>
+
+// Project includes, Other libraries and framework includes
+#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
+/// @brief 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();
+
+ PTInstruction(const PTInstruction &insn);
+
+ PTInstruction(const std::shared_ptr<ptdecoder_private::Instruction> &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<ptdecoder_private::Instruction> m_opaque_sp;
+};
+
+//---------------------------------------------------------------------------
+/// @class PTInstructionList
+/// @brief Represents a list of assembly instructions. Each instruction is of
+/// type PTInstruction.
+//---------------------------------------------------------------------------
+class PTInstructionList {
+public:
+ PTInstructionList();
+
+ PTInstructionList(const PTInstructionList &insn_list);
+
+ ~PTInstructionList();
+
+ // 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<ptdecoder_private::InstructionList> &ptr);
+
+ std::shared_ptr<ptdecoder_private::InstructionList> m_opaque_sp;
+};
+
+//----------------------------------------------------------------------
+/// @class PTTraceOptions
+/// @brief 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:
+ PTTraceOptions();
+
+ PTTraceOptions(const PTTraceOptions &options);
+
+ ~PTTraceOptions();
+
+ 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<ptdecoder_private::TraceOptions> &ptr);
+
+ std::shared_ptr<ptdecoder_private::TraceOptions> m_opaque_sp;
+};
+
+//----------------------------------------------------------------------
+/// @class PTDecoder
+/// @brief 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);
+
+ PTDecoder(const PTDecoder &ptdecoder);
+
+ ~PTDecoder();
+
+ //------------------------------------------------------------------
+ /// 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<ptdecoder_private::Decoder> m_opaque_sp;
+};
+
+} // namespace ptdecoder
+#endif // PTDecoder_h_
Added: lldb/trunk/tools/intel-features/intel-pt/README_CLI.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-pt/README_CLI.txt?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-pt/README_CLI.txt (added)
+++ lldb/trunk/tools/intel-features/intel-pt/README_CLI.txt Mon Aug 7 08:26:11 2017
@@ -0,0 +1,123 @@
+****************************************************************************
+* 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 <buffer-size>] [<thread-index>]
+
+ Start Intel(R) Processor Trace on a specific thread or on the whole process
+
+ Syntax: processor-trace start <cmd-options>
+
+ cmd-options Usage:
+ processor-trace start [-b <buffer-size>] [<thread-index>]
+
+ -b <buffer-size>
+ size of the trace buffer to store the trace data. If not specified
+ then a default value (=4KB) will be taken
+
+ <thread-index>
+ 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 [<thread-index>]
+
+ Stop Intel(R) Processor Trace on a specific thread or on the whole process
+
+ Syntax: processor-trace stop <cmd-options>
+
+ cmd-options Usage:
+ processor-trace stop [<thread-index>]
+
+ <thread-index>
+ 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 [<thread-index>]
+
+ 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>
+
+ cmd-options Usage:
+ processor-trace show-trace-options [<thread-index>]
+
+ <thread-index>
+ 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 <offset>] [-c <count>] [<thread-index>]
+
+ 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>
+
+ cmd-options Usage:
+ processor-trace show-instr-log [-o <offset>] [-c <count>] [<thread-index>]
+
+ -c <count>
+ number of instructions to be displayed. If not specified then a
+ default value (=10) will be taken
+
+ -o <offset>
+ 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>
+ 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
Added: lldb/trunk/tools/intel-features/intel-pt/README_TOOL.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-pt/README_TOOL.txt?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-pt/README_TOOL.txt (added)
+++ lldb/trunk/tools/intel-features/intel-pt/README_TOOL.txt Mon Aug 7 08:26:11 2017
@@ -0,0 +1,311 @@
+*******************************************************************************
+* 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.
Added: lldb/trunk/tools/intel-features/intel-pt/interface/PTDecoder.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/intel-pt/interface/PTDecoder.i?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/intel-pt/interface/PTDecoder.i (added)
+++ lldb/trunk/tools/intel-features/intel-pt/interface/PTDecoder.i Mon Aug 7 08:26:11 2017
@@ -0,0 +1,10 @@
+%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"
Added: lldb/trunk/tools/intel-features/scripts/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/scripts/CMakeLists.txt?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/scripts/CMakeLists.txt (added)
+++ lldb/trunk/tools/intel-features/scripts/CMakeLists.txt Mon Aug 7 08:26:11 2017
@@ -0,0 +1,37 @@
+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
+ )
Added: lldb/trunk/tools/intel-features/scripts/lldb-intel-features.swig
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/scripts/lldb-intel-features.swig?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/scripts/lldb-intel-features.swig (added)
+++ lldb/trunk/tools/intel-features/scripts/lldb-intel-features.swig Mon Aug 7 08:26:11 2017
@@ -0,0 +1,16 @@
+%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"
Added: lldb/trunk/tools/intel-features/scripts/python-typemaps.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-features/scripts/python-typemaps.txt?rev=310261&view=auto
==============================================================================
--- lldb/trunk/tools/intel-features/scripts/python-typemaps.txt (added)
+++ lldb/trunk/tools/intel-features/scripts/python-typemaps.txt Mon Aug 7 08:26:11 2017
@@ -0,0 +1,31 @@
+/* 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<const char*>($1), result);
+ $result = py_bytes;
+ }
+ free($1);
+}
Removed: lldb/trunk/tools/intel-mpx/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/CMakeLists.txt?rev=310260&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/CMakeLists.txt (original)
+++ lldb/trunk/tools/intel-mpx/CMakeLists.txt (removed)
@@ -1,15 +0,0 @@
-if (NOT CMAKE_SYSTEM_NAME MATCHES "Linux")
- return ()
-endif ()
-
-include(${LLDB_PROJECT_ROOT}/cmake/LLDBDependencies.cmake)
-
-add_library(lldb-intel-mpxtable SHARED
- IntelMPXTablePlugin.cpp
- )
-
-target_link_libraries(lldb-intel-mpxtable
- PUBLIC liblldb LLVMSupport)
-
-install(TARGETS lldb-intel-mpxtable
- LIBRARY DESTINATION bin)
Removed: lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp?rev=310260&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp (original)
+++ lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp (removed)
@@ -1,427 +0,0 @@
-//===-- IntelMPXTablePlugin.cpp----------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// C++ includes
-#include <cerrno>
-#include <string>
-
-// Project includes
-#include "lldb/API/SBCommandInterpreter.h"
-#include "lldb/API/SBCommandReturnObject.h"
-#include "lldb/API/SBMemoryRegionInfo.h"
-#include "lldb/API/SBProcess.h"
-#include "lldb/API/SBTarget.h"
-#include "lldb/API/SBThread.h"
-
-#include "llvm/ADT/Triple.h"
-
-namespace lldb {
-bool PluginInitialize(lldb::SBDebugger debugger);
-}
-
-static bool GetPtr(char *cptr, uint64_t &ptr, lldb::SBFrame &frame,
- lldb::SBCommandReturnObject &result) {
- if (!cptr) {
- result.SetError("Bad argument.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- lldb::SBValue ptr_addr = frame.GetValueForVariablePath(cptr);
- if (!ptr_addr.IsValid()) {
- result.SetError("Invalid pointer.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
- ptr = ptr_addr.GetLoadAddress();
- return true;
-}
-
-enum {
- mpx_base_mask_64 = ~(uint64_t)0xFFFULL,
- mpx_bd_mask_64 = 0xFFFFFFF00000ULL,
- bd_r_shift_64 = 20,
- bd_l_shift_64 = 3,
- bt_r_shift_64 = 3,
- bt_l_shift_64 = 5,
- bt_mask_64 = 0x0000000FFFF8ULL,
-
- mpx_base_mask_32 = 0xFFFFFFFFFFFFF000ULL,
- mpx_bd_mask_32 = 0xFFFFF000ULL,
- bd_r_shift_32 = 12,
- bd_l_shift_32 = 2,
- bt_r_shift_32 = 2,
- bt_l_shift_32 = 4,
- bt_mask_32 = 0x00000FFCULL,
-};
-
-static void PrintBTEntry(lldb::addr_t lbound, lldb::addr_t ubound,
- uint64_t value, uint64_t meta,
- lldb::SBCommandReturnObject &result) {
- const lldb::addr_t one_cmpl64 = ~((lldb::addr_t)0);
- const lldb::addr_t one_cmpl32 = ~((uint32_t)0);
-
- if ((lbound == one_cmpl64 || one_cmpl32) && ubound == 0) {
- result.Printf("Null bounds on map: pointer value = 0x%lx\n", value);
- } else {
- result.Printf(" lbound = 0x%lx,", lbound);
- result.Printf(" ubound = 0x%lx", ubound);
- result.Printf(" (pointer value = 0x%lx,", value);
- result.Printf(" metadata = 0x%lx)\n", meta);
- }
-}
-
-static bool GetBTEntryAddr(uint64_t bndcfgu, uint64_t ptr,
- lldb::SBTarget &target, llvm::Triple::ArchType arch,
- size_t &size, lldb::addr_t &bt_entry_addr,
- lldb::SBCommandReturnObject &result,
- lldb::SBError &error) {
- lldb::addr_t mpx_base_mask;
- lldb::addr_t mpx_bd_mask;
- lldb::addr_t bd_r_shift;
- lldb::addr_t bd_l_shift;
- lldb::addr_t bt_r_shift;
- lldb::addr_t bt_l_shift;
- lldb::addr_t bt_mask;
-
- if (arch == llvm::Triple::ArchType::x86_64) {
- mpx_base_mask = mpx_base_mask_64;
- mpx_bd_mask = mpx_bd_mask_64;
- bd_r_shift = bd_r_shift_64;
- bd_l_shift = bd_l_shift_64;
- bt_r_shift = bt_r_shift_64;
- bt_l_shift = bt_l_shift_64;
- bt_mask = bt_mask_64;
- } else if (arch == llvm::Triple::ArchType::x86) {
- mpx_base_mask = mpx_base_mask_32;
- mpx_bd_mask = mpx_bd_mask_32;
- bd_r_shift = bd_r_shift_32;
- bd_l_shift = bd_l_shift_32;
- bt_r_shift = bt_r_shift_32;
- bt_l_shift = bt_l_shift_32;
- bt_mask = bt_mask_32;
- } else {
- result.SetError("Invalid arch.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- size = target.GetAddressByteSize();
- lldb::addr_t mpx_bd_base = bndcfgu & mpx_base_mask;
- lldb::addr_t bd_entry_offset = ((ptr & mpx_bd_mask) >> bd_r_shift)
- << bd_l_shift;
- lldb::addr_t bd_entry_addr = mpx_bd_base + bd_entry_offset;
-
- std::vector<uint8_t> bd_entry_v(size);
- size_t ret = target.GetProcess().ReadMemory(
- bd_entry_addr, static_cast<void *>(bd_entry_v.data()), size, error);
- if (ret != size || !error.Success()) {
- result.SetError("Failed access to BD entry.");
- return false;
- }
-
- lldb::SBData data;
- data.SetData(error, bd_entry_v.data(), bd_entry_v.size(),
- target.GetByteOrder(), size);
- lldb::addr_t bd_entry = data.GetAddress(error, 0);
-
- if (!error.Success()) {
- result.SetError("Failed access to BD entry.");
- return false;
- }
-
- if ((bd_entry & 0x01) == 0) {
- result.SetError("Invalid bound directory.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- // Clear status bit.
- //
- bd_entry--;
-
- lldb::addr_t bt_addr = bd_entry & ~bt_r_shift;
- lldb::addr_t bt_entry_offset = ((ptr & bt_mask) >> bt_r_shift) << bt_l_shift;
- bt_entry_addr = bt_addr + bt_entry_offset;
-
- return true;
-}
-
-static bool GetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::SBTarget &target,
- llvm::Triple::ArchType arch,
- lldb::SBCommandReturnObject &result,
- lldb::SBError &error) {
- lldb::addr_t bt_entry_addr;
- size_t size;
- if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,
- error))
- return false;
-
- // bt_entry_v must have space to store the 4 elements of the BT entry (lower
- // boundary,
- // upper boundary, pointer value and meta data), which all have the same size
- // 'size'.
- //
- std::vector<uint8_t> bt_entry_v(size * 4);
- size_t ret = target.GetProcess().ReadMemory(
- bt_entry_addr, static_cast<void *>(bt_entry_v.data()), size * 4, error);
-
- if ((ret != (size * 4)) || !error.Success()) {
- result.SetError("Unsuccessful. Failed access to BT entry.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- lldb::addr_t lbound;
- lldb::addr_t ubound;
- uint64_t value;
- uint64_t meta;
- lldb::SBData data;
- data.SetData(error, bt_entry_v.data(), bt_entry_v.size(),
- target.GetByteOrder(), size);
- lbound = data.GetAddress(error, size * 0);
- ubound = data.GetAddress(error, size * 1);
- value = data.GetAddress(error, size * 2);
- meta = data.GetAddress(error, size * 3);
- // ubound is stored as one's complement.
- if (arch == llvm::Triple::ArchType::x86) {
- ubound = (~ubound) & 0x00000000FFFFFFFF;
- } else {
- ubound = ~ubound;
- }
-
- if (!error.Success()) {
- result.SetError("Failed access to BT entry.");
- return false;
- }
-
- PrintBTEntry(lbound, ubound, value, meta, result);
-
- result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
- return true;
-}
-
-static std::vector<uint8_t> uIntToU8(uint64_t input, size_t size) {
- std::vector<uint8_t> output;
- for (size_t i = 0; i < size; i++)
- output.push_back(
- static_cast<uint8_t>((input & (0xFFULL << (i * 8))) >> (i * 8)));
-
- return output;
-}
-
-static bool SetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::addr_t lbound,
- lldb::addr_t ubound, lldb::SBTarget &target,
- llvm::Triple::ArchType arch,
- lldb::SBCommandReturnObject &result,
- lldb::SBError &error) {
- lldb::addr_t bt_entry_addr;
- size_t size;
-
- if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,
- error))
- return false;
-
- // bt_entry_v must have space to store only 2 elements of the BT Entry, the
- // lower boundary and the upper boundary, which both have size 'size'.
- //
- std::vector<uint8_t> bt_entry_v(size * 2);
-
- std::vector<uint8_t> lbound_v = uIntToU8(lbound, size);
- bt_entry_v.insert(bt_entry_v.begin(), lbound_v.begin(), lbound_v.end());
- std::vector<uint8_t> ubound_v = uIntToU8(~ubound, size);
- bt_entry_v.insert(bt_entry_v.begin() + size, ubound_v.begin(),
- ubound_v.end());
-
- size_t ret = target.GetProcess().WriteMemory(
- bt_entry_addr, (void *)(bt_entry_v.data()), size * 2, error);
- if ((ret != (size * 2)) || !error.Success()) {
- result.SetError("Failed access to BT entry.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
- return true;
-}
-
-static bool GetInitInfo(lldb::SBDebugger debugger, lldb::SBTarget &target,
- llvm::Triple::ArchType &arch, uint64_t &bndcfgu,
- char *arg, uint64_t &ptr,
- lldb::SBCommandReturnObject &result,
- lldb::SBError &error) {
- target = debugger.GetSelectedTarget();
- if (!target.IsValid()) {
- result.SetError("Invalid target.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- const std::string triple_s(target.GetTriple());
- const llvm::Triple triple(triple_s);
-
- arch = triple.getArch();
-
- if ((arch != llvm::Triple::ArchType::x86) &&
- (arch != llvm::Triple::ArchType::x86_64)) {
- result.SetError("Platform not supported.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- lldb::SBFrame frame =
- target.GetProcess().GetSelectedThread().GetSelectedFrame();
- if (!frame.IsValid()) {
- result.SetError("No valid process, thread or frame.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- lldb::SBValue bndcfgu_val = frame.FindRegister("bndcfgu");
- if (!bndcfgu_val.IsValid()) {
- result.SetError(
- "Cannot access register BNDCFGU. Does the target support MPX?");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- lldb::SBData bndcfgu_data = bndcfgu_val.GetData();
- bndcfgu = bndcfgu_data.GetUnsignedInt64(error, 0);
- if (!error.Success()) {
- result.SetError(error, "Invalid read of register BNDCFGU.");
- return false;
- }
-
- if (!GetPtr(arg, ptr, frame, result))
- return false;
-
- return true;
-}
-
-class MPXTableShow : public lldb::SBCommandPluginInterface {
-public:
- virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
- lldb::SBCommandReturnObject &result) {
-
- if (command) {
- int arg_c = 0;
- char *arg;
-
- while (*command) {
- if (arg_c >= 1) {
- result.SetError("Too many arguments. See help.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
- arg_c++;
- arg = *command;
- command++;
- }
-
- if (!debugger.IsValid()) {
- result.SetError("Invalid debugger.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-
- lldb::SBTarget target;
- llvm::Triple::ArchType arch;
- lldb::SBError error;
- uint64_t bndcfgu;
- uint64_t ptr;
-
- if (!GetInitInfo(debugger, target, arch, bndcfgu, arg, ptr, result,
- error))
- return false;
-
- return GetBTEntry(bndcfgu, ptr, target, arch, result, error);
- }
-
- result.SetError("Too few arguments. See help.");
- result.SetStatus(lldb::eReturnStatusFailed);
- return false;
- }
-};
-
-class MPXTableSet : public lldb::SBCommandPluginInterface {
-public:
- virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
- lldb::SBCommandReturnObject &result) {
-
- if (command) {
- int arg_c = 0;
- char *arg[3];
-
- while (*command) {
- arg[arg_c] = *command;
- command++;
- arg_c++;
- }
-
- if (arg_c != 3) {
- result.SetError("Wrong arguments. See help.");
- return false;
- }
-
- if (!debugger.IsValid()) {
- result.SetError("Invalid debugger.");
- return false;
- }
-
- lldb::SBTarget target;
- llvm::Triple::ArchType arch;
- lldb::SBError error;
- uint64_t bndcfgu;
- uint64_t ptr;
-
- if (!GetInitInfo(debugger, target, arch, bndcfgu, arg[0], ptr, result,
- error))
- return false;
-
- char *endptr;
- errno = 0;
- uint64_t lbound = std::strtoul(arg[1], &endptr, 16);
- if (endptr == arg[1] || errno == ERANGE) {
- result.SetError("Lower Bound: bad argument format.");
- errno = 0;
- return false;
- }
-
- uint64_t ubound = std::strtoul(arg[2], &endptr, 16);
- if (endptr == arg[1] || errno == ERANGE) {
- result.SetError("Upper Bound: bad argument format.");
- errno = 0;
- return false;
- }
-
- return SetBTEntry(bndcfgu, ptr, lbound, ubound, target, arch, result,
- error);
- }
-
- result.SetError("Too few arguments. See help.");
- return false;
- }
-};
-
-bool lldb::PluginInitialize(lldb::SBDebugger debugger) {
- lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
- lldb::SBCommand mpxTable = interpreter.AddMultiwordCommand(
- "mpx-table", "A utility to access the MPX table entries.");
-
- const char *mpx_show_help = "Show the MPX table entry of a pointer.\n"
- "mpx-table show <pointer>";
- mpxTable.AddCommand("show", new MPXTableShow(), mpx_show_help);
-
- const char *mpx_set_help =
- "Set the MPX table entry of a pointer.\n"
- "mpx-table set <pointer> <lower bound> <upper bound>";
- mpxTable.AddCommand("set", new MPXTableSet(), mpx_set_help);
-
- return true;
-}
Removed: lldb/trunk/tools/intel-mpx/test/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/test/Makefile?rev=310260&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/Makefile (original)
+++ lldb/trunk/tools/intel-mpx/test/Makefile (removed)
@@ -1,7 +0,0 @@
-LEVEL = ../../../../make
-
-CXX_SOURCES := main.cpp
-
-CFLAGS_EXTRAS += -mmpx -fcheck-pointer-bounds -lmpxwrappers -lmpx -fuse-ld=bfd
-
-include $(LEVEL)/Makefile.rules
Removed: lldb/trunk/tools/intel-mpx/test/README.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/test/README.txt?rev=310260&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/README.txt (original)
+++ lldb/trunk/tools/intel-mpx/test/README.txt (removed)
@@ -1,6 +0,0 @@
-In order to run this test, create the following directory:
-
- packages/Python/lldbsuite/test/functionalities/plugins/commands/mpxtablecmd
-
-and copy into it the contents of this direcotry.
-
Removed: lldb/trunk/tools/intel-mpx/test/TestMPXTable.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/test/TestMPXTable.py?rev=310260&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/TestMPXTable.py (original)
+++ lldb/trunk/tools/intel-mpx/test/TestMPXTable.py (removed)
@@ -1,168 +0,0 @@
-"""
-Test mpx-table command.
-"""
-
-from __future__ import print_function
-
-
-import os
-import time
-import re
-import lldb
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class TestMPXTable(TestBase):
-
- mydir = TestBase.compute_mydir(__file__)
-
- def setUp(self):
- TestBase.setUp(self)
-
- @skipIf(compiler="clang")
- @skipIf(oslist=no_match(['linux']))
- @skipIf(archs=no_match(['i386', 'x86_64']))
- @skipIf(compiler="gcc", compiler_version=["<", "5"]) #GCC version >= 5 supports Intel(R) MPX.
- def test_show_command(self):
- """Test 'mpx-table show' command"""
- self.build()
-
- lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"]
- lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib")
- plugin_file = os.path.join(lldb_lib_dir, "liblldb-intel-mpxtable.so")
- if not os.path.isfile(plugin_file):
- self.skipTest("Intel(R) mpx-table plugin missing.")
- plugin_command = " "
- seq = ("plugin", "load", plugin_file)
- plugin_command = plugin_command.join(seq)
- self.runCmd(plugin_command)
-
- exe = os.path.join(os.getcwd(), "a.out")
- self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
-
- self.b1 = line_number('main.cpp', '// Break 1.')
- self.b2 = line_number('main.cpp', '// Break 2.')
- self.b3 = line_number('main.cpp', '// Break 3.')
- self.b4 = line_number('main.cpp', '// Break 4.')
- lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b1, num_expected_locations=1)
- lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b2, num_expected_locations=1)
- lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b3, num_expected_locations=1)
- lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b4, num_expected_locations=1)
- self.runCmd("run", RUN_SUCCEEDED)
-
- target = self.dbg.GetSelectedTarget()
- process = target.GetProcess()
-
- if (process.GetState() == lldb.eStateExited):
- self.skipTest("Intel(R) MPX is not supported.")
- else:
- self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
- substrs = ["stop reason = breakpoint 1."])
-
- self.expect("mpx-table show a",
- substrs = ['lbound = 0x',
- ', ubound = 0x',
- '(pointer value = 0x',
- ', metadata = 0x',
- ')'],
- error = False)
-
- self.expect("continue", STOPPED_DUE_TO_BREAKPOINT,
- substrs = ["stop reason = breakpoint 2."])
-
- # Check that out of scope pointer cannot be reached.
- #
- self.expect("mpx-table show a",
- substrs = ['Invalid pointer.'],
- error = True)
-
- self.expect("mpx-table show tmp",
- substrs = ['lbound = 0x',
- ', ubound = 0x',
- '(pointer value = 0x',
- ', metadata = 0x',
- ')'],
- error = False)
-
- self.expect("continue", STOPPED_DUE_TO_BREAKPOINT,
- substrs = ["stop reason = breakpoint 3."])
-
- # Check that the pointer value is correctly updated.
- #
- self.expect("mpx-table show tmp",
- substrs = ['lbound = 0x',
- ', ubound = 0x',
- '(pointer value = 0x2',
- ', metadata = 0x',
- ')'],
- error = False)
-
- self.expect("continue", STOPPED_DUE_TO_BREAKPOINT,
- substrs = ["stop reason = breakpoint 4."])
-
- # After going back to main(), check that out of scope pointer cannot be
- # reached.
- #
- self.expect("mpx-table show tmp",
- substrs = ['Invalid pointer.'],
- error = True)
-
- self.expect("mpx-table show a",
- substrs = ['lbound = 0x',
- ', ubound = 0x',
- '(pointer value = 0x',
- ', metadata = 0x',
- ')'],
- error = False)
-
- def test_set_command(self):
- """Test 'mpx-table set' command"""
- self.build()
-
- lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"]
- lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib")
- plugin_file = os.path.join(lldb_lib_dir, "liblldb-intel-mpxtable.so")
- if not os.path.isfile(plugin_file):
- self.skipTest("Intel(R) mpx-table plugin missing.")
- plugin_command = " "
- seq = ("plugin", "load", plugin_file)
- plugin_command = plugin_command.join(seq)
- self.runCmd(plugin_command)
-
- exe = os.path.join(os.getcwd(), "a.out")
- self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
-
- self.b1 = line_number('main.cpp', '// Break 1.')
- lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b1, num_expected_locations=1)
- self.runCmd("run", RUN_SUCCEEDED)
-
- target = self.dbg.GetSelectedTarget()
- process = target.GetProcess()
-
- if (process.GetState() == lldb.eStateExited):
- self.skipTest("Intel(R) MPX is not supported.")
- else:
- self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
- substrs = ["stop reason = breakpoint 1."])
-
- # Check that the BT Entry doesn't already contain the test values.
- #
- self.expect("mpx-table show a", matching=False,
- substrs = ['lbound = 0xcafecafe',
- ', ubound = 0xbeefbeef'])
-
- # Set the test values.
- #
- self.expect("mpx-table set a 0xcafecafe 0xbeefbeef", error = False)
-
- # Verify that the test values have been correctly written in the BT
- # entry.
- #
- self.expect("mpx-table show a",
- substrs = ['lbound = 0xcafecafe',
- ', ubound = 0xbeefbeef'],
- error = False)
-
-
Removed: lldb/trunk/tools/intel-mpx/test/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/test/main.cpp?rev=310260&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/main.cpp (original)
+++ lldb/trunk/tools/intel-mpx/test/main.cpp (removed)
@@ -1,48 +0,0 @@
-//===-- main.cpp ------------------------------------------------*- C++ -*-===//
-////
-//// The LLVM Compiler Infrastructure
-////
-//// This file is distributed under the University of Illinois Open Source
-//// License. See LICENSE.TXT for details.
-////
-////===----------------------------------------------------------------------===//
-//
-
-const int size = 5;
-
-#include <cstddef>
-#include <cstdlib>
-#include <sys/prctl.h>
-
-void func(int *ptr) {
- int *tmp;
-
-#if defined __GNUC__ && !defined __INTEL_COMPILER
- __builtin___bnd_store_ptr_bounds ((void**)&ptr, ptr);
-#endif
- tmp = ptr + size - 1;
-#if defined __GNUC__ && !defined __INTEL_COMPILER
- __builtin___bnd_store_ptr_bounds ((void**)&tmp, tmp);
-#endif
- tmp = (int*)0x2; // Break 2.
-
- return; // Break 3.
-}
-
-int
-main(int argc, char const *argv[])
-{
- // This call returns 0 only if the CPU and the kernel support Intel(R) MPX.
- if (prctl(PR_MPX_ENABLE_MANAGEMENT, 0, 0, 0, 0) != 0)
- return -1;
-
- int* a = (int *) calloc(size, sizeof(int));
-#if defined __GNUC__ && !defined __INTEL_COMPILER
- __builtin___bnd_store_ptr_bounds ((void**)&a, a);
-#endif
- func(a); // Break 1.
-
- free(a); // Break 4.
-
- return 0;
-}
More information about the lldb-commits
mailing list