aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:12:36 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:12:36 +0000
commitef5d0b5e97ec8e6fa395d377b09aa7755e345b4f (patch)
tree27916256fdeeb57d10d2f3d6948be5d71a703215 /tools
parent76e0736e7fcfeb179779e49c05604464b1ccd704 (diff)
Notes
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt3
-rw-r--r--tools/argdumper/CMakeLists.txt4
-rw-r--r--tools/debugserver/source/CMakeLists.txt112
-rw-r--r--tools/debugserver/source/DNB.cpp6
-rw-r--r--tools/debugserver/source/DNBDataRef.cpp12
-rw-r--r--tools/debugserver/source/DNBRegisterInfo.cpp4
-rw-r--r--tools/debugserver/source/JSON.cpp3
-rw-r--r--tools/debugserver/source/MacOSX/MachException.cpp21
-rw-r--r--tools/debugserver/source/MacOSX/MachException.h9
-rw-r--r--tools/debugserver/source/MacOSX/MachProcess.mm112
-rw-r--r--tools/debugserver/source/MacOSX/MachTask.mm2
-rw-r--r--tools/debugserver/source/MacOSX/MachThread.cpp10
-rw-r--r--tools/debugserver/source/MacOSX/OsLogger.cpp4
-rw-r--r--tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp12
-rw-r--r--tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp12
-rw-r--r--tools/debugserver/source/RNBRemote.cpp76
-rw-r--r--tools/debugserver/source/RNBServices.cpp2
-rw-r--r--tools/debugserver/source/RNBSocket.cpp5
-rw-r--r--tools/debugserver/source/debugserver.cpp6
-rw-r--r--tools/driver/CMakeLists.txt2
-rw-r--r--tools/driver/Driver.cpp10
-rw-r--r--tools/intel-features/CMakeLists.txt67
-rw-r--r--tools/intel-features/README.txt73
-rw-r--r--tools/intel-features/cli-wrapper.cpp43
-rw-r--r--tools/intel-features/intel-mpx/CMakeLists.txt9
-rw-r--r--tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp (renamed from tools/intel-mpx/IntelMPXTablePlugin.cpp)22
-rw-r--r--tools/intel-features/intel-mpx/cli-wrapper-mpxtable.h12
-rw-r--r--tools/intel-features/intel-mpx/test/Makefile (renamed from tools/intel-mpx/test/Makefile)0
-rw-r--r--tools/intel-features/intel-mpx/test/README.txt (renamed from tools/intel-mpx/test/README.txt)2
-rw-r--r--tools/intel-features/intel-mpx/test/TestMPXTable.py (renamed from tools/intel-mpx/test/TestMPXTable.py)11
-rw-r--r--tools/intel-features/intel-mpx/test/main.cpp (renamed from tools/intel-mpx/test/main.cpp)3
-rw-r--r--tools/intel-features/intel-pt/CMakeLists.txt31
-rw-r--r--tools/intel-features/intel-pt/Decoder.cpp904
-rw-r--r--tools/intel-features/intel-pt/Decoder.h327
-rw-r--r--tools/intel-features/intel-pt/PTDecoder.cpp175
-rw-r--r--tools/intel-features/intel-pt/PTDecoder.h310
-rw-r--r--tools/intel-features/intel-pt/README_CLI.txt123
-rw-r--r--tools/intel-features/intel-pt/README_TOOL.txt311
-rw-r--r--tools/intel-features/intel-pt/cli-wrapper-pt.cpp583
-rw-r--r--tools/intel-features/intel-pt/cli-wrapper-pt.h13
-rw-r--r--tools/intel-features/intel-pt/interface/PTDecoder.i10
-rw-r--r--tools/intel-features/scripts/CMakeLists.txt37
-rw-r--r--tools/intel-features/scripts/lldb-intel-features.swig16
-rw-r--r--tools/intel-features/scripts/python-typemaps.txt31
-rw-r--r--tools/intel-mpx/CMakeLists.txt15
-rw-r--r--tools/lldb-mi/MICmdCmdVar.cpp14
-rw-r--r--tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp4
-rw-r--r--tools/lldb-mi/MIDriverMain.cpp8
-rw-r--r--tools/lldb-server/CMakeLists.txt37
-rw-r--r--tools/lldb-server/lldb-gdbserver.cpp99
-rw-r--r--tools/lldb-test/CMakeLists.txt27
-rw-r--r--tools/lldb-test/FormatUtil.cpp69
-rw-r--r--tools/lldb-test/FormatUtil.h75
-rw-r--r--tools/lldb-test/SystemInitializerTest.cpp345
-rw-r--r--tools/lldb-test/SystemInitializerTest.h35
-rw-r--r--tools/lldb-test/lldb-test.cpp126
56 files changed, 4130 insertions, 264 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 7b26f5907a86..75c9c15c487d 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -8,4 +8,5 @@ add_subdirectory(lldb-mi)
if (LLDB_CAN_USE_LLDB_SERVER)
add_subdirectory(lldb-server)
endif()
-add_subdirectory(intel-mpx)
+add_subdirectory(intel-features)
+add_subdirectory(lldb-test)
diff --git a/tools/argdumper/CMakeLists.txt b/tools/argdumper/CMakeLists.txt
index 42f1dd51582a..9b22103bc8af 100644
--- a/tools/argdumper/CMakeLists.txt
+++ b/tools/argdumper/CMakeLists.txt
@@ -1,10 +1,6 @@
-include(${LLDB_PROJECT_ROOT}/cmake/LLDBDependencies.cmake)
-
add_lldb_tool(lldb-argdumper INCLUDE_IN_FRAMEWORK
argdumper.cpp
LINK_LIBS
- lldbCore
lldbUtility
)
-
diff --git a/tools/debugserver/source/CMakeLists.txt b/tools/debugserver/source/CMakeLists.txt
index bdca1602f4a8..d99880cd97f3 100644
--- a/tools/debugserver/source/CMakeLists.txt
+++ b/tools/debugserver/source/CMakeLists.txt
@@ -1,4 +1,5 @@
include(CheckCXXCompilerFlag)
+include(CheckLibraryExists)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/..)
include_directories(${LLDB_SOURCE_DIR}/source)
include_directories(MacOSX/DarwinLog)
@@ -26,6 +27,8 @@ if (CXX_SUPPORTS_NO_EXTENDED_OFFSETOF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-extended-offsetof")
endif ()
+check_library_exists(compression compression_encode_buffer "" HAVE_LIBCOMPRESSION)
+
add_subdirectory(MacOSX)
set(generated_mach_interfaces
@@ -94,32 +97,108 @@ add_library(lldbDebugserverCommon ${lldbDebugserverCommonSources})
if (APPLE)
if(IOS)
- find_library(COCOA_LIBRARY UIKit)
- target_link_libraries(lldbDebugserverCommon INTERFACE ${COCOA_LIBRARY} ${CORE_FOUNDATION_LIBRARY} ${FOUNDATION_LIBRARY})
+ find_library(BACKBOARD_LIBRARY BackBoardServices
+ PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks)
+ find_library(FRONTBOARD_LIBRARY FrontBoardServices
+ PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks)
+ find_library(SPRINGBOARD_LIBRARY SpringBoardServices
+ PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks)
+ find_library(MOBILESERVICES_LIBRARY MobileCoreServices
+ PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks)
+ find_library(LOCKDOWN_LIBRARY lockdown)
+
+ if(NOT BACKBOARD_LIBRARY)
+ set(SKIP_DEBUGSERVER True)
+ endif()
else()
find_library(COCOA_LIBRARY Cocoa)
- target_link_libraries(lldbDebugserverCommon INTERFACE ${COCOA_LIBRARY})
endif()
endif()
-target_link_libraries(lldbDebugserverCommon
+if(HAVE_LIBCOMPRESSION)
+ set(LIBCOMPRESSION compression)
+endif()
+
+if(NOT SKIP_DEBUGSERVER)
+ target_link_libraries(lldbDebugserverCommon
+ INTERFACE ${COCOA_LIBRARY}
+ ${CORE_FOUNDATION_LIBRARY}
+ ${FOUNDATION_LIBRARY}
+ ${BACKBOARD_LIBRARY}
+ ${FRONTBOARD_LIBRARY}
+ ${SPRINGBOARD_LIBRARY}
+ ${MOBILESERVICES_LIBRARY}
+ ${LOCKDOWN_LIBRARY}
+ lldbDebugserverArchSupport
+ lldbDebugserverDarwin_DarwinLog
+ ${LIBCOMPRESSION})
+ if(HAVE_LIBCOMPRESSION)
+ set_property(TARGET lldbDebugserverCommon APPEND PROPERTY
+ COMPILE_DEFINITIONS HAVE_LIBCOMPRESSION)
+ endif()
+ set(LLVM_OPTIONAL_SOURCES ${lldbDebugserverCommonSources})
+ add_lldb_tool(debugserver INCLUDE_IN_FRAMEWORK
+ debugserver.cpp
+
+ LINK_LIBS
+ lldbDebugserverCommon
+ )
+ if(IOS)
+ set_property(TARGET lldbDebugserverCommon APPEND PROPERTY COMPILE_DEFINITIONS
+ WITH_LOCKDOWN
+ WITH_FBS
+ WITH_BKS
+ )
+ set_property(TARGET debugserver APPEND PROPERTY COMPILE_DEFINITIONS
+ WITH_LOCKDOWN
+ WITH_FBS
+ WITH_BKS
+ )
+ set_property(TARGET lldbDebugserverCommon APPEND PROPERTY COMPILE_FLAGS
+ -F${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks
+ )
+ endif()
+endif()
+
+if(IOS)
+ add_library(lldbDebugserverCommon_NonUI ${lldbDebugserverCommonSources})
+ target_link_libraries(lldbDebugserverCommon_NonUI
INTERFACE ${COCOA_LIBRARY}
${CORE_FOUNDATION_LIBRARY}
${FOUNDATION_LIBRARY}
lldbDebugserverArchSupport
- lldbDebugserverDarwin_DarwinLog)
+ lldbDebugserverDarwin_DarwinLog
+ ${LIBCOMPRESSION})
+ if(HAVE_LIBCOMPRESSION)
+ set_property(TARGET lldbDebugserverCommon_NonUI APPEND PROPERTY
+ COMPILE_DEFINITIONS HAVE_LIBCOMPRESSION)
+ endif()
-set(LLVM_OPTIONAL_SOURCES ${lldbDebugserverCommonSources})
-add_lldb_tool(debugserver INCLUDE_IN_FRAMEWORK
- debugserver.cpp
+ add_lldb_tool(debugserver-nonui
+ debugserver.cpp
- LINK_LIBS
- lldbDebugserverCommon
- )
+ LINK_LIBS
+ lldbDebugserverCommon_NonUI
+ )
+endif()
+
+set(entitlements_xml ${CMAKE_CURRENT_SOURCE_DIR}/debugserver-macosx-entitlements.plist)
+if(IOS)
+ set(entitlements_xml ${CMAKE_CURRENT_SOURCE_DIR}/debugserver-entitlements.plist)
+endif()
set(LLDB_CODESIGN_IDENTITY "lldb_codesign"
CACHE STRING "Identity used for code signing. Set to empty string to skip the signing step.")
+set(LLDB_USE_ENTITLEMENTS_Default On)
+if("${LLDB_CODESIGN_IDENTITY}" STREQUAL "lldb_codesign")
+ set(LLDB_USE_ENTITLEMENTS_Default Off)
+endif()
+option(LLDB_USE_ENTITLEMENTS "Use entitlements when codesigning (Defaults Off when using lldb_codesign identity, otherwise On)" ${LLDB_USE_ENTITLEMENTS_Default})
+
if (NOT ("${LLDB_CODESIGN_IDENTITY}" STREQUAL ""))
+ if(LLDB_USE_ENTITLEMENTS)
+ set(entitlements_flags --entitlements ${entitlements_xml})
+ endif()
execute_process(
COMMAND xcrun -f codesign_allocate
OUTPUT_STRIP_TRAILING_WHITESPACE
@@ -129,9 +208,20 @@ if (NOT ("${LLDB_CODESIGN_IDENTITY}" STREQUAL ""))
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env CODESIGN_ALLOCATE=${CODESIGN_ALLOCATE}
codesign --force --sign ${LLDB_CODESIGN_IDENTITY}
+ ${entitlements_flags}
$<TARGET_FILE:debugserver>
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
+ if(IOS)
+ add_custom_command(TARGET debugserver-nonui
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E env CODESIGN_ALLOCATE=${CODESIGN_ALLOCATE}
+ codesign --force --sign ${LLDB_CODESIGN_IDENTITY}
+ ${entitlements_flags}
+ $<TARGET_FILE:debugserver>
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+ )
+ endif()
endif()
diff --git a/tools/debugserver/source/DNB.cpp b/tools/debugserver/source/DNB.cpp
index 9c6c44d18df1..1168f1fc0a1e 100644
--- a/tools/debugserver/source/DNB.cpp
+++ b/tools/debugserver/source/DNB.cpp
@@ -368,7 +368,7 @@ nub_process_t DNBProcessLaunch(
if (launch_err.Fail()) {
const char *launch_err_str = launch_err.AsString();
if (launch_err_str) {
- strncpy(err_str, launch_err_str, err_len - 1);
+ strlcpy(err_str, launch_err_str, err_len - 1);
err_str[err_len - 1] =
'\0'; // Make sure the error string is terminated
}
@@ -1698,7 +1698,7 @@ nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path,
if (realpath(path, max_path)) {
// Found the path relatively...
- ::strncpy(resolved_path, max_path, resolved_path_size);
+ ::strlcpy(resolved_path, max_path, resolved_path_size);
return strlen(resolved_path) + 1 < resolved_path_size;
} else {
// Not a relative path, check the PATH environment variable if the
@@ -1722,7 +1722,7 @@ nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path,
result += path;
struct stat s;
if (stat(result.c_str(), &s) == 0) {
- ::strncpy(resolved_path, result.c_str(), resolved_path_size);
+ ::strlcpy(resolved_path, result.c_str(), resolved_path_size);
return result.size() + 1 < resolved_path_size;
}
}
diff --git a/tools/debugserver/source/DNBDataRef.cpp b/tools/debugserver/source/DNBDataRef.cpp
index d7dce1ab7338..8c12b0afac69 100644
--- a/tools/debugserver/source/DNBDataRef.cpp
+++ b/tools/debugserver/source/DNBDataRef.cpp
@@ -60,7 +60,7 @@ uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const {
uint16_t val = 0;
if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
const uint8_t *p = m_start + *offset_ptr;
- val = *(uint16_t *)p;
+ memcpy(&val, p, sizeof(uint16_t));
if (m_swap)
val = OSSwapInt16(val);
@@ -78,7 +78,7 @@ uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const {
uint32_t val = 0;
if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
const uint8_t *p = m_start + *offset_ptr;
- val = *(uint32_t *)p;
+ memcpy(&val, p, sizeof(uint32_t));
if (m_swap)
val = OSSwapInt32(val);
@@ -95,7 +95,7 @@ uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const {
uint64_t val = 0;
if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
const uint8_t *p = m_start + *offset_ptr;
- val = *(uint64_t *)p;
+ memcpy(&val, p, sizeof(uint64_t));
if (m_swap)
val = OSSwapInt64(val);
@@ -123,7 +123,7 @@ uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const {
return Get32(offset_ptr);
break;
default:
- assert(!"GetMax32 unhandled case!");
+ assert(false && "GetMax32 unhandled case!");
break;
}
return 0;
@@ -150,7 +150,7 @@ uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const {
return Get64(offset_ptr);
break;
default:
- assert(!"GetMax64 unhandled case!");
+ assert(false && "GetMax64 unhandled case!");
break;
}
return 0;
@@ -174,7 +174,7 @@ const char *DNBDataRef::GetCStr(offset_t *offset_ptr,
uint32_t fixed_length) const {
const char *s = NULL;
if (m_start < m_end) {
- s = (char *)m_start + *offset_ptr;
+ s = (const char *)m_start + *offset_ptr;
// Advance the offset
if (fixed_length)
diff --git a/tools/debugserver/source/DNBRegisterInfo.cpp b/tools/debugserver/source/DNBRegisterInfo.cpp
index fadcc5ddb06e..b85b39378183 100644
--- a/tools/debugserver/source/DNBRegisterInfo.cpp
+++ b/tools/debugserver/source/DNBRegisterInfo.cpp
@@ -35,7 +35,7 @@ bool DNBRegisterValueClass::IsValid() const {
do { \
if (pos < end) { \
if (i > 0) { \
- strncpy(pos, ", ", end - pos); \
+ strlcpy(pos, ", ", end - pos); \
pos += 2; \
} \
} \
@@ -69,7 +69,7 @@ void DNBRegisterValueClass::Dump(const char *pre, const char *post) const {
value.v_uint64[1]);
break;
default:
- strncpy(str, "0x", 3);
+ strlcpy(str, "0x", 3);
pos = str + 2;
for (uint32_t i = 0; i < info.size; ++i) {
if (pos < end)
diff --git a/tools/debugserver/source/JSON.cpp b/tools/debugserver/source/JSON.cpp
index c914f2498f09..439918b6fcc4 100644
--- a/tools/debugserver/source/JSON.cpp
+++ b/tools/debugserver/source/JSON.cpp
@@ -58,7 +58,6 @@ uint64_t JSONNumber::GetAsUnsigned() const {
case DataType::Double:
return (uint64_t)m_data.m_double;
}
- assert("Unhandled data type");
}
int64_t JSONNumber::GetAsSigned() const {
@@ -70,7 +69,6 @@ int64_t JSONNumber::GetAsSigned() const {
case DataType::Double:
return (int64_t)m_data.m_double;
}
- assert("Unhandled data type");
}
double JSONNumber::GetAsDouble() const {
@@ -82,7 +80,6 @@ double JSONNumber::GetAsDouble() const {
case DataType::Double:
return m_data.m_double;
}
- assert("Unhandled data type");
}
void JSONNumber::Write(std::ostream &s) {
diff --git a/tools/debugserver/source/MacOSX/MachException.cpp b/tools/debugserver/source/MacOSX/MachException.cpp
index 5f085867db2c..cc309e47d86b 100644
--- a/tools/debugserver/source/MacOSX/MachException.cpp
+++ b/tools/debugserver/source/MacOSX/MachException.cpp
@@ -47,13 +47,13 @@ extern "C" kern_return_t catch_mach_exception_raise_state_identity(
extern "C" boolean_t mach_exc_server(mach_msg_header_t *InHeadP,
mach_msg_header_t *OutHeadP);
-// Any access to the g_message variable should be done by locking the
-// g_message_mutex first, using the g_message variable, then unlocking
-// the g_message_mutex. See MachException::Message::CatchExceptionRaise()
-// for sample code.
-
+// Note: g_message points to the storage allocated to catch the data from
+// catching the current exception raise. It's populated when we catch a raised
+// exception which can't immediately be replied to.
+//
+// If it becomes possible to catch exceptions from multiple threads
+// simultaneously, accesses to g_message would need to be mutually exclusive.
static MachException::Data *g_message = NULL;
-// static pthread_mutex_t g_message_mutex = PTHREAD_MUTEX_INITIALIZER;
extern "C" kern_return_t catch_mach_exception_raise_state(
mach_port_t exc_port, exception_type_t exc_type,
@@ -113,8 +113,7 @@ catch_mach_exception_raise(mach_port_t exc_port, mach_port_t thread_port,
g_message->task_port = task_port;
g_message->thread_port = thread_port;
g_message->exc_type = exc_type;
- for (mach_msg_type_number_t i=0; i<exc_data_count; ++i)
- g_message->exc_data.push_back(exc_data[i]);
+ g_message->AppendExceptionData(exc_data, exc_data_count);
return KERN_SUCCESS;
} else if (!MachTask::IsValid(g_message->task_port)) {
// Our original exception port isn't valid anymore check for a SIGTRAP
@@ -126,8 +125,7 @@ catch_mach_exception_raise(mach_port_t exc_port, mach_port_t thread_port,
g_message->task_port = task_port;
g_message->thread_port = thread_port;
g_message->exc_type = exc_type;
- for (mach_msg_type_number_t i=0; i<exc_data_count; ++i)
- g_message->exc_data.push_back(exc_data[i]);
+ g_message->AppendExceptionData(exc_data, exc_data_count);
return KERN_SUCCESS;
}
}
@@ -272,9 +270,6 @@ kern_return_t MachException::Message::Receive(mach_port_t port,
bool MachException::Message::CatchExceptionRaise(task_t task) {
bool success = false;
- // locker will keep a mutex locked until it goes out of scope
- // PThreadMutex::Locker locker(&g_message_mutex);
- // DNBLogThreaded("calling mach_exc_server");
state.task_port = task;
g_message = &state;
// The exc_server function is the MIG generated server handling function
diff --git a/tools/debugserver/source/MacOSX/MachException.h b/tools/debugserver/source/MacOSX/MachException.h
index a45a41e01f42..e1af12def10a 100644
--- a/tools/debugserver/source/MacOSX/MachException.h
+++ b/tools/debugserver/source/MacOSX/MachException.h
@@ -71,6 +71,15 @@ public:
return (exc_type == EXC_BREAKPOINT ||
((exc_type == EXC_SOFTWARE) && exc_data[0] == 1));
}
+ void AppendExceptionData(mach_exception_data_t Data,
+ mach_msg_type_number_t Count) {
+ mach_exception_data_type_t Buf;
+ for (mach_msg_type_number_t i = 0; i < Count; ++i) {
+ // Perform an unaligned copy.
+ memcpy(&Buf, Data + i, sizeof(mach_exception_data_type_t));
+ exc_data.push_back(Buf);
+ }
+ }
void Dump() const;
void DumpStopReason() const;
bool GetStopInfo(struct DNBThreadStopInfo *stop_info) const;
diff --git a/tools/debugserver/source/MacOSX/MachProcess.mm b/tools/debugserver/source/MacOSX/MachProcess.mm
index a93f724849b8..d4dff223bde0 100644
--- a/tools/debugserver/source/MacOSX/MachProcess.mm
+++ b/tools/debugserver/source/MacOSX/MachProcess.mm
@@ -112,7 +112,9 @@ static bool CallBoardSystemServiceOpenApplication(NSString *bundleIDNSStr,
if (!cstr)
cstr = "<Unknown Bundle ID>";
- DNBLog("About to launch process for bundle ID: %s", cstr);
+ NSString *description = [options description];
+ DNBLog("About to launch process for bundle ID: %s - options:\n%s", cstr,
+ [description UTF8String]);
[system_service
openApplication:bundleIDNSStr
options:options
@@ -188,6 +190,28 @@ static bool CallBoardSystemServiceOpenApplication(NSString *bundleIDNSStr,
}
#endif
+#if defined(WITH_BKS) || defined(WITH_FBS)
+static void SplitEventData(const char *data, std::vector<std::string> &elements)
+{
+ elements.clear();
+ if (!data)
+ return;
+
+ const char *start = data;
+
+ while (*start != '\0') {
+ const char *token = strchr(start, ':');
+ if (!token) {
+ elements.push_back(std::string(start));
+ return;
+ }
+ if (token != start)
+ elements.push_back(std::string(start, token - start));
+ start = ++token;
+ }
+}
+#endif
+
#ifdef WITH_BKS
#import <Foundation/Foundation.h>
extern "C" {
@@ -222,21 +246,31 @@ static void SetBKSError(NSInteger error_code, DNBError &error) {
static bool BKSAddEventDataToOptions(NSMutableDictionary *options,
const char *event_data,
DNBError &option_error) {
- if (strcmp(event_data, "BackgroundContentFetching") == 0) {
- DNBLog("Setting ActivateForEvent key in options dictionary.");
- NSDictionary *event_details = [NSDictionary dictionary];
- NSDictionary *event_dictionary = [NSDictionary
- dictionaryWithObject:event_details
- forKey:
- BKSActivateForEventOptionTypeBackgroundContentFetching];
- [options setObject:event_dictionary
- forKey:BKSOpenApplicationOptionKeyActivateForEvent];
- return true;
- } else {
- DNBLogError("Unrecognized event type: %s. Ignoring.", event_data);
- option_error.SetErrorString("Unrecognized event data.");
- return false;
+ std::vector<std::string> values;
+ SplitEventData(event_data, values);
+ bool found_one = false;
+ for (std::string value : values)
+ {
+ if (value.compare("BackgroundContentFetching") == 0) {
+ DNBLog("Setting ActivateForEvent key in options dictionary.");
+ NSDictionary *event_details = [NSDictionary dictionary];
+ NSDictionary *event_dictionary = [NSDictionary
+ dictionaryWithObject:event_details
+ forKey:
+ BKSActivateForEventOptionTypeBackgroundContentFetching];
+ [options setObject:event_dictionary
+ forKey:BKSOpenApplicationOptionKeyActivateForEvent];
+ found_one = true;
+ } else if (value.compare("ActivateSuspended") == 0) {
+ DNBLog("Setting ActivateSuspended key in options dictionary.");
+ [options setObject:@YES forKey: BKSOpenApplicationOptionKeyActivateSuspended];
+ found_one = true;
+ } else {
+ DNBLogError("Unrecognized event type: %s. Ignoring.", value.c_str());
+ option_error.SetErrorString("Unrecognized event data");
+ }
}
+ return found_one;
}
static NSMutableDictionary *BKSCreateOptionsDictionary(
@@ -322,21 +356,31 @@ static void SetFBSError(NSInteger error_code, DNBError &error) {
static bool FBSAddEventDataToOptions(NSMutableDictionary *options,
const char *event_data,
DNBError &option_error) {
- if (strcmp(event_data, "BackgroundContentFetching") == 0) {
- DNBLog("Setting ActivateForEvent key in options dictionary.");
- NSDictionary *event_details = [NSDictionary dictionary];
- NSDictionary *event_dictionary = [NSDictionary
- dictionaryWithObject:event_details
- forKey:
- FBSActivateForEventOptionTypeBackgroundContentFetching];
- [options setObject:event_dictionary
- forKey:FBSOpenApplicationOptionKeyActivateForEvent];
- return true;
- } else {
- DNBLogError("Unrecognized event type: %s. Ignoring.", event_data);
- option_error.SetErrorString("Unrecognized event data.");
- return false;
+ std::vector<std::string> values;
+ SplitEventData(event_data, values);
+ bool found_one = false;
+ for (std::string value : values)
+ {
+ if (value.compare("BackgroundContentFetching") == 0) {
+ DNBLog("Setting ActivateForEvent key in options dictionary.");
+ NSDictionary *event_details = [NSDictionary dictionary];
+ NSDictionary *event_dictionary = [NSDictionary
+ dictionaryWithObject:event_details
+ forKey:
+ FBSActivateForEventOptionTypeBackgroundContentFetching];
+ [options setObject:event_dictionary
+ forKey:FBSOpenApplicationOptionKeyActivateForEvent];
+ found_one = true;
+ } else if (value.compare("ActivateSuspended") == 0) {
+ DNBLog("Setting ActivateSuspended key in options dictionary.");
+ [options setObject:@YES forKey: FBSOpenApplicationOptionKeyActivateSuspended];
+ found_one = true;
+ } else {
+ DNBLogError("Unrecognized event type: %s. Ignoring.", value.c_str());
+ option_error.SetErrorString("Unrecognized event data.");
+ }
}
+ return found_one;
}
static NSMutableDictionary *
@@ -3105,7 +3149,8 @@ pid_t MachProcess::PosixSpawnChildForPTraceDebugging(
::chdir(working_directory);
err.SetError(::posix_spawnp(&pid, path, &file_actions, &attr,
- (char *const *)argv, (char *const *)envp),
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp)),
DNBError::POSIX);
if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = "
@@ -3117,8 +3162,9 @@ pid_t MachProcess::PosixSpawnChildForPTraceDebugging(
if (working_directory)
::chdir(working_directory);
- err.SetError(::posix_spawnp(&pid, path, NULL, &attr, (char *const *)argv,
- (char *const *)envp),
+ err.SetError(::posix_spawnp(&pid, path, NULL, &attr,
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp)),
DNBError::POSIX);
if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = "
@@ -3215,7 +3261,7 @@ pid_t MachProcess::ForkChildForPTraceDebugging(const char *path,
::sleep(1);
// Turn this process into
- ::execv(path, (char *const *)argv);
+ ::execv(path, const_cast<char *const *>(argv));
}
// Exit with error code. Child process should have taken
// over in above exec call and if the exec fails it will
diff --git a/tools/debugserver/source/MacOSX/MachTask.mm b/tools/debugserver/source/MacOSX/MachTask.mm
index bd7047ecdff7..1d177bd53cb7 100644
--- a/tools/debugserver/source/MacOSX/MachTask.mm
+++ b/tools/debugserver/source/MacOSX/MachTask.mm
@@ -188,7 +188,7 @@ nub_size_t MachTask::WriteMemory(nub_addr_t addr, nub_size_t size,
(uint64_t)addr, (uint64_t)size, buf, (uint64_t)n);
if (DNBLogCheckLogBit(LOG_MEMORY_DATA_LONG) ||
(DNBLogCheckLogBit(LOG_MEMORY_DATA_SHORT) && size <= 8)) {
- DNBDataRef data((uint8_t *)buf, n, false);
+ DNBDataRef data((const uint8_t *)buf, n, false);
data.Dump(0, static_cast<DNBDataRef::offset_t>(n), addr,
DNBDataRef::TypeUInt8, 16);
}
diff --git a/tools/debugserver/source/MacOSX/MachThread.cpp b/tools/debugserver/source/MacOSX/MachThread.cpp
index 5686e42e4a49..fc97825786a0 100644
--- a/tools/debugserver/source/MacOSX/MachThread.cpp
+++ b/tools/debugserver/source/MacOSX/MachThread.cpp
@@ -164,15 +164,15 @@ const char *MachThread::GetBasicInfoAsString() const {
// size_t run_state_str_size = sizeof(run_state_str);
// switch (basicInfo.run_state)
// {
- // case TH_STATE_RUNNING: strncpy(run_state_str, "running",
+ // case TH_STATE_RUNNING: strlcpy(run_state_str, "running",
// run_state_str_size); break;
- // case TH_STATE_STOPPED: strncpy(run_state_str, "stopped",
+ // case TH_STATE_STOPPED: strlcpy(run_state_str, "stopped",
// run_state_str_size); break;
- // case TH_STATE_WAITING: strncpy(run_state_str, "waiting",
+ // case TH_STATE_WAITING: strlcpy(run_state_str, "waiting",
// run_state_str_size); break;
- // case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str,
+ // case TH_STATE_UNINTERRUPTIBLE: strlcpy(run_state_str,
// "uninterruptible", run_state_str_size); break;
- // case TH_STATE_HALTED: strncpy(run_state_str, "halted",
+ // case TH_STATE_HALTED: strlcpy(run_state_str, "halted",
// run_state_str_size); break;
// default: snprintf(run_state_str,
// run_state_str_size, "%d", basicInfo.run_state); break; // ???
diff --git a/tools/debugserver/source/MacOSX/OsLogger.cpp b/tools/debugserver/source/MacOSX/OsLogger.cpp
index 6cc04a8a7c83..40aeec73f0aa 100644
--- a/tools/debugserver/source/MacOSX/OsLogger.cpp
+++ b/tools/debugserver/source/MacOSX/OsLogger.cpp
@@ -56,9 +56,7 @@ void DarwinLogCallback(void *baton, uint32_t flags, const char *format,
}
}
-DNBCallbackLog OsLogger::GetLogFunction() {
- return _os_log_impl ? DarwinLogCallback : nullptr;
-}
+DNBCallbackLog OsLogger::GetLogFunction() { return DarwinLogCallback; }
#else
diff --git a/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
index 6cc5ae6c36c4..e0e8e27a1c2d 100644
--- a/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
+++ b/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
@@ -1086,7 +1086,7 @@ const DNBRegisterInfo DNBArchImplI386::g_fpu_registers_no_avx[] = {
{e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw),
FPU_OFFSET(fsw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
- {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, FPU_SIZE_UINT(ftw),
+ {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, 2 /* sizeof __fpu_ftw + sizeof __fpu_rsrv1 */,
FPU_OFFSET(ftw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
{e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop),
@@ -1177,7 +1177,7 @@ const DNBRegisterInfo DNBArchImplI386::g_fpu_registers_avx[] = {
{e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw),
AVX_OFFSET(fsw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
- {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, FPU_SIZE_UINT(ftw),
+ {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, 2 /* sizeof __fpu_ftw + sizeof __fpu_rsrv1 */,
AVX_OFFSET(ftw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
{e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop),
@@ -1414,7 +1414,7 @@ bool DNBArchImplI386::GetRegisterValue(uint32_t set, uint32_t reg,
*((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw));
return true;
case fpu_ftw:
- value->value.uint8 = m_state.context.fpu.no_avx.__fpu_ftw;
+ memcpy (&value->value.uint16, &m_state.context.fpu.no_avx.__fpu_ftw, 2);
return true;
case fpu_fop:
value->value.uint16 = m_state.context.fpu.no_avx.__fpu_fop;
@@ -1607,7 +1607,7 @@ bool DNBArchImplI386::SetRegisterValue(uint32_t set, uint32_t reg,
success = true;
break;
case fpu_ftw:
- m_state.context.fpu.no_avx.__fpu_ftw = value->value.uint8;
+ memcpy (&m_state.context.fpu.no_avx.__fpu_ftw, &value->value.uint16, 2);
success = true;
break;
case fpu_fop:
@@ -1886,7 +1886,7 @@ nub_size_t DNBArchImplI386::SetRegisterContext(const void *buf,
if (size > buf_len)
size = buf_len;
- uint8_t *p = (uint8_t *)buf;
+ const uint8_t *p = (const uint8_t *)buf;
// Copy the GPR registers
memcpy(&m_state.context.gpr, p, sizeof(GPR));
p += sizeof(GPR);
@@ -1927,7 +1927,7 @@ nub_size_t DNBArchImplI386::SetRegisterContext(const void *buf,
p += sizeof(EXC);
// make sure we end up with exactly what we think we should have
- size_t bytes_written = p - (uint8_t *)buf;
+ size_t bytes_written = p - (const uint8_t *)buf;
UNUSED_IF_ASSERT_DISABLED(bytes_written);
assert(bytes_written == size);
kern_return_t kret;
diff --git a/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
index 416b21f29958..86843fd97c06 100644
--- a/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
+++ b/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
@@ -1380,7 +1380,7 @@ const DNBRegisterInfo DNBArchImplX86_64::g_fpu_registers_no_avx[] = {
FPU_OFFSET(fcw), -1U, -1U, -1U, -1U, NULL, NULL},
{e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw),
FPU_OFFSET(fsw), -1U, -1U, -1U, -1U, NULL, NULL},
- {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, FPU_SIZE_UINT(ftw),
+ {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, 2 /* sizeof __fpu_ftw + sizeof __fpu_rsrv1 */,
FPU_OFFSET(ftw), -1U, -1U, -1U, -1U, NULL, NULL},
{e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop),
FPU_OFFSET(fop), -1U, -1U, -1U, -1U, NULL, NULL},
@@ -1495,7 +1495,7 @@ const DNBRegisterInfo DNBArchImplX86_64::g_fpu_registers_avx[] = {
AVX_OFFSET(fcw), -1U, -1U, -1U, -1U, NULL, NULL},
{e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw),
AVX_OFFSET(fsw), -1U, -1U, -1U, -1U, NULL, NULL},
- {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, FPU_SIZE_UINT(ftw),
+ {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, 2 /* sizeof __fpu_ftw + sizeof __fpu_rsrv1 */,
AVX_OFFSET(ftw), -1U, -1U, -1U, -1U, NULL, NULL},
{e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop),
AVX_OFFSET(fop), -1U, -1U, -1U, -1U, NULL, NULL},
@@ -1776,7 +1776,7 @@ bool DNBArchImplX86_64::GetRegisterValue(uint32_t set, uint32_t reg,
*((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw));
return true;
case fpu_ftw:
- value->value.uint8 = m_state.context.fpu.no_avx.__fpu_ftw;
+ memcpy (&value->value.uint16, &m_state.context.fpu.no_avx.__fpu_ftw, 2);
return true;
case fpu_fop:
value->value.uint16 = m_state.context.fpu.no_avx.__fpu_fop;
@@ -1932,7 +1932,7 @@ bool DNBArchImplX86_64::SetRegisterValue(uint32_t set, uint32_t reg,
success = true;
break;
case fpu_ftw:
- m_state.context.fpu.no_avx.__fpu_ftw = value->value.uint8;
+ memcpy (&m_state.context.fpu.no_avx.__fpu_ftw, &value->value.uint8, 2);
success = true;
break;
case fpu_fop:
@@ -2164,7 +2164,7 @@ nub_size_t DNBArchImplX86_64::SetRegisterContext(const void *buf,
if (size > buf_len)
size = static_cast<uint32_t>(buf_len);
- uint8_t *p = (uint8_t *)buf;
+ const uint8_t *p = (const uint8_t *)buf;
// Copy the GPR registers
memcpy(&m_state.context.gpr, p, sizeof(GPR));
p += sizeof(GPR);
@@ -2205,7 +2205,7 @@ nub_size_t DNBArchImplX86_64::SetRegisterContext(const void *buf,
p += sizeof(EXC);
// make sure we end up with exactly what we think we should have
- size_t bytes_written = p - (uint8_t *)buf;
+ size_t bytes_written = p - (const uint8_t *)buf;
UNUSED_IF_ASSERT_DISABLED(bytes_written);
assert(bytes_written == size);
diff --git a/tools/debugserver/source/RNBRemote.cpp b/tools/debugserver/source/RNBRemote.cpp
index cf6b4b626914..0a2eef3feacd 100644
--- a/tools/debugserver/source/RNBRemote.cpp
+++ b/tools/debugserver/source/RNBRemote.cpp
@@ -710,29 +710,29 @@ std::string RNBRemote::CompressString(const std::string &orig) {
size_t compressed_size = 0;
#if defined(HAVE_LIBCOMPRESSION)
- if (compression_decode_buffer &&
- compression_type == compression_types::lz4) {
+ if (compression_type == compression_types::lz4) {
compressed_size = compression_encode_buffer(
- encoded_data.data(), encoded_data_buf_size, (uint8_t *)orig.c_str(),
- orig.size(), nullptr, COMPRESSION_LZ4_RAW);
+ encoded_data.data(), encoded_data_buf_size,
+ (const uint8_t *)orig.c_str(), orig.size(), nullptr,
+ COMPRESSION_LZ4_RAW);
}
- if (compression_decode_buffer &&
- compression_type == compression_types::zlib_deflate) {
+ if (compression_type == compression_types::zlib_deflate) {
compressed_size = compression_encode_buffer(
- encoded_data.data(), encoded_data_buf_size, (uint8_t *)orig.c_str(),
- orig.size(), nullptr, COMPRESSION_ZLIB);
+ encoded_data.data(), encoded_data_buf_size,
+ (const uint8_t *)orig.c_str(), orig.size(), nullptr,
+ COMPRESSION_ZLIB);
}
- if (compression_decode_buffer &&
- compression_type == compression_types::lzma) {
+ if (compression_type == compression_types::lzma) {
compressed_size = compression_encode_buffer(
- encoded_data.data(), encoded_data_buf_size, (uint8_t *)orig.c_str(),
- orig.size(), nullptr, COMPRESSION_LZMA);
+ encoded_data.data(), encoded_data_buf_size,
+ (const uint8_t *)orig.c_str(), orig.size(), nullptr,
+ COMPRESSION_LZMA);
}
- if (compression_decode_buffer &&
- compression_type == compression_types::lzfse) {
+ if (compression_type == compression_types::lzfse) {
compressed_size = compression_encode_buffer(
- encoded_data.data(), encoded_data_buf_size, (uint8_t *)orig.c_str(),
- orig.size(), nullptr, COMPRESSION_LZFSE);
+ encoded_data.data(), encoded_data_buf_size,
+ (const uint8_t *)orig.c_str(), orig.size(), nullptr,
+ COMPRESSION_LZFSE);
}
#endif
@@ -2247,7 +2247,7 @@ rnb_err_t set_logging(const char *p) {
continue;
}
char *fn = (char *) alloca (c - p + 1);
- strncpy (fn, p, c - p);
+ strlcpy (fn, p, c - p);
fn[c - p] = '\0';
// A file name of "asl" is special and is another way to indicate
@@ -2862,7 +2862,7 @@ rnb_err_t RNBRemote::SendStopReplyPacketForThread(nub_thread_t tid) {
else {
// the thread name contains special chars, send as hex bytes
ostrm << std::hex << "hexname:";
- uint8_t *u_thread_name = (uint8_t *)thread_name;
+ const uint8_t *u_thread_name = (const uint8_t *)thread_name;
for (size_t i = 0; i < thread_name_len; i++)
ostrm << RAWHEX8(u_thread_name[i]);
ostrm << ';';
@@ -3049,7 +3049,7 @@ rnb_err_t RNBRemote::HandlePacket_last_signal(const char *unused) {
// If we have an empty exit packet, lets fill one in to be safe.
if (!pid_exited_packet[0]) {
- strncpy(pid_exited_packet, "W00", sizeof(pid_exited_packet) - 1);
+ strlcpy(pid_exited_packet, "W00", sizeof(pid_exited_packet) - 1);
pid_exited_packet[sizeof(pid_exited_packet) - 1] = '\0';
}
@@ -3621,7 +3621,7 @@ rnb_err_t RNBRemote::HandlePacket_qSupported(const char *p) {
#if defined(HAVE_LIBCOMPRESSION)
// libcompression is weak linked so test if compression_decode_buffer() is
// available
- if (enable_compression && compression_decode_buffer != NULL) {
+ if (enable_compression) {
strcat(buf, ";SupportedCompressions=lzfse,zlib-deflate,lz4,lzma;"
"DefaultCompressionMinSize=");
char numbuf[16];
@@ -3667,7 +3667,7 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) {
return RNBRemote::HandlePacket_s("s");
} else if (strstr(p, "vCont") == p) {
DNBThreadResumeActions thread_actions;
- char *c = (char *)(p += strlen("vCont"));
+ char *c = const_cast<char *>(p += strlen("vCont"));
char *c_end = c + strlen(c);
if (*c == '?')
return SendPacket("vCont;c;C;s;S");
@@ -4307,24 +4307,22 @@ rnb_err_t RNBRemote::HandlePacket_QEnableCompression(const char *p) {
}
#if defined(HAVE_LIBCOMPRESSION)
- if (compression_decode_buffer != NULL) {
- if (strstr(p, "type:zlib-deflate;") != nullptr) {
- EnableCompressionNextSendPacket(compression_types::zlib_deflate);
- m_compression_minsize = new_compression_minsize;
- return SendPacket("OK");
- } else if (strstr(p, "type:lz4;") != nullptr) {
- EnableCompressionNextSendPacket(compression_types::lz4);
- m_compression_minsize = new_compression_minsize;
- return SendPacket("OK");
- } else if (strstr(p, "type:lzma;") != nullptr) {
- EnableCompressionNextSendPacket(compression_types::lzma);
- m_compression_minsize = new_compression_minsize;
- return SendPacket("OK");
- } else if (strstr(p, "type:lzfse;") != nullptr) {
- EnableCompressionNextSendPacket(compression_types::lzfse);
- m_compression_minsize = new_compression_minsize;
- return SendPacket("OK");
- }
+ if (strstr(p, "type:zlib-deflate;") != nullptr) {
+ EnableCompressionNextSendPacket(compression_types::zlib_deflate);
+ m_compression_minsize = new_compression_minsize;
+ return SendPacket("OK");
+ } else if (strstr(p, "type:lz4;") != nullptr) {
+ EnableCompressionNextSendPacket(compression_types::lz4);
+ m_compression_minsize = new_compression_minsize;
+ return SendPacket("OK");
+ } else if (strstr(p, "type:lzma;") != nullptr) {
+ EnableCompressionNextSendPacket(compression_types::lzma);
+ m_compression_minsize = new_compression_minsize;
+ return SendPacket("OK");
+ } else if (strstr(p, "type:lzfse;") != nullptr) {
+ EnableCompressionNextSendPacket(compression_types::lzfse);
+ m_compression_minsize = new_compression_minsize;
+ return SendPacket("OK");
}
#endif
diff --git a/tools/debugserver/source/RNBServices.cpp b/tools/debugserver/source/RNBServices.cpp
index d0b7e099d238..9f90f349f3af 100644
--- a/tools/debugserver/source/RNBServices.cpp
+++ b/tools/debugserver/source/RNBServices.cpp
@@ -220,7 +220,7 @@ int ListApplications(std::string &plist, bool opt_runningApps,
CFIndex size = ::CFDataGetLength(plistData.get());
const UInt8 *bytes = ::CFDataGetBytePtr(plistData.get());
if (bytes != NULL && size > 0) {
- plist.assign((char *)bytes, size);
+ plist.assign((const char *)bytes, size);
return 0; // Success
} else {
DNBLogError("empty application property list.");
diff --git a/tools/debugserver/source/RNBSocket.cpp b/tools/debugserver/source/RNBSocket.cpp
index f1db5e419ff2..88136c210acc 100644
--- a/tools/debugserver/source/RNBSocket.cpp
+++ b/tools/debugserver/source/RNBSocket.cpp
@@ -373,9 +373,10 @@ rnb_err_t RNBSocket::Write(const void *buffer, size_t length) {
DNBLogThreadedIf(
LOG_RNB_PACKETS, "putpkt: %*s", (int)length,
- (char *)
+ (const char *)
buffer); // All data is string based in debugserver, so this is safe
- DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, (char *)buffer);
+ DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length,
+ (const char *)buffer);
return rnb_success;
}
diff --git a/tools/debugserver/source/debugserver.cpp b/tools/debugserver/source/debugserver.cpp
index 318e72e971a5..8291f8d32b51 100644
--- a/tools/debugserver/source/debugserver.cpp
+++ b/tools/debugserver/source/debugserver.cpp
@@ -232,7 +232,7 @@ RNBRunLoopMode RNBRunLoopLaunchInferior(RNBRemote *remote,
// were given and hope for the best
if (!DNBResolveExecutablePath(inferior_argv[0], resolved_path,
sizeof(resolved_path)))
- ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
+ ::strlcpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
char launch_err_str[PATH_MAX];
launch_err_str[0] = '\0';
@@ -676,7 +676,7 @@ static void PortWasBoundCallbackUnixSocket(const void *baton, in_port_t port) {
}
saddr_un.sun_family = AF_UNIX;
- ::strncpy(saddr_un.sun_path, unix_socket_name,
+ ::strlcpy(saddr_un.sun_path, unix_socket_name,
sizeof(saddr_un.sun_path) - 1);
saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
saddr_un.sun_len = SUN_LEN(&saddr_un);
@@ -1366,7 +1366,7 @@ int main(int argc, char *argv[]) {
DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
} else if (argv[0][0] == '/') {
port = INT32_MAX;
- strncpy(str, argv[0], sizeof(str));
+ strlcpy(str, argv[0], sizeof(str));
} else {
show_usage_and_exit(2);
}
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 6384d5a92c2c..1fac2e5d1687 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -1,5 +1,3 @@
-include(${LLDB_PROJECT_ROOT}/cmake/LLDBDependencies.cmake)
-
if ((CMAKE_SYSTEM_NAME MATCHES "Windows") OR
(CMAKE_SYSTEM_NAME MATCHES "NetBSD" ))
# These targets do not have getopt support, so they rely on the one provided by
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp
index 102ba775da91..7e1dec7a34fa 100644
--- a/tools/driver/Driver.cpp
+++ b/tools/driver/Driver.cpp
@@ -9,6 +9,7 @@
#include "Driver.h"
+#include <atomic>
#include <csignal>
#include <fcntl.h>
#include <limits.h>
@@ -1177,17 +1178,16 @@ void sigwinch_handler(int signo) {
}
void sigint_handler(int signo) {
- static bool g_interrupt_sent = false;
+ static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
if (g_driver) {
- if (!g_interrupt_sent) {
- g_interrupt_sent = true;
+ if (!g_interrupt_sent.test_and_set()) {
g_driver->GetDebugger().DispatchInputInterrupt();
- g_interrupt_sent = false;
+ g_interrupt_sent.clear();
return;
}
}
- exit(signo);
+ _exit(signo);
}
void sigtstp_handler(int signo) {
diff --git a/tools/intel-features/CMakeLists.txt b/tools/intel-features/CMakeLists.txt
new file mode 100644
index 000000000000..b5316540fdf3
--- /dev/null
+++ b/tools/intel-features/CMakeLists.txt
@@ -0,0 +1,67 @@
+# 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()
+
+if (NOT CLI_WRAPPER_PREPROCESSORS)
+ return()
+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)
+endif()
+
+install(TARGETS lldbIntelFeatures
+ LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX})
diff --git a/tools/intel-features/README.txt b/tools/intel-features/README.txt
new file mode 100644
index 000000000000..d46bf1392dcf
--- /dev/null
+++ b/tools/intel-features/README.txt
@@ -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.
diff --git a/tools/intel-features/cli-wrapper.cpp b/tools/intel-features/cli-wrapper.cpp
new file mode 100644
index 000000000000..8b1471509663
--- /dev/null
+++ b/tools/intel-features/cli-wrapper.cpp
@@ -0,0 +1,43 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef BUILD_INTEL_MPX
+#include "intel-mpx/cli-wrapper-mpxtable.h"
+#endif
+
+#ifdef BUILD_INTEL_PT
+#include "intel-pt/cli-wrapper-pt.h"
+#endif
+
+#include "lldb/API/SBDebugger.h"
+
+namespace lldb {
+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;
+}
diff --git a/tools/intel-features/intel-mpx/CMakeLists.txt b/tools/intel-features/intel-mpx/CMakeLists.txt
new file mode 100644
index 000000000000..319f712b82bd
--- /dev/null
+++ b/tools/intel-features/intel-mpx/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lldb_library(lldbIntelMPX
+ cli-wrapper-mpxtable.cpp
+
+ LINK_LIBS
+ liblldb
+
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/tools/intel-mpx/IntelMPXTablePlugin.cpp b/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp
index 0f86ce661def..e654f076fb3a 100644
--- a/tools/intel-mpx/IntelMPXTablePlugin.cpp
+++ b/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp
@@ -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 debugger, lldb::SBTarget &target,
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);
diff --git a/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.h b/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.h
new file mode 100644
index 000000000000..00028a93fb43
--- /dev/null
+++ b/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.h
@@ -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);
diff --git a/tools/intel-mpx/test/Makefile b/tools/intel-features/intel-mpx/test/Makefile
index b18044407a70..b18044407a70 100644
--- a/tools/intel-mpx/test/Makefile
+++ b/tools/intel-features/intel-mpx/test/Makefile
diff --git a/tools/intel-mpx/test/README.txt b/tools/intel-features/intel-mpx/test/README.txt
index 314e78d3e0eb..6797eff30a79 100644
--- a/tools/intel-mpx/test/README.txt
+++ b/tools/intel-features/intel-mpx/test/README.txt
@@ -2,5 +2,5 @@ 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.
+and copy into it the contents of this directory.
diff --git a/tools/intel-mpx/test/TestMPXTable.py b/tools/intel-features/intel-mpx/test/TestMPXTable.py
index f2468abd59a1..f571252e26f7 100644
--- a/tools/intel-mpx/test/TestMPXTable.py
+++ b/tools/intel-features/intel-mpx/test/TestMPXTable.py
@@ -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)
diff --git a/tools/intel-mpx/test/main.cpp b/tools/intel-features/intel-mpx/test/main.cpp
index 214332338d87..110befb1e250 100644
--- a/tools/intel-mpx/test/main.cpp
+++ b/tools/intel-features/intel-mpx/test/main.cpp
@@ -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;
diff --git a/tools/intel-features/intel-pt/CMakeLists.txt b/tools/intel-features/intel-pt/CMakeLists.txt
new file mode 100644
index 000000000000..9750ed83ce2d
--- /dev/null
+++ b/tools/intel-features/intel-pt/CMakeLists.txt
@@ -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
+ )
diff --git a/tools/intel-features/intel-pt/Decoder.cpp b/tools/intel-features/intel-pt/Decoder.cpp
new file mode 100644
index 000000000000..0c385adc811c
--- /dev/null
+++ b/tools/intel-features/intel-pt/Decoder.cpp
@@ -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;
+ }
+}
diff --git a/tools/intel-features/intel-pt/Decoder.h b/tools/intel-features/intel-pt/Decoder.h
new file mode 100644
index 000000000000..dc2794ac3bc3
--- /dev/null
+++ b/tools/intel-features/intel-pt/Decoder.h
@@ -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_
diff --git a/tools/intel-features/intel-pt/PTDecoder.cpp b/tools/intel-features/intel-pt/PTDecoder.cpp
new file mode 100644
index 000000000000..4f3554e84d3c
--- /dev/null
+++ b/tools/intel-features/intel-pt/PTDecoder.cpp
@@ -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);
+}
diff --git a/tools/intel-features/intel-pt/PTDecoder.h b/tools/intel-features/intel-pt/PTDecoder.h
new file mode 100644
index 000000000000..9eb92745a863
--- /dev/null
+++ b/tools/intel-features/intel-pt/PTDecoder.h
@@ -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_
diff --git a/tools/intel-features/intel-pt/README_CLI.txt b/tools/intel-features/intel-pt/README_CLI.txt
new file mode 100644
index 000000000000..2a497c4b3ef1
--- /dev/null
+++ b/tools/intel-features/intel-pt/README_CLI.txt
@@ -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
diff --git a/tools/intel-features/intel-pt/README_TOOL.txt b/tools/intel-features/intel-pt/README_TOOL.txt
new file mode 100644
index 000000000000..d1ec1caf73ca
--- /dev/null
+++ b/tools/intel-features/intel-pt/README_TOOL.txt
@@ -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.
diff --git a/tools/intel-features/intel-pt/cli-wrapper-pt.cpp b/tools/intel-features/intel-pt/cli-wrapper-pt.cpp
new file mode 100644
index 000000000000..1fa236cb0bc7
--- /dev/null
+++ b/tools/intel-features/intel-pt/cli-wrapper-pt.cpp
@@ -0,0 +1,583 @@
+//===-- cli-wrapper-pt.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// CLI Wrapper of PTDecoder Tool to enable it to be used through LLDB's CLI. The
+// wrapper provides a new command called processor-trace with 4 child
+// subcommands as follows:
+// processor-trace start
+// processor-trace stop
+// processor-trace show-trace-options
+// processor-trace show-instr-log
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cinttypes>
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include "PTDecoder.h"
+#include "cli-wrapper-pt.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStructuredData.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBThread.h"
+
+static bool GetProcess(lldb::SBDebugger &debugger,
+ lldb::SBCommandReturnObject &result,
+ lldb::SBProcess &process) {
+ if (!debugger.IsValid()) {
+ result.Printf("error: invalid debugger\n");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::SBTarget target = debugger.GetSelectedTarget();
+ if (!target.IsValid()) {
+ result.Printf("error: invalid target inside debugger\n");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ process = target.GetProcess();
+ if (!process.IsValid() ||
+ (process.GetState() == lldb::StateType::eStateDetached) ||
+ (process.GetState() == lldb::StateType::eStateExited) ||
+ (process.GetState() == lldb::StateType::eStateInvalid)) {
+ result.Printf("error: invalid process inside debugger's target\n");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ return true;
+}
+
+static bool ParseCommandOption(char **command,
+ lldb::SBCommandReturnObject &result,
+ uint32_t &index, const std::string &arg,
+ uint32_t &parsed_result) {
+ char *endptr;
+ if (!command[++index]) {
+ result.Printf("error: option \"%s\" requires an argument\n", arg.c_str());
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ errno = 0;
+ unsigned long output = strtoul(command[index], &endptr, 0);
+ if ((errno != 0) || (*endptr != '\0')) {
+ result.Printf("error: invalid value \"%s\" provided for option \"%s\"\n",
+ command[index], arg.c_str());
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ if (output > UINT32_MAX) {
+ result.Printf("error: value \"%s\" for option \"%s\" exceeds UINT32_MAX\n",
+ command[index], arg.c_str());
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ parsed_result = (uint32_t)output;
+ return true;
+}
+
+static bool ParseCommandArgThread(char **command,
+ lldb::SBCommandReturnObject &result,
+ lldb::SBProcess &process, uint32_t &index,
+ lldb::tid_t &thread_id) {
+ char *endptr;
+ if (!strcmp(command[index], "all"))
+ thread_id = LLDB_INVALID_THREAD_ID;
+ else {
+ uint32_t thread_index_id;
+ errno = 0;
+ unsigned long output = strtoul(command[index], &endptr, 0);
+ if ((errno != 0) || (*endptr != '\0') || (output > UINT32_MAX)) {
+ result.Printf("error: invalid thread specification: \"%s\"\n",
+ command[index]);
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ thread_index_id = (uint32_t)output;
+
+ lldb::SBThread thread = process.GetThreadByIndexID(thread_index_id);
+ if (!thread.IsValid()) {
+ result.Printf(
+ "error: process has no thread with thread specification: \"%s\"\n",
+ command[index]);
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ thread_id = thread.GetThreadID();
+ }
+ return true;
+}
+
+class ProcessorTraceStart : public lldb::SBCommandPluginInterface {
+public:
+ ProcessorTraceStart(std::shared_ptr<ptdecoder::PTDecoder> &pt_decoder)
+ : SBCommandPluginInterface(), pt_decoder_sp(pt_decoder) {}
+
+ ~ProcessorTraceStart() {}
+
+ virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
+ lldb::SBCommandReturnObject &result) {
+ lldb::SBProcess process;
+ lldb::SBThread thread;
+ if (!GetProcess(debugger, result, process))
+ return false;
+
+ // Default initialize API's arguments
+ lldb::SBTraceOptions lldb_SBTraceOptions;
+ uint32_t trace_buffer_size = m_default_trace_buff_size;
+ lldb::tid_t thread_id;
+
+ // Parse Command line options
+ bool thread_argument_provided = false;
+ if (command) {
+ for (uint32_t i = 0; command[i]; i++) {
+ if (!strcmp(command[i], "-b")) {
+ if (!ParseCommandOption(command, result, i, "-b", trace_buffer_size))
+ return false;
+ } else {
+ thread_argument_provided = true;
+ if (!ParseCommandArgThread(command, result, process, i, thread_id))
+ return false;
+ }
+ }
+ }
+
+ if (!thread_argument_provided) {
+ thread = process.GetSelectedThread();
+ if (!thread.IsValid()) {
+ result.Printf("error: invalid current selected thread\n");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ thread_id = thread.GetThreadID();
+ }
+
+ if (trace_buffer_size > m_max_trace_buff_size)
+ trace_buffer_size = m_max_trace_buff_size;
+
+ // Set API's arguments with parsed values
+ lldb_SBTraceOptions.setType(lldb::TraceType::eTraceTypeProcessorTrace);
+ lldb_SBTraceOptions.setTraceBufferSize(trace_buffer_size);
+ lldb_SBTraceOptions.setMetaDataBufferSize(0);
+ lldb_SBTraceOptions.setThreadID(thread_id);
+ lldb::SBStream sb_stream;
+ sb_stream.Printf("{\"trace-tech\":\"intel-pt\"}");
+ lldb::SBStructuredData custom_params;
+ lldb::SBError error = custom_params.SetFromJSON(sb_stream);
+ if (!error.Success()) {
+ result.Printf("error: %s\n", error.GetCString());
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ lldb_SBTraceOptions.setTraceParams(custom_params);
+
+ // Start trace
+ pt_decoder_sp->StartProcessorTrace(process, lldb_SBTraceOptions, error);
+ if (!error.Success()) {
+ result.Printf("error: %s\n", error.GetCString());
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ return true;
+ }
+
+private:
+ std::shared_ptr<ptdecoder::PTDecoder> pt_decoder_sp;
+ const uint32_t m_max_trace_buff_size = 0x3fff;
+ const uint32_t m_default_trace_buff_size = 4096;
+};
+
+class ProcessorTraceInfo : public lldb::SBCommandPluginInterface {
+public:
+ ProcessorTraceInfo(std::shared_ptr<ptdecoder::PTDecoder> &pt_decoder)
+ : SBCommandPluginInterface(), pt_decoder_sp(pt_decoder) {}
+
+ ~ProcessorTraceInfo() {}
+
+ virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
+ lldb::SBCommandReturnObject &result) {
+ lldb::SBProcess process;
+ lldb::SBThread thread;
+ if (!GetProcess(debugger, result, process))
+ return false;
+
+ lldb::tid_t thread_id;
+
+ // Parse command line options
+ bool thread_argument_provided = false;
+ if (command) {
+ for (uint32_t i = 0; command[i]; i++) {
+ thread_argument_provided = true;
+ if (!ParseCommandArgThread(command, result, process, i, thread_id))
+ return false;
+ }
+ }
+
+ if (!thread_argument_provided) {
+ thread = process.GetSelectedThread();
+ if (!thread.IsValid()) {
+ result.Printf("error: invalid current selected thread\n");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ thread_id = thread.GetThreadID();
+ }
+
+ size_t loop_count = 1;
+ bool entire_process_tracing = false;
+ if (thread_id == LLDB_INVALID_THREAD_ID) {
+ entire_process_tracing = true;
+ loop_count = process.GetNumThreads();
+ }
+
+ // Get trace information
+ lldb::SBError error;
+ lldb::SBCommandReturnObject res;
+ for (size_t i = 0; i < loop_count; i++) {
+ error.Clear();
+ res.Clear();
+
+ if (entire_process_tracing)
+ thread = process.GetThreadAtIndex(i);
+ else
+ thread = process.GetThreadByID(thread_id);
+ thread_id = thread.GetThreadID();
+
+ ptdecoder::PTTraceOptions options;
+ pt_decoder_sp->GetProcessorTraceInfo(process, thread_id, options, error);
+ if (!error.Success()) {
+ res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 ", error: %s",
+ thread.GetIndexID(), thread_id, error.GetCString());
+ result.AppendMessage(res.GetOutput());
+ continue;
+ }
+
+ lldb::SBStructuredData data = options.GetTraceParams(error);
+ if (!error.Success()) {
+ res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 ", error: %s",
+ thread.GetIndexID(), thread_id, error.GetCString());
+ result.AppendMessage(res.GetOutput());
+ continue;
+ }
+
+ lldb::SBStream s;
+ error = data.GetAsJSON(s);
+ if (!error.Success()) {
+ res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 ", error: %s",
+ thread.GetIndexID(), thread_id, error.GetCString());
+ result.AppendMessage(res.GetOutput());
+ continue;
+ }
+
+ res.Printf("thread #%" PRIu32 ": tid=%" PRIu64
+ ", trace buffer size=%" PRIu64 ", meta buffer size=%" PRIu64
+ ", trace type=%" PRIu32 ", custom trace params=%s",
+ thread.GetIndexID(), thread_id, options.GetTraceBufferSize(),
+ options.GetMetaDataBufferSize(), options.GetType(),
+ s.GetData());
+ result.AppendMessage(res.GetOutput());
+ }
+ return true;
+ }
+
+private:
+ std::shared_ptr<ptdecoder::PTDecoder> pt_decoder_sp;
+};
+
+class ProcessorTraceShowInstrLog : public lldb::SBCommandPluginInterface {
+public:
+ ProcessorTraceShowInstrLog(std::shared_ptr<ptdecoder::PTDecoder> &pt_decoder)
+ : SBCommandPluginInterface(), pt_decoder_sp(pt_decoder) {}
+
+ ~ProcessorTraceShowInstrLog() {}
+
+ virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
+ lldb::SBCommandReturnObject &result) {
+ lldb::SBProcess process;
+ lldb::SBThread thread;
+ if (!GetProcess(debugger, result, process))
+ return false;
+
+ // Default initialize API's arguments
+ uint32_t offset;
+ bool offset_provided = false;
+ uint32_t count = m_default_count;
+ lldb::tid_t thread_id;
+
+ // Parse command line options
+ bool thread_argument_provided = false;
+ if (command) {
+ for (uint32_t i = 0; command[i]; i++) {
+ if (!strcmp(command[i], "-o")) {
+ if (!ParseCommandOption(command, result, i, "-o", offset))
+ return false;
+ offset_provided = true;
+ } else if (!strcmp(command[i], "-c")) {
+ if (!ParseCommandOption(command, result, i, "-c", count))
+ return false;
+ } else {
+ thread_argument_provided = true;
+ if (!ParseCommandArgThread(command, result, process, i, thread_id))
+ return false;
+ }
+ }
+ }
+
+ if (!thread_argument_provided) {
+ thread = process.GetSelectedThread();
+ if (!thread.IsValid()) {
+ result.Printf("error: invalid current selected thread\n");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ thread_id = thread.GetThreadID();
+ }
+
+ size_t loop_count = 1;
+ bool entire_process_tracing = false;
+ if (thread_id == LLDB_INVALID_THREAD_ID) {
+ entire_process_tracing = true;
+ loop_count = process.GetNumThreads();
+ }
+
+ // Get instruction log and disassemble it
+ lldb::SBError error;
+ lldb::SBCommandReturnObject res;
+ for (size_t i = 0; i < loop_count; i++) {
+ error.Clear();
+ res.Clear();
+
+ if (entire_process_tracing)
+ thread = process.GetThreadAtIndex(i);
+ else
+ thread = process.GetThreadByID(thread_id);
+ thread_id = thread.GetThreadID();
+
+ // If offset is not provided then calculate a default offset (to display
+ // last 'count' number of instructions)
+ if (!offset_provided)
+ offset = count - 1;
+
+ // Get the instruction log
+ ptdecoder::PTInstructionList insn_list;
+ pt_decoder_sp->GetInstructionLogAtOffset(process, thread_id, offset,
+ count, insn_list, error);
+ if (!error.Success()) {
+ res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 ", error: %s",
+ thread.GetIndexID(), thread_id, error.GetCString());
+ result.AppendMessage(res.GetOutput());
+ continue;
+ }
+
+ // Disassemble the instruction log
+ std::string disassembler_command("dis -c 1 -s ");
+ res.Printf("thread #%" PRIu32 ": tid=%" PRIu64 "\n", thread.GetIndexID(),
+ thread_id);
+ lldb::SBCommandInterpreter sb_cmnd_interpreter(
+ debugger.GetCommandInterpreter());
+ lldb::SBCommandReturnObject result_obj;
+ for (size_t i = 0; i < insn_list.GetSize(); i++) {
+ ptdecoder::PTInstruction insn = insn_list.GetInstructionAtIndex(i);
+ uint64_t addr = insn.GetInsnAddress();
+ std::string error = insn.GetError();
+ if (!error.empty()) {
+ res.AppendMessage(error.c_str());
+ continue;
+ }
+
+ result_obj.Clear();
+ std::string complete_disassembler_command =
+ disassembler_command + std::to_string(addr);
+ sb_cmnd_interpreter.HandleCommand(complete_disassembler_command.c_str(),
+ result_obj, false);
+ std::string result_str(result_obj.GetOutput());
+ if (result_str.empty()) {
+ lldb::SBCommandReturnObject output;
+ output.Printf(" Disassembly not found for address: %" PRIu64, addr);
+ res.AppendMessage(output.GetOutput());
+ continue;
+ }
+
+ // LLDB's disassemble command displays assembly instructions along with
+ // the names of the functions they belong to. Parse this result to
+ // display only the assembly instructions and not the function names
+ // in an instruction log
+ std::size_t first_new_line_index = result_str.find_first_of('\n');
+ std::size_t last_new_line_index = result_str.find_last_of('\n');
+ if (first_new_line_index != last_new_line_index)
+ res.AppendMessage((result_str.substr(first_new_line_index + 1,
+ last_new_line_index -
+ first_new_line_index - 1))
+ .c_str());
+ else
+ res.AppendMessage(
+ (result_str.substr(0, result_str.length() - 1)).c_str());
+ }
+ result.AppendMessage(res.GetOutput());
+ }
+ return true;
+ }
+
+private:
+ std::shared_ptr<ptdecoder::PTDecoder> pt_decoder_sp;
+ const uint32_t m_default_count = 10;
+};
+
+class ProcessorTraceStop : public lldb::SBCommandPluginInterface {
+public:
+ ProcessorTraceStop(std::shared_ptr<ptdecoder::PTDecoder> &pt_decoder)
+ : SBCommandPluginInterface(), pt_decoder_sp(pt_decoder) {}
+
+ ~ProcessorTraceStop() {}
+
+ virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
+ lldb::SBCommandReturnObject &result) {
+ lldb::SBProcess process;
+ lldb::SBThread thread;
+ if (!GetProcess(debugger, result, process))
+ return false;
+
+ lldb::tid_t thread_id;
+
+ // Parse command line options
+ bool thread_argument_provided = false;
+ if (command) {
+ for (uint32_t i = 0; command[i]; i++) {
+ thread_argument_provided = true;
+ if (!ParseCommandArgThread(command, result, process, i, thread_id))
+ return false;
+ }
+ }
+
+ if (!thread_argument_provided) {
+ thread = process.GetSelectedThread();
+ if (!thread.IsValid()) {
+ result.Printf("error: invalid current selected thread\n");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ thread_id = thread.GetThreadID();
+ }
+
+ // Stop trace
+ lldb::SBError error;
+ pt_decoder_sp->StopProcessorTrace(process, error, thread_id);
+ if (!error.Success()) {
+ result.Printf("error: %s\n", error.GetCString());
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ return true;
+ }
+
+private:
+ std::shared_ptr<ptdecoder::PTDecoder> pt_decoder_sp;
+};
+
+bool PTPluginInitialize(lldb::SBDebugger &debugger) {
+ lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
+ lldb::SBCommand proc_trace = interpreter.AddMultiwordCommand(
+ "processor-trace", "Intel(R) Processor Trace for thread/process");
+
+ std::shared_ptr<ptdecoder::PTDecoder> PTDecoderSP(
+ new ptdecoder::PTDecoder(debugger));
+
+ lldb::SBCommandPluginInterface *proc_trace_start =
+ new ProcessorTraceStart(PTDecoderSP);
+ const char *help_proc_trace_start = "start Intel(R) Processor Trace on a "
+ "specific thread or on the whole process";
+ const char *syntax_proc_trace_start =
+ "processor-trace start <cmd-options>\n\n"
+ "\rcmd-options Usage:\n"
+ "\r processor-trace start [-b <buffer-size>] [<thread-index>]\n\n"
+ "\t\b-b <buffer-size>\n"
+ "\t size of the trace buffer to store the trace data. If not "
+ "specified then a default value will be taken\n\n"
+ "\t\b<thread-index>\n"
+ "\t thread index of the thread. If no threads are specified, "
+ "currently selected thread is taken.\n"
+ "\t Use the thread-index 'all' to start tracing the whole process\n";
+ proc_trace.AddCommand("start", proc_trace_start, help_proc_trace_start,
+ syntax_proc_trace_start);
+
+ lldb::SBCommandPluginInterface *proc_trace_stop =
+ new ProcessorTraceStop(PTDecoderSP);
+ const char *help_proc_trace_stop =
+ "stop Intel(R) Processor Trace on a specific thread or on whole process";
+ const char *syntax_proc_trace_stop =
+ "processor-trace stop <cmd-options>\n\n"
+ "\rcmd-options Usage:\n"
+ "\r processor-trace stop [<thread-index>]\n\n"
+ "\t\b<thread-index>\n"
+ "\t thread index of the thread. If no threads are specified, "
+ "currently selected thread is taken.\n"
+ "\t Use the thread-index 'all' to stop tracing the whole process\n";
+ proc_trace.AddCommand("stop", proc_trace_stop, help_proc_trace_stop,
+ syntax_proc_trace_stop);
+
+ lldb::SBCommandPluginInterface *proc_trace_show_instr_log =
+ new ProcessorTraceShowInstrLog(PTDecoderSP);
+ const char *help_proc_trace_show_instr_log =
+ "display a log of assembly instructions executed for a specific thread "
+ "or for the whole process.\n"
+ "The length of the log to be displayed and the offset in the whole "
+ "instruction log from where the log needs to be displayed can also be "
+ "provided. The offset is counted from the end of this whole "
+ "instruction log which means the last executed instruction is at offset "
+ "0 (zero)";
+ const char *syntax_proc_trace_show_instr_log =
+ "processor-trace show-instr-log <cmd-options>\n\n"
+ "\rcmd-options Usage:\n"
+ "\r processor-trace show-instr-log [-o <offset>] [-c <count>] "
+ "[<thread-index>]\n\n"
+ "\t\b-o <offset>\n"
+ "\t offset in the whole instruction log from where the log will be "
+ "displayed. If not specified then a default value will be taken\n\n"
+ "\t\b-c <count>\n"
+ "\t number of instructions to be displayed. If not specified then a "
+ "default value will be taken\n\n"
+ "\t\b<thread-index>\n"
+ "\t thread index of the thread. If no threads are specified, "
+ "currently selected thread is taken.\n"
+ "\t Use the thread-index 'all' to show instruction log for all the "
+ "threads of the process\n";
+ proc_trace.AddCommand("show-instr-log", proc_trace_show_instr_log,
+ help_proc_trace_show_instr_log,
+ syntax_proc_trace_show_instr_log);
+
+ lldb::SBCommandPluginInterface *proc_trace_options =
+ new ProcessorTraceInfo(PTDecoderSP);
+ const char *help_proc_trace_show_options =
+ "display all the information regarding Intel(R) Processor Trace for a "
+ "specific thread or for the whole process.\n"
+ "The information contains trace buffer size and configuration options"
+ " of Intel(R) Processor Trace.";
+ const char *syntax_proc_trace_show_options =
+ "processor-trace show-options <cmd-options>\n\n"
+ "\rcmd-options Usage:\n"
+ "\r processor-trace show-options [<thread-index>]\n\n"
+ "\t\b<thread-index>\n"
+ "\t thread index of the thread. If no threads are specified, "
+ "currently selected thread is taken.\n"
+ "\t Use the thread-index 'all' to display information for all threads "
+ "of the process\n";
+ proc_trace.AddCommand("show-trace-options", proc_trace_options,
+ help_proc_trace_show_options,
+ syntax_proc_trace_show_options);
+
+ return true;
+}
diff --git a/tools/intel-features/intel-pt/cli-wrapper-pt.h b/tools/intel-features/intel-pt/cli-wrapper-pt.h
new file mode 100644
index 000000000000..e2a0ee47b579
--- /dev/null
+++ b/tools/intel-features/intel-pt/cli-wrapper-pt.h
@@ -0,0 +1,13 @@
+//===-- cli-wrapper-pt.h----------------------------------*- C++ -*-==========//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// CLI Wrapper of PTDecoder Tool to enable it to be used through LLDB's CLI.
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBDebugger.h"
+
+bool PTPluginInitialize(lldb::SBDebugger &debugger);
diff --git a/tools/intel-features/intel-pt/interface/PTDecoder.i b/tools/intel-features/intel-pt/interface/PTDecoder.i
new file mode 100644
index 000000000000..f662b8ff3599
--- /dev/null
+++ b/tools/intel-features/intel-pt/interface/PTDecoder.i
@@ -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"
diff --git a/tools/intel-features/scripts/CMakeLists.txt b/tools/intel-features/scripts/CMakeLists.txt
new file mode 100644
index 000000000000..6df97a4b006d
--- /dev/null
+++ b/tools/intel-features/scripts/CMakeLists.txt
@@ -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
+ )
diff --git a/tools/intel-features/scripts/lldb-intel-features.swig b/tools/intel-features/scripts/lldb-intel-features.swig
new file mode 100644
index 000000000000..c035fb6132dd
--- /dev/null
+++ b/tools/intel-features/scripts/lldb-intel-features.swig
@@ -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"
diff --git a/tools/intel-features/scripts/python-typemaps.txt b/tools/intel-features/scripts/python-typemaps.txt
new file mode 100644
index 000000000000..888d5321393f
--- /dev/null
+++ b/tools/intel-features/scripts/python-typemaps.txt
@@ -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);
+}
diff --git a/tools/intel-mpx/CMakeLists.txt b/tools/intel-mpx/CMakeLists.txt
deleted file mode 100644
index 29ba9a1cacec..000000000000
--- a/tools/intel-mpx/CMakeLists.txt
+++ /dev/null
@@ -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)
diff --git a/tools/lldb-mi/MICmdCmdVar.cpp b/tools/lldb-mi/MICmdCmdVar.cpp
index 66b392be6bed..85f14ec29b93 100644
--- a/tools/lldb-mi/MICmdCmdVar.cpp
+++ b/tools/lldb-mi/MICmdCmdVar.cpp
@@ -509,19 +509,19 @@ bool CMICmdCmdVarUpdate::ExamineSBValueForChange(lldb::SBValue &vrwValue,
return MIstatus::success;
}
- lldb::SBType valueType = vrwValue.GetType();
-
const MIuint nChildren = vrwValue.GetNumChildren();
for (MIuint i = 0; i < nChildren; ++i) {
lldb::SBValue member = vrwValue.GetChildAtIndex(i);
if (!member.IsValid())
continue;
- if (member.GetValueDidChange()) {
- vrwbChanged = true;
- return MIstatus::success;
- } else if (ExamineSBValueForChange(member, vrwbChanged) && vrwbChanged)
- // Handle composite types (i.e. struct or arrays)
+ // skip pointers and references to avoid infinite loop
+ if (member.GetType().GetTypeFlags() &
+ (lldb::eTypeIsPointer | lldb::eTypeIsReference))
+ continue;
+
+ // Handle composite types (i.e. struct or arrays)
+ if (ExamineSBValueForChange(member, vrwbChanged) && vrwbChanged)
return MIstatus::success;
}
vrwbChanged = false;
diff --git a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
index a61244f92fc2..561fa91a0ee3 100644
--- a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
+++ b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
@@ -262,6 +262,10 @@ bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakPoint(
pEventType = "eBreakpointEventTypeIgnoreChanged";
bOk = HandleEventSBBreakpointCmn(vEvent);
break;
+ case lldb::eBreakpointEventTypeAutoContinueChanged:
+ pEventType = "eBreakpointEventTypeAutoContinueChanged";
+ bOk = HandleEventSBBreakpointCmn(vEvent);
+ break;
}
m_pLog->WriteLog(CMIUtilString::Format(
"##### An SB Breakpoint event occurred: %s", pEventType));
diff --git a/tools/lldb-mi/MIDriverMain.cpp b/tools/lldb-mi/MIDriverMain.cpp
index be01f1d97790..eda67782ad67 100644
--- a/tools/lldb-mi/MIDriverMain.cpp
+++ b/tools/lldb-mi/MIDriverMain.cpp
@@ -33,6 +33,7 @@
// Third party headers:
#include "lldb/API/SBHostOS.h"
+#include <atomic>
#include <csignal>
#include <stdio.h>
@@ -72,14 +73,13 @@ void sigint_handler(int vSigno) {
#ifdef _WIN32 // Restore handler as it is not persistent on Windows
signal(SIGINT, sigint_handler);
#endif
- static bool g_interrupt_sent = false;
+ static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
lldb::SBDebugger *pDebugger = rDriverMgr.DriverGetTheDebugger();
if (pDebugger != nullptr) {
- if (!g_interrupt_sent) {
- g_interrupt_sent = true;
+ if (!g_interrupt_sent.test_and_set()) {
pDebugger->DispatchInputInterrupt();
- g_interrupt_sent = false;
+ g_interrupt_sent.clear();
}
}
diff --git a/tools/lldb-server/CMakeLists.txt b/tools/lldb-server/CMakeLists.txt
index f8c57cb9488f..b226adb2b570 100644
--- a/tools/lldb-server/CMakeLists.txt
+++ b/tools/lldb-server/CMakeLists.txt
@@ -24,41 +24,6 @@ endif ()
include_directories(../../source)
-set(LLDB_SYSTEM_LIBS)
-if (NOT LLDB_DISABLE_LIBEDIT)
- list(APPEND LLDB_SYSTEM_LIBS edit)
-endif()
-if (NOT LLDB_DISABLE_CURSES)
- list(APPEND LLDB_SYSTEM_LIBS ${CURSES_LIBRARIES})
- if(LLVM_ENABLE_TERMINFO AND HAVE_TERMINFO)
- list(APPEND LLDB_SYSTEM_LIBS ${TERMINFO_LIBS})
- endif()
-endif()
-
-if (NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB )
- list(APPEND LLDB_SYSTEM_LIBS atomic)
-endif()
-
-# On FreeBSD/NetBSD backtrace() is provided by libexecinfo, not libc.
-if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR CMAKE_SYSTEM_NAME MATCHES "NetBSD")
- list(APPEND LLDB_SYSTEM_LIBS execinfo)
-endif()
-
-if (NOT LLDB_DISABLE_PYTHON AND NOT LLVM_BUILD_STATIC)
- list(APPEND LLDB_SYSTEM_LIBS ${PYTHON_LIBRARIES})
-endif()
-
-list(APPEND LLDB_SYSTEM_LIBS ${system_libs})
-
-if (LLVM_BUILD_STATIC)
- if (NOT LLDB_DISABLE_PYTHON)
- list(APPEND LLDB_SYSTEM_LIBS python2.7 util)
- endif()
- if (NOT LLDB_DISABLE_CURSES)
- list(APPEND LLDB_SYSTEM_LIBS gpm)
- endif()
-endif()
-
set(LLDB_PLUGINS)
if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
@@ -89,4 +54,4 @@ add_lldb_tool(lldb-server INCLUDE_IN_FRAMEWORK
Support
)
-target_link_libraries(lldb-server ${LLDB_SYSTEM_LIBS})
+target_link_libraries(lldb-server PRIVATE ${LLDB_SYSTEM_LIBS})
diff --git a/tools/lldb-server/lldb-gdbserver.cpp b/tools/lldb-server/lldb-gdbserver.cpp
index f1a9b113c8ee..810cb92e4ffc 100644
--- a/tools/lldb-server/lldb-gdbserver.cpp
+++ b/tools/lldb-server/lldb-gdbserver.cpp
@@ -106,6 +106,7 @@ static struct option g_long_options[] = {
// than llgs listening for a connection from address on port.
{"setsid", no_argument, NULL,
'S'}, // Call setsid() to make llgs run in its own session.
+ {"fd", required_argument, NULL, 'F'},
{NULL, 0, NULL, 0}};
//----------------------------------------------------------------------
@@ -132,13 +133,13 @@ static void display_usage(const char *progname, const char *subcommand) {
"[--log-file log-file-name] "
"[--log-channels log-channel-list] "
"[--setsid] "
+ "[--fd file-descriptor]"
"[--named-pipe named-pipe-path] "
"[--native-regs] "
"[--attach pid] "
"[[HOST]:PORT] "
"[-- PROGRAM ARG1 ARG2 ...]\n",
progname, subcommand);
- exit(0);
}
void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server,
@@ -176,27 +177,28 @@ void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server,
void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, int argc,
const char *const argv[]) {
- Status error;
- error = gdb_server.SetLaunchArguments(argv, argc);
- if (error.Fail()) {
- fprintf(stderr, "error: failed to set launch args for '%s': %s\n", argv[0],
- error.AsCString());
+ ProcessLaunchInfo info;
+ info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug |
+ eLaunchFlagDisableASLR);
+ info.SetArguments(const_cast<const char **>(argv), true);
+
+ llvm::SmallString<64> cwd;
+ if (std::error_code ec = llvm::sys::fs::current_path(cwd)) {
+ llvm::errs() << "Error getting current directory: " << ec.message() << "\n";
exit(1);
}
+ info.SetWorkingDirectory(FileSpec(cwd, true));
- unsigned int launch_flags = eLaunchFlagStopAtEntry | eLaunchFlagDebug;
+ StringList env;
+ Host::GetEnvironment(env);
+ info.GetEnvironmentEntries() = Args(env);
- error = gdb_server.SetLaunchFlags(launch_flags);
- if (error.Fail()) {
- fprintf(stderr, "error: failed to set launch flags for '%s': %s\n", argv[0],
- error.AsCString());
- exit(1);
- }
+ gdb_server.SetLaunchInfo(info);
- error = gdb_server.LaunchProcess();
+ Status error = gdb_server.LaunchProcess();
if (error.Fail()) {
- fprintf(stderr, "error: failed to launch '%s': %s\n", argv[0],
- error.AsCString());
+ llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n",
+ argv[0], error);
exit(1);
}
}
@@ -232,10 +234,34 @@ void ConnectToRemote(MainLoop &mainloop,
GDBRemoteCommunicationServerLLGS &gdb_server,
bool reverse_connect, const char *const host_and_port,
const char *const progname, const char *const subcommand,
- const char *const named_pipe_path, int unnamed_pipe_fd) {
+ const char *const named_pipe_path, int unnamed_pipe_fd,
+ int connection_fd) {
Status error;
- if (host_and_port && host_and_port[0]) {
+ std::unique_ptr<Connection> connection_up;
+ if (connection_fd != -1) {
+ // Build the connection string.
+ char connection_url[512];
+ snprintf(connection_url, sizeof(connection_url), "fd://%d", connection_fd);
+
+ // Create the connection.
+#if !defined LLDB_DISABLE_POSIX && !defined _WIN32
+ ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC);
+#endif
+ connection_up.reset(new ConnectionFileDescriptor);
+ auto connection_result = connection_up->Connect(connection_url, &error);
+ if (connection_result != eConnectionStatusSuccess) {
+ fprintf(stderr, "error: failed to connect to client at '%s' "
+ "(connection status: %d)\n",
+ connection_url, static_cast<int>(connection_result));
+ exit(-1);
+ }
+ if (error.Fail()) {
+ fprintf(stderr, "error: failed to connect to client at '%s': %s\n",
+ connection_url, error.AsCString());
+ exit(-1);
+ }
+ } else if (host_and_port && host_and_port[0]) {
// Parse out host and port.
std::string final_host_and_port;
std::string connection_host;
@@ -255,7 +281,6 @@ void ConnectToRemote(MainLoop &mainloop,
connection_portno = StringConvert::ToUInt32(connection_port.c_str(), 0);
}
- std::unique_ptr<Connection> connection_up;
if (reverse_connect) {
// llgs will connect to the gdb-remote client.
@@ -263,7 +288,7 @@ void ConnectToRemote(MainLoop &mainloop,
// Ensure we have a port number for the connection.
if (connection_portno == 0) {
fprintf(stderr, "error: port number must be specified on when using "
- "reverse connect");
+ "reverse connect\n");
exit(1);
}
@@ -277,12 +302,12 @@ void ConnectToRemote(MainLoop &mainloop,
auto connection_result = connection_up->Connect(connection_url, &error);
if (connection_result != eConnectionStatusSuccess) {
fprintf(stderr, "error: failed to connect to client at '%s' "
- "(connection status: %d)",
+ "(connection status: %d)\n",
connection_url, static_cast<int>(connection_result));
exit(-1);
}
if (error.Fail()) {
- fprintf(stderr, "error: failed to connect to client at '%s': %s",
+ fprintf(stderr, "error: failed to connect to client at '%s': %s\n",
connection_url, error.AsCString());
exit(-1);
}
@@ -290,7 +315,7 @@ void ConnectToRemote(MainLoop &mainloop,
std::unique_ptr<Acceptor> acceptor_up(
Acceptor::Create(final_host_and_port, false, error));
if (error.Fail()) {
- fprintf(stderr, "failed to create acceptor: %s", error.AsCString());
+ fprintf(stderr, "failed to create acceptor: %s\n", error.AsCString());
exit(1);
}
error = acceptor_up->Listen(1);
@@ -304,7 +329,7 @@ void ConnectToRemote(MainLoop &mainloop,
if (named_pipe_path && named_pipe_path[0]) {
error = writeSocketIdToPipe(named_pipe_path, socket_id);
if (error.Fail())
- fprintf(stderr, "failed to write to the named pipe \'%s\': %s",
+ fprintf(stderr, "failed to write to the named pipe \'%s\': %s\n",
named_pipe_path, error.AsCString());
}
// If we have an unnamed pipe to write the socket id back to, do that
@@ -312,7 +337,7 @@ void ConnectToRemote(MainLoop &mainloop,
else if (unnamed_pipe_fd >= 0) {
error = writeSocketIdToPipe(unnamed_pipe_fd, socket_id);
if (error.Fail())
- fprintf(stderr, "failed to write to the unnamed pipe: %s",
+ fprintf(stderr, "failed to write to the unnamed pipe: %s\n",
error.AsCString());
}
} else {
@@ -328,14 +353,14 @@ void ConnectToRemote(MainLoop &mainloop,
}
connection_up.reset(conn);
}
- error = gdb_server.InitializeConnection(std::move(connection_up));
- if (error.Fail()) {
- fprintf(stderr, "Failed to initialize connection: %s\n",
- error.AsCString());
- exit(-1);
- }
- printf("Connection established.\n");
}
+ error = gdb_server.InitializeConnection(std::move(connection_up));
+ if (error.Fail()) {
+ fprintf(stderr, "Failed to initialize connection: %s\n",
+ error.AsCString());
+ exit(-1);
+ }
+ printf("Connection established.\n");
}
//----------------------------------------------------------------------
@@ -364,6 +389,7 @@ int main_gdbserver(int argc, char *argv[]) {
log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
int unnamed_pipe_fd = -1;
bool reverse_connect = false;
+ int connection_fd = -1;
// ProcessLaunchInfo launch_info;
ProcessAttachInfo attach_info;
@@ -413,6 +439,10 @@ int main_gdbserver(int argc, char *argv[]) {
reverse_connect = true;
break;
+ case 'F':
+ connection_fd = StringConvert::ToUInt32(optarg, -1);
+ break;
+
#ifndef _WIN32
case 'S':
// Put llgs into a new session. Terminals group processes
@@ -472,7 +502,8 @@ int main_gdbserver(int argc, char *argv[]) {
argc -= optind;
argv += optind;
- if (argc == 0) {
+ if (argc == 0 && connection_fd == -1) {
+ fputs("No arguments\n", stderr);
display_usage(progname, subcommand);
exit(255);
}
@@ -501,7 +532,7 @@ int main_gdbserver(int argc, char *argv[]) {
ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port,
progname, subcommand, named_pipe_path.c_str(),
- unnamed_pipe_fd);
+ unnamed_pipe_fd, connection_fd);
if (!gdb_server.IsConnected()) {
fprintf(stderr, "no connection information provided, unable to run\n");
diff --git a/tools/lldb-test/CMakeLists.txt b/tools/lldb-test/CMakeLists.txt
new file mode 100644
index 000000000000..2ab1ceacdcd1
--- /dev/null
+++ b/tools/lldb-test/CMakeLists.txt
@@ -0,0 +1,27 @@
+get_property(LLDB_ALL_PLUGINS GLOBAL PROPERTY LLDB_PLUGINS)
+
+add_lldb_tool(lldb-test
+ FormatUtil.cpp
+ lldb-test.cpp
+ SystemInitializerTest.cpp
+
+ LINK_LIBS
+ lldbBase
+ lldbBreakpoint
+ lldbCore
+ lldbDataFormatters
+ lldbExpression
+ lldbHost
+ lldbInitialization
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ lldbUtility
+ ${LLDB_ALL_PLUGINS}
+ ${host_lib}
+
+ LINK_COMPONENTS
+ Support
+ )
+
+include_directories(${LLDB_SOURCE_DIR}/source)
diff --git a/tools/lldb-test/FormatUtil.cpp b/tools/lldb-test/FormatUtil.cpp
new file mode 100644
index 000000000000..381cbd6e25b8
--- /dev/null
+++ b/tools/lldb-test/FormatUtil.cpp
@@ -0,0 +1,69 @@
+//===- FormatUtil.cpp ----------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatUtil.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace lldb_private;
+using namespace llvm;
+
+LinePrinter::LinePrinter(int Indent, llvm::raw_ostream &Stream)
+ : OS(Stream), IndentSpaces(Indent), CurrentIndent(0) {}
+
+void LinePrinter::Indent(uint32_t Amount) {
+ if (Amount == 0)
+ Amount = IndentSpaces;
+ CurrentIndent += Amount;
+}
+
+void LinePrinter::Unindent(uint32_t Amount) {
+ if (Amount == 0)
+ Amount = IndentSpaces;
+ CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
+}
+
+void LinePrinter::NewLine() {
+ OS << "\n";
+ OS.indent(CurrentIndent);
+}
+
+void LinePrinter::print(const Twine &T) { OS << T; }
+
+void LinePrinter::printLine(const Twine &T) {
+ NewLine();
+ OS << T;
+}
+
+void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+ uint32_t StartOffset) {
+ NewLine();
+ OS << Label << " (";
+ if (!Data.empty()) {
+ OS << "\n";
+ OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ NewLine();
+ }
+ OS << ")";
+}
+
+void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+ uint64_t Base, uint32_t StartOffset) {
+ NewLine();
+ OS << Label << " (";
+ if (!Data.empty()) {
+ OS << "\n";
+ Base += StartOffset;
+ OS << format_bytes_with_ascii(Data, Base, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ NewLine();
+ }
+ OS << ")";
+}
diff --git a/tools/lldb-test/FormatUtil.h b/tools/lldb-test/FormatUtil.h
new file mode 100644
index 000000000000..f22ee41662ee
--- /dev/null
+++ b/tools/lldb-test/FormatUtil.h
@@ -0,0 +1,75 @@
+//===- FormatUtil.h ------------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLDBTEST_FORMATUTIL_H
+#define LLVM_TOOLS_LLDBTEST_FORMATUTIL_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <list>
+
+namespace lldb_private {
+
+class LinePrinter {
+ llvm::raw_ostream &OS;
+ int IndentSpaces;
+ int CurrentIndent;
+
+public:
+ LinePrinter(int Indent, llvm::raw_ostream &Stream);
+
+ void Indent(uint32_t Amount = 0);
+ void Unindent(uint32_t Amount = 0);
+ void NewLine();
+
+ void printLine(const llvm::Twine &T);
+ void print(const llvm::Twine &T);
+ template <typename... Ts> void formatLine(const char *Fmt, Ts &&... Items) {
+ printLine(llvm::formatv(Fmt, std::forward<Ts>(Items)...));
+ }
+ template <typename... Ts> void format(const char *Fmt, Ts &&... Items) {
+ print(llvm::formatv(Fmt, std::forward<Ts>(Items)...));
+ }
+
+ void formatBinary(llvm::StringRef Label, llvm::ArrayRef<uint8_t> Data,
+ uint32_t StartOffset);
+ void formatBinary(llvm::StringRef Label, llvm::ArrayRef<uint8_t> Data,
+ uint64_t BaseAddr, uint32_t StartOffset);
+
+ llvm::raw_ostream &getStream() { return OS; }
+ int getIndentLevel() const { return CurrentIndent; }
+};
+
+struct AutoIndent {
+ explicit AutoIndent(LinePrinter &L, uint32_t Amount = 0)
+ : L(&L), Amount(Amount) {
+ L.Indent(Amount);
+ }
+ ~AutoIndent() {
+ if (L)
+ L->Unindent(Amount);
+ }
+
+ LinePrinter *L = nullptr;
+ uint32_t Amount = 0;
+};
+
+template <class T>
+inline llvm::raw_ostream &operator<<(LinePrinter &Printer, const T &Item) {
+ Printer.getStream() << Item;
+ return Printer.getStream();
+}
+
+} // namespace lldb_private
+
+#endif
diff --git a/tools/lldb-test/SystemInitializerTest.cpp b/tools/lldb-test/SystemInitializerTest.cpp
new file mode 100644
index 000000000000..cae395e133ee
--- /dev/null
+++ b/tools/lldb-test/SystemInitializerTest.cpp
@@ -0,0 +1,345 @@
+//===-- SystemInitializerTest.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemInitializerTest.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Initialization/SystemInitializerCommon.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/GoASTContext.h"
+#include "lldb/Symbol/JavaASTContext.h"
+#include "lldb/Symbol/OCamlASTContext.h"
+#include "lldb/Utility/Timer.h"
+
+#include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h"
+#include "Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h"
+#include "Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h"
+#include "Plugins/ABI/SysV-arm/ABISysV_arm.h"
+#include "Plugins/ABI/SysV-arm64/ABISysV_arm64.h"
+#include "Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h"
+#include "Plugins/ABI/SysV-i386/ABISysV_i386.h"
+#include "Plugins/ABI/SysV-mips/ABISysV_mips.h"
+#include "Plugins/ABI/SysV-mips64/ABISysV_mips64.h"
+#include "Plugins/ABI/SysV-ppc/ABISysV_ppc.h"
+#include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h"
+#include "Plugins/ABI/SysV-s390x/ABISysV_s390x.h"
+#include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h"
+#include "Plugins/Architecture/Arm/ArchitectureArm.h"
+#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
+#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h"
+#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
+#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
+#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
+#include "Plugins/InstrumentationRuntime/ASan/ASanRuntime.h"
+#include "Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h"
+#include "Plugins/InstrumentationRuntime/TSan/TSanRuntime.h"
+#include "Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h"
+#include "Plugins/JITLoader/GDB/JITLoaderGDB.h"
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/Language/Go/GoLanguage.h"
+#include "Plugins/Language/Java/JavaLanguage.h"
+#include "Plugins/Language/OCaml/OCamlLanguage.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
+#include "Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h"
+#include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h"
+#include "Plugins/LanguageRuntime/Go/GoLanguageRuntime.h"
+#include "Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h"
+#include "Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h"
+#include "Plugins/MemoryHistory/asan/MemoryHistoryASan.h"
+#include "Plugins/OperatingSystem/Go/OperatingSystemGo.h"
+#include "Plugins/Platform/Android/PlatformAndroid.h"
+#include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h"
+#include "Plugins/Platform/Kalimba/PlatformKalimba.h"
+#include "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
+#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
+#include "Plugins/Platform/NetBSD/PlatformNetBSD.h"
+#include "Plugins/Platform/OpenBSD/PlatformOpenBSD.h"
+#include "Plugins/Platform/Windows/PlatformWindows.h"
+#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+#include "Plugins/Process/minidump/ProcessMinidump.h"
+#include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
+#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h"
+#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
+#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
+
+#if defined(__APPLE__)
+#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
+#include "Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h"
+#include "Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h"
+#include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h"
+#include "Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h"
+#include "Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h"
+#include "Plugins/Platform/MacOSX/PlatformiOSSimulator.h"
+#include "Plugins/Process/MacOSX-Kernel/ProcessKDP.h"
+#include "Plugins/Process/mach-core/ProcessMachCore.h"
+#include "Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h"
+#endif
+#include "Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h"
+
+#if defined(__FreeBSD__)
+#include "Plugins/Process/FreeBSD/ProcessFreeBSD.h"
+#endif
+
+#if defined(_WIN32)
+#include "Plugins/Process/Windows/Common/ProcessWindows.h"
+#include "lldb/Host/windows/windows.h"
+#endif
+
+#include "llvm/Support/TargetSelect.h"
+
+#include <string>
+
+using namespace lldb_private;
+
+SystemInitializerTest::SystemInitializerTest() {}
+
+SystemInitializerTest::~SystemInitializerTest() {}
+
+void SystemInitializerTest::Initialize() {
+ SystemInitializerCommon::Initialize();
+ ScriptInterpreterNone::Initialize();
+
+ OperatingSystemGo::Initialize();
+
+ platform_freebsd::PlatformFreeBSD::Initialize();
+ platform_linux::PlatformLinux::Initialize();
+ platform_netbsd::PlatformNetBSD::Initialize();
+ platform_openbsd::PlatformOpenBSD::Initialize();
+ PlatformWindows::Initialize();
+ PlatformKalimba::Initialize();
+ platform_android::PlatformAndroid::Initialize();
+ PlatformRemoteiOS::Initialize();
+ PlatformMacOSX::Initialize();
+#if defined(__APPLE__)
+ PlatformiOSSimulator::Initialize();
+ PlatformDarwinKernel::Initialize();
+#endif
+
+ // Initialize LLVM and Clang
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllDisassemblers();
+
+ ClangASTContext::Initialize();
+ GoASTContext::Initialize();
+ JavaASTContext::Initialize();
+ OCamlASTContext::Initialize();
+
+ ABIMacOSX_i386::Initialize();
+ ABIMacOSX_arm::Initialize();
+ ABIMacOSX_arm64::Initialize();
+ ABISysV_arm::Initialize();
+ ABISysV_arm64::Initialize();
+ ABISysV_hexagon::Initialize();
+ ABISysV_i386::Initialize();
+ ABISysV_x86_64::Initialize();
+ ABISysV_ppc::Initialize();
+ ABISysV_ppc64::Initialize();
+ ABISysV_mips::Initialize();
+ ABISysV_mips64::Initialize();
+ ABISysV_s390x::Initialize();
+
+ ArchitectureArm::Initialize();
+
+ DisassemblerLLVMC::Initialize();
+
+ JITLoaderGDB::Initialize();
+ ProcessElfCore::Initialize();
+ minidump::ProcessMinidump::Initialize();
+ MemoryHistoryASan::Initialize();
+ AddressSanitizerRuntime::Initialize();
+ ThreadSanitizerRuntime::Initialize();
+ UndefinedBehaviorSanitizerRuntime::Initialize();
+ MainThreadCheckerRuntime::Initialize();
+
+ SymbolVendorELF::Initialize();
+ SymbolFileDWARF::Initialize();
+ SymbolFilePDB::Initialize();
+ SymbolFileSymtab::Initialize();
+ UnwindAssemblyInstEmulation::Initialize();
+ UnwindAssembly_x86::Initialize();
+ EmulateInstructionARM64::Initialize();
+ SymbolFileDWARFDebugMap::Initialize();
+ ItaniumABILanguageRuntime::Initialize();
+ AppleObjCRuntimeV2::Initialize();
+ AppleObjCRuntimeV1::Initialize();
+ SystemRuntimeMacOSX::Initialize();
+ RenderScriptRuntime::Initialize();
+ GoLanguageRuntime::Initialize();
+ JavaLanguageRuntime::Initialize();
+
+ CPlusPlusLanguage::Initialize();
+ GoLanguage::Initialize();
+ JavaLanguage::Initialize();
+ ObjCLanguage::Initialize();
+ ObjCPlusPlusLanguage::Initialize();
+ OCamlLanguage::Initialize();
+
+#if defined(_WIN32)
+ ProcessWindows::Initialize();
+#endif
+#if defined(__FreeBSD__)
+ ProcessFreeBSD::Initialize();
+#endif
+#if defined(__APPLE__)
+ SymbolVendorMacOSX::Initialize();
+ ProcessKDP::Initialize();
+ ProcessMachCore::Initialize();
+ PlatformAppleTVSimulator::Initialize();
+ PlatformAppleWatchSimulator::Initialize();
+ PlatformRemoteAppleTV::Initialize();
+ PlatformRemoteAppleWatch::Initialize();
+ DynamicLoaderDarwinKernel::Initialize();
+#endif
+
+ // This plugin is valid on any host that talks to a Darwin remote.
+ // It shouldn't be limited to __APPLE__.
+ StructuredDataDarwinLog::Initialize();
+
+ //----------------------------------------------------------------------
+ // Platform agnostic plugins
+ //----------------------------------------------------------------------
+ platform_gdb_server::PlatformRemoteGDBServer::Initialize();
+
+ process_gdb_remote::ProcessGDBRemote::Initialize();
+ DynamicLoaderMacOSXDYLD::Initialize();
+ DynamicLoaderMacOS::Initialize();
+ DynamicLoaderPOSIXDYLD::Initialize();
+ DynamicLoaderStatic::Initialize();
+ DynamicLoaderWindowsDYLD::Initialize();
+
+ // Scan for any system or user LLDB plug-ins
+ PluginManager::Initialize();
+
+ // The process settings need to know about installed plug-ins, so the Settings
+ // must be initialized
+ // AFTER PluginManager::Initialize is called.
+
+ Debugger::SettingsInitialize();
+}
+
+void SystemInitializerTest::Terminate() {
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
+
+ Debugger::SettingsTerminate();
+
+ // Terminate and unload and loaded system or user LLDB plug-ins
+ PluginManager::Terminate();
+
+ ClangASTContext::Terminate();
+ GoASTContext::Terminate();
+ JavaASTContext::Terminate();
+ OCamlASTContext::Terminate();
+
+ ABIMacOSX_i386::Terminate();
+ ABIMacOSX_arm::Terminate();
+ ABIMacOSX_arm64::Terminate();
+ ABISysV_arm::Terminate();
+ ABISysV_arm64::Terminate();
+ ABISysV_hexagon::Terminate();
+ ABISysV_i386::Terminate();
+ ABISysV_x86_64::Terminate();
+ ABISysV_ppc::Terminate();
+ ABISysV_ppc64::Terminate();
+ ABISysV_mips::Terminate();
+ ABISysV_mips64::Terminate();
+ ABISysV_s390x::Terminate();
+ DisassemblerLLVMC::Terminate();
+
+ JITLoaderGDB::Terminate();
+ ProcessElfCore::Terminate();
+ minidump::ProcessMinidump::Terminate();
+ MemoryHistoryASan::Terminate();
+ AddressSanitizerRuntime::Terminate();
+ ThreadSanitizerRuntime::Terminate();
+ UndefinedBehaviorSanitizerRuntime::Terminate();
+ MainThreadCheckerRuntime::Terminate();
+ SymbolVendorELF::Terminate();
+ SymbolFileDWARF::Terminate();
+ SymbolFilePDB::Terminate();
+ SymbolFileSymtab::Terminate();
+ UnwindAssembly_x86::Terminate();
+ UnwindAssemblyInstEmulation::Terminate();
+ EmulateInstructionARM64::Terminate();
+ SymbolFileDWARFDebugMap::Terminate();
+ ItaniumABILanguageRuntime::Terminate();
+ AppleObjCRuntimeV2::Terminate();
+ AppleObjCRuntimeV1::Terminate();
+ SystemRuntimeMacOSX::Terminate();
+ RenderScriptRuntime::Terminate();
+ JavaLanguageRuntime::Terminate();
+
+ CPlusPlusLanguage::Terminate();
+ GoLanguage::Terminate();
+ JavaLanguage::Terminate();
+ ObjCLanguage::Terminate();
+ ObjCPlusPlusLanguage::Terminate();
+ OCamlLanguage::Terminate();
+
+#if defined(__APPLE__)
+ DynamicLoaderDarwinKernel::Terminate();
+ ProcessMachCore::Terminate();
+ ProcessKDP::Terminate();
+ SymbolVendorMacOSX::Terminate();
+ PlatformAppleTVSimulator::Terminate();
+ PlatformAppleWatchSimulator::Terminate();
+ PlatformRemoteAppleTV::Terminate();
+ PlatformRemoteAppleWatch::Terminate();
+#endif
+
+#if defined(__FreeBSD__)
+ ProcessFreeBSD::Terminate();
+#endif
+ Debugger::SettingsTerminate();
+
+ platform_gdb_server::PlatformRemoteGDBServer::Terminate();
+ process_gdb_remote::ProcessGDBRemote::Terminate();
+ StructuredDataDarwinLog::Terminate();
+
+ DynamicLoaderMacOSXDYLD::Terminate();
+ DynamicLoaderMacOS::Terminate();
+ DynamicLoaderPOSIXDYLD::Terminate();
+ DynamicLoaderStatic::Terminate();
+ DynamicLoaderWindowsDYLD::Terminate();
+
+ OperatingSystemGo::Terminate();
+
+ platform_freebsd::PlatformFreeBSD::Terminate();
+ platform_linux::PlatformLinux::Terminate();
+ platform_netbsd::PlatformNetBSD::Terminate();
+ platform_openbsd::PlatformOpenBSD::Terminate();
+ PlatformWindows::Terminate();
+ PlatformKalimba::Terminate();
+ platform_android::PlatformAndroid::Terminate();
+ PlatformMacOSX::Terminate();
+ PlatformRemoteiOS::Terminate();
+#if defined(__APPLE__)
+ PlatformiOSSimulator::Terminate();
+ PlatformDarwinKernel::Terminate();
+#endif
+
+ // Now shutdown the common parts, in reverse order.
+ SystemInitializerCommon::Terminate();
+}
diff --git a/tools/lldb-test/SystemInitializerTest.h b/tools/lldb-test/SystemInitializerTest.h
new file mode 100644
index 000000000000..887d6243765d
--- /dev/null
+++ b/tools/lldb-test/SystemInitializerTest.h
@@ -0,0 +1,35 @@
+//===-- SystemInitializerTest.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_API_SYSTEM_INITIALIZER_TEST_H
+#define LLDB_API_SYSTEM_INITIALIZER_TEST_H
+
+#include "lldb/Initialization/SystemInitializerCommon.h"
+
+namespace lldb_private {
+//------------------------------------------------------------------
+/// Initializes lldb.
+///
+/// This class is responsible for initializing all of lldb system
+/// services needed to use the full LLDB application. This class is
+/// not intended to be used externally, but is instead used
+/// internally by SBDebugger to initialize the system.
+//------------------------------------------------------------------
+class SystemInitializerTest : public SystemInitializerCommon {
+public:
+ SystemInitializerTest();
+ ~SystemInitializerTest() override;
+
+ void Initialize() override;
+ void Terminate() override;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_API_SYSTEM_INITIALIZER_FULL_H
diff --git a/tools/lldb-test/lldb-test.cpp b/tools/lldb-test/lldb-test.cpp
new file mode 100644
index 000000000000..1fe2f5b63859
--- /dev/null
+++ b/tools/lldb-test/lldb-test.cpp
@@ -0,0 +1,126 @@
+//===- lldb-test.cpp ------------------------------------------ *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatUtil.h"
+#include "SystemInitializerTest.h"
+
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Initialization/SystemLifetimeManager.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include <thread>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm;
+
+namespace opts {
+cl::SubCommand ModuleSubcommand("module-sections",
+ "Display LLDB Module Information");
+cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file");
+
+namespace module {
+cl::opt<bool> SectionContents("contents",
+ cl::desc("Dump each section's contents"),
+ cl::sub(ModuleSubcommand));
+cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
+ cl::OneOrMore, cl::sub(ModuleSubcommand));
+} // namespace module
+
+namespace symbols {
+cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
+ cl::OneOrMore, cl::sub(SymbolsSubcommand));
+}
+} // namespace opts
+
+static llvm::ManagedStatic<SystemLifetimeManager> DebuggerLifetime;
+
+static void dumpSymbols(Debugger &Dbg) {
+ for (const auto &File : opts::symbols::InputFilenames) {
+ ModuleSpec Spec{FileSpec(File, false)};
+ Spec.GetSymbolFileSpec().SetFile(File, false);
+
+ auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
+
+ StreamString Stream;
+ ModulePtr->ParseAllDebugSymbols();
+ ModulePtr->Dump(&Stream);
+ llvm::outs() << Stream.GetData() << "\n";
+ llvm::outs().flush();
+ }
+}
+
+static void dumpModules(Debugger &Dbg) {
+ LinePrinter Printer(4, llvm::outs());
+
+ for (const auto &File : opts::module::InputFilenames) {
+ ModuleSpec Spec{FileSpec(File, false)};
+ Spec.GetSymbolFileSpec().SetFile(File, false);
+
+ auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
+ SectionList *Sections = ModulePtr->GetSectionList();
+ if (!Sections) {
+ llvm::errs() << "Could not load sections for module " << File << "\n";
+ continue;
+ }
+
+ size_t Count = Sections->GetNumSections(0);
+ Printer.formatLine("Showing {0} sections", Count);
+ for (size_t I = 0; I < Count; ++I) {
+ AutoIndent Indent(Printer, 2);
+ auto S = Sections->GetSectionAtIndex(I);
+ assert(S);
+ Printer.formatLine("Index: {0}", I);
+ Printer.formatLine("Name: {0}", S->GetName().GetStringRef());
+ Printer.formatLine("VM size: {0}", S->GetByteSize());
+ Printer.formatLine("File size: {0}", S->GetFileSize());
+
+ if (opts::module::SectionContents) {
+ DataExtractor Data;
+ S->GetSectionData(Data);
+ ArrayRef<uint8_t> Bytes = {Data.GetDataStart(), Data.GetDataEnd()};
+ Printer.formatBinary("Data: ", Bytes, 0);
+ }
+ Printer.NewLine();
+ }
+ }
+}
+
+int main(int argc, const char *argv[]) {
+ StringRef ToolName = argv[0];
+ sys::PrintStackTraceOnErrorSignal(ToolName);
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y;
+
+ cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
+
+ DebuggerLifetime->Initialize(llvm::make_unique<SystemInitializerTest>(),
+ nullptr);
+
+ auto Dbg = lldb_private::Debugger::CreateInstance();
+
+ if (opts::ModuleSubcommand)
+ dumpModules(*Dbg);
+ else if (opts::SymbolsSubcommand)
+ dumpSymbols(*Dbg);
+
+ DebuggerLifetime->Terminate();
+ return 0;
+}